Sketch läuft instabil - Grund herausfinden

Hallo Zusammen,

ich habe ein Sektch welches seit über einem Jahr stabil auf einem ESp32 läuft.

Es erkennt Daten die über Serielle Schnittstelle von einer Füllstandsanzeige kommt.
Wertet diese aus und stellt sie über Webserver dar. Weiterhin läd es die Daten zu Thinkspeak hoch und füttert eine InfluxDB. Debug Infos werden über Telnet gesendet.
Da am Aufstellungsort nicht immer WLAN vorhanden ist, werden Daten die während der Zeit ohne WLAN angefallen sind gecached.

Aus Platzgründen würde ich das Ganze gerne auf einen ESP8266 ESP01 bringen.
Leider kommt es hier immer wieder zu Abstürzen. Die ich seit Wochen versuche auszumerzen.
Bisher ohne Erfolg :frowning:
Was ich bisher festgestellt habe, es passiert häufig nach dem WLAN reconnet.

Wenn man das Modul anpingt ist auffällig, dass nach dem ersten connect und somit den ersten 10-20 erfolgreichen Pings wieder ein paar Aussetzer kommen. Häufig hat es Ihn in dem Moment gekillt manchmal auch 10min später.
Was noch auffällig ist, dass Telnet häufiger nach dem Reconnect keine Daten mehr sendet trotzdessen die Verbindung hergestellt werden kann.

Darum habe ich schon abfragen eingebaut die Telnet und andere Dienste die auf WiFi angewiesen sein ausklammern solange WiFi nicht länger stabiel läuft.
Aber bisher habe ich es hat das nicht gefruchtet.

Hier mal das Skript. Ja, ich bin Anfänger :wink:

// heap fragmentation mitloggen
//V3 --> Umbau loop nur 3 Datensätze auf einmal. Qeue wird alle 5 sec. geleert
//V4 --> TelnetPrint
// V5 ohne Telnet
// V6 Umbau Transfer ohne StringStream
// V7 wieder mit Telnet
// V8 mit Telnet.Stop
// V9 all in one TAB

//=======Libraries
#include <ThingSpeak.h>            // Thinkspeak  
#include <ESP8266WebServer.h>
#include <ESP8266HTTPClient.h>
#include <uptime_formatter.h>
#include <time.h>
#include <ArduinoOTA.h>                  // IDE OTA Upload via ArduinoIDE
#include <TelnetPrint.h>
#include <QList.h>



//=======SETTINGS=======SETTINGS=======SETTINGS=======SETTINGS=======SETTINGS=======SETTINGS=======SETTINGS=======SETTINGS

//Hostname
const char myhostname[] {"ESP8266-Zisterne"};      // Eindeutige Kennung für diesen ESP32


//ThingSpeak
unsigned long myChannelNumber = XXX;             // ThingSpeak Channel
const char * myWriteAPIKey = "XXX";     // ThingSpeak WriteAPI
String lastgood = "no entry until now";              // ThinkSpeak Übertragung

//Timer für Thingspeak
unsigned long ThingSpeakMillis = 0;               // will store last time ThingSpeak was updated
const long ThingSpeakinterval = 300000;           // interval at which to send (milliseconds)


//variables for string
const byte numChars = 46;                            //Länge Zeichenkette
char receivedChars[numChars];
char tempChars[numChars];                            // temporary array for use when parsing

//variables to hold the parsed data
int start = 0;
int date = 0;
int pressure = 0;
int temperature = 0;
int height = 0;
int percent = 0;
int volume = 0;

boolean newData = false;                       //Serial input prüfen

// Define data record
struct Measurement {
  uint16_t waterlevel;
  int fragmentation;
  time_t time;
};

// lesbare Anzeige der Speichergrößen
const String formatBytes(size_t const& bytes) {
  return bytes < 1024 ? static_cast<String>(bytes) + " Byte" : bytes < 1048576 ? static_cast<String>(bytes / 1024.0) + " KB" : static_cast<String>(bytes / 1048576.0) + " MB";
};

//Queue for caching Data
QList<Measurement> queue;       

//holding HTTP response Influx DB
int httpResponseCode = 0;

//Datas for Influx DB
char payload[500];


//Timer für InfluxDB
unsigned long InfluxDBMillis = 0;        // will store last time InfluxDB was updated
const long InfluxDBinterval = 20000;     // interval at which to send (milliseconds)

//Webserver
ESP8266WebServer server(80);                           // WebServer Library als Server initialisieren

// WiFiClient espClient;                                  // WiFiClient Library als Client initialisieren <<-- jetzt in ThinkSpeak Void


uint16_t MinFreeHeap = 50000;
int MaxHeapFragmentation = 0;


//Timer für Heartbeat
unsigned long HeartbeatMillis = 0;        // will store last time Heartbeat was running
const long Heartbeatinterval = 1000;           // interval at which to send (milliseconds)

//Timer für WiFi reconnect
unsigned long WiFiMillis = 0;        // will store last time Heartbeat was running
const long WiFiinterval = 60000;           // interval at which to send (milliseconds)

//Checking WiFi Status
int WiFiactivecount = 0;
bool Wifiactive = false;

//status of telnetprint
bool TelnetPrintactive = false;


//WiFi
const char* ssid = "XXX";                             // << kann bis zu 32 Zeichen haben
const char* password = "XXX";  // << mindestens 8 Zeichen jedoch nicht länger als 64 Zeichen

//============VOID============VOID============VOID============VOID============VOID============VOID============VOID============VOID

/**
   WiFi
*/

void Connect() {      // Funktionsaufruf "Connect();" muss im Setup eingebunden werden
  byte i = 0;
  WiFi.disconnect(true);
  WiFi.setAutoReconnect(false);
  WiFi.mode(WIFI_STA);
  WiFi.hostname("ESP8266-Zisterne");
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    ++i;
    if (i > 9) {
      time_t now;
      time(&now);
      if (now < 1000000000) {
        ESP.restart();
      }
      WiFi.mode(WIFI_OFF);
      break;
    }
  }
}



/**
   Uhrzeit generieren
*/

//== LocalTime

void timeSetup()
{
  // Zeitzone einstellen https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
  // Es können durch Komma getrennt bis zu 3 NTP Server eingegeben werden.
  //configTime("CET-1CEST,M3.5.0,M10.5.0/3", "fritz.box", "de.pool.ntp.org");
  //https://fipsok.de/Esp8266-Webserver/ntp-zeit-esp8266.tab
  // für Core Versionen vor 2.6.0. folgende Konfiguration verwenden.
  configTime(0, 0, "fritz.box", "de.pool.ntp.org");
   setenv("TZ", "CET-1CEST,M3.5.0,M10.5.0/3", 1);
  server.on("/time", []() {
    server.send(200, "application/json", localTime());
  });
}

char* localTime() {
  struct tm tm;
  static char buf[26];
  time_t now = time(&now);
  localtime_r(&now, &tm);
  strftime (buf, sizeof(buf), R"(%d.%m.%Y - %T)", &tm);   // http://www.cplusplus.com/reference/ctime/strftime/
  return buf;
}


/**
    http Webserver ohne OTA
*/


void serverSetup() {

  
 MessDaten(height, volume, pressure, percent).reserve(900);

  
  //-------------- Send 'MessDaten' HTMLPage when a client requests URI "/"
  server.on("/", HTTP_GET, []() {
    server.sendHeader("Connection", "close");
    server.send(200, "text/html", MessDaten(height, volume, pressure, percent));
 
     
  });
  server.on("/reconnect", []() {
    Connect();
  });

  server.on("/reset", []() {
    ESP.restart();
  });

    //------------- When a client requests an unknown URI (i.e. something other than "/"), call function "handleNotFound"
  server.onNotFound(handleNotFound);


  server.begin();                               // Webserver starten
 }


/*
   Webseiten des Webservers
*/


//==wenn Client anfrage ungültig

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);

}



//== Messdaten Webseite

String MessDaten(int height, int volume, int pressure, int percent) //Send temperature , humidity , pressure und altitude

{
  String str = F("<!DOCTYPE html> <html>\n");
  str += F("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n"
           "<meta http-equiv=\"refresh\" content=\"1\">\n"
           "<title>Zisterne Fuellstand</title>\n"
           "<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n"
           "h1 {color: #0000FF;}\n"
           "body{margin-top: 50px;} h1 {color: #0000FF;margin: 50px auto 30px;}\n"
           "p {font-size: 24px;color: #444444;margin-bottom: 10px;}\n"
           "</style>\n"
           "</head>\n"
           "<body>\n"
           "<div id=\"webpage\">\n"
           "<h1>Zisterne F&uumlllstand</h1>\n"
           "<p>Gef&uumlllt: ");
  str += percent;
  str += F("%</p>"
           "<p>F&uumlllh&oumlhe: ");
  str += height;
  str += F("cm</p>"
           "<p>F&uumlllmenge: ");
  str += volume;
  str += F("l</p>"
           "<p>Duckwert: ");
  str += pressure;
  str += F("<br><br>"
           "<br><br>"
           "<br><br>"
           "<br><br>"
           "<p style=line-height:1.2;font-size:10px>"
           "UpTime: ");
  str += uptime_formatter::getUptime();
  str += F("<br><br>"
           "Last ThingSpeak update: ");
  str += lastgood;
  str += F("<br><br>"
           "Free RAM: ");
  str += formatBytes(ESP.getFreeHeap());
  str += F("  |  Lowest free RAM: ");
  str += formatBytes(MinFreeHeap);
  str += F("<br><br>"
           "RAM Fragmentation: ");
  str += ESP.getHeapFragmentation();
  str += F("%  |  Max. RAM Fragmentation: ");
  str += MaxHeapFragmentation;
  str += F("%<br><br> "
           "WiFi RSSI: ");
  str += WiFi.RSSI();
  str += F("</div>\n"
           "</body>\n"
           "</html>\n");

  return str;
}




/**
  Daten auf Korrektheit prüfen und ggf. in die Variablen schieben
*/


//==Datenerkennung

void datenerkennung() {
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '#';
  char endMarker = '?';
  char rxdata;

  rxdata = Serial.read();

  // TelnetPrint.println(rxdata);


  if (recvInProgress == true) {
    if (rxdata != endMarker) {
      receivedChars[ndx] = rxdata;
      ndx++;
      if (ndx >= numChars) {
        ndx = numChars - 1;
      }
    }
    else {
      receivedChars[ndx] = '\0'; // terminate the string
      recvInProgress = false;
      ndx = 0;
      newData = true;
      if (Wifiactive == true) {
        TelnetPrint.println();
        TelnetPrint.println(F("Ende der relevanten Daten erkannt"));
      }
    }
  }

  else if (rxdata == startMarker) {
    recvInProgress = true;
    if (Wifiactive == true) {
      TelnetPrint.println();
      TelnetPrint.println(F("Relevante Daten erkannt"));
    }
  }
}

//==PARSEN

void parseData() {      // split the data into its parts

  char * strtokIndx;
  if (Wifiactive == true) {
    TelnetPrint.println();
    TelnetPrint.println(F("Daten String: "));
    TelnetPrint.println(tempChars);
  }

  strtokIndx = strtok(tempChars, " ");
  start = atoi(strtokIndx);                // startkey

  strtokIndx = strtok(NULL, " ");
  date = atoi(strtokIndx);                // date

  strtokIndx = strtok(NULL, " ");
  pressure = atoi(strtokIndx);            // pressure

  strtokIndx = strtok(NULL, " ");
  temperature = atoi(strtokIndx);         // temperature

  strtokIndx = strtok(NULL, " ");
  height = atoi(strtokIndx);             // height

  strtokIndx = strtok(NULL, " ");
  percent = atoi(strtokIndx);            // percent

  strtokIndx = strtok(NULL, " ");
  volume = atoi(strtokIndx);            // volume

}

//==showParsedData

void showParsedData() {
  if (Wifiactive == true) {
    TelnetPrint.println();
    TelnetPrint.println(F("Paresd Data:"));
    TelnetPrint.print(F("Key "));
    TelnetPrint.println(start);
    TelnetPrint.print(F("Datum "));
    TelnetPrint.println(date);
    TelnetPrint.print(F("Druck "));
    TelnetPrint.println(pressure);
    TelnetPrint.print(F("Hoehe "));
    TelnetPrint.println(height);
    TelnetPrint.print(F("Prozent "));
    TelnetPrint.println(percent);
    TelnetPrint.print(F("Liter "));
    TelnetPrint.println(volume);
    TelnetPrint.println();
  }
}

/**
   IDE OTA Upload via ArduinoIDE
*/

void  ideOTASetup()
{
  ArduinoOTA.setHostname("ESP8266-Zisterne");      // IDE OTA give a name to your ESP for the Arduino IDE
  ArduinoOTA.onStart([]() {
    TelnetPrint.println("[otaide] OTA started");
  });
}


/**
   Updates the measure for the sensor
   Args:
    m: pointer to the Measurement to update
*/
void writeSensorMeasure(struct Measurement *m) {

  m->waterlevel = height;
  m->fragmentation = ESP.getHeapFragmentation();
  time(&m->time);
  if (Wifiactive == true) {
    TelnetPrint.print(F("Recording measurement with waterlevel: "));
    TelnetPrint.print(m->waterlevel);
    TelnetPrint.println ();
    TelnetPrint.print(F("Records in cache: "));
    TelnetPrint.println(queue.size() + 1);
    TelnetPrint.println(F("-----------------------------------------------------"));
    TelnetPrint.println();
    TelnetPrint.println();
  }
}



/**
   Transfers the data to the server.
*/
void transferData() {
  TelnetPrint.println(F("Transfering data to InfluxDB"));
  int endIndex = queue.size() - 1;
  int startIndex = endIndex - 7;
  if (startIndex < 0) {
    startIndex = 0;
  }
  WiFiClient client; //https://forum.arduino.cc/t/absturze-beim-senden-und-empfangen-von-http-requestes/859254/29
  HTTPClient http;
  http.begin(client, "http://192.168.0.13:8086/write?db=peffs&u=admin&p=XXX");
  http.addHeader("Content-type", "text/plain");
  char *pos = payload;
  for (int i = endIndex; i >= startIndex; i--) {
    struct Measurement m = queue[i];
    pos += sprintf(pos, "Zisterne value=%d,fragmentation=%d %d000000000\n", m.waterlevel, m.fragmentation, m.time);
  }

  TelnetPrint.println(payload);
  int httpResponseCode = http.POST((uint8_t *)payload, strlen(payload));
  http.end();

  if (httpResponseCode == 204) {
    // clear the transferred items from the queue
    for (int i = endIndex; i >= startIndex; i--) {
      queue.clear(i);
    }
    TelnetPrint.println(F("Data successfully sent to DB"));
    TelnetPrint.print(F("Records in cache: "));
    TelnetPrint.println(queue.size());
  }
  else {
    TelnetPrint.println(F("DB not reachable. Retry...next Time."));
    TelnetPrint.print(F("Records in cache: "));
    TelnetPrint.println(queue.size());
  }
  TelnetPrint.println();
  TelnetPrint.println(F("-----------------------------------------------------"));
  TelnetPrint.println();
  TelnetPrint.println();
}


/**
  Daten nach Thinkspeak hochschieben
*/


void thingspeak() {

  WiFiClient espClient;
  ThingSpeak.begin(espClient);
  ThingSpeak.setField(1, percent);                                    // Feld 1 mit Prozent
  ThingSpeak.setField(2, height);                                      // Feld 2 mit Fuellhoehe
  ThingSpeak.setField(3, volume);                                     // Feld 3 mit Volumen
  // ThingSpeak.setField(4, pressure);                                     // Feld 4 mit Druck
  int x = ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);       // write to the ThingSpeak channel


  if (x == 200) {
    TelnetPrint.println();
    TelnetPrint.println(F("ThinkSpeak Channel update successful."));
    lastgood = localTime();
  }
  else {
    //   lastfail = localTime() + String(x);
    TelnetPrint.println();
    TelnetPrint.println("Problem updating ThinkSpeak channel. HTTP error code " + String(x));
  }
}





//============SETUP============SETUP============SETUP============SETUP============SETUP============SETUP============SETUP============SETUP

void setup() {
  Serial.begin(9600);
  // ThingSpeak.begin(espClient);                  // Initialize ThingSpeak mit espClient <<--jetzt in Thinkspeak Void
  Connect();
  timeSetup();
  ideOTASetup();
  ArduinoOTA.begin();
  //  TelnetPrint.begin();                        // now startet with Connect void
  serverSetup();
}

//============LOOP============LOOP============LOOP============LOOP============LOOP============LOOP============LOOP============LOOP============LOOP

void loop() {

  if (Wifiactive == true) {
    server.handleClient();                        // Listen for HTTP requests from clients
    delay(2);                                     //allow the cpu to switch to other tasks
    ArduinoOTA.handle();                          // IDE OTA Upload via ArduinoIDE
  }


  if (ESP.getFreeHeap() < MinFreeHeap) {
    MinFreeHeap = ESP.getFreeHeap();
  }

  if (ESP.getHeapFragmentation() > MaxHeapFragmentation) {
    MaxHeapFragmentation = ESP.getHeapFragmentation();
  }


  while (Serial.available() > 0 && newData == false) {
    datenerkennung();
  }
  if (newData == true) {
    strcpy(tempChars, receivedChars);      // this temporary copy is necessary to protect the original data because strtok() used in parseData() replaces the commas with \0
    parseData();
    showParsedData();
    struct Measurement m;
    writeSensorMeasure(&m);
    queue.push_back(m);
    newData = false;
  }



  unsigned long currentMillis = millis();

  if (currentMillis - HeartbeatMillis >= Heartbeatinterval) {
    HeartbeatMillis = currentMillis;
    if (WiFi.status() == WL_CONNECTED) {
      ++WiFiactivecount;
      if (WiFiactivecount >= 30) {
        Wifiactive = true;
        TelnetPrint.print(F("."));
        --WiFiactivecount;
        if (TelnetPrintactive == false) {
          TelnetPrint.begin();
          TelnetPrintactive = true;
        }
      }
    }
    else {
      WiFiactivecount = 0;
      Wifiactive = false;
      TelnetPrintactive = false;
      TelnetPrint.stop();
    }
  }


  if (currentMillis - ThingSpeakMillis >= ThingSpeakinterval) {
    ThingSpeakMillis = currentMillis;     // save the last time send to ThingSpeak
    if (Wifiactive == true) {
      thingspeak();
    }
  }


  if ((currentMillis - InfluxDBMillis >= InfluxDBinterval) && (queue.size() >= 1)) {
    InfluxDBMillis = currentMillis;
    if (Wifiactive == true) {
      TelnetPrint.print(F("Remaining free RAM: "));
      TelnetPrint.println(formatBytes(ESP.getFreeHeap()));
      TelnetPrint.print(F("Lowest free RAM: "));
      TelnetPrint.println(formatBytes(MinFreeHeap));
      TelnetPrint.print(F("RSSI: --> "));
      TelnetPrint.println(WiFi.RSSI());
      TelnetPrint.print(F("Heap Fragmentation: --> "));
      TelnetPrint.println(ESP.getHeapFragmentation());
      TelnetPrint.print(F("Heap LargestBlock: --> "));
      TelnetPrint.println(formatBytes(ESP.getMaxFreeBlockSize()));
      transferData ();
    }
  }



  if ((currentMillis - WiFiMillis >= WiFiinterval) && (WiFi.status() != WL_CONNECTED)) {
    WiFiMillis = currentMillis;
    Connect();
  }
}

Hast Du mal den verfügbaren RAM zwischen ESP32 und ESP8266 verglichen?
Evtl. recht der bei zu zu vielen gecachten Messungen nicht aus.

Gruß Tommy

Hi,
klar hat der ESP32 mehr RAM und somit geht er nicht ganz soweit runter.
Ich logge den niedrigsten Wert sowie die Fragmentation ja mit
146.18 KB beim ESP32 zu 35.21KB beim ESP8266
Aber das sollte doch zum überleben reichen?

Per WLAN senden verursacht Stromspitzen.

In unmittelbarer Nähe des ESP8266-01 einen 2200µF Kondensator zwischen GND und 3.3V.
Als Goldcap müsste das als 5V-Version auch recht klein zu bekommen sein.
Für den Test ist erst einmal jede 2200µF-Elko gut.
vgs

Besser ist eine stabile Spannungsversorgung mit kurzen Leitungen. Dann braucht es nur 47µF - 220µF.

Stabile Spannungsversorgung mit genug Reserven ist gegeben.
Kann da dann wirklich nen Kondensator helfen?

Ich habe von dem Thema gelesen im Zusammenhang von Stromversorgung über USB Anschlüsse

Das gilt immer. Spannungsversorgung ist immer wichtig und muss stabil und sauber sein.
Aber klar, ein Elko reicht meist aus. Kommt immer auf das gesamte Projekt an.

Ich verwende für die ESP-01 immer einen eigenen Regler für 3,3V. Meist einen StepDown.

Strom könnte ein Problem sein.
Stell mal deine Debug-Ausgaben auf 74880 baud um und sieh dir an, welcher Boot Mode dir nach so einem ungewollten Restart angezeigt wird.

https://docs.espressif.com/projects/esptool/en/latest/esp8266/advanced-topics/boot-mode-selection.html

direkt aus der Seriellen werde ich das nicht bekommen, da ich die auf 9600 stehen haben muss, da ich darüber ja die Daten empfange.

Könnte man doch aber über ESP.getResetReason() abfragen, oder?

eventuell.

hast noch einen Pin frei für SoftSerial - RX?

nen Pin wäre schon noch frei, aber keine Möglichkeit es dort aufzuzeichnen.

Habe jetzt mal ESP.getResetInfoPtr() ins Skript mit aufgenommen.

Aber ich vermute dass da irgendwas mit dem WiFi quer geht.
Warum sollte ich sonst z.B. so was haben wie oben mit dem Telnet beschrieben.
hatte schon gedacht dass die Lib Mist is, aber als ich sie rausgenommen haben, kam es genauso nach einiger Zeit zu einem Reset.

Hast du einen ESP8266-01 oder einen 01s ?
Wenn 01, welche Farbe hat das Board ?

In welchen Zeitabständen fällt der Controller aus ?

es ist ein ESP8266-01

  • rote und blaue LED
  • 1MB
  • Board ist schwarz

Bitte auch diese Frage beantworten.

Und wie ist deine Speichervergabe im ESP festgelegt ?
OTA / Flash / (FS) ?

Sorry überlesen^^

Die Zeitabstände sind unterschiedlich.
Längste Laufzeit waren 4 Tage, meist aber eher 1-2Tage

Speichervergabe ist FS: None / OTA:~502

ist unklar.
Warum ist ein Pin frei "aber keine Möglichkeit es dort aufzuzeichnen".

Debuggen ohne Serieller Schnittstelle ist fischen im trüben Wasser.
Nimm halt einen ESP mit mehreren GPIOs.
Alles andere ist rumgerate.

bin schon dabei ein System zum debuggen aufzusetzen.

Und habe schon wieder was dazu gelernt.
Reset Causes!= Boot Modes :smirk:

Hast du die Möglichkeit ein komplettes 2. System aufzubauen, um an diesem System den Sketch Stück für Stück zu testen ?
Somache ich es beispielsweise an Projekten, die eine Änderung erfahren sollen. Da kann man dann problemlos dran testen.

ja, könnte ich.
Müsste halt einen anderen ESP nehmen der dann Pseudodaten liefert.

ich hatte nur gehofft das jemand direkter was sagen könnte...
Dass

  • ich Bockmist im Skript habe
  • Webserver, Telnet, Thingspeak und Influx over HTTP sind einem ESP8266 zu viel
  • Webserver und HTTP send beissen sich auf dem 8266 mit dem Wificlient
  • etc.

so werde ich im Ausschlussverfahren alles nach und nach mal abschalten bis es stabil läuft.
Telnet hatte ich schon ausgeschlossen, da es ohne auch passiert ist.

Wobei ich mir halt nicht erklären kann warum Telnet teilweise nach WiFi reconnects aufhört zu senden. Ich vermute da is irgendwas mit WiFi lib faul, da TelnetStream ja direkt drauf aufsetzt.

Dann müsste ja schon jemand genau dein Setup aufgebaut haben.

Bei mit läuft WIFI und Webserver prima zusammen. Auch auf dem ESP-01. Andere Configs habe ich noch nicht am Laufen.