ESP32 Datalogging mit FTP unstabil

Ich verwende ein AZDelivery ESP32 NodeMCU Module WLAN WiFi Dev Kit C Development Board zum Loggen von analogen Messwerten auf dem FTP Server meines Providers via WLAN im Abstand von etwa 15 Sekunden. Parallel dazu werden die Messwerte auch noch via Telnet z.B. zu einem Telnet Client auf einem Smartphone übertragen. Mittels Telnet können auch Anweisungen an den ESP32 übertragen werden.
Der Sketch läuft insgesamt auch sehr gut, jedoch bricht die FTP-Übertragung nach einiger Zeit (Stunden bis Tagen) ab, während die Telnet Verbindung stabil weiter läuft. Ich schließe daraus, dass es ein Problem mit der FTP Verbindung gibt, die vermutlich kurzfristig unterbrochen und danach nicht mehr reaktiviert wird. Die Unterbrechung wäre an sich kein Problem, jedoch habe ich keine Ahnung, wie ich diese Unterbrechung detektieren soll. Ich verwende die <FTPClient_Generic.h> Library.
Tests unter Verwendung eines anderen FTP Servers auf einem PC haben ergeben, dass eine kurzfristige Deaktivierung der FTP Verbindung (FTP Server stop) dazu führt, dass der Programmablauf hängt. Erst nach einem Reset geht es wieder weiter. Die Funktion ftp.isConnected() bringt vor der Schreibsequenz ein 'True' zurück.

Hier die 'Schreibsequenz:

  ftp.InitFile("Type A");
  ftp.AppendFile(ftp_file);
  ftp.Write(loglineFTP);
  ftp.CloseFile();

in dieser Schreibsequenz bleibt der Programmablauf hängen.
Der eigentliche Fehlerfall ist allerdings etwas anders, da dann das FTP Logging einfach nicht mehr ausgeführt wird, der ESP32-Programmablauf aber weiter läuft (Telnet läuft weiter).

Wie kann ich einen solchen Fehler abfangen und danach z.B. einfach die FTP Verbindung wieder aufbauen?

Vielen Dank schon im Voraus für Eure Hilfe.
Dieter

Ich benutze für solche Sachen einen ESP8266 (WEMOS D1 mini) mit https zum Webserver beim Provider an ein PHP-Script, dass die Daten in eine MySQL/MariaDB-Datenbank einträgt. Damit habe ich keine Ausfälle.

Gruß Tommy

Danke Tommy,
aktuell ist mein kleines Projekt kurz vor dem Ziel (hoffe ich zumindest), es muss nur noch dieses Problem(chen) gelöst werden. Vorerst möchte ich noch nicht von Grund auf mit einem neuen MC durchstarten und mich erneut einarbeiten und werde das erst in Betracht ziehen, wenn ich keine befriedigende Lösung finde.
Aktuell habe ich einfach mal angenommen, dass sich der Fehler doch in der Funktion ftp.isConnected() zeigt und führe dann einfach einen ESP.restart() aus. Mal sehen, ob das geht und wie es sich im praktischen Einsatz verhält. Dieser Test könnte jedoch durchaus einige Tage dauern.

Viele Grüße
Dieter

Hallo
Aber es ist schon so das die Verbindung abgebaut und beim nächsten mal planmäßig wieder aufgebaut wird.
Oder willst du die Verbindung stehen lassen ?
Es könnte ja sein das du nach einer Zeit rausgeschmissen wirst .

Hallo Rentner,

da bringst Du ein interessantes Thema hoch. Ich bin bisher davon ausgegangen, dass mit ftp.InitFile("Type A") die Verbindung hergestellt und mit ftp.CloseFile() wieder geschlossen wird. Nun ist mir aber aufgefallen, dass es in meinem Sketch einen Befehl ftp.OpenConnection() gibt, aber keinen Befehl ftp.CloseConnection() , das gibt mir zu denken. Ich muss nun erst testen, ob ich diese Anweisungen einarbeiten kann und ob sich eine Veränderung ergibt, oder noch besser, dass diese Anweisungen das Problem lösen. Ich werde das baldmöglichst tun. Allerdings läuft das Modul gerade in einem Langzeittest, den ich nicht abbrechen möchte. Ich melde mich wieder, wenn ich neue Erkenntnisse habe.

Vielen Dank für diesen interessanten Hinweis
Dieter

Und wenn nun während der Schreibsequenz die Verbindung zusammenbricht. also irgendwo jeweils zwischen den Aktionen?

Ich habe niemals vom ESP aus ftp betrieben, aber "atomar" im Sinne der Verbindung ist die Sequenz ja vermutlich nicht.

Zumal alle diese Methoden keinen Returncode haben und man damit den Erfolg nicht prüfen kann.

Gruß Tommy

Edit: Man könnte höchstens das Datum der letzten Änderung des Files nach dem Close abrufen. Wenn es neuer ist, als das letzte Datum, dann war das Schreiben wohl erfolgreich.

Hallo
Das liegt aber dann an der verwendeten Lib .
FTP liefert schon Returncodes die eine Aussage darüber zulassen ob die Anweisung erfolgreich war.
Wenn das alle 15 Sekunden auf FTP schreiben zu häufig ist, dann könntest du die Messwerte erst mal zwischen speichern und bei jedem 10 mal dann halt die 10 Messwerte auf FTP speichern. Das gibt dann eventuell nur am Ende ein Problem wenn die 10 nicht mehr voll werden dann fehlen die letzten auf der FTP Datei.

Ich nutze einen lokalen FTP Server auf der Fritzbox , der Verbindungsaufbau und das Schreiben dauert nicht lang schätze mal 100ms sowas in der Größenordnung.

Das kann ich natürlich nicht ausschließen. Mal sehen, was die weitere Untersuchung ergibt.
Bisher läuft der Test 24h ohne Probleme. Allerdings ist das nicht ungewöhnlich bisher hat es durchaus auch 2 bis 3 Tage gedauert, bis das Problem aufgetreten ist. Vielleicht helfen dann ja auch die weiteren Antworten weiter.

Vielen Dank
Dieter

Ja, das ist leider so. Ich hatte auch schon daran gedacht, das Datum oder die Dateilänge zu verwenden, um einen erfolgreichen Schreibvorgang zu überprüfen. Das aktuelle Datei-Datum müsste ja mit der 'Methode' ftp.GetLastModifiedTime() abrufbar sein.
Wie schon vorher gesagt, möchte ich nun erst mal sehen, wie sich der aktuelle Sketch im Fehlerfall verhält.

Ich verwende aktuell die Lib <FTPClient_Generic.h> aus den Arduino IDE Beispielen, da ich damit die besten Erfahrungen gemacht habe. Kannst Du mir eine andere Lib empfehlen, die Returncodes bereitstellt?
Klar könnte ich mehrere Messungen zusammenfassen und dann erst zum Server schicken. Ob das helfen würde, ist zu untersuchen.

Das war auch mein ursprüngliches Ziel, jedoch habe ich es bisher noch nicht geschafft, mit meinem ESP32 darauf zuzugreifen. Es klappt mit meinem externen Web-Provider und mit einem lokalen FTP Server auf einem PC. Mit Filezilla kann ich jedoch problemlos auch mit FTP auf die Fritzbox zugreifen.
Die Rechte müssten korrekt vergeben sein. Mangels Zeit habe ich das aber zurückgestellt und eben den externen FTP-Server verwendet.
Um das zu diskutieren, sollte ich aber ein neues Thema aufmachen. Vielleicht gibt es ja auch schon Lösungen im Forum. Dazu habe ich bisher noch nicht intensiver recherchiert.

Vielen Dank und viele Grüße
Dieter

Update: Nach etwas mehr als 100 Stunden ist der FTP Schreibfehler gestern Abend wieder aufgetreten und zu meiner Freude hat die Methode ftp.isConnected() offenbar doch richtig funktioniert und den erwünschten Restart des ESP32 ausgelöst. Nach etwa einer Minute war die Verbindung wieder aufgebaut und der Log-Vorgang wurde fortgesetzt. Diese lange Zeitspanne von über 4 Tagen war ungewöhnlich und ich hatte schon den Verdacht, dass der Fehler verschwunden sei. Nun möchte ich den Test noch einige Zeit fortsetzen (mindestens noch einen Fehler) und dann die FTP Verbindung periodisch erneuern (entweder bei jedem Schreibvorgang bei wenig Zeitverlust oder z.B. einmal pro Stunde).
Gibt es noch Antworten zu den Fragen in meinem letzten Post?

Danke und viele Grüße
Dieter

Hallo ESP32 Freunde
es gibt wieder Neuigkeiten: nach etwa 7 Tagen ist gestern wieder ein Absturz passiert: dieses Mal blieb der ESP hängen und der automatische Restart konnte nicht mehr ausgeführt werden. Das Problem konnte nur durch einen manuellen Reboot beseitigt werden. Danach ist nach nur 3 Stunden schon wieder ein Abbruch aufgetreten, der jedoch durch einen automatischen Restart beseitigt werden konnte.
Nachdem ich gestern noch erfolglos versucht habe, eine andere FTP Lib einzubinden (ließ sich leider nicht fehlerfrei kompilieren). Habe ich aus Zeitgründen beschlossen, zuerst einen Watchdog zu implementieren, was relativ schnell ging und nun hoffe ich, dass dieser auch bei hängendem ESP noch funktioniert.
Außerdem wird die FTP Verbindung nun stündlich unterbrochen und neu aufgebaut.
Nun bin ich gespannt, ob der ESP bis nach meinem bevorstehenden Urlaub funktioniert.

Viele Grüße und bis dann
Dieter

Hallo,
da verspreche ich mit am ehesten was von. Reset ist doch keine Lösung.

Watchdog ?? wie gemacht, wenn er abgestürzt ist wird der eventuell nicht zum Zuge kommen. Wenn er in einer Endlosschleife gelandet ist sollte unter Umständen der interne Watchdog kommen und einen Reset auslösen.

Aber ich habe auch einen ESP32 im Einsatz , Webserver, TCP Server , Touchdisplay , Temperaur sensor. Das Ding läuft seit 3-4 Jahren . So 3-4 mal im Jahr hängt das Ding dann auch. Nicht mehr erreichbar aus dem Wlan , Touch geht nicht mehr , Messwerte werden nicht aktualisiert. Mit einem Ping auf die IP hab ich das schon mal wieder zum laufen gebracht. Aber das ist nicht reproduzierbar. Dann hilft nur Netzstecker ziehen.

Hallo,

Du hast recht, mir wäre eine saubere Lösung auch lieber. Allerdings weiß ich zum jetzigen Zeitpunkt noch nicht, was die eigentliche Ursache ist und nachdem ich doch relativ viele Beiträge zu Hängern bei ESPs gesehen habe (und Du bestätigst das auch), kann ich nicht ausschließen, dass es am ESP selbst liegt. Schließlich handelt es sich um Consumer Elektronik und so wie unsere PCs und Smartphones gelegentlich abstürzen, kann das auch unserem kleinen Wunderwerk passieren. Daher habe ich versucht, alle bisher unter Verdacht stehenden Bereiche 'unschädlich' zu machen. Die Zeit wird zeigen, welche Problemfälle auftreten und ob ich alle erwischt habe. Ansonsten muss ich mir was Neues einfallen lassen.

Der Watchdog ist übrigens eine Funktion (Timer) des ESP, der oft genau für solche Fälle eingesetzt wird. Ich habe sie übrigens hier im Forum gefunden: Link
Das war sehr simpel und hat auf Anhieb funktioniert.

Nochmals vielen Dank für Eure Unterstützung, die mich dem Ziel auf jeden Fall näher gebracht hat.
Ich werde nun noch etwas warten und dann diesen Beitrag als erledigt kennzeichnen.
Dieter

Seit über einem Jahr lese ich menütlich meinen Stromverbrauch, speichere die Daten in LittleFS in eine Datei, die ich wöchentlich per FTP auf eine externe Festplatte an der Fritz!Box 7590 speichere. Abgesehen von einem Programmierfehler meinerseits funktioniert das erfreulich gut.

Da Du ja bei einem Provider speicherst, hatte ich mich bislang nicht gemeldet.

Solltest Du nach Deinem Urlaub Interesse an einem Austausch haben, dann gerne, ich muß da auch noch nacharbeiten, hatte aber bislang andere Prioritäten :slightly_smiling_face:

Hallo Agmue

vielen Dank für Deinen Feedback. Gerne komme ich auf Dein Angebot zurück, um mein Problem mit dem Logging meiner Daten auf unserer Fritzbox (7490) zu besprechen und hoffentlich eine Lösung dafür zu finden, dass ich via FTP bisher nicht darauf speichern kann.

Die Speicherung bei meinem Web-Space Provider ist nur eine Notlösung, bis es mir gelingt, die Messdaten auf meiner Fritzbox abzulegen. Da ich aber die Notlösung habe, ist die Lösung des Problems nicht so dringend und kann warten, bis dafür Zeit zur Verfügung steht. Es ist jedenfalls nicht wünschenswert, dass die Daten kreuz und quer durch das Internet reisen, bis sie schließlich auf meinem PC Zuhause landen.

Sofern Du einverstanden bist, melde ich mich nach meinem Urlaub wieder zu diesem Thema.

Viele Grüße und eine gute Zeit
Dieter

Viel Spaß im Urlaub und gute Erholung!

Hallo @agmue
das macht der ESP automatisch ? Nutzt Du dazu eine lib oder das Programteil über das wir beide uns mal ausgetauscht hatten.

ich nutze halt auch dieses Programmteil seit nun mehreren Jahren. Ok das Teil ist nicht ganz optimal das könnte man optimieren, aber es läuft. Es werden Daten auf auf einem Stick in der Fritzbox in einer CSV Datei gespeichert, und dabei alle 2 Stunden eine neue Zeile angehängt. Jeden Monat wird eine neue Datei erzeugt. Immer schön Verbindung aufbauen, schreiben und wieder abbauen.

Die Datei kann ich dann mit Excell auswerten. Ja eine Datenbank auf einem PI wäre besser, aber da hab ich keine Ahnung von.

Gruß Heinz

Ja, mit meinem Programm, basierend auf den Tabs von Fips ( Anleitung: Einführung zu fipsok.de) und als fauler Mensch nutze ich auch Programmbibliotheken. Wenn Du schauen möchtest:

FTP-Tab
#include <FTPClient.h>  //FTPServer and FTPClient Version=0.9.7 https://github.com/dplasa/FTPClientServer
FTPClient ftpClient(LittleFS);                                                 // tell the FTP Client to use LittleFS
FTPClient::ServerInfo ftpServerInfo(FTP_USER, FTP_PASSWORD, "www.fritz.box");  // provide FTP servers credentials and servername

byte altesJahr = 24;  // Mein Fehler, das sollte eigentlich flexibel sein!
byte alteWoche = 0;

void setup_ftp()
{
  ftpClient.begin(ftpServerInfo);
  alteWoche = rtc.getTime("%W").toInt();
  //alteWoche--;  // nur zum Testen!
}

void verarbeiteFTP()
{
  ftpClient.handleFTP();

  enum class Aktion {START, WARTEN, LOESCHEN};
  static Aktion schritt = Aktion::START;
  char buf[80] = {"\n"};
  char dateiName[] = {"/sml000000.csv  "};                                  // Inhalt zur Längenbestimmung
  char fernerDateiName[] = {"/GEMEINSAM/Strom/sml000000.csv  "};            // Inhalt zur Längenbestimmung
  byte aktWoche = rtc.getTime("%W").toInt();
  if ( aktWoche != alteWoche )
  {
    if ( (schritt == Aktion::START) && (rtc.getSecond() == 11) )
    {
      snprintf( dateiName, sizeof(dateiName), "/sml20%02u%02u.csv", altesJahr, alteWoche );
      snprintf( fernerDateiName, sizeof(fernerDateiName), "/GEMEINSAM/Strom/sml20%02u%02u.hsv", altesJahr, alteWoche );  // csv -> hsv
      ftpClient.transfer(dateiName, fernerDateiName, FTPClient::FTP_PUT_NONBLOCKING);
      snprintf( buf, sizeof(buf), "Kopiere von LittleFS %s nach %s", dateiName, fernerDateiName );
      debPrintln( buf );
      DEBUG_L ( buf );
      schritt = Aktion::WARTEN;
    }
    else if (schritt == Aktion::WARTEN)
    {
      const FTPClient::Status &r = ftpClient.check();
      switch (r.result)
      {
        case FTPClient::OK:
          debPrintln( "Transfer fertig." );
          DEBUG_L ( "Transfer fertig." );
          schritt = Aktion::LOESCHEN;
          break;
        case FTPClient::ERROR:
          snprintf( buf, sizeof(buf), "Transfer fehlgeschlagen! code: %u, descr=%s\n", ftpClient.check().code, ftpClient.check().desc.c_str());
          debPrintln( buf );
          DEBUG_L ( buf );
          schritt = Aktion::START;
          break;
        case FTPClient::PROGRESS:
          break;
      }
    }
    else if (schritt == Aktion::LOESCHEN)
    {
      snprintf( dateiName, sizeof(dateiName), "/sml20%02u%02u.csv", altesJahr, alteWoche );
      if (LittleFS.exists(dateiName)) LittleFS.remove(dateiName);             // Datei löschen
      debPrintf( "Datei %s in LittleFS gelöscht.", dateiName );
      DEBUG_F  ( "Datei %s in LittleFS gelöscht.", dateiName );
      alteWoche = aktWoche;
      schritt = Aktion::START;
    }
  }
}

Weil mir andere Sachen dazwischen gekommen sind, sammle ich nun Daten seit Ende Februar letzten Jahres mit einem unvollkommenen Programm. Leider habe ich nicht alle Eventualitäten bedacht, weshalb ich das Projekt auch nicht öffentlich gemacht habe. Ein zweiter ESP32 wartet zwar schon auf ein Testprogramm, aber dann schieben sich wichtigere Dinge dazwischen.

Der Rest läuft, wie von Dir beschrieben.