esp8266nodemcuarduino-c++

ESP8266 crashes after simple http request


I am working with the NodeMCU V3 module. Whenever I try to make an http request to my server, the module crashes.

Here's the code:

void setup() {
    WiFi.begin("wifi-name", "wifi-password");  

    while (WiFi.status() != WL_CONNECTED) {  //Wait for the WiFI to connect }
}
void loop() {
   HTTPClient http; 
   WiFiClient client;

   http.begin( client, "server-address" );  

   int httpCode = http.GET();  
   String payload = http.getString();  //Get the response payload

   Serial.println(httpCode);   //Print HTTP return code
   Serial.println(payload);    //Print request response payload

   http.end();  //Close connection

   delay( 1000 );
}

Here's the result, as seen in the serial monitor:

200
["JSON response from the server"]

Exception (28):
epc1=0x40212e82 epc2=0x00000000 epc3=0x00000000 excvaddr=0x000001b6 depc=0x00000000

>>>stack>>>

ctx: cont
sp: 3ffffc90 end: 3fffffc0 offset: 01a0
3ffffe30:  00000000 4bc6a7f0 0000333f 3ffee5f8  
3ffffe40:  00000000 00000000 4bc6a7f0 00000000  
[...] 
3fffffb0:  feefeffe feefeffe 3ffe84e8 40100c41  
<<<stack<<<

The strange thing is that it retrieves the response from the server correctly, but then, about one second later, it spits out the exception to the serial monitor and resets. At first I thought it could be because I am running ESP8266WebServer at the same time, but it still crashes even when I run the most basic example I could find on the internet. I tried compiling the same code on the Arduino IDE instead of PlatformIO, or even using a different NodeMCU, to no avail.

EDIT: After playing around a bit more, it seems like setting the delay to at least 10 seconds makes the NodeMCU crash after 3 requests instead of after the first one. Could it be that it's memory overflows after a few requests? Am I missing a crucial part that should prepare the ESP8266 for a new request?


Solution

  • There is no need to re-create the WiFi and HTTP clients in the loop() over and over again. You can declare them once globally. Here's a stable version of this simple sketch:

    #include <Arduino.h>
    
    #include <ESP8266WiFi.h>
    #include <ESPHTTPClient.h>
    
    WiFiClient client;
    HTTPClient http;
    
    void setup() {
      Serial.begin(115200);
      Serial.println();
      WiFi.begin("****", "****");  
    
      Serial.print("Connecting to WiFi");
      while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
      }
      Serial.println("done.");
    }
    
    void loop() {
      http.begin(client, "http://httpbin.org/get"); // <1KB payload
    //  http.begin(client, "http://www.geekstips.com/esp8266-arduino-tutorial-iot-code-example/"); // 30KB payload
      
      int httpCode = http.GET();  
      String payload = http.getString();  //Get the response payload
      
      Serial.println(httpCode);   //Print HTTP return code
      Serial.println(payload);    //Print request response payload
      
      http.end();  //Close connection
    
      Serial.printf("Free heap: %d\n", ESP.getFreeHeap());
      delay(1000);
    }
    

    The reported free heap is very stable over time. Please take note of the second URL I added for testing in the commented line. That http.getString() is convenient and works well for small resources but yields unexpected i.e. wrong results for larger resources - you only see a small fraction of the body printed to the console.

    For larger payloads you should use the low-level WiFiClient directly and read/parse the response line-by-line or character-by-character. See the documentation at https://arduino-esp8266.readthedocs.io/en/latest/esp8266wifi/client-examples.html for a template.

    void loop()
    {
      WiFiClient client;
    
      Serial.printf("\n[Connecting to %s ... ", host);
      if (client.connect(host, 80))
      {
        Serial.println("connected]");
    
        Serial.println("[Sending a request]");
        client.print(String("GET /") + " HTTP/1.1\r\n" +
                     "Host: " + host + "\r\n" +
                     "Connection: close\r\n" +
                     "\r\n"
                    );
    
        Serial.println("[Response:]");
        while (client.connected() || client.available())
        {
          if (client.available())
          {
            String line = client.readStringUntil('\n');
            Serial.println(line);
          }
        }
        client.stop();
        Serial.println("\n[Disconnected]");
      }
      else
      {
        Serial.println("connection failed!]");
        client.stop();
      }
      delay(5000);
    }