Can't get public IP address from ESP8266 using ipify - arduino

I'm using NodeMCU to use ESP8266 and I want to use ipify to get public IP address.
But I get -1 on httpCode. Why is that?
If I type api.ipify.org, it gets my public IP address properly.
void loop() {
Serial.println(WiFi.status());
if (WiFi.status() == WL_CONNECTED) { //Check WiFi connection status
Serial.println("az");
HTTPClient http; //Declare an object of class HTTPClient
http.begin("https://api.ipify.org/?format=json"); //Specify request destination
int httpCode = http.GET(); //Send the request
Serial.println(httpCode); //<<---- Here I get -1
if (httpCode > 0) { //Check the returning code
String payload = http.getString(); //Get the request response payload
Serial.println(payload); //Print the response payload
}
http.end(); //Close connection
}
delay(10000); //Send a request every 30 seconds
}

http.begin("https://api.ipify.org/?format=json");
You are using your HTTPClient to browse a HTTPS website (HTTP + SSL/TLS tunnel), but you're using the wrong .begin() call. The begin(String url call expects a http:// URL, not a https://. If you want to securely browse the website using HTTPS, you need to use the function begin(String url, String httpsFingerprint) (link). You can find the needed httpsFingerprint by following this guide. Using HTTPS will induce a whole lot of memory overhead and processing time, though. For the case of browsing a "what is my public IP" website, I would just advise to browse the http:// version instead, since the response is not confidential information.
So, you could just do
http.begin("http://api.ipify.org/?format=json");

You can try:
String getIp()
{
WiFiClient client;
if (client.connect("api.ipify.org", 80))
{
Serial.println("connected");
client.println("GET / HTTP/1.0");
client.println("Host: api.ipify.org");
client.println();
} else {
Serial.println("Connection to ipify.org failed");
return String();
}
delay(5000);
String line;
while(client.available())
{
line = client.readStringUntil('\n');
Serial.println(line);
}
return line;
}

Related

Why can't ESP8266 HTTP client receive data?

When I type the serverName into the browser, it returns a json object. But here, it Serial.print(payload) returns -1.
How can I fix this?
void loop() {
if (WiFi.status() == WL_CONNECTED) { //Check WiFi connection status
HTTPClient http; //Declare an object of class HTTPClient
http.begin(serverName); //Specify request destination
int httpCode = http.GET();
//Send the request
if (httpCode > 0) { //Check the returning code
String payload = http.getString(); //Get the request response payload
Serial.println(payload); //Print the response payload
}
http.end(); //Close connection
}
delay(10000); //Send a request every 30 seconds
}
Use HTTP instead of HTTPS.
If you want to use HTTPS, you will have to specify the server's certificate's SHA1 fingerprint. How to do that is easily googled.
Some libraries will allow something like client->setInsecure();, but I wouldn't go there because, well, it's insecure.

ESP32: HttpClient.get() fails with -1

I'm programming my ESP32 with the ArduinoIDE and have a problem with HTTP GET. What I'm doing:
the ESP32 connects as WiFi client to an existing WiFi network using a static, fixed IP
a webserver is started which provides a webpage for OTA firmware update -> this works, the webpage is accessible via the static IP
using HttpClient I try to GET an other, remote webserver, but this fails
This is the code I'm using for the HTTP GET call:
static WiFiClient wifi;
HttpClient wlanHttp=HttpClient(wifi,"my.server.tld");
wlanHttp.get("/setpos.php?id=DEADBEEF"); // -> this fails with error code -1
wlanHttp.responseStatusCode(); // follow-up error -1
wlanHttp.stop();
Any idea what goes wrong here?
The confusing part here is the ESP32 has a built in http client called HTTPClient. The one for Arduino is called HttpClient and I'd like to find the guy who decided on that name and see if he's okay. HTTPClient has a routine called getString() that is a lovely way to gather info from a json api call, but HttpClient won't compile with that because it has no clue what that is.
On ESp32 (if using the HTTPClient.h) the code should look like that:
static WiFiClient wifi;
HttpClient wlanHttp;
wlanHttp.begin("http://my.server.tld/setpos.php?id=DEADBEEF"); //Specify the URL
int httpCode = wlanHttp.GET(); //Make the request
if (httpCode > 0) { //Check for the returning code
if (httpCode == HTTP_CODE_OK) {
// get payload with http.getString();
Serial.println(httpCode);
// Serial.println(payload);
} else {
Serial.printf("[HTTP] GET... failed, error: %s\n", wlanHttp.errorToString(httpCode).c_str());
}
} else {
Serial.println("Error on HTTP request");
}
wlanHttp.end(); //Free the resources

Arduino mega + esp 8266 sending get request

i have a php script which help to store data into google firebase.
i am using this url to access my php scipt and input the data:
arduino.byethost22.com/FirebaseTest.php?slot1_data=empty&slot2_data=occupied
i have tried it and it is able to store slot1_data as empty and slot2_data as occupied. However i need to use arduino to send this url. i am using this code currently
#include "SoftwareSerial.h"
#define DEBUG false // turn debug message on or off in serial
String server = "arduino.byethost22.com";
String uri = "/FirebaseTest.php?slot1_data=empty&slot2_data=occupied";
void setup() {
Serial3.begin(115200); //serial3 for esp8266
Serial.begin(115200);
sendData("AT+RST\r\n",2000,DEBUG); // reset module
sendData("AT+CWMODE=3\r\n",1000,DEBUG); // configure as access point
//sendData("AT+CWJAP=\"WifiName\",\"Password\"\r\n",3000,DEBUG);
//delay(20000);
sendData("AT+CIFSR\r\n",1000,DEBUG); // get ip address
sendData("AT+CIPMUX=0\r\n",1000,DEBUG); // configure for single connections
}
void loop() {
Serial3.println("AT+CIPSTART=\"TCP\",\"" + server + "\",80");//start a TCP connection.
if( Serial3.find("OK")) {
Serial.println("TCP connection ready");
}
delay(1000);
String getRequest = "GET " + uri + " HTTP/1.1\r\n" +
"Host: " + server + "\r\n\r\n";
String sendCmd = "AT+CIPSEND=";//determine the number of caracters to be sent.
Serial3.print(sendCmd);
Serial3.println(getRequest.length() );
delay(500);
if(Serial3.find(">")) {
Serial.println("Sending..");
}
Serial3.print(getRequest);
if( Serial3.find("SEND OK")) {
Serial.println("Packet sent");
}
while (Serial3.available()) {
String tmpResp = Serial3.readString();
Serial.println(tmpResp);
}
delay(20000);
}
String sendData(String command, const int timeout, boolean debug)
{
String response = "";
Serial3.print(command); // send the read character to the esp8266
long int time = millis();
while( (time+timeout) > millis())
{
while(Serial3.available())
{
// The esp has data so display its output to the serial window
char c = Serial3.read(); // read the next character.
response+=c;
}
}
//if(debug)
//{
Serial.print(response);
//}
return response;
}
it seems that it have problem sending the get request to the php script.
i am getting packet sent in the serial monitor but nothing changed in the firebase data
i am also getting
+IPD,1104:HTTP/1.1 200 OK
Server: nginx
Date: Sat, 15 Oct 2016 09:21:34 GMT
Content-Type: text/html
Content-Length: 875
Connection: keep-alive
Vary: Accept-Encoding
Expires: Thu, 01 Jan 1970 00:00:01 GMT
Cache-Control: no-cache
<html><body><script type="text/javascript" src="/aes.js" ></script><script>function toNumbers(d){var e=[];d.replace(/(..)/g,function(d){e.push(parseInt(d,16))});return e}function toHex(){for(var d=[],d=1==arguments.length&&arguments[0].constructor==Array?arguments[0]:arguments,e="",f=0;f<d.length;f++)e+=(16>d[f]?"0":"")+d[f].toString(16);return e.toLowerCase()}var a=toNumbers("f655ba9d09a112d4968c63579db590b4"),b=toNumbers("98344c2eee86c3994890592585b49f80"),c=toNumbers("b5ebc3b806c39a4a7fc1e4cecb45feab");document.cookie="__test="+toHex(slowAES.decrypt(c,2,a,b))+"; expires=Thu, 31-Dec-37 23:55:55 GMT; path=/"; location.href="http://arduino.byethost22.com/FirebaseTest.php?slot1_data=0&slot2_data=1&i=1";</script><noscript>This site requires Javascript to work, please enable Javascript in your browser or use a browser with Javascript support</noscript></body></html>
It asked me to enable javascript in my browser, but i am using arduino, how do i do it?
When i key in the same uri in google chrome, the data can be updated
how do i solve this problem?
My code finally can work and send data online. i change to use 000webhost as my host server instead of byethost and the data manage to be updated.
i dont really know why but i guess that byethost dont support javascript.

Sample server to support 100-continue

I started implementing a sample server (in netty) to support 100 continue.
I got some confusion when I go thrugh the RCF2616 section 8.2.3. It says
Upon receiving a request which includes an Expect request-header
field with the "100-continue" expectation, an origin server MUST
either respond with 100 (Continue) status and continue to read
from the input stream, or respond with a final status code. The
origin server MUST NOT wait for the request body before sending
the 100 (Continue) response. If it responds with a final status
code, it MAY close the transport connection or it MAY continue
to read and discard the rest of the request. It MUST NOT
perform the requested method if it returns a final status code.
What does it mean by The origin server MUST NOT wait for the request body before sending the 100 (Continue) response.
Should my server first validate the headers and then send the 100 (continue) status code or Immediately send the 100 status code ?
Please clarify me the actual behavior of a http server to support 100 continue
Currently this is my channelRead
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
if (msg instanceof HttpRequest) {
HttpRequest req = (HttpRequest) msg;
request = req;
if (req.getMethod() != HttpMethod.POST) {
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, METHOD_NOT_ALLOWED);
ctx.write(response).addListener(ChannelFutureListener.CLOSE);
} else {
boolean valid = false;
for (Map.Entry<String, String> header : req.headers()) {
if (header.getKey().equals("my-special-header")) {
valid = true;
break;
}
}
if (!valid) {
FullHttpResponse resp = new DefaultFullHttpResponse(HTTP_1_1, BAD_REQUEST);
ctx.write(resp).addListener(ChannelFutureListener.CLOSE);
} else {
if (HttpHeaders.is100ContinueExpected(request)) {
ctx.write(new DefaultFullHttpResponse(HTTP_1_1, CONTINUE));
}
}
}
} else if (msg instanceof LastHttpContent && msg != LastHttpContent.EMPTY_LAST_CONTENT) {
DefaultLastHttpContent content = (DefaultLastHttpContent) msg;
System.out.println("content read");
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK, content.content());
response.headers().set(CONTENT_TYPE, "text/plain");
response.headers().set(CONTENT_LENGTH, response.content().readableBytes());
boolean keepAlive =HttpHeaders.isKeepAlive(request);
if (!keepAlive) {
ctx.write(response).addListener(ChannelFutureListener.CLOSE);
} else {
response.headers().set(CONNECTION, Values.KEEP_ALIVE);
ctx.write(response);
}
}
}
I think "MUST NOT wait for the request body" is pretty clear. The body does not include thee headers, so I'm not sure where your confusion comes from...

Communication with GPRS module using C#, with TCP

I have searched a lot for this but could not find any specific answer that applies to my case. I have made device using GPS module and GSM/GPRS module with Arduino Mega 2560, and it sends me the location through SMS. Now I want to get the location parameters using GPRS. I have in mind to use TCP. I will send data through AT Commands from GPRS module, but I am confused on how to make a server on C#. I know that I would be needing a static/public IP for this. But I don't know how to get the public IP, and start receiving data which I send from GPRS module. Please please I need help because I am a beginner in Client/Server programming, and I am working on my final year project. Many thanks in advance!
please take a look at this TCP server and client example.
You will need a public static IP address. That is something you have to ask your broadband provider, and they will explain you the available options they have, probably you will have to pay extra money. You can use your current public IP address, that will be probably dynamic, but they don't use to change way to often, so whenever you are unable to connect, you will have to check if the IP changed or not, and set the new one.
This video series maybe a good introduction: https://vimeo.com/38103518
Here is the Server Code:
class Server
{
TcpListener server = null;
public Server(string ip, int port)
{
IPAddress localAddr = IPAddress.Parse(ip);
server = new TcpListener(localAddr, port);
server.Start();
StartListener();
}
public void StartListener()
{
try
{
while (true)
{
Console.WriteLine("Waiting for a connection... ");
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("Connected!");
Thread t = new Thread(new ParameterizedThreadStart(HandleDeivce));
t.Start(client);
}
}
catch (SocketException e)
{
Console.WriteLine("SocketException: {0}", e);
}
}
public void HandleDeivce(Object obj)
{
TcpClient client = (TcpClient)obj;
NetworkStream stream = client.GetStream();
string data = null;
Byte[] bytes = new Byte[256];
int i;
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
data = Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("{1}: Received: {0}", data, Thread.CurrentThread.ManagedThreadId);
if (data.StartsWith("##"))
{
data = "LOAD";
}
else
{
data = "ON";
}
byte[] msg = Encoding.ASCII.GetBytes(data);
stream.Write(msg, 0, msg.Length);
Console.WriteLine("{1}: Sent: {0}", data, Thread.CurrentThread.ManagedThreadId);
}
client.Close();
}
}

Resources