Hello fellow programmers!
I am having trouble with my ESP, it seems to be crashing at an odd place.
I am using this function (I cut out some of the code, a lot of it is not relevant):
#include <ESP8266HTTPClient.h> // At the top of the project
String CollectExternalResponse(String URL) {
WiFiClient client;
HTTPClient HTTP;
HTTP.begin(URL);
int HTTPCode = HTTP.GET();
Serial.println("A");
String Response = "";
Serial.println("B");
if (HTTPCode > 0) {
Serial.println("1");
Response = HTTP.getString();
Serial.println("2");
}
HTTP.end();
return Response;
}
When I run it, the "A" and "B" print to the Serial monitor but "1" and "2" do not. The full output is this:
A
B
Exception (3):
epc1=0x40100621 epc2=0x00000000 epc3=0x00000000 excvaddr=0x40068648 depc=0x00000000
>>>stack>>>
ctx: cont
sp: 3ffffd80 end: 3fffffc0 offset: 01a0
3fffff20: 4010000a 002a8400 3ffee75c 3ffee700
3fffff30: 3fffdad0 00000000 00000020 401008cb
3fffff40: 00001388 3ffee75c 00000000 00000000
3fffff50: 3ffef800 0035003f 3fffff80 4020424a
3fffff60: 3fffff8c 3fffff8c 3ffee6c0 40204260
3fffff70: 3fffdad0 00000000 3ffee6c0 402012ad
3fffff80: 3ffe8648 8000001c 00000000 3ffef76c
3fffff90: 0035003f 00000000 3ffee6c0 402010f6
3fffffa0: feefeffe feefeffe feefeffe 402051a8
3fffffb0: feefeffe feefeffe 3ffe84e8 40100b8d
<<<stack<<<
ets Jan 8 2013,rst cause:1, boot mode:(3,0)
load 0x4010f000, len 1392, room 16
tail 0
chksum 0xd0
csum 0xd0
v3d128e5c
~ld
Anyone know what is going on here? It seems odd that it would crash at this if statement, especially given the same function works when I do not pass the URL as a variable. Just to be clear, in another test, I printed the URL at the beginning of the function and it worked.
Here is the URL: https://blockchain.info/tobtc?currency=USD&value=1000
I would really appreciate some help!
"Anyone know what is going on here? It seems odd that it would crash at this if statement, especially given the same function works when I do not pass the URL as a variable. Just to be clear, in another test, I printed the URL at the beginning of the function and it worked. "
If you hard code the URL in in place of the URL variable, does it work? What format/type is the URL variable?
Exception 3 is a stack overflow. Most likely the call to HTTP.getString() is returning a gigantic string, which causing the error.
Your print statements do NOT necessarily indicate WHERE the problem is, because it takes a long time for the characters to actually be sent out the serial port. If you follow each Serial.print with a Serial.flush(), the characters will all be sent before the next line of code is executed. If you do that, I expect you will see the "1" come out, but not the "2", which will confirm what I wrote above.
Regards,
Ray L.
Response = HTTP.getString();As Ray says, if the code isn't '0' then you should not attempt to do that.
RayLivingston:
Exception 3 is a stack overflow. Most likely the call to HTTP.getString() is returning a gigantic string, which causing the error.
Your print statements do NOT necessarily indicate WHERE the problem is, because it takes a long time for the characters to actually be sent out the serial port. If you follow each Serial.print with a Serial.flush(), the characters will all be sent before the next line of code is executed. If you do that, I expect you will see the "1" come out, but not the "2", which will confirm what I wrote above.
Regards,
Ray L.
Good suggestion, but that your prediction did not quite match the results. When I added Serial.flush() after each print, a bunch of gibberish was printed as well. The first character is discernible, but anything else is hidden in the spam.
If you follow the link I posted in the original thread, it leads to the conversion rate for Bitcoin in USD. It should be returning something like 0.14789, not a gigantic string (unless it is sending things in a different format... perhaps json?).
zoomkat:
"Anyone know what is going on here? It seems odd that it would crash at this if statement, especially given the same function works when I do not pass the URL as a variable. Just to be clear, in another test, I printed the URL at the beginning of the function and it worked. "
If you hard code the URL in in place of the URL variable, does it work? What format/type is the URL variable?
It does not. I am sending the variable to the function as a String type. When I define it as const char*, as shown in the ESP examples and is functional on a server I made myself to return predictable strings, I receive the same error.
UPDATE:
I changed the URL to "http://worldtimeapi.org/api/ip/75.110.25.187.txt" and had a successful response from the server.
There are two observations I have about this:
-
It uses http instead of https. I don't know if this makes a difference, but I will test it to see.
-
The URL ends in .txt. Though the original claims to be in plain text, this may be significant.
UPDATE:
Since the api uses HTTPS, I needed to specify a fingerprint in the code:
HTTP.begin(URL, Fingerprint);
This did not solve the stack overflow problem, though.
Have you tried to download the URL with a browser and store it to a file and see how big that file is?
Deva_Rishi:
Response = HTTP.getString();
As Ray says, if the code isn't '0' then you should not attempt to do that.
All of the examples I've seen specify the code should be greater than 0. A positive response from http is 200...
Danois90:
Have you tried to download the URL with a browser and store it to a file and see how big that file is?
I just tried something similar. I made the same request with python and used a function to see that the response was 48 bytes.
Is this similar enough to what you suggested?
"1) It uses http instead of https. I don't know if this makes a difference, but I will test it to see."
As best as I know, there is a lot of extra stuff you have to do with https.
The HTTPClient has no valid WiFi client applied - look at this example.
SOLVED
Ok! The issue was with this particular API and its need for https. The solution should apply to any plaintext API using https:
You need to specify the SHA-1 fingerprint in the code:
http.begin(URL, SHA1Fingerprint);
It is important to use the SHA-1 fingerprint! When I first tried this, I used SHA-256 which did not solve the problem.
How do you get the SHA-1 fingerprint, you may wonder! Here is what to do on a Mac (specifically Safari):
-
In Safari, click on the green lock next to the url.
-
Click "Show Certificate"
-
Click "Details"
-
At the very bottom you will find your SHA-1 fingerprint
My only question at this point is whether the fingerprint will eventually need to be updated. Will it ever expire? Will this happen in a predictable time frame?
My code is dynamic, so I can specify the fingerprint from the outside, but will I need to check in every so often to update that data?
The fingerprint will expire with the certificate, expiration date is shown in the certificate. If you properly implement SSL/TLS in you application, you do not need to worry about this.