Get IP from text (public IP)

Hi

I'm developing an Arduino + ESP8266 + Mobile App + NodeJS and I need to use the public IP, so I can access the DATA out of my network

The example code that I'm testing is the following (USING GENERIC ESP8266-01 MODULE):

#include <ESP8266WiFi.h>

void setup() {
  Serial.begin(115200);
  const char* ssid = "PMPB";
  const char* password = "!?#123PmpB123#?!";
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");

    delay(1000);
  }

  GetExternalIP();
}

void loop() {
}

void GetExternalIP()
{
  WiFiClient client;
  if (!client.connect("api.ipify.org", 80)) {
    Serial.println("Failed to connect with 'api.ipify.org' !");
  }
  else {
    int timeout = millis() + 5000;
    client.println("GET /?format=text HTTP/1.1\r\nHost: api.ipify.org\r\n\r\n");
    while (client.available() == 0) {
      if (timeout - millis() < 0) {
        Serial.println(">>> Client Timeout !");
        client.stop();
        return;
      }
    }
    int size;
    while ((size = client.available()) > 0) {
      uint8_t* msg = (uint8_t*)malloc(size);
      size = client.read(msg, size);
      Serial.write(msg, size);
      free(msg);
    }
  }
}

The output:
..HTTP/1.1 200 OK
Server: Cowboy
Connection: keep-alive
Content-Type: text/plain
Vary: Origin
Date: Fri, 26 Jun 2020 23:07:39 GMT
Content-Length: 13
Via: 1.1 vegur
188.82.xxx.xx <--- IP

The thing is, I just want the IP and not the rest of the message

Thanks in advance !!!

You can't get any better than that using HTTP - what you are seeing is how the response to an HTTP request is required to be formatted.

However, it's easy enough to process - the HTTP response always separates the headers from the actual body with a blank line, ie the sequence of characters (in 'C' notation) "\r\n\r\n".

So, just read characters one at a time from the input stream until you see that sequence, now you are positioned at the start of the payload (the part you want)

//  Locate the end of the header
			int HeaderMarker = 0;

			//  Bulk reading the header is awkward, since if we read too much, some of it
			//  is actually the payload and would have to be passed through.  So, we just
			//  read 1 byte at a time, and once we've found the end of the headers we are
			//  positioned to read the payload.
			while (client.connected() && HeaderMarker != 4)
			{
				int c = client.read();

				if (c > 0)
				{
					//  The end of the header is *defined* as an empty line, ie.
					//  the sequence "\r\n\r\n".
					switch (HeaderMarker)
					{
					case 0:
					case 2:
						if (c == '\r') HeaderMarker++; else HeaderMarker = 0;
						break;

					case 1:
					case 3:
						if (c == '\n') HeaderMarker++; else HeaderMarker = 0;
						break;
					}
				}
			}

			if (HeaderMarker == 4)
			{
				//  We found our blank line, everything else is payload.
				//  Do your thing here
			}

Unfortunately, it's more complicated than that. PROBABLY very host on your LAN has the SAME public IP address. Unless you've specifically set it up on your router to forward certain ports, you usually can't establish an IP connection from the Public WAN to your private LAN. Automatic translations that allow two-way communications are set up when a LAN host establishes a connection to something on the WAN, but an incoming connection or packet doesn't have any way to know which LAN host should get it.
(It's called "NAT" - Network Address Translation...)

MHotchin:
You can't get any better than that using HTTP - what you are seeing is how the response to an HTTP request is required to be formatted.

However, it's easy enough to process - the HTTP response always separates the headers from the actual body with a blank line, ie the sequence of characters (in 'C' notation) "\r\n\r\n".

So, just read characters one at a time from the input stream until you see that sequence, now you are positioned at the start of the payload (the part you want)

//  Locate the end of the header
		int HeaderMarker = 0;

		//  Bulk reading the header is awkward, since if we read too much, some of it
		//  is actually the payload and would have to be passed through.  So, we just
		//  read 1 byte at a time, and once we've found the end of the headers we are
		//  positioned to read the payload.
		while (client.connected() && HeaderMarker != 4)
		{
			int c = client.read();

			if (c > 0)
			{
				//  The end of the header is *defined* as an empty line, ie.
				//  the sequence "\r\n\r\n".
				switch (HeaderMarker)
				{
				case 0:
				case 2:
					if (c == '\r') HeaderMarker++; else HeaderMarker = 0;
					break;

				case 1:
				case 3:
					if (c == '\n') HeaderMarker++; else HeaderMarker = 0;
					break;
				}
			}
		}

		if (HeaderMarker == 4)
		{
			//  We found our blank line, everything else is payload.
			//  Do your thing here
		}

Thank you for your reply and the example, worked perfectly. +1 karma :smiley:

westfw:
Unfortunately, it's more complicated than that. PROBABLY very host on your LAN has the SAME public IP address. Unless you've specifically set it up on your router to forward certain ports, you usually can't establish an IP connection from the Public WAN to your private LAN. Automatic translations that allow two-way communications are set up when a LAN host establishes a connection to something on the WAN, but an incoming connection or packet doesn't have any way to know which LAN host should get it.
(It's called "NAT" - Network Address Translation...)

Hello, westfw

Sorry for the ignorance, but I didn't understand you at all.

I have my NodeJS server (using Axios and express) receiving connections (tested by myself) from the exterior, via Public IP, because I won't be able to make it from the exterior with the private one.

I will need to do the same thing with the ESP, cause it will establish a connection from the exterior to my own network.

If you can be more clear, I would be grateful :smiley: as I'm a newbie with network things ahahah

westfw:
Unfortunately, it's more complicated than that. PROBABLY very host on your LAN has the SAME public IP address. Unless you've specifically set it up on your router to forward certain ports, you usually can't establish an IP connection from the Public WAN to your private LAN. Automatic translations that allow two-way communications are set up when a LAN host establishes a connection to something on the WAN, but an incoming connection or packet doesn't have any way to know which LAN host should get it.
(It's called "NAT" - Network Address Translation...)

Ok, as I'm facing the error you have stated, after reading again your post, I understand it now.

I was checking the public IP, on my ESP8266, and saw that it was the same as my desktop (it might be obvious, but not for me, as I'm a newbie with these things) and, indeed, I wasn't able to connect to the ESP from other device using the public IP

If you can tell me how can I connect to my ESP8266 from the exterior, I would be so grateful :slight_smile:

batista742k2:
If you can tell me how can I connect to my ESP8266 from the exterior, I would be so grateful :slight_smile:

At this point, this is a problem with your network configuration, not with your hardware. You'll need to see if your router supports a way of externally connecting to internal hardware.

If you see a feature called 'DMZ', I would NOT recommend using it - it basically puts your hardware directly on the internet.

Look for 'Port Forwarding' on your Router. This tells the router that if it gets an incoming connection on a particular port number, to forward it to a specific device on your network. The details depend on your specific router.