ESP8266 nodeMCU Dev.Board verliert WIFI Verbindung

Ich dachte immer mein Programm stürzt nach einigen Stunden ab.

Aber nach etlichen Versuchen musste ich feststellen: Der ESP verliert die Internetverbindung und verbindet sich nicht neu.

Starte ich nur meinen Router neu funktioniert wieder alles.

Hat jemand einen Tip für mich? Was mache ich falsch?

...
void  loop()
{
  //Anzeige der Zeit am seriellen Monitor
  //digitalClockDisplay();                      
  Alarm.delay(1000); // wait one second between clock display


  //Prozess um Tastenimpuls auszugeben - Aufruf mit trigger();
  if (triggered && (millis() - previousMillis > 100))
  {
    digitalWrite(Ausgangsnummer, LOW);
    triggered = false;
  }

 
  if (hour()<WLANaus && hour()>=WLANan)                     //kein WLAN zwischen 23-6°°
  {
    // check if WLAN is connected
    if (WiFi.status() != WL_CONNECTED)
    {
      WiFiStart();                                //Wenn keine Verbindung zum Router dann Unterprogramm aufrufen
    }

    // Check if a client has connected
    WiFiClient client = server.available();
    if (!client) {
      return;                                     //Wenn kein Client da gehe zurück zum Anfang loop()
    }
  
   // Wait until the client sends some data
    Serial.println("new client");
    unsigned long ultimeout = millis()+250;
    while(!client.available() && (millis()<ultimeout) )
    {
      delay(1);
    }
    if(millis()>ultimeout) 
    { 
      Serial.println("client connection time-out!");
      return; 
    }
  
    // Read the first line of the request
    req1 = client.readStringUntil('\r');
    Serial.println(req1);
    client.flush();

    req2 = req1;
    req3 = req1;

    //192.168.100.56/DATA/18:00/00:15/4
    //192.168.100.56/RESP/18:00/00:15/4
    if (req1.substring(5, 9)== ("DATA")) {
      WiFiDatenEmpfangen();
      DatenResponse();                          //Unterprogramm um interne Daten per HTML zu senden. Aufruf mit 192.168.100.54/RESP/
      client.print(resp);                       // Send the response to the client
    }
    //GET /RESP?Startstunde=19&Startminute=20&Dauer=1&Umlauf=4 HTTP/1.1
    //GET /RESP?WiFiStartzeit=6&WiFiAusschaltzeit=22 HTTP/1.1
    q = 0;
    if (req1.substring(5, 9)== ("RESP")) {               //ohne RESP an dieser Stelle erfolgt keine Reaktion
      Serial.println(req1.substring(9, 22));
      if (req1.substring(9, 10)== ("/")) {               //falls nach RESP ein / steht muss ein Zeichen + gelesen werden
        q = 1;
      }
      if (req1.substring((9+q), (22+q))== ("?Startstunde=")) {   //Startzeiten nur einstellen wenn nach RESP auch Daten folgen
        WiFiDatenEmpfangenWebseite();             //von der generierten Webseite gesendete Daten einlesen
      }
      Serial.println(req1.substring((9+q), (24+q)));
      if (req1.substring((9+q), (24+q))== ("?WiFiStartzeit=")) {   //WiFi-Startzeiten nur einstellen wenn nach RESP auch Daten folgen
        WiFiAusschaltzeitenDatenEmpfangenWebseite();             //von der generierten Webseite gesendete Daten einlesen
      }
      DatenResponse();                          //Unterprogramm um interne Daten per HTML zu senden. Aufruf mit 192.168.100.54/RESP/
      client.print(resp);                       // Send the response to the client
    }
  }
  else                                          //Wenn zw. 23-6°° dann WiFi aus
  {
    if (WiFi.status() == WL_CONNECTED)
    {
      //client.disconnect();
      WiFi.disconnect();
      Serial.println("WiFi disconnected");
      delay(1);
    }  
  }
  
}






void WiFiStart()                              // Unterprogramm um WiFi am Router anzumelden
{
 // 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");

  // Print the IP address
  Serial.println(WiFi.localIP());
}



...

Hmmm, auch nach vielen Versuchen:

Nach einigen Betriebsstunden kann ich den ESP mit fester IP nicht mehr ansprechen.

Wenn ich den Router auslese ist der ESP aber angemeldet mit guter Signalstärke.

Schalte ich nur kurz am Router WLAN aus und wieder an funktioniert wieder alles.

Ich muss den ESP nicht resetten. Seine Variablenwerte sind auch noch alle gespeichert.

Hat keiner einen Tip für mich? :o

Sch... Router? (Speedlink 5501)

Hmmm, mein Webserver bleibt auch nach vielen Änderungen weiterhin instabil.

Dieser Webserver läuft sehr sehr schnell und stabil - kann ich empfehlen.

Hab eigentlich fast alles gleich was Wifi betrifft - weiß noch nicht so recht warum meiner instabil ist...

also nur Sketch gewechselt bei identischer Hardware und Netzwerk?

Dann sollte es eigentlich am Sketch liegen. Kommt noch was per seriell vom Esp8266, wenn er über Web nicht mehr reagiert?

Ja, nur anderen Sketch geladen. An der Hardware kann es nicht liegen. Ist jetzt sogar am I2C ein LCD 16x2 Shield dran. Lasse mir dort "new client" usw anzeigen.

Der ESP stürzt bei meinem Programm nicht ab, er reagiert nur nicht mehr auf Wifi-Anfragen. Wenn ich Wifi am Router aus/einschalte geht wieder alles.

Ich werde jetzt mal testweise Stück für Stück alles andere in meinem Programm deaktivieren. Irgendetwas muss "stören".
Alles was mit Wifi & client zu tun hat ist eigentlich identisch mit dem "stabilen Webserverprogramm".

Poste doch mal beide Sketche

Hier den von Stefan Thesen. Hab nur lcd.print mit integriert um etwas "zu sehen".

/*--------------------------------------------------
HTTP 1.1 Webserver for ESP8266 
for ESP8266 adapted Arduino IDE

Stefan Thesen 04/2015

Running stable for days 
(in difference to all samples I tried)

Does HTTP 1.1 with defined connection closing.
Reconnects in case of lost WiFi.
Handles empty requests in a defined manner.
Handle requests for non-exisiting pages correctly.

This demo allows to switch two functions:
Function 1 creates serial output and toggels GPIO2
Function 2 just creates serial output.

Serial output can e.g. be used to steer an attached
Arduino, Raspberry etc.
--------------------------------------------------*/

#include <ESP8266WiFi.h>

#include <Wire.h>                                         //I2C Anschlüsse
#include <utility/Adafruit_MCP23017.h>                    //LCD Shield
#include <Adafruit_RGBLCDShield.h>                        //LCD Shield

Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();      //LCD Shield
#define WHITE 0x7                                         //LCD Shield

const char* ssid = "SSID";
const char* password = "Passw";

unsigned long ulReqcount;
unsigned long ulReconncount;


// Create an instance of the server on Port 80
WiFiServer server(80);

void setup() 
{
  Wire.begin(1,3);                            //SDA / SCL Anschlüsse festlegen für I2C
  lcd.begin(16, 2);
  // setup globals
  ulReqcount=0; 
  ulReconncount=0;
  
  // prepare GPIO2
  pinMode(2, OUTPUT);
  digitalWrite(2, 0);
  
  // start serial
  //Serial.begin(9600);
  delay(1);
  
  // inital connect
  WiFi.mode(WIFI_STA);
  WiFiStart();
}

void WiFiStart()
{
  ulReconncount++;
  
  // 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");
  lcd.setCursor(0,0);
  lcd.print("WiFi connected  ");           //LCD
  
  // Start the server
  server.begin();
  //Serial.println("Server started");

  // Print the IP address
  //Serial.println(WiFi.localIP());
}

void loop() 
{
  // check if WLAN is connected
  if (WiFi.status() != WL_CONNECTED)
  {
    WiFiStart();
  }
  
  // Check if a client has connected
  WiFiClient client = server.available();
  if (!client) 
  {
    return;
  }
  
  // Wait until the client sends some data
  //Serial.println("new client");
  lcd.setCursor(0,0);
  lcd.print("new client      ");           //LCD
  unsigned long ultimeout = millis()+250;
  while(!client.available() && (millis()<ultimeout) )
  {
    delay(1);
  }
  if(millis()>ultimeout) 
  { 
    //Serial.println("client connection time-out!");
    lcd.setCursor(0,0);
    lcd.print("time-out        ");           //LCD
    return; 
  }
  
  // Read the first line of the request
  String sRequest = client.readStringUntil('\r');
  //Serial.println(sRequest);
  client.flush();
  
  // stop client, if request is empty
  if(sRequest=="")
  {
    //Serial.println("empty request! - stopping client");
    lcd.setCursor(0,0);
    lcd.print("emptyReqStopClie");           //LCD
    client.stop();
    return;
  }
  
  // get path; end of path is either space or ?
  // Syntax is e.g. GET /?pin=MOTOR1STOP HTTP/1.1
  String sPath="",sParam="", sCmd="";
  String sGetstart="GET ";
  int iStart,iEndSpace,iEndQuest;
  iStart = sRequest.indexOf(sGetstart);
  if (iStart>=0)
  {
    iStart+=+sGetstart.length();
    iEndSpace = sRequest.indexOf(" ",iStart);
    iEndQuest = sRequest.indexOf("?",iStart);
    
    // are there parameters?
    if(iEndSpace>0)
    {
      if(iEndQuest>0)
      {
        // there are parameters
        sPath  = sRequest.substring(iStart,iEndQuest);
        sParam = sRequest.substring(iEndQuest,iEndSpace);
      }
      else
      {
        // NO parameters
        sPath  = sRequest.substring(iStart,iEndSpace);
      }
    }
  }
  
  ///////////////////////////////////////////////////////////////////////////////
  // output parameters to serial, you may connect e.g. an Arduino and react on it
  ///////////////////////////////////////////////////////////////////////////////
  if(sParam.length()>0)
  {
    int iEqu=sParam.indexOf("=");
    if(iEqu>=0)
    {
      sCmd = sParam.substring(iEqu+1,sParam.length());
      //Serial.println(sCmd);
    }
  }
  
  
  ///////////////////////////
  // format the html response
  ///////////////////////////
  String sResponse,sHeader;
  
  ////////////////////////////
  // 404 for non-matching path
  ////////////////////////////
  if(sPath!="/")
  {
    sResponse="<html><head><title>404 Not Found</title></head><body><h1>Not Found</h1><p>The requested URL was not found on this server.</p></body></html>";
    
    sHeader  = "HTTP/1.1 404 Not found\r\n";
    sHeader += "Content-Length: ";
    sHeader += sResponse.length();
    sHeader += "\r\n";
    sHeader += "Content-Type: text/html\r\n";
    sHeader += "Connection: close\r\n";
    sHeader += "\r\n";
  }
  ///////////////////////
  // format the html page
  ///////////////////////
  else
  {
    ulReqcount++;
    sResponse  = "<html><head><title>Demo f&uumlr ESP8266 Steuerung</title></head><body>";
    sResponse += "<font color=\"#000000\"><body bgcolor=\"#d0d0f0\">";
    sResponse += "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=yes\">";
    sResponse += "<h1>Demo f&uumlr ESP8266 Steuerung</h1>";
    sResponse += "Funktion 1 schaltet GPIO2 und erzeugt eine serielle Ausgabe.
";
    sResponse += "Funktion 2 erzeugt nur eine serielle Ausgabe.
";
    sResponse += "<FONT SIZE=+1>";
    sResponse += "<p>Funktion 1 <a href=\"?pin=FUNCTION1ON\"><button>einschalten</button></a>&nbsp;<a href=\"?pin=FUNCTION1OFF\"><button>ausschalten</button></a></p>";
    sResponse += "<p>Funktion 2 <a href=\"?pin=FUNCTION2ON\"><button>einschalten</button></a>&nbsp;<a href=\"?pin=FUNCTION2OFF\"><button>ausschalten</button></a></p>";
    
    //////////////////////
    // react on parameters
    //////////////////////
    if (sCmd.length()>0)
    {
      // write received command to html page
      sResponse += "Kommando:" + sCmd + "
";
      
      // switch GPIO
      if(sCmd.indexOf("FUNCTION1ON")>=0)
      {
        digitalWrite(2, 1);
        lcd.setCursor(0,1);
        lcd.print("GPIO2 = 1      ");           //LCD
      }
      else if(sCmd.indexOf("FUNCTION1OFF")>=0)
      {
        digitalWrite(2, 0);
        lcd.setCursor(0,1);
        lcd.print("GPIO2 = 0      ");           //LCD
      }
    }
    
    sResponse += "<FONT SIZE=-2>";
    sResponse += "
Aufrufz&auml;hler="; 
    sResponse += ulReqcount;
    sResponse += " - Verbindungsz&auml;hler="; 
    sResponse += ulReconncount;
    sResponse += "
";
    sResponse += "Stefan Thesen 04/2015
";
    sResponse += "</body></html>";
    
    sHeader  = "HTTP/1.1 200 OK\r\n";
    sHeader += "Content-Length: ";
    sHeader += sResponse.length();
    sHeader += "\r\n";
    sHeader += "Content-Type: text/html\r\n";
    sHeader += "Connection: close\r\n";
    sHeader += "\r\n";
  }
  
  // Send the response to the client
  client.print(sHeader);
  client.print(sResponse);
  
  // and stop the client
  client.stop();
  //Serial.println("Client disonnected");
  lcd.setCursor(0,0);
  lcd.print("clieDisonnected ");           //LCD
}

Mein Sketch ist zum reinstellen zu groß. Hab ihn im Anhang.
Ist jetzt etwas rumgewurschtelt - bin ja am Probieren...

SprengerZentraleESPnodeMCU_LCD-25_ohneSerialPrint_stabiler.ino (25.3 KB)

Ich hab mal im loop "Alarm.delay(1000); // wait one second between clock display" testweise rausgenommen:

Webserver reagiert dann sehr viel schneller. Langzeit-Test steht noch aus.

alarm.delay ist für Time.Alarms drin - läuft Time.Alarm auch ohne alarm.delay?

Scheint den Programmablauf zu stören...

Ich kenne dein Alarm Delay nicht, aber vielleicht das Problem.
ohne Gewähr

Das ist eine ESP Typische Angelegenheit.

Grundsätzlich muss mindestens alle 50 mS delay(0), yield(), aufgerufen, oder loop() durchlaufen werden, sonst versagt WiFi. Der WiFi Part braucht Rechenzeit, und die musst du ihm geben.

Ja, so kommt mir das auch vor.

Ohne "Alarm.delay()" funktioniert Time.Alarm nicht mehr.

Hab jetzt mal von "Alarm.delay(1000)" auf "Alarm.delay(1)" gestellt:

  • Time.Alarm funktioniert wieder
  • Webserver scheint stabil zu laufen (der Seeehr-Langzeittest steht noch aus)

Ich glaube, die 1000 von "Alarm.delay(1000)" werden nur benötigt um nur jede Sekunde serial.print auszugeben - bräuchte ich eh nicht. Hab ja digitalClockDisplay() von Time.Alarm deaktiviert.

Fazit: Schau an, was nicht alles so stänkern kann.... So ein kleiner Scheißer wie Alarm.delay... erst mal drauf kommen... :o :grin:

Wenn du dennoch Serial etwas ausgeben willst, gibt es einen kleinen "Workaround":

  1. Definiere eine neue, klassenweite variable z.B. "int outputTimer = 5000;"
  2. Verringere diese variable in deiner Loop-Schleife um 1
  3. Überprüfe nun den Wert von outputTimer:
    Wenn outputTimer = 0, gebe mache deine print-Ausgaben und setze outputTimer danach wieder auf deinen Startwert

Der Startwert lässt sich dabei natürlich in einer Konstanten speichern.

Die 5000 sind übrigens nur als Beispiel - du musst selbst mal nach einem guten Wert gucken (Probieren!).

Vielleicht konnte ich dir ja noch einen kleinen Tipp geben!
Viele Grüße

Gute Idee!! Danke.

Muss man nur testen nach wieviel Durchläufen von loop eine Sekunde ensteht.

stoni99:
Gute Idee!! Danke.

Muss man nur testen nach wieviel Durchläufen von loop eine Sekunde ensteht.

Es gibt doch millis(), oder nicht?
Damit lässt sich ein Sekundenablauf recht einfach feststellen....
Siehe: "Blink without Delay"

Ach ja, wieder die millis.... die ich immer noch nicht so recht verstanden habe...aber wird irgendwann... :smiley:

stoni99:
... die ich immer noch nicht so recht verstanden habe.....

Solltest du aber bald. Ist wirklich wichtig und trägt unheimlich zum Verständnis bei.

Mit "Alarm.delay(1)" bisher kein einzigen WiFi Ausfall mehr gehabt.

Verbindung läuft sehr stabil und auch wesentlich schnellere client Befehlsausführung.

Der code von Stefan Thesen ist top!

@MaxFrank1990:

Ja, das funktioniert. Danke für den Tip! Hab im loop getestet:

//Anzeige der Zeit am Display
  ++c;
  if (c == 2000) {
    digitalClockDisplay();
    c = 0;   
  }
  //digitalClockDisplay();                      
  Alarm.delay(1);                               // wait one second between clock display

Ist nur recht unbestimmt, wann genau die Anzeige aktualisiert. Muss man viel "testen" um in ca. 1s Rytmus zu kommen.

Ich steh zwar immer noch mit den millis auf Kriegsfuß aber Stoni wäre ja nicht Stoni wenn ihm nicht eine "umgehende" Alternative eingefallen wäre. :grin:

Unter dem Motto: "Viele Wege führen nach Rom" & "Nutze schon vorhandene millis", habe ich mich auf die im Hintergrund eh schon laufende "second()" gestürzt und sie schamlos ausgenutzt. :grinning:

Jetzt läuft meine Uhr schamlos und peinlich genau... Und das, ohne Wifi zu stören...

.
.
.
void  loop()
{
  //Anzeige der Zeit am Display
  if (second() != lastsecond) {
    digitalClockDisplay();                      // UP um Zeit anzuzeigen
    lastsecond = second();   
  }
  Alarm.delay(1);                               // wait one second between clock display

.
.
.
void digitalClockDisplay()
{
  // digital clock display of the time
  display.setTextSize(1);
  display.setCursor(78,0);
  display.setTextColor(BLACK, WHITE);     // 'inverted' text
  display.print("        ");
  display.display();
  display.setTextColor(BLACK, WHITE);     // 'inverted' text
  display.setCursor(78,0);
  display.print(hour());
  printDigits(minute());                  //Unterprogramm um evtl. 0 vor Minute
  printDigits(second());                  //Unterprogramm um evtl. 0 vor Sekunde
  display.display(); 
}







void printDigits(int digits)
{
  display.print(":");
  if(digits < 10)
    display.print('0');
  display.print(digits);
}

Was hast du gegen sowas:

void loop() {
static uint32_t previousmillis;

  if (millis()-previousmillis >= 1000){
    previousmillis=millis();
    Serial.println((float)millis()/1000.0);

    //oder tu was anderes, wie display aktualisieren  digitalClockDisplay();
  }
}

Hab nix dagegen. Sieht schön aus. Besonders gut gefallen mir die häufigen "..illi..." ! :slight_smile:

ElEspanol:
Was hast du gegen sowas:

void loop() {

static uint32_t previousmillis;

if (millis()-previousmillis >= 1000){
    previousmillis=millis();
    Serial.println((float)millis()/1000.0);

//oder tu was anderes, wie display aktualisieren  digitalClockDisplay();
  }
}

ElEspanol:
Was hast du gegen sowas:

void loop() {

static uint32_t previousmillis;

if (millis()-previousmillis >= 1000){
    previousmillis=millis();
    Serial.println((float)millis()/1000.0);

//oder tu was anderes, wie display aktualisieren  digitalClockDisplay();
  }
}

Alarm.delay(0) geht übrigens auch

Steht in der Anleitung:
https://www.pjrc.com/teensy/td_libs_TimeAlarms.html