SOLVED : Retreive External IP Address of connection and Tweet it to me

Hi everyone, as usual when i'm able to solve :slight_smile: a problem I also like to share the solution and hope that maybe someone can improve it and shorten the code making it use less memory.

Here below a perfectly working code which retreives you pubblic ip and sends it by tweeter every X milliseconds specified in the sketch.

I have added to the tweet also the milliseconds that have passed since Arduino has powered on, this is needed to avoid the 403 error that Twitter shoots when you're trying to post a duplicate data already posted. Since time passes and milliseconds will always increase, adding them to the post will result in different posts always avoiding the Error 403 of Twitter.

Below is the code, i would like someone to help me make it better and especially make it send the IP only when it has changed since the first reading. :wink:

// reads IP address output from the www.realip.info website
// Thanks to ZoomKat for his precious help

#include <SPI.h>
#include <Ethernet.h>
String readString, tempstring;
#include <Twitter.h>

Twitter twitter("your token");    //token di tweeter per inviare messaggi
char tweetText[100];

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };                      //physical mac address
const unsigned long requestInterval = 120000;                             //delay between requests 300.000 = 5 min / 60.000 = 1 minuto  / 120.000 = 2 minuti   
unsigned long lastAttemptTime = 0 ;                                       //var for lastattemptTime for requesting new ip reading
int lastStringLength = readString.length();                               //var for reading length of ipaddress string output from website
int octet1,octet2,octet3,octet4 ;                                         //integers for ip address
char serverName[] = "www.realip.info";                                    //myIP server test web page server
EthernetClient client;



void setup(){

  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // no point in carrying on, so do nothing forevermore:
    while(true);
  }
  Serial.begin(9600); 
  sendGET();                                                              //asks for the ip address      
  }

void loop()
{
   if (millis() - lastAttemptTime > requestInterval)                    // se sono passati almeno x minuti dall'ultimo tweet d'allarme allora invia di nuovo se necessario
        {  
       sendGET(); 
       lastAttemptTime = millis();                                      // note the time of this connect attempt:
        } 
  //occorre attendere prima di poter eseguire un nuovo controllo dell'ip
}
void sendGET() //client function to send/receive GET request data.
{
  if (client.connect(serverName, 80)) {                   //starts client connection, checks for connection
    Serial.println("connected");
    client.println("GET /api/p/realip.php HTTP/1.1");     //download text
    client.println("Host: www.realip.info");
    client.println("Connection: close");                  //close 1.1 persistent connection  
    client.println();                                     //end of get request
  } 
  else {
    Serial.println("connection failed");                  //error message if no client connect
    Serial.println();
  }

  while(client.connected() && !client.available()) delay(1);  //waits for data
  while (client.connected() || client.available()) {          //connected or data available
    char c = client.read();                                   //gets byte from ethernet buffer
    readString += c;                                          //places captured byte in readString
  }

  client.stop(); //stop client
  Serial.print("IP = ");
  
  int primaricerca = readString.indexOf('{');                   //inserisce in variabile la posizione della prima parentesi graffa all'interno della quale c'è l'IP
  lastStringLength = readString.length();                       //assegna alla variabile lastringlength la lunghezza della stringa letta contenente l'IP
  readString.remove(0, primaricerca+7);                         //rimuove tutto quello che c'è dall'inizio della stringa fino alla prima parentesi graffa + 7 caratteri per arrivare all'ip
  lastStringLength = readString.length();                       //rilegge la lunghezza della stringa ora che abbiamo rimosso parte delle cose inutili
  readString.remove(lastStringLength-2, lastStringLength);      //rimuove tutto il resto partendo dalla fine -2 verso la fine in modo da ottenere solo l'IP
  Serial.println(readString);                                   //stampa sul monitor seriale l'IP

  //trasforma l'ip letto in numeri interi
  int punto1 = readString.indexOf('.');                              //legge la posizione del primo punto dell'IP
  tempstring = readString.substring(0,punto1);                       //inserisce in variabile tempstring il primo otteto
  octet1 = tempstring.toInt ();                                      //assegna a variabile octet1 il valore numerico della stringa tempstring
  readString.remove(0, punto1+1);                                    //rimuove dalla stringa readString tutto quello che c'è dall'inizio fino al punto
  
  int punto2 = readString.indexOf('.');                              //legge la posizione del primo punto dell'IP
  tempstring = readString.substring(0,punto2);                       //inserisce in variabile tempstring il secondo otteto
  octet2 = tempstring.toInt ();                                      //assegna a variabile octet2 il valore numerico della stringa tempstring
  readString.remove(0, punto2+1);                                    //rimuove dalla stringa readString tutto quello che c'è dall'inizio fino al punto
  
  int punto3 = readString.indexOf('.');                              //legge la posizione del primo punto dell'IP
  tempstring = readString.substring(0,punto3);                       //inserisce in variabile tempstring il terzo otteto
  octet3 = tempstring.toInt ();                                      //assegna a variabile octet3 il valore numerico della stringa tempstring
  readString.remove(0, punto3+1);                                    //rimuove dalla stringa readString tutto quello che c'è dall'inizio fino al punto
  
  lastStringLength = readString.length();                            //legge la lunghezza stringa dell'IP
  tempstring = readString.substring(0,lastStringLength+1);           //inserisce in variabile tempstring il quarto otteto
  octet4 = tempstring.toInt ();                                      //assegna a variabile octet4 il valore numerico della stringa tempstring
  readString.remove(0, lastStringLength+1);                          //rimuove dalla stringa readString tutto quello che c'è dall'inizio fino alla fine
  
  Serial.print("otteto 1 = ");
  Serial.println(octet1);
  Serial.print("otteto 2 = ");
  Serial.println(octet2);
  Serial.print("otteto 3 = ");
  Serial.println(octet3);
  Serial.print("otteto 4 = ");
  Serial.println(octet4);

   
  sprintf(tweetText, "http://%d.%d.%d.%d/\nTempo trascorso ms : %d", octet1,octet2,octet3,octet4, millis());      //prepara la stringa da inviare con tweeter             
  tweet(tweetText);                                                              //invia il tweet
  readString="";                                                                 //svuota la variabile readString 
  tempstring="";                                                                 //svuota la variabile tempstring 

}

void tweet(char msg[])
{
  Serial.println("connecting ...");
  if (twitter.post(msg))
     {
          // Specify &Serial to output received response to Serial.
          // If no output is required, you can just omit the argument, e.g.
          // int status = twitter.wait();
          // int status = twitter.wait(&Serial);
          int status = twitter.wait();
          if (status == 200)
              {
                Serial.println("OK.");
              } 
          else
              {
                Serial.print("failed : code ");
                Serial.println(status);
              }
      } 
  else
      {
               Serial.println("connection failed.");
      }
  }

Ok, i modified this sketch in order to be able to send only upon IP change, I still have to test this (my IP hasn't changed yet).

// reads IP address output from the www.realip.info website
// Thanks to ZoomKat for his precious help

#include <SPI.h>
#include <Ethernet.h>
String readString,lastip,ipattuale,tempstring;
#include <Twitter.h>

Twitter twitter("your token");    //token di tweeter per inviare messaggi
char tweetText[100];

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };                      //physical mac address
const unsigned long requestInterval = 120000;                             //delay between requests 300.000 = 5 min / 60.000 = 1 minuto  / 120.000 = 2 minuti   
unsigned long lastAttemptTime = 0 ;                                       //var for lastattemptTime for requesting new ip reading
int lastStringLength = readString.length();                               //var for reading length of ipaddress string output from website
int octet1,octet2,octet3,octet4 ;                                         //integers for ip address
char serverName[] = "www.realip.info";                                    //myIP server test web page server
EthernetClient client;



void setup(){

  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // no point in carrying on, so do nothing forevermore:
    while(true);
  }
  Serial.begin(9600); 
  sendGET();                                                              //asks for the ip address      
  }

void loop()
{
   if (millis() - lastAttemptTime > requestInterval)                    // se sono passati almeno x minuti dall'ultimo tweet d'allarme allora invia di nuovo se necessario
        {  
       sendGET(); 
       lastAttemptTime = millis();                                      // note the time of this connect attempt:
        } 
   //occorre attendere prima di poter eseguire un nuovo controllo dell'ip
}
void sendGET() //client function to send/receive GET request data.
{
  if (client.connect(serverName, 80)) {                   //starts client connection, checks for connection
    Serial.println("connected");
    client.println("GET /api/p/realip.php HTTP/1.1");     //download text
    client.println("Host: www.realip.info");
    client.println("Connection: close");                  //close 1.1 persistent connection  
    client.println();                                     //end of get request
  } 
  else {
    Serial.println("connection failed");                  //error message if no client connect
    Serial.println();
  }

  while(client.connected() && !client.available()) delay(1);  //waits for data
  while (client.connected() || client.available()) {          //connected or data available
    char c = client.read();                                   //gets byte from ethernet buffer
    readString += c;                                          //places captured byte in readString
  }

  client.stop(); //stop client
  Serial.print("IP = ");
  
  int primaricerca = readString.indexOf('{');                   //inserisce in variabile la posizione della prima parentesi graffa all'interno della quale c'è l'IP
  lastStringLength = readString.length();                       //assegna alla variabile lastringlength la lunghezza della stringa letta contenente l'IP
  readString.remove(0, primaricerca+7);                         //rimuove tutto quello che c'è dall'inizio della stringa fino alla prima parentesi graffa + 7 caratteri per arrivare all'ip
  lastStringLength = readString.length();                       //rilegge la lunghezza della stringa ora che abbiamo rimosso parte delle cose inutili
  readString.remove(lastStringLength-2, lastStringLength);      //rimuove tutto il resto partendo dalla fine -2 verso la fine in modo da ottenere solo l'IP
  ipattuale = readString;                                       //memorizza il valore dell'ip nella variabile ipattuale per un futuro confronto
  Serial.println(readString);                                   //stampa sul monitor seriale l'IP

   //trasforma l'ip letto in numeri interi
  int punto1 = readString.indexOf('.');                              //legge la posizione del primo punto dell'IP
  tempstring = readString.substring(0,punto1);                       //inserisce in variabile tempstring il primo otteto
  octet1 = tempstring.toInt ();                                      //assegna a variabile octet1 il valore numerico della stringa tempstring
  readString.remove(0, punto1+1);                                    //rimuove dalla stringa readString tutto quello che c'è dall'inizio fino al punto
    
  int punto2 = readString.indexOf('.');                              //legge la posizione del primo punto dell'IP
  tempstring = readString.substring(0,punto2);                       //inserisce in variabile tempstring il secondo otteto
  octet2 = tempstring.toInt ();                                      //assegna a variabile octet2 il valore numerico della stringa tempstring
  readString.remove(0, punto2+1);                                    //rimuove dalla stringa readString tutto quello che c'è dall'inizio fino al punto
  
  int punto3 = readString.indexOf('.');                              //legge la posizione del primo punto dell'IP
  tempstring = readString.substring(0,punto3);                       //inserisce in variabile tempstring il terzo otteto
  octet3 = tempstring.toInt ();                                      //assegna a variabile octet3 il valore numerico della stringa tempstring
  readString.remove(0, punto3+1);                                    //rimuove dalla stringa readString tutto quello che c'è dall'inizio fino al punto
  
  lastStringLength = readString.length();                            //legge la lunghezza stringa dell'IP
  tempstring = readString.substring(0,lastStringLength+1);           //inserisce in variabile tempstring il quarto otteto
  octet4 = tempstring.toInt ();                                      //assegna a variabile octet4 il valore numerico della stringa tempstring
  readString.remove(0, lastStringLength+1);                          //rimuove dalla stringa readString tutto quello che c'è dall'inizio fino alla fine
/*  
  Serial.print("otteto 1 = ");
  Serial.println(octet1);
  Serial.print("otteto 2 = ");
  Serial.println(octet2);
  Serial.print("otteto 3 = ");
  Serial.println(octet3);
  Serial.print("otteto 4 = ");
  Serial.println(octet4);
*/

 if (lastip != ipattuale ) // se lastip è diverso da ipattuale allora dobbiamo inviare il tweet
      {
        Serial.print("IP variato da ");
        Serial.print(lastip);
        Serial.print("a ");
        Serial.println(ipattuale);
        
        lastip="";
        lastip = ipattuale;
        sprintf(tweetText, "http://%d.%d.%d.%d/\nTempo trascorso ms : %d", octet1,octet2,octet3,octet4, millis());      //prepara la stringa da inviare con tweeter             
        tweet(tweetText);                                                                                               //invia il tweet  
      }

  readString="";                                                                 //svuota la variabile readString 
  tempstring="";                                                                 //svuota la variabile tempstring 
  ipattuale="";                                                                  //svuota la variabile ipattuale 

}

void tweet(char msg[])
{
  Serial.println("connecting ...");
  if (twitter.post(msg))
     {
          // Specify &Serial to output received response to Serial.
          // If no output is required, you can just omit the argument, e.g.
          // int status = twitter.wait();
          // int status = twitter.wait(&Serial);
          int status = twitter.wait();
          if (status == 200)
              {
                Serial.println("OK.");
              } 
          else
              {
                Serial.print("failed : code ");
                Serial.println(status);
              }
      } 
  else
      {
               Serial.println("connection failed.");
      }
  }

Possible improvements :

Don't use Strings, use NULL terminated arrays of chars (aka strings) instead. This is regarded by many as better practice when used on a processor with limited memory but does cause debate.

Declare all variables with an appropriate size ro save memory where possible. For instance int octet1, octet2, octet3, octet4 ; The octets will never exceed 255 so could be declared as type byte.

thank you so much, i will change octet to byte type as you suggested.

I didn't understand this statement :

Don't use Strings, use NULL terminated arrays of chars (aka strings) instead.

Can you make an example that i can apply to my sketch?

Maybe you know the question to this : As you see i tweet my ip and it's all ok, but when i receive it, it's plain text and not clickable.

I was wondering how can i write an url in the sprintf (maybe backslashes or double apostrofes) :

sprintf(tweetText, "<a href=http://%d.%d.%d.%d/></a>\nTempo trascorso ms : %d", octet1,octet2,octet3,octet4, millis());      //prepara la stringa da inviare con tweeter             
        tweet(tweetText);

Thanks.

Can you make an example that i can apply to my sketch?

Have a look at the examples in this thread Serial input basics Although it is about serial input the techniques are equally applicable to any system then receives data byte by byte and needs to construct a string (lowercase s) from them to be used subsequently.

I was wondering how can i write an url in the sprintf (maybe backslashes or double apostrofes) :

What have you tried ? You can print a quotation mark by preceding it with a backslash like this

void setup()
{
  Serial.begin(115200);
  char buffer[20];
  char * aName = "Bob";
  sprintf(buffer, "\"hello\" %s", aName);
  Serial.println(buffer);
}

void loop()
{
}

HI, thanks for suggestions, unfortunately i can't seem to get thew active link work when tweeted, who know why!?

What should the active link look like ?

HI, well i just need a tweet with the ip address link so that i tap it and connect thru my smartphone browser to my arduino.

I don't know what Twitter wants for being a valid link but i made some testing and if i manually write the link in a tweet as this it will work but if i don't and just do http://192.168.1.1 it won't transform it to a link but just text

What happens if you use

nothing, the same as www.example.com that i've used!

I thought that you said that the www.example.com version worked and produced a clickable link.

I note that www.example.com is an address on the internet whilst 192.168.1.1 is an address on your network, quite possibly your router.

Maybe i haven't explained well :

If i manually write on the twitter webpage an ip address or url using the sintax


or

i obtain a cliccable link formatted as LINK

My goal is to tweet from Arduino a cliccable link but it does not show up in twitter as a link but only as plain text.

Actually my arduino is doing the following :

        lastip="";
        lastip = ipattuale;  //it's a string where ip address is stored in the format of 192.168.1.1 for ex.
        char urlinit[]="<a href=\"http://";
        char urlfine[]="\"></a>";
        sprintf(tweetText, "%s%s%s\nTempo trascorso ms : %d", urlinit,lastip.c_str(),urlfine, millis());               
        tweet(tweetText);  //invia il tweet

The result i obtain is as follows :


Tempo trascorso ms : 1186

But the address is not cliccable, just plain text

Actually my arduino is doing the following :

It best be doing a lot more than that.

Well, yes it does alot more :confused:

marcomaroso:
Well, yes it does alot more :confused:

But you are going to keep the rest a secret. I see.

Well, I'll guess, then, that you are not telling twit that the whole stream of text is html data, do it assumes that it is just text.

What do you mean for the rest a secret?

I have posted my peice of code at the begining of this thread.

I will post the tweet function here too :

void tweet(char msg[])
{
  Serial.println("connecting ...");
  if (twitter.post(msg))
     {
          // Specify &Serial to output received response to Serial.
          // If no output is required, you can just omit the argument, e.g.
          // int status = twitter.wait();
          // int status = twitter.wait(&Serial);
          int status = twitter.wait();
          if (status == 200)
              {
                Serial.println("OK.");
              } 
          else
              {
                Serial.print("failed : code ");
                Serial.println(status);
              }
      } 
  else
      {
               Serial.println("connection failed.");
      }
  }


void tweetText_clear()
{
   // Now we clear our array
   memset( tweetText, 0, sizeof(tweetText) );
}

I have posted my peice of code at the begining of this thread.

Well, I've posted all of the answer that I am going to until you post ALL of your code as it is now.

Ok, it's pretty long and i hope it fit's here ... it didn't so i had to modify post and put it in attachment:

att.txt (31.7 KB)

                       tweetText_clear;

What do you think this is doing? It is not calling a function.

I don't understand why you think that tweet() is going to post a complete HTML page. I don't understand how you think that tweetText is going to contain an a tag, with an href value.

        sprintf(tweetText, "http://%s\nTempo trascorso ms : %d",lastip.c_str(), millis());      //prepara la stringa da inviare con twitter             
        tweet(tweetText);  //invia il tweet

I'm really grateful if you could be more clear with me because right now i just fell like a finger pointed against me making me feel ashame about something i'm not understanding right now.

As you can see, my Karma is Noob so i'm here to learn but I can't understand what you're trying to teach me.

Could you be more clear?

By the way, the code i post for the tweet right now is not coming out as a link i know , i have changed it to have at least a plain readable text message via twitter instead of a plain <a href "http bla bla bla.

Thanks for any help that could make me solve my problem.