[SOLVED] NodeMCU Timing Out After ~15 Minutes

I am using the NodeMCU V2 ESP8266 module as the main controller of my room automation project.

As a result, I’m relying on this module run consistently 24/7. It works very well up until it reaches “Cmd Error” and begins looping “Connecting to blynk-cloud.com:8442”. Here is my code and the interesting part of the Serial debug output.

#define BLYNK_DEBUG #define BLYNK_PRINT Serial // Comment this out to disable prints and save space
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <BlynkSimpleEsp8266.h>

//Network Info
const char* ssid = "ssid";
const char* password = "password";

//Blynk
char auth[] = "auth";

//  Hue constants 
const char hueHubIP[] = "hubIP";  // Hue hub IP
const char hueUsername[] = "username";  // Hue username
const int hueHubPort = 80;

//  Hue variables
String command;

ESP8266WebServer server(80);

String webPage = "";

boolean nextRoomLightState = 0;
boolean currentRoomLightState = 0;

boolean nextLEDState = 0;
boolean currentLEDState = 0;

boolean nextLampState = 0;
boolean currentLampState = 0;

int currDimValue = 0;
int prevDimValue = 0;

boolean sleepButton = false;

unsigned long previousMillis = 0;
const long interval = 500;

BLYNK_WRITE(V0){
  nextRoomLightState = param.asInt(); // assigning incoming value from pin V0 to a variable
}

BLYNK_WRITE(V1){
  nextLEDState = param.asInt(); // assigning incoming value from pin V1 to a variable
}

BLYNK_WRITE(V3){
  nextLampState = param.asInt(); // assigning incoming value from pin V3 to a variable
}

BLYNK_WRITE(V4){
  currDimValue = param.asInt(); // assigning incoming value from pin V4 to a variable
}

BLYNK_WRITE(V5){
  sleepButton = param.asInt(); // assigning incoming value from pin V4 to a variable
}

void handleRoot() {  
}

void handleNotFound(){
  String message = "File Not Found\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET)?"GET":"POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  for (uint8_t i=0; i<server.args(); i++){
    message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
  }
  server.send(404, "text/plain", message);
}

void setup(void){  
  //Blynk
  Blynk.begin(auth, ssid, password);
  pinMode(V0, INPUT); //room lights
  pinMode(V1, INPUT); //LEDs
  pinMode(V3, INPUT); //lamp
  pinMode(V4, INPUT); //dim
  
  pinMode(D2, OUTPUT);
  
  pinMode(1, OUTPUT);
  digitalWrite(1, LOW);
  
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  Serial.println("");

  //Root Webpage HTML
  webPage += "<a href=\"LEDon\"><button>LED On</button></a><br>";
  webPage += "<a href=\"LEDoff\"><button>LED Off</button></a><br>";
  webPage += "<a href=\"lamp_on\"><button>Lamp On</button></a><br>";
  webPage += "<a href=\"lamp_off\"><button>Lamp Off</button></a><br>";
  webPage += "<a href=\"room_light_on\"><button>Room Light On</button></a><br>";
  webPage += "<a href=\"room_light_off\"><button>Room Light Off</button></a><br>";

  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  
  if (MDNS.begin("esp8266")) {
    Serial.println("MDNS responder started");
  }

  //Root Site
  server.on("/", [](){
    server.send(200, "text/html", webPage);
  });

  server.on("/LEDon", [](){
    server.sendHeader("Location", String("/"), true);
    server.send ( 302, "text/plain", "");        
    nextLEDState = 1;
    LEDon();
  });
 
  server.on("/LEDoff", [](){
    server.sendHeader("Location", String("/"), true);
    server.send ( 302, "text/plain", "");        
    nextLEDState = 0;
    LEDoff();
  });

  server.on("/lamp_on", [](){
    server.sendHeader("Location", String("/"), true);
    server.send ( 302, "text/plain", "");        
    nextLampState = 1;
    lamp_on();
    
  });

  server.on("/lamp_off", [](){
    server.sendHeader("Location", String("/"), true);
    server.send ( 302, "text/plain", "");        
    nextLampState = 0;
    lamp_off();
    
  });

  server.on("/room_light_on", [](){
    server.sendHeader("Location", String("/"), true);
    server.send ( 302, "text/plain", "");
    nextRoomLightState = 1;
    roomLightOn();
  });
 
  server.on("/room_light_off", [](){
    server.sendHeader("Location", String("/"), true);
    server.send ( 302, "text/plain", "");        
    nextRoomLightState = 0;
    roomLightOff();
  });
  
  server.onNotFound(handleNotFound);

  server.begin();
  Serial.println("HTTP server started");
}

void loop(void){
  Blynk.run();
  server.handleClient();
  updateAllSystems();
}
  
void updateAllSystems(){
  unsigned long currentMillis = millis();
  if(currentMillis - previousMillis >= interval){
    previousMillis = currentMillis; 
    updateRoomLights();
    updateLED();
    updateLamp();
    updateDim();
    sleepMode();
  }
}

void sleepMode(){
  if(sleepButton == true){
    nextLampState = 0;
    nextLEDState = 0;
    nextRoomLightState = 0;
    roomLightOff();
    lamp_off();
    LEDoff();
  }
}

void updateDim(){
  if(currDimValue != prevDimValue){
    command = "{\"bri\":" + String(currDimValue) + "}";
    setHue(1,command);
    setHue(2,command);
    Serial.println(currDimValue);
    prevDimValue = currDimValue;
  }
}

void updateLamp(){
  //if light should be on, turn on light
  if(nextLampState == 1 && currentLampState == 0){
    lamp_on();
  }//if light should be off, turn off light 
  else if(nextLampState == 0 & currentLampState == 1){
    lamp_off();
  }
}

//Virtual Pin V3 == lamp
void lamp_on(){
    Serial.println("lamp_on");
    currentLampState = 1;
    HTTP_GET_REQ("10.0.0.250", "/lightOn");
    Blynk.virtualWrite(3, 1);
    Blynk.syncVirtual(3);
}

void lamp_off(){
    Serial.println("lamp_off");
    currentLampState = 0; 
    HTTP_GET_REQ("10.0.0.250", "/lightOff");
    Blynk.virtualWrite(3, 0);
    Blynk.syncVirtual(3);
}

void updateLED(){
  //if light should be on, turn on light
  if(nextLEDState == 1 && currentLEDState == 0){
    LEDon();
  }//if light should be off, turn off light 
  else if(nextLEDState == 0 & currentLEDState == 1){
    LEDoff();
  }
}

//Virtual Pin V1 == LED
void LEDon(){
    Serial.println("LEDon");
    digitalWrite(D2, HIGH);
    currentLEDState = 1;
    Blynk.virtualWrite(1, 1);
    Blynk.syncVirtual(1);
}

void LEDoff(){
    Serial.println("LEDoff");
    digitalWrite(D2, LOW);
    currentLEDState = 0; 
    Blynk.virtualWrite(1, 0);
    Blynk.syncVirtual(1);
}

void updateRoomLights(){
  //if light should be on, turn on light
  if(nextRoomLightState == 1 && currentRoomLightState == 0){
    roomLightOn();
  }//if light should be off, turn off light 
  else if(nextRoomLightState == 0 & currentRoomLightState == 1){
    roomLightOff();
  }
}

void roomLightOn(){
    Serial.println("roomLightOn");
    command = "{\"on\":true, \"bri\":" + String(currDimValue) + "}";
    setHue(1,command);
    delay(5);
    setHue(2,command);
    currentRoomLightState = 1;
    Blynk.virtualWrite(0, 1);
    Blynk.syncVirtual(0);
}

void roomLightOff(){
    Serial.println("roomLightOff");
    command = "{\"on\": false}";
    setHue(1,command);
    delay(5);
    setHue(2,command); 
    currentRoomLightState = 0; 
    Blynk.virtualWrite(0, 0);
    Blynk.syncVirtual(0);
}

void HTTP_GET_REQ(char* host, char* url){
  // Use WiFiClient class to create TCP connections
  WiFiClient client;
  const int httpPort = 80;
  if (!client.connect(host, httpPort)) {
    return;
  }  
  
  Serial.print("Requesting URL: ");
  Serial.println(url);
  
   //This will send the request to the server
  client.print(String("GET ") + url + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" + 
               "Connection: close\r\n\r\n");

  unsigned long timeout = millis();
  while (client.available() == 0) {
    if (millis() - timeout > 5000) {
      Serial.println(">>> Client Timeout !");
      client.stop();
      return;
    }
  }
}


/* setHue() is our main command function, which needs to be passed a light number and a 
 * properly formatted command string in JSON format (basically a Javascript style array of variables
 * and values. It then makes a simple HTTP PUT request to the Bridge at the IP specified at the start.
 */
boolean setHue(int lightNum, String command)
{
 Serial.print("setHue: ");
 Serial.println(String(lightNum));
  WiFiClient client;
  if (client.connect(hueHubIP, hueHubPort))
  {
      client.print("PUT /api/");
      client.print(hueUsername);
      client.print("/lights/");
      client.print(lightNum);  // hueLight zero based, add 1
      client.println("/state HTTP/1.1");
      client.println("keep-alive");
      client.print("Host: ");
      client.println(hueHubIP);
      client.print("Content-Length: ");
      client.println(command.length());
      client.println("Content-Type: text/plain;charset=UTF-8");
      client.println();  // blank line before body
      client.println(command);  // Hue command
    client.stop();
    return true;  // command executed
  }
  else
    return false;  // command failed
}

Serial Output:

lamp_on
Requesting URL: /lightOn
[2548382] <[14|01|11|00|06]vw[00]3[00]1
[2548505] <[10|01|12|00|04]vr[00]3
[2548591] >[14|01|12|00|06]
[2548591] >vw[00]3[00]1
[2549553] >[14]R[0A|00|06]
[2549553] >vw[00]3[00]0
lamp_off
Requesting URL: /lightOff
[2549972] <[14|01|13|00|06]vw[00]3[00]0
[2550105] <[10|01|14|00|04]vr[00]3
[2550202] >[14|01|14|00|06]
[2550203] >vw[00]3[00]0
[2560200] <[06|01|15|00|00]
[2560319] >[00|01|15|00]È
[2570320] <[06|01|16|00|00]
[2573108] >[00|01|16|00]È
[2583108] <[06|01|17|00|00]
[2583200] >[00|01|17|00]È
[2593198] <[06|01|18|00|00]
[2594526] >[00|01|18|00]È
[2604526] <[06|01|19|00|00]
[2604625] >[00|01|19|00]È
[2614625] <[06|01|1A|00|00]
[2615255] >[00|01|1A|00]È
[2625255] <[06|01|1B|00|00]
[2625364] >[00|01|1B|00]È
[2635365] <[06|01|1C|00|00]
[2635458] >[00|01|1C|00]È
[2645459] <[06|01|1D|00|00]
[2646033] >[00|01|1D|00]È
[2656033] <[06|01|1E|00|00]
[2656154] >[00|01|1E|00]È
[2666155] <[06|01|1F|00|00]
[2671155] Cmd error
[2671156] Connecting to blynk-cloud.com:8442
[2685026] Connecting to blynk-cloud.com:8442
[2699150] Connecting to blynk-cloud.com:8442
[2713199] Connecting to blynk-cloud.com:8442
[2727323] Connecting to blynk-cloud.com:8442
[2741447] Connecting to blynk-cloud.com:8442
[2755597] Connecting to blynk-cloud.com:8442
[2769721] Connecting to blynk-cloud.com:8442
[2783845] Connecting to blynk-cloud.com:8442
[2797994] Connecting to blynk-cloud.com:8442
[2812068] Connecting to blynk-cloud.com:8442
[2826242] Connecting to blynk-cloud.com:8442
[2840341] Connecting to blynk-cloud.com:8442
[2854465] Connecting to blynk-cloud.com:8442
[2868639] Connecting to blynk-cloud.com:8442
[2882763] Connecting to blynk-cloud.com:8442
[2896862] Connecting to blynk-cloud.com:8442
[2910912] Connecting to blynk-cloud.com:8442
[2925061] Connecting to blynk-cloud.com:8442
[2939285] Connecting to blynk-cloud.com:8442
[2953359] Connecting to blynk-cloud.com:8442
[2967433] Connecting to blynk-cloud.com:8442
[2981532] Connecting to blynk-cloud.com:8442
[2995556] Connecting to blynk-cloud.com:8442
[3009680] Connecting to blynk-cloud.com:8442
[3023804] Connecting to blynk-cloud.com:8442
[3037879] Connecting to blynk-cloud.com:8442
[3051978] Connecting to blynk-cloud.com:8442

Is this something that I can fix or am I asking too much of the ESP8266, and should I instead use my Raspberry Pi as my Blynk host?

@Zach_Bellay the great thing about ESP’s compared with some other MCU’s is that it is easy to recover from such a problem. You just add a few lines of code and it will connect again to the Blynk server.

Some hardware will only reconnect if you push various buttons or power the device on and off but not the ESP.

I think most ESP’s will have some kind of problem if you push them close to their limit but as I say this is not a major problem, just restart and move on.

I ahve taken a very quick look at your sketch. What I do now with all Blynk sketches is search for Blynk.run() and see if the loop() is cluttered up and if it includes timer.run().

Your loop is not cluttered but it doesn’t contain timer.run() which suggests possible problems.

What you do have in loop() is the updateAllSystems() function and I guess this is your substitute for SimpleTimer ie. timer.run(). It runs at 500ms intervals which shouldn’t be a problem if the following don’t take too long.

updateRoomLights();
updateLED();
updateLamp();
updateDim();
sleepMode();

Some of these functions are tied to http requests which might be running slowly on the ESP.
Perhaps try increasing the 500ms to 2000ms and see how that goes and if it still fails regularly then maybe try a Pi as a host.

Failing that live with it and just add code to deal with it, quick reconnect etc.

HTH

2 Likes

Awesome! Thank you so much @Costas!!!

Actually, @Costas, could you refer me to a quick reconnect thread/example? I can’t seem to find any on the forums at least.

@Costas there are several threads on the site but I will try to direct you towards a definitive one.

It contains a sketch written by @Costas so it must be pretty good :slight_smile:

Even I struggle to find some of the threads but I do remember that there is a function called mywifi().

Quick search brings up this thread Check connection status in loop and reconect

It tries to cover all eventualities so it is more than a couple of lines and you can probably cut it down a bit but most lines of code do serve some purpose.

2 Likes

This code thanks to a post by @vshymanskyy a month ago allows me to reconnect to the Blynk server if it loses connection for some reason. In my experience, instead of using millis() use the SimpleTimer library and you should have cleaner and better performing code.

The only change I made was to check every 10 seconds instead of every 60 seconds to increase responsiveness.

void setup()
{
  Serial.begin(9600);
  Blynk.begin(auth);
  timer.setInterval(60000, reconnectBlynk);
}

void reconnectBlynk() {
  if (!Blynk.connected()) {
    if(Blynk.connect()) {
      BLYNK_LOG("Reconnected");
    } else {
      BLYNK_LOG("Not reconnected");
    }
  }
}

void loop()
{
  if (Blynk.connected()) {
    Blynk.run();
  }
  timer.run();
}
2 Likes