NodeMCU web server stops responding

Hello there,

as many others I wanted to create a NodeMCU based web server from which I can control a relay. The problem I'm facing with is that after a while (couple minutes) the web page running on my nodeMCU stops responding.

I have tried pretty much everything I have found on forums about this topic without any success. What I found though on my own if that I include a meta tag in the HTML code which forces the client browser to reload the page in every 15 seconds

<meta http-equiv="Refresh" content="15; url='/'">

then the webserver keeps working. So for me it seems that the server just stops working if it doesnt get a connection periodically.

Any ideas how can make the server keep working even if there are no connections happen for a while?

thx!

(eg: one topic I have found describing the same behaviour, but I believe it has nothing to do with the real solution: Here)

Maybe you should post your code?

(Please read the forum guide first so that you don't post it in a way which breaks the forum rules.)

Sure... this is the code I have started to based my work on and it shows the same behaviour. My code is just an extension with different html content and some relay controlling.

Note: the problem is that by time the page becomes unavailable. If you refresh the page periodically (before it becomes unavailable) then the page stays available. (but of course this is not a solution). I have also tried to stop and to restart the server object every couple minutes, but that doesnt help either.

#include<ESP8266WiFi.h>

#define LED D2 //LED at GPIO4 D2
const char * ssid = "ssidhere";
const char * password = "passwordhere";
unsigned char status_led = 0;
WiFiServer server(80);
void setup() {
  Serial.begin(9600);

  // Connect to WiFi network
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  // Start the server
  server.begin();
  Serial.println("Server started at...");
  Serial.println(WiFi.localIP());
}
void loop() {
    // Check if a client has connected
    WiFiClient client = server.available();
    if (!client) {
      return;
    }
    // Wait until the client sends some data
    Serial.println("new client");
    while (!client.available()) {
      delay(1);
    }
    // Read the first line of the request
    String req = client.readStringUntil('\r');
    // Match the request

    // Return the response
    client.println("HTTP/1.1 200 OK");
    client.println("Content-Type: text/html");
    client.println("Connection: close");
    client.println("");
    // Display the HTML web page
    client.println("<!DOCTYPE HTML>");
    client.println("<HTML>");
    client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
    client.println("<link rel=\"icon\" href=\"data:,\">");
    client.println("<h1>LED CONTROL<h1>");
    client.println("<p><a href=\"/ledon\" > < button class = \"button\" > ON < /button></a > ");
    client.println("<p><a href=\"/ledoff\" > < button class = \"button2\" >");
    client.println("</body></html>"); delay(1); Serial.println("Client disonnected"); Serial.println("");
        }

I have used the HelloServer example and runs stable, but that is based on ESP8266WebServer.h.

That sounds like your router could be timing out the wi-fi connection after a few minutes of no activity.

Try adding this line at the top of loop()

Serial.println(WiFi.status() == WL_CONNECTED);

What do you see on serial monitor? What do you see after the page stops responding?

Try adding this line at the top of loop()
Serial.println(WiFi.status() == WL_CONNECTED);
What do you see on serial monitor? What do you see after the page stops responding?

Yeap, I have tried that. Actually I've defined an interrupt running every 5s:

void stayAliveInterrupt(void){
  Serial.print(F("Wifi status: ")); Serial.print(WiFi.status());
  Serial.print(F(", Server available: ")); Serial.println(server.available());
  }

This responds with:

Wifi status: 3, Server available: 0

all the time from the beginning and it keeps responding even after the webpage became unavailable.

That's an error. It should have </h1> after the heading.

Here also there is an error. The second button has no text such as "OFF" and there is no < /button></a > after it.

I don't know if these can be the cause of the problem, but I noticed them while reviewing your code.

Yeah, thats a mistake in the HTML, but has absolutely nothing to do with the problem. The problem persists even if you dont even have anything in the HTML part. The key is that the server itself stops responding.

Probably not a good idea. Using Serial.print() inside an interrupt is going to make the interrupt quite long to run and esp8266 does not like that because it can interfere with background wi-fi maintenance activities. Better to just use millis() to limit the test to every 5s.

And just to emphasise it again: the nodeMCU itself remains connected to the network, as I can ping it successfully.

Probably not a good idea. Using Serial.print() inside an interrupt is going to make the interrupt quite long to run and esp8266 does not like that because it can interfere with background wi-fi maintenance activities. Better to just use millis() to limit the test to every 5s.

Thats true Paul, but it has nothing to do with the root cause. I've created this interrupt just to see if I can get more info about the problem I see. I would be very happy if I could delay this :slight_smile:

FYI, using the F() macro on esp8266 is pointless. I don't think it actually does anything except on AVR based Arduino. On esp, all code is fetched from SPI flash chip into RAM before it is run, and there is no shortage of RAM.

1 Like

Ok... new clue!!! I have pasted the Serial.println(WiFi.status() == WL_CONNECTED); to my main loop which kept responding with 1. And then suddenly it stopped doing it. The last message displayed by the main loop is "new client" which - I assume - means that my code is stuck at right here: while(!client.available()){delay(1);}

I believe we are on the right track, although I dont know what should I if the client never becomes available.

As a workaround I have expanded my code like this:

    restartCounter = 0;
    while (!client.available()) {
      delay(1);
      restartCounter++;
      if (restartCounter > 5000) {
        Serial.println("--- Restart counter exceeded! ---");
        ESP.restart();
      }
      Serial.printf("--- Restartcounter value: %d ---\n", restartCounter);
    }

So even if the device never sees client.available() is can timeout and reset the CPU. Certainly not ideal, but it seems to work.

Interesting (to me) that if a clients wants to connect then I see two requests and my code returns the followings:

13:54:36.540 -> new client
13:54:36.540 -> --- Restart counter value: 0 ---
13:54:36.574 -> GET / HTTP/1.1
13:54:36.574 -> RSSI: -72dBm
13:54:36.608 -> Client disonnected
13:54:36.608 ->
13:54:36.608 -> new client
13:54:36.753 -> --- Restart counter value: 215 ---
13:54:36.793 -> GET /favicon.ico HTTP/1.1
13:54:36.793 -> RSSI: -71dBm
13:54:36.833 -> Client disonnected
13:54:36.833 ->

UPDATE: the latter described behavior is browser related. I use crome and have just noticed that even if I just start typing the IP of the nodeMCU to the url field, it sends a request to the unit immediately. Its not like this with Firefox.

Just reading along here.

F-macro is futile with ESP's. Thanks, PaulRB.

delay(1) - is that in place of yield() ?
Is the effect the same?
I know that yield() is millis() compatible.

I'm getting the same problem while testing your code:

15:11:18.060 -> 0⸮~?⸮4⸮!⸮{⸮OzI{⸮⸮8V⸮⸮
15:11:18.193 -> 
15:11:18.193 -> Connecting to granary
15:11:18.691 -> .......
15:11:22.405 -> WiFi connected
15:11:22.438 -> Server started at...
15:11:22.438 -> 192.168.1.145
15:11:35.705 -> new client
15:11:35.705 -> GET /ledon HTTP/1.1
15:11:35.739 -> Client disonnected
15:11:35.739 -> 
15:11:39.390 -> new client
15:11:39.390 -> GET /ledoff HTTP/1.1
15:11:39.423 -> Client disonnected
15:11:39.456 -> 
15:23:14.491 -> new client
15:23:14.525 -> GET /ledon HTTP/1.1
15:23:14.557 -> Client disonnected
15:23:14.557 -> 
15:23:16.448 -> new client

The strange thing is, when I clicked the ON button at 15:23:14, I only clicked it once. The esp responded correctly. But then 2 seconds later it reports a new client has connected. But I only clicked once. Now, if I click again, Firefox just hangs.

I think I have a solution, or at least something works reliably on my nodeMCU for hours.

      if (restartCounter > 5000) {
        Serial.println("--- Restart counter exceeded! ---");
        break;
      }

So it seems that a reboot is not necessary, we can simply break from the loop. I dont have the faintest idea whats going on, but I'm fairly happy with the fact that now my webpage seems working fine.

Let me know if you need the full source code, I'm happy to share it. (Although you might frown when you see my crappy style of programming). And for sure thanks for holding my hands while I was going thru this :slight_smile:

To me, that still feels like a workaround, not a proper fix. We don't understand what's going on or why.

Is still like to understand why the server thinks a client is trying to connect.

One thing that I've seen in other sketches like this, and this one, that doesn't sit right with me, is that we are printing "client disconnected" without actually checking if that's true.

I fully agree. I've been programming 30+ years and being fluent (15+ years) in a language in which I would never be this sloppy. Its just that for me I'm a bit lazy to figure out whats going on and I'm happy that I could make it work.

That doesnt mean that it is THE solution.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.