TinyGPS+SMS+Arduino Mega

Hello Everyone I’m having trouble with this code. I have tried google but to no avail. I stumbled upon this code by abuwesam on this page here.

now my problems are:

1.) I want it to send the coordinates continuously until receiving a message for it to stop.
2.) This line of text is not being sent. any tips on this? sen = "\n\nhttps://maps.google.com/maps?q=[" + strN + "],[" + strL+ "]";

#include <SoftwareSerial.h>
#include "SIM900.h"
#include <TinyGPS.h>
#include "sms.h"
SMSGSM sms;


TinyGPS gps;
SoftwareSerial ss(10, 9);



static void smartdelay(unsigned long ms);
static void print_float(float val, float invalid, int len, int prec);
static void print_int(unsigned long val, unsigned long invalid, int len);
static void print_str(const char *str, int len);
String strL, strN, poss, msg, sen;
char charL[10], charN[10], text[2000];
char remoteNumber[] = "+639059456422";
int o = 1;
boolean started = false;


void setup()


      {
         Serial.begin(9600);
         ss.begin(9600);
      }


void loop()
{
            float flat, flon;
            unsigned long age, date, time, chars = 0;
            unsigned short sentences = 0, failed = 0;


         while (o<4) 
         {
            gps.f_get_position(&flat, &flon, &age);
            Serial.print("longitude: ");
            print_float(flat, TinyGPS::GPS_INVALID_F_ANGLE, 10, 6);
            Serial.println("");
            Serial.print("latitude : ");
            print_float(flon, TinyGPS::GPS_INVALID_F_ANGLE, 10, 6);
            smartdelay(1000);
            Serial.println(""); //till here
            o++;

           
         
}


    Serial.println("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"); 

         dtostrf(flat, 8, 6, charL);
            for (int i = 0; i < 10; i++)
             {
                 strL += charL[i];
             }
         dtostrf(flon, 8, 6, charN);
            for (int i = 0; i < 10; i++)
            {
                strN += charN[i];
            }

 msg = "Current Motorcycle Location";
 msg = msg + "\nlongitude: " + strN + "\nlatitude :  " + strL;
 sen = "\n\nhttps://maps.google.com/maps?q=[" + strN + "],[" + strL+ "]"; //line not sending
 poss = msg + sen;
 poss.toCharArray(text, 2000);
 gsm.begin(9600);
         
 
 Serial.println(text);

 if (sms.SendSMS(remoteNumber, text))
   {
   Serial.println("\nSMS sent OK.");
   }
   else
   {
   Serial.println("\nError sending SMS.");
   }
   do {} while (1);



}


static void smartdelay(unsigned long ms)
{
 unsigned long start = millis();
 do
 {
   while (ss.available())
     gps.encode(ss.read());
 } while (millis() - start < ms);
}


static void print_float(float val, float invalid, int len, int prec)
{
 if (val == invalid)
 {
   while (len-- > 1)
     Serial.print('*');
   Serial.print(' ');
 }
 else
 {
   Serial.print(val, prec);
   int vi = abs( val);
   int flen = prec + (val < 0.0 ? 2 : 1); // . and -
   flen += vi >= 1000 ? 4 : vi >= 100 ? 3 : vi >= 10 ? 2 : 1;
   for (int i = flen; i < len; ++i)
     Serial.print(' ');
 }
 smartdelay(0);
}


static void print_str(const char *str, int len)
{
 int slen = strlen(str);
 for (int i = 0; i < len; ++i)
   Serial.print(i < slen ? str[i] : ' ');
 smartdelay(0);
}

Cheers,
sen

That SIM900 library is awful, and that example uses the stupid smartDelay! SIM900 has several compile warnings, and does not play nicely with other libraries.

Did you read my suggestion to abuwesam? Here is a NeoGPS version of your sketch:

#include <SIM900.h>
#include "sms.h"
SMSGSM sms;

#undef STATUS_NONE // bad SIM900 library!
#include <NMEAGPS.h>
NMEAGPS gps;
gps_fix fix;

//----------------------------------------------------------------
// Pick one of these for your GPS serial port and uncomment it:
//
//       NOTE: The SIM900/sms library uses SoftwareSerial explicitly, so 
//       you would have to search and replace all occurrences 
//       of 'SoftwareSerial' with 'HardwareSerial', 'AltSoftSerial' 
//       or 'NeoSWSerial', based on the choices below.  A quick search 
//       shows that GSM.h, SIM900.h, and WideTextFinder.h & cpp would 
//       have to be modified.  :P

// 1st CHOICE: For a Mega, Due or Leo, use the extra built-in HardwareSerial port.
//       On a Mega, you could also use Serial2 or Serial3
//#define gps_port Serial1

// 2nd BEST: For UNO, Micro, Mini and other 328-based boards must use pins 8 & 9.
//      Very efficient!  (Other boards require different pins.)
//#include <AltSoftSerial.h>
//AltSoftSerial gps_port;

// 3rd BEST: Same boards, but you can't use required pins 8 & 9 (are you sure?)
//       GPS baud rates 9600, 19200 or 38400.  Almost as efficient.
//#include <NeoSWSerial.h>
//NeoSWSerial gps_port( 10, 11 );

// WORST:  If you can't use baud rates 9600, 19200 or 38400 (are you sure?)
//        SoftwareSerial disables interrupts for long periods of time.
//        *** This will interfere with the SIM900 library! ***
#include <SoftwareSerial.h>
SoftwareSerial gps_port( 10, 11 );



char remoteNumber[] = "+639059456422";


void setup()
{
   Serial.begin(9600);
   gps_port.begin(9600);
}


void loop()
{
  while (gps.available( gps_port )) {
    fix = gps.read();

    // Make sure we have a location to send
    if (fix.valid.location) {
    
      Serial.print( F("longitude: ") );
      Serial.println( fix.latitude(), 5 );
      Serial.print( F("latitude : ") );
      Serial.println( fix.longitude(), 5 );

      // Build the message to send
      char text[ 128 ];

      strcpy_P( text, (const char *) F("Current Motorcycle Location\nlongitude: ") );
      char *ptr = &text[ strlen(text) ]; // end of the text so far
      
      dtostrf( fix.latitude(), 4, 5, ptr ); // append the latitude
      char   *lat    = ptr;                 // remember where these characters are...
      size_t  latLen = strlen(ptr);         //   ... and how many.
      ptr = &ptr[ latLen ];

      strcpy_P( ptr, (const char *) F("\nlongitude: ") ); // append this string
      ptr = &ptr[ strlen(ptr) ];

      dtostrf( fix.longitude(), 4, 5, ptr ); // append the longitude
      char   *lon    = ptr;                  // remember...
      size_t  lonLen = strlen(ptr);
      ptr = &ptr[ lonLen ];

      strcpy_P( ptr, (const char *) F("\n\nhttps://maps.google.com/maps/@") );
      ptr = &ptr[ strlen(ptr) ];

      strncpy( ptr, lat, latLen );  // copy those latitude characters again
      ptr = &ptr[ latLen ];

      *ptr++ = ',';  // append one character

      strncpy( ptr, lon, lonLen );  // copy those longitude characters again
      ptr = &ptr[ lonLen ];

      strcpy_P( ptr, (const char *) F(",16z") ); // and finish the URL


      //  Make sure we didn't run past the end of the text[array]
      size_t textLen = strlen(text);
      if (textLen >= sizeof(text)) {
        Serial.print( F("text array too small!  Needs to be at least text[") );
        Serial.print( textLen + 1 );
        Serial.println( F("] !") );
      }

      Serial.println( text );

      //  Send the message

      gsm.begin(9600);
      if (sms.SendSMS( remoteNumber, text ))
        {
        Serial.println( F("\nSMS sent OK.") );
        }
      else
        {
        Serial.println( F("\nError sending SMS.") );
        }

      // Hang here!
      do {} while (1);

    }
  }
}

It stops after sending one message, and there are probably other problems caused by SoftwareSerial. If you want to try it, NeoGPS is available from the Arduino IDE Library Manager, under the menu Sketch → Include Library → Manage Libraries.

You did not provide any code that would watch for an SMS to be received.

Cheers,
/dev

/dev:
That SIM900 library is awful, and that example uses the stupid smartDelay! SIM900 has several compile warnings, and does not play nicely with other libraries.

Did you read my suggestion to abuwesam? Here is a NeoGPS version of your sketch:

#include <SIM900.h>

#include “sms.h”
SMSGSM sms;

#undef STATUS_NONE // bad SIM900 library!
#include <NMEAGPS.h>
NMEAGPS gps;
gps_fix fix;

//----------------------------------------------------------------
// Pick one of these for your GPS serial port and uncomment it:
//
//      NOTE: The SIM900/sms library uses SoftwareSerial explicitly, so
//      you would have to search and replace all occurrences
//      of ‘SoftwareSerial’ with ‘HardwareSerial’, ‘AltSoftSerial’
//      or ‘NeoSWSerial’, based on the choices below.  A quick search
//      shows that GSM.h, SIM900.h, and WideTextFinder.h & cpp would
//      have to be modified.  :stuck_out_tongue:

// 1st CHOICE: For a Mega, Due or Leo, use the extra built-in HardwareSerial port.
//      On a Mega, you could also use Serial2 or Serial3
//#define gps_port Serial1

// 2nd BEST: For UNO, Micro, Mini and other 328-based boards must use pins 8 & 9.
//      Very efficient!  (Other boards require different pins.)
//#include <AltSoftSerial.h>
//AltSoftSerial gps_port;

// 3rd BEST: Same boards, but you can’t use required pins 8 & 9 (are you sure?)
//      GPS baud rates 9600, 19200 or 38400.  Almost as efficient.
//#include <NeoSWSerial.h>
//NeoSWSerial gps_port( 10, 11 );

// WORST:  If you can’t use baud rates 9600, 19200 or 38400 (are you sure?)
//        SoftwareSerial disables interrupts for long periods of time.
//        *** This will interfere with the SIM900 library! ***
#include <SoftwareSerial.h>
SoftwareSerial gps_port( 10, 11 );

char remoteNumber = “+639059456422”;

void setup()
{
  Serial.begin(9600);
  gps_port.begin(9600);
}

void loop()
{
  while (gps.available( gps_port )) {
    fix = gps.read();

// Make sure we have a location to send
    if (fix.valid.location) {
   
      Serial.print( F("longitude: ") );
      Serial.println( fix.latitude(), 5 );
      Serial.print( F("latitude : ") );
      Serial.println( fix.longitude(), 5 );

// Build the message to send
      char text[ 128 ];

strcpy_P( text, (const char *) F("Current Motorcycle Location\nlongitude: ") );
      char *ptr = &text[ strlen(text) ]; // end of the text so far
     
      dtostrf( fix.latitude(), 4, 5, ptr ); // append the latitude
      char  *lat    = ptr;                // remember where these characters are…
      size_t  latLen = strlen(ptr);        //  … and how many.
      ptr = &ptr[ latLen ];

strcpy_P( ptr, (const char *) F("\nlongitude: ") ); // append this string
      ptr = &ptr[ strlen(ptr) ];

dtostrf( fix.longitude(), 4, 5, ptr ); // append the longitude
      char  *lon    = ptr;                  // remember…
      size_t  lonLen = strlen(ptr);
      ptr = &ptr[ lonLen ];

strcpy_P( ptr, (const char *) F("\n\nhttps://maps.google.com/maps/@") );
      ptr = &ptr[ strlen(ptr) ];

strncpy( ptr, lat, latLen );  // copy those latitude characters again
      ptr = &ptr[ latLen ];

*ptr++ = ‘,’;  // append one character

strncpy( ptr, lon, lonLen );  // copy those longitude characters again
      ptr = &ptr[ lonLen ];

strcpy_P( ptr, (const char *) F(",16z") ); // and finish the URL

//  Make sure we didn’t run past the end of the text[array]
      size_t textLen = strlen(text);
      if (textLen >= sizeof(text)) {
        Serial.print( F(“text array too small!  Needs to be at least text[”) );
        Serial.print( textLen + 1 );
        Serial.println( F("] !") );
      }

Serial.println( text );

//  Send the message

gsm.begin(9600);
      if (sms.SendSMS( remoteNumber, text ))
        {
        Serial.println( F("\nSMS sent OK.") );
        }
      else
        {
        Serial.println( F("\nError sending SMS.") );
        }

// Hang here!
      do {} while (1);

}
  }
}



It stops after sending one message, and there are probably other problems caused by SoftwareSerial. If you want to try it, NeoGPS is available from the Arduino IDE Library Manager, under the menu **Sketch -> Include Library -> Manage Libraries**.

You did not provide any code that would watch for an SMS to be received.

Cheers,
/dev

thank you very much for the answer mate, it works like a charm.

also abut the continuous sending (every 5 minutes with updated GPS coordinates), should I create a new function like void continuous() or just use the millis() function? and also how would I go about refreshing the gps data? any tip on how to do it? thanks.

EDIT: I can now send message continuously, but I can’t seem to set the frequency of message to every 5 minutes. Any tip on how can I go about this?

can’t seem to set the frequency of message to every 5 minutes. Any tip on how can I go about this?

There are two clocks you could use determine the 5-minute interval: millis() and the GPS clock. Personally, I prefer the GPS clock. Because a new fix arrives once per second, you could simply count the number of fixes to get the number of seconds:

uint16_t fixCount;

void loop()
{
  while (gps.available( gps_port )) {
    fix = gps.read();
    fixCount++;

    // Make sure we have a location to send
    if ((fixCount > 5 * 60) && fix.valid.location) {
      fixCount = 0; // reset the counter

        ... send a message ...

This won’t send a message if it doesn’t have a valid location. If you want to send a message without a location, change the if statement:

    if (fixCount > 5 * 60) {

… and change how the message is built in these lines:

      // Build the message to send
      char text[ 128 ];

      strcpy_P( text, (const char *) F("Current Motorcycle Location\nlongitude: ") );
      char *ptr = &text[ strlen(text) ]; // end of the text so far

      if (fix.valid.location)                 //  <-- add this if test
        dtostrf( fix.latitude(), 4, 5, ptr ); // append the latitude
      char   *lat    = ptr;                 // remember where these characters are...
      size_t  latLen = strlen(ptr);         //   ... and how many.
      ptr = &ptr[ latLen ];

      strcpy_P( ptr, (const char *) F("\nlongitude: ") ); // append this string
      ptr = &ptr[ strlen(ptr) ];

      if (fix.valid.location)                 //  <-- add this if test
        dtostrf( fix.longitude(), 4, 5, ptr ); // append the longitude
      char   *lon    = ptr;                  // remember...
      size_t  lonLen = strlen(ptr);
      ptr = &ptr[ lonLen ];

That will leave empty fields for the lat/lon when there is no valid location.

You could also use millis(), but it will drift against the GPS clock. The Arduino frequency crystal is not as accurate as the GPS clock. You should read the “Blink without delay” or “How to do several things” examples in Useful Links.

how would I go about refreshing the gps data?

The sketch already updates the fix variable with gps.read() when gps.available. As long as you don’t use delay, the fix variable is always up-to-date.

Cheers,
/dev

P.S. This statement makes SoftwareSerial listen to the GSM, not the GPS:

    gsm.listen()

After the SMS has been sent, you must listen to the GPS to receive new fixes:

     //  Send the message

      gsm.begin(9600);
      if (sms.SendSMS( remoteNumber, text ))
        Serial.println( F("\nSMS sent OK.") );
      else
        Serial.println( F("\nError sending SMS.") );

      gps_port.listen();   // <-- switch back to GPS device

Note that GPS fixes will be ignored while the GSM is sending the message. I assume it only takes a few seconds to send the message. This means you will send a message once every 303 seconds (approx.), not once every 300 seconds.

If you really want an exact 5-minute interval, there is a way to use fix.dateTime.

Cheers,
/dev

/dev:
P.S. This statement makes SoftwareSerial listen to the GSM, not the GPS:

    gsm.listen()

After the SMS has been sent, you must listen to the GPS to receive new fixes:

     //  Send the message

gsm.begin(9600);
      if (sms.SendSMS( remoteNumber, text ))
        Serial.println( F("\nSMS sent OK.") );
      else
        Serial.println( F("\nError sending SMS.") );

gps_port.listen();  // ← switch back to GPS device



Note that GPS fixes will be ignored while the GSM is sending the message. I assume it only takes a few seconds to send the message. This means you will send a message once every 30[u]**3**[/u] seconds (approx.), not once every 300 seconds.

If you really want an exact 5-minute interval, there is a way to use `fix.dateTime`.

Cheers,
/dev

Hey mate thanks for answering all my noobish question. I’ll be sure to try your suggestions when I get home.

By the way are your two replies make up one code or is it 2 different ways to send the message every 5 minutes?

By the way are your two replies make up one code

No, they are just “snippets” that show the modifications to my sketch in reply #1. The first snippet has 4 new lines of code to add counting fixes for a 5 minute delay. The second snippet has 2 new lines of code if you want to send an SMS even if there is no location yet (2 if statements added, see comments).

or is it 2 different ways to send the message every 5 minutes?

Yes, but I only showed code for the first way, counting fixes. I mentioned millis() because you should know how to avoid using delay in all your sketches. You would have to use the “Blink Without Delay” technique (aka “BWoD”) if you didn’t have a GPS, or if you need to time an interval < 1 second.

Cheers,
/dev

/dev:
No, they are just “snippets” that show the modifications to my sketch in reply #1. The first snippet has 4 new lines of code to add counting fixes for a 5 minute delay. The second snippet has 2 new lines of code if you want to send an SMS even if there is no location yet (2 if statements added, see comments).
Yes, but I only showed code for the first way, counting fixes. I mentioned millis() because you should know how to avoid using delay in all your sketches. You would have to use the “Blink Without Delay” technique (aka “BWoD”) if you didn’t have a GPS, or if you need to time an interval < 1 second.

Cheers,
/dev

if works perfectly now. thank you very much mate.

PS. sorry if I only replied now, I’ve been away for almost a week without internet. XD