GPS map / tracker

Hi Team,

Im trying to set up a simple map widget with Blynk2.0 and using my ESP32 and gps module but nothing works.
Every post on this forum about the code for this widget is different every time and none seem to work or they haven’t posted their complete code for me to see.

Please Can someone please tell me what I’m doing wrong?

#include <TinyGPSPlus.h>
#include <SoftwareSerial.h>

// Fill-in information from your Blynk Template here
#define BLYNK_TEMPLATE_ID "***************"
#define BLYNK_DEVICE_NAME "**************"

#define BLYNK_FIRMWARE_VERSION        "0.1.0"

#define BLYNK_PRINT Serial
//#define BLYNK_DEBUG

#define APP_DEBUG

// Uncomment your board, or configure a custom board in Settings.h
//#define USE_WROVER_BOARD
//#define USE_TTGO_T7

#include "BlynkEdgent.h"

static const int RXPin = 3, TXPin = 1;
static const uint32_t GPSBaud = 4800;

TinyGPSPlus gps;

WidgetMap myMap(V1);

SoftwareSerial ss(RXPin, TXPin);

void setup()
{
  Serial.begin(9600);
  delay(100);

  ss.begin(GPSBaud);

  BlynkEdgent.begin();

  int index = 0;
  float lat = 51.5074;
  float lon = 0.1278;
  
  Blynk.virtualWrite(V1,lon, lat, "GPS");
}

void loop() {
  BlynkEdgent.run();

}

void displayInfo()
{
  Serial.print(F("Location: ")); 
  if (gps.location.isValid())
  {
    Serial.print(gps.location.lat(), 6);
    Serial.print(F(","));
    Serial.print(gps.location.lng(), 6);
  }
  else
  {
    Serial.print(F("INVALID"));
  }
    Serial.println();
}

To begin with, these needs to the the first lines of your sketch…

Secondly, placing a Blynk.virtualWrite in your void setup is very unlikely to work. If you want to do this once only at startup then you should put this command in a BLYNK_CONNECTED function.

Pete.

Hi Pete, Ok changed that now but I dont see how it made a difference, my device still connected and linked up from what the web console was displaying.

I did originally just have “myMap.location(index, lat, lon, “value”);”
here in the void setup exactly as the blynk example generator said to but I came across a comment from you on another map project and you said you recommended using “Blynk.virtualWrite”.

Ok what Blynk connected function should I be using? would hugely appreciated if you can just show me exactly what I need to put into my sketch to make it work.

Im not using the legacy app either im using the new IOT app version.

Please help me here.

Hi, I have had success with this approach:

double latID = 0;
double lonID = 0;

...

void getGPS() {

  String line1, line2;
  
// Using Sparkfun GPS module
  myGNSS.checkUblox(); //See if new data is available. Process bytes as they come in.

  if(nmea.isValid() == true) // if valid data go get it
  {
    long latitude_mdeg = nmea.getLatitude();
    long longitude_mdeg = nmea.getLongitude();
   
    latI = latitude_mdeg / 1000000.;
    lonI = longitude_mdeg / 1000000.;
    
    latID = latitude_mdeg/1000000.;
    lonID = longitude_mdeg/1000000.;

    line1 = String("lat: ") + String(latI, 6);
    line2 = String("lng: ") + String(lonI, 6);

    mapGPS(); //update location on Blynk map

    nmea.clear(); // Clear the MicroNMEA storage to make sure we are getting fresh data
  }
  else
  {
   // Serial.println("Waiting for fresh data");
  }

}

void mapGPS() {
...

sprintf(pmLabel, "PM2.5:%4dug/m3\n", dustvalues1.PM2_5Val_atm); // use PM2.5 value for marker label

 Blynk.virtualWrite(V5, markerNum, latID, lonID, pmLabel, newColor); // update marker position=GPS, color=PMAQI (marker color hack for iOS)

...

}

void setup() {

...

 timer.setInterval(3000L, getGPS); // get GPS coords.

...

}
1 Like

It’s all in the documentation…

but I don’t understand why you’d just want to send the GPS location to Blynk when the device first boots up.
I would have thought that you’d be using a BlynkTimer to take location readings on a regular basis and send them to Blynk. Your displayInfo function seems to be doing half of this task, but isn’t being called as far as I can tell.

Pete.

Honestly Pete I am extremely new to coding so I barely understand what half of this code does, I’m learning as much as I can but learning to code as you would know is not something you can do over night so for now im copying and pasting other peoples code from other posts and hoping it works and so far none of them do and it definitely doesn’t help that every sketch i find are all somehow completely different despite somehow achieving the same goal of making the map widget work.

I’m here now asking for help because I dont know what the correct sketch is or pieces of code that I need and every guide that blynk has expects you to understand coding. Also Blynks, example sketches for GPS and the mapwidget dont do anything.

So please Im begging you pete, tell me what to fix in my code and if what I have is entirely wrong then please tell me how to fix it.

All I want, is to make my esp32 with my neo-7m GPS module correctly link up to the map widget in my app so i can open up the app at any time and see where the device currently is.

Im only using the new Blynk 2.0 consoles and app.

Really would appreciate your help.

This might help you

I have now changed the code i was using to the one below to atleast first confirm i can get my esp32 to receive the GPS data from my neo-7m module and display it on a small LED screen which has worked successfully.

Now Pete please tell me how I can send the data to the Blynk2.0 app and the web app from this code below.

I have ofcourse created my template with a gps location data stream for the map assigned to virtual pin1.

#define BLYNK_TEMPLATE_ID "*****"
#define BLYNK_DEVICE_NAME "*****"

#define BLYNK_FIRMWARE_VERSION        "0.1.0"

#define BLYNK_PRINT Serial

#define APP_DEBUG

#include "BlynkEdgent.h"

#include <TinyGPS++.h>
#include <TinyGPSPlus.h>
#include <SoftwareSerial.h>
#include <NMEAGPS.h>

#include <Adafruit_SSD1306.h>
#include <splash.h>
#include <Wire.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64

#define OLED_RESET -1 
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

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

TinyGPSPlus gps;

SoftwareSerial ss(RXD2, TXD2);

WidgetMap myMap(V1);

void setup()
{
  Serial.begin(9600);
  delay(100);

  BlynkEdgent.begin();

  neogps.begin(9600, SERIAL_8N1, RXD2, TXD2);

  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  }
  display.clearDisplay();
  display.display();
  delay(2000);

  int index = 0;
  float lat = 51.5074;
  float lon = 0.1278;
  Blynk.virtualWrite(V1, lon, lat);
  
}

void loop() {
  BlynkEdgent.run();

  boolean newData = false;
  for (unsigned long start = millis(); millis() - start < 1000;)
  {
    while (neogps.available())
    {
      if (gps.encode(neogps.read()))
      {
        newData = true;
      }
    }
  }

  if(newData == true)
  {
    newData = false;
    Serial.println(gps.satellites.value());
    print_speed();
  }
  else
  {
    display.clearDisplay();
    display.setTextColor(SSD1306_WHITE);
    display.setCursor(0, 0);
    display.setTextSize(3);
    display.print("No Data");
    display.display();
  }

}

void print_speed()
{
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
       
  if (gps.location.isValid() == 1)
  {
   //String gps_speed = String(gps.speed.kmph());
    display.setTextSize(1);
    
    display.setCursor(25, 5);
    display.print("Lat: ");
    display.setCursor(50, 5);
    display.print(gps.location.lat(),6);

    display.setCursor(25, 20);
    display.print("Lng: ");
    display.setCursor(50, 20);
    display.print(gps.location.lng(),6);

    display.setCursor(25, 35);
    display.print("Speed: ");
    display.setCursor(65, 35);
    display.print(gps.speed.kmph());
    
    display.setTextSize(1);
    display.setCursor(0, 50);
    display.print("SAT:");
    display.setCursor(25, 50);
    display.print(gps.satellites.value());

    display.setTextSize(1);
    display.setCursor(70, 50);
    display.print("ALT:");
    display.setCursor(95, 50);
    display.print(gps.altitude.meters(), 0);

    display.display();
    
  }
  else
  {
    display.clearDisplay();
    display.setTextColor(SSD1306_WHITE);
    display.setCursor(0, 0);
    display.setTextSize(3);
    display.print("No Data");
    display.display();
  }  

}

Okay, I’ve made some changes to the structure of this, to make it more likely to work with Blynk.
The code isn’t tested, as I don’t have your hardware or the libraries installed that you are using, so you may get some silly compilation errors to sort-out.

I’ve added some comments to help you understand and learn. Please read them. If you don’t understand any of them then please ask.

This may not work with Blynk yet, it depends on how you’ve configured your datastreams. I’d suggest you try it and provide some feedback and details of your V1 datastream configuration and map widget setup if it doesn’t work as expected…

#define BLYNK_TEMPLATE_ID "*****"
#define BLYNK_DEVICE_NAME "*****"

#define BLYNK_FIRMWARE_VERSION        "0.1.0"

#define BLYNK_PRINT Serial

#define APP_DEBUG

#include "BlynkEdgent.h"

#include <TinyGPS++.h>
#include <TinyGPSPlus.h>
#include <SoftwareSerial.h>
#include <NMEAGPS.h>

#include <Adafruit_SSD1306.h>
#include <splash.h>
#include <Wire.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64

#define OLED_RESET -1 
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

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

TinyGPSPlus gps;

SoftwareSerial ss(RXD2, TXD2);

//WidgetMap myMap(V1);

BlynkTimer timer; // Declare a BlynkTimer object called 'timer'

// These variables move out of void setup, so that they become global variables which are visible everywhere in the sketch
int index = 0;
float lat = 51.5074;
float lon = 0.1278;

// and some new global variables created to store some other values...
float speed;
float satellites;
float altitude;

void setup()
{
  Serial.begin(9600);
  delay(100);

  BlynkEdgent.begin();

  neogps.begin(9600, SERIAL_8N1, RXD2, TXD2);

  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  }
  display.clearDisplay();
  display.display();
  delay(2000);

  // You shouldn't decalre variables in void setup, it makes them local variables, so they cant bve seen in the rest of the sketch
  // These have been moved up to the top of the sketch to make them global
  // int index = 0;
  // float lat = 51.5074;
  // float lon = 0.1278;
  
  //Blynk.virtualWrite(V1, lon, lat); // we don't want this here, as it would only run once and Blynk may not be listening yet anyway

  timer.setInterval(1000L, readGPS; // initialise a timer that runs every second and reads the GPS data
}

void loop()
{
  BlynkEdgent.run();
  timer run(); // feed the BlynkTimer object
}


void readGPS()
{
  // This code was in your void loop, it's now been moved out and placed into a new function which we've called 'readGPS'
  // the function will be triggered once every second by the timer
  
  boolean newData = false;
  for (unsigned long start = millis(); millis() - start < 1000;)
  {
    while (neogps.available())
    {
      if (gps.encode(neogps.read()))
      {
        newData = true;
      }
    }
  }

  if(newData == true)
  {
    newData = false;
    Serial.println(gps.satellites.value());
    print_speed();
  }
  else
  {
    display.clearDisplay();
    display.setTextColor(SSD1306_WHITE);
    display.setCursor(0, 0);
    display.setTextSize(3);
    display.print("No Data");
    display.display();
  }
}


void print_speed()  // Not a very accurate name for this function!
{
  // Code changed to capture the lat, lon, speed etc to the global variables we created, so that
  // they can be re-used multiple times...

  lat = gps.location.lat();         // capture latitude to the `lat` global variable
  lon = gps.location.lng();         // capture longitude to the `lon` global variable
  speed = gps.speed.kmph();         // you get the general idea of what's happening here...
  satellites = gps.satellites.value();
  altitude = gps.altitude.meters();
  
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
       
  if (gps.location.isValid() == 1)
  {
   //String gps_speed = String(gps.speed.kmph());
    display.setTextSize(1);
    
    display.setCursor(25, 5);
    display.print("Lat: ");
    display.setCursor(50, 5);
    display.print(lat,6);       // uses the 'lat` global variable value

    display.setCursor(25, 20);
    display.print("Lng: ");
    display.setCursor(50, 20);
    display.print(lon,6);     // uses the 'lon` global variable value

    display.setCursor(25, 35);
    display.print("Speed: ");
    display.setCursor(65, 35);
    display.print(speed);     // you get the general idea...
    
    display.setTextSize(1);
    display.setCursor(0, 50);
    display.print("SAT:");
    display.setCursor(25, 50);
    display.print(satellites);

    display.setTextSize(1);
    display.setCursor(70, 50);
    display.print("ALT:");
    display.setCursor(95, 50);
    display.print(altitude, 0);

    display.display();

    // new code added to the existing function to write the data to Blynk...

    Blynk.virtualWrite(V1, lon, lat); // re-uses the values we stored in the global variables earlier
    // you couldf all extra lines in here to send the spped, satellites & altitude to display widgets in
    // Blynk that are connected to their own vitrual pins by ysing code like this:
    // Blynk.virtualWrite(V99, speed);

    // We can also send the info we've collected to the serial monitor...
    Serial.print("Lat: ");
    Serial.println(lat,6);

    Serial.print("Lng: ");
    Serial.println(lon,6);

    Serial.print("Speed: ");
    Serial.println(speed);      

    Serial.print("SAT:");
    Serial.println(satellites);

    Serial.print("ALT:");
    Serial.println(altitude, 0);

    Serial.println();   
  }
  else
  {
    display.clearDisplay();
    display.setTextColor(SSD1306_WHITE);
    display.setCursor(0, 0);
    display.setTextSize(3);
    display.print("No Data");
    display.display();

    // You could send invalid or default coordinates to Blynk here if you wanted to
    // but at this stage that may give some confusing results, so we'll leave that out
    //Blynk.virtualWrite(V1, 0, 0);
    // Blynk.virtualWrite(V99, 0);    
    
    Serial.println("No Data");
    Serial.println();  
   }  
}

Note that I am NOT going to keep tweaking this code for you to add-in additional features etc. once it’s working. I’ve given you some tools and knowledge for you to do that yourself.

Pete.

1 Like

Pete… I could kiss you. 100% works in both the app and the web browser console.

Apart from a couple tiny errors in the sketch I did have to move the global variables you created back into local variables because it kept giving me an error message saying that
"exit status 1 ‘int index’ redeclared as different kind of symbol"
I think it was conflicting with something in one of the libraries maybe? however moving the variables back under the void print_speed() function fixed it, unless you can see another way to fix it i can move them back.

Either way now it works perfectly. Im going to play around with adding a virtual pin data stream to display the speed gauge in the app too.

Here’s the full functioning sketch with the changes below.

And once again thank you for your quality work Pete!! I hugely appreciate it and the notes you added into the sketch to show me how parts of it work.

#define BLYNK_TEMPLATE_ID "*****"
#define BLYNK_DEVICE_NAME "****"

#define BLYNK_FIRMWARE_VERSION        "0.1.0"

#define BLYNK_PRINT Serial

#define APP_DEBUG

#include "BlynkEdgent.h"

#include <TinyGPS++.h>
#include <TinyGPSPlus.h>
#include <SoftwareSerial.h>
#include <NMEAGPS.h>

#include <Adafruit_SSD1306.h>
#include <splash.h>
#include <Wire.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64

#define OLED_RESET -1 
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

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

TinyGPSPlus gps;

SoftwareSerial ss(RXD2, TXD2);

BlynkTimer timer;

float speed;
float satellites;
float altitude;

WidgetMap myMap(V1);

void setup()
{
  Serial.begin(9600);
  delay(100);

  BlynkEdgent.begin();

  neogps.begin(9600, SERIAL_8N1, RXD2, TXD2);

  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  }
  display.clearDisplay();
  display.display();
  delay(2000);

  timer.setInterval(1000L, readGPS);

}


void loop() {
  BlynkEdgent.run();
  
  timer.run(); // feed the BlynkTimer object
}

void readGPS()
{
  // This code was in your void loop, it's now been moved out and placed into a new function which we've called 'readGPS'
  // the function will be triggered once every second by the timer
  
  boolean newData = false;
  for (unsigned long start = millis(); millis() - start < 1000;)
  {
    while (neogps.available())
    {
      if (gps.encode(neogps.read()))
      {
        newData = true;
      }
    }
  }

  if(newData == true)
  {
    newData = false;
    Serial.println(gps.satellites.value());
    print_speed();
  }
  else
  {
    display.clearDisplay();
    display.setTextColor(SSD1306_WHITE);
    display.setCursor(0, 0);
    display.setTextSize(3);
    display.print("No Data");
    display.display();
  }
}


void print_speed()  // Not a very accurate name for this function!
{
  // Code changed to capture the lat, lon, speed etc to the global variables we created, so that
  // they can be re-used multiple times...

  int index = 0;
  float lat = 51.5074;
  float lon = 0.1278;

  lat = gps.location.lat();         // capture latitude to the `lat` global variable
  lon = gps.location.lng();         // capture longitude to the `lon` global variable
  speed = gps.speed.kmph();         // you get the general idea of what's happening here...
  satellites = gps.satellites.value();
  altitude = gps.altitude.meters();
  
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
       
  if (gps.location.isValid() == 1)
  {
   //String gps_speed = String(gps.speed.kmph());
    display.setTextSize(1);
    
    display.setCursor(25, 5);
    display.print("Lat: ");
    display.setCursor(50, 5);
    display.print(lat,6);       // uses the 'lat` global variable value

    display.setCursor(25, 20);
    display.print("Lng: ");
    display.setCursor(50, 20);
    display.print(lon,6);     // uses the 'lon` global variable value

    display.setCursor(25, 35);
    display.print("Speed: ");
    display.setCursor(65, 35);
    display.print(speed);     // you get the general idea...
    
    display.setTextSize(1);
    display.setCursor(0, 50);
    display.print("SAT:");
    display.setCursor(25, 50);
    display.print(satellites);

    display.setTextSize(1);
    display.setCursor(70, 50);
    display.print("ALT:");
    display.setCursor(95, 50);
    display.print(altitude, 0);

    display.display();

    // new code added to the existing function to write the data to Blynk...

    Blynk.virtualWrite(V1, lon, lat); // re-uses the values we stored in the global variables earlier
    // you couldf all extra lines in here to send the spped, satellites & altitude to display widgets in
    // Blynk that are connected to their own vitrual pins by ysing code like this:
    // Blynk.virtualWrite(V99, speed);

    // We can also send the info we've collected to the serial monitor...
    Serial.print("Lat: ");
    Serial.println(lat,6);

    Serial.print("Lng: ");
    Serial.println(lon,6);

    Serial.print("Speed: ");
    Serial.println(speed);      

    Serial.print("SAT:");
    Serial.println(satellites);

    Serial.print("ALT:");
    Serial.println(altitude, 0);

    Serial.println();   
  }
  else
  {
    display.clearDisplay();
    display.setTextColor(SSD1306_WHITE);
    display.setCursor(0, 0);
    display.setTextSize(3);
    display.print("No Data");
    display.display();

    // You could send invalid or default coordinates to Blynk here if you wanted to
    // but at this stage that may give some confusing results, so we'll leave that out
    //Blynk.virtualWrite(V1, 0, 0);
    // Blynk.virtualWrite(V99, 0);    
    
    Serial.println("No Data");
    Serial.println();  
   }  
}

I don’t know what the index variable is used for, I didn’t look that closely.
I guess that it’s because you’ve in-commented this line:

Which is declaring wrapper function object which allows you to write data to the Blynk app widget by refernci h it as myMap.
You aren’t using the wrapper, instead you’re doing a direct Blynk.virtualWrite to pin V1…

So the wrapper object declaration, and the corresponding index variable should probably be commented-out.

Pete.

Thanks for the good job, I am trying to do the same thing, wonder if this can shown GPS route on a offline map?