ESP8266 mit Telegram Bot - im Dauerbetrieb unzuverlässig

Hallo
ich habe einen NodeMCU (ESP8266) mit einem kleinen Programm bestückt, mit dem ich per Telegram Bot ein Relais betätige, das meinen Türöffner im Haus betätigt.
Damit kann ich dann per Telefon und ohne Schlüssel das Haus betreten.
Das ist ganz praktisch, allerdings wird der NodeMCU nach ein paar Tagen immer unzuverlässiger, er öffnet dann gar nicht mehr gleich und dann ein paar Minuten später gleich mehrfach und so Fürze.
Ich zieh dann die Stromversorgung raus und dann geht es wieder eine Weile.
Das ist aber kein befriedigender Zustand.

Ich habe daher überlegt, ob ich die Stromversorgung in eine automatische Schaltsteckdose stecken soll, die jede Nacht (wenn ich es nicht brauche) mal kurz aus und anschaltet.

Aber gibt es evtl elegantere Möglichkeiten, also dass der NodeMCU zB täglich (nächtlich) von sich aus neustartet?

Mein Programm ist jetzt nichts besonderes, dass es den NodeMCU überlasten könnte.
Ich weiß auch gar nicht, was der NodeMCU dann hat, dass er rumfurzt.
Unser Internet hat zur Zeit auch immer wieder mal DSL-Aussetzer (muss die FB sich neu syncen, warum auch immer), könnte auch daran liegen, aber wie gesagt, nach Reboot geht es ja wieder.

Danke für Tipps.
franc

Da bei einem ESP8266 ein Spannungverlust ähnlich dem Reset ist, könntest du deinen ESP8266 zu bestimmten Zeiten kurzzeitig in den DeepSleep schicken. Beim aufwachen startet alles neu.

Aber vielleicht müllst du auch nur dein RAM zu, wodurch der ESP8266 Probleme bekommt.

1 Like

Das deutet auf einen Schaltungsfehler hin.
Zeig duch mal dein Schaltbild. Und bitte auch den Sketch posten, damit wir sehen können, ob das alles past.

OK, ich hab mein Programm mal auf pastebin:
Tueroeffner mit NodeMCU (ESP8266)
(habe vorher alle persönlichen Telegram-Daten geändert)

Schaltungsfehler wundert mich, es ist ja nur an der 5 Volt Versorgung und (bisher) ein Ausgang an einem 5V Relais (ja, kein 3.3V Relais, schaltet aber dennoch zuverlässig, wenn der NodeMCU denn schaltet), nämlich die Stromversorung für das Relais an G und VV angeschlossen und der Ausgang vom NodeMCU ist D1, der geht an den Eingang vom Relais.
Hier zwei Fotos:

grafik

Das grüne Kabel im Vordergrund soll dann mal für die Anzapfung der Klingel dienen (noch nicht implementiert). Also das soll dann an D2 (als Eingang) für den NodeMCU angeschlossen werden und dem sagen, wenn es klingelt (ToDo).

Hier ein Screenshot aus Telegram:

So sieht es dann im Chat aus, mit Buttons.
Man sieht weiter oben, 5. Juli, wie es spinnt, nämlich hatte ich um 8:49 /open1 gedrückt, um 9:42 reagierte es dann doppelt und gibt 4 x die Startmeldung aus.

Den Sketch immer hier im Forum in Code-Tags posten. Auf externen Servern ist der Sketch demnächst verschwunden und der Thread zerrissen.
Leider vermisse ich das Schaltbild, auf den Fotos ist fast nichts zu erkennen.

OK, dann noch mal hier:

#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <UniversalTelegramBot.h>

// Wifi network station credentials
#define WIFI_SSID "accesspoint"
#define WIFI_PASSWORD "wifi-password"
#define BOT_TOKEN "1234567890:ABCDEF-123abcd3141239ajdfafwj93blabla"


// 2022-04-10: fuer Debug Ausgaben im Serial Monitor (Tools >) debug auf true setzen
bool debug = false;

const unsigned long BOT_MTBS = 1000; // mean time between scan messages

X509List cert(TELEGRAM_CERTIFICATE_ROOT);
WiFiClientSecure secured_client;
UniversalTelegramBot bot(BOT_TOKEN, secured_client);
unsigned long bot_lasttime; // last time messages' scan has been done

// 2022-05-11: LED Ansteuerung deaktiviert, braucht man wohl nicht mehr
// const int ledPin = LED_BUILTIN;
// int ledStatus = 0;

// relaisDelay (open_time) kann per Kommando veraendert werden (bis Reboot) aber nicht laenger als relaisMaxDelay ms sein
int relaisDelay = 3000;
int relaisMaxDelay = 10000;

// falscher from_name oder chat_id ergibt eine Pause von nagDelay ms fuer das naechste Kommando
int nagDelay = 10000;

// Anmerkung: 2022-04-06: von: https://www.smarthome-tricks.de/esp8266/relais-schalten/
// (GPIO 5)
int pinRelais1 = D1;
// 2022-05-12: siehe: https://randomnerdtutorials.com/esp8266-pinout-reference-gpios/
// (GPIO 4)
int pinKlingel = D2;
int relaisStatus = 0;

// Anmerkung: 2022-04-09: trusted_chat_ids und temp_trusted_chat_ids
// ToDo: hier ein String-Array fuer dauerhaft erlaubte und temporaer erlaubte chat_id anlegen, die man im laufenden ESP hinzufuegen kann.
String trusted_chat_id1 = "1234567890";
String trusted_chat_id2 = "0987654321";
// mit trusted_chat_ids.length() dann ein loop o.ae. durchlaufen

// temp. chat_id default auf Anna gesetzt, zur Laufzeit ueberschreibbar durch Befehl
String temp_trusted_chat_id = "1234567890";
String temp_trusted_from_name = "123beda6725423548245093854f19cd9";

// Befehlsbuttons global hier 
String keyboardJson = "[[\"/help\", \"/open\"],[\"/open_in_10\", \"/open1\"]]";

// function to check if a string is a valid number (for relaisDelay setting by command)
boolean isNumber(String str)
{
  for(byte i=0;i<str.length();i++)
  {
    if(!isDigit(str.charAt(i))) return false;
  }
  return true;
}

void handleNewMessages(int numNewMessages)
{
  if (debug) Serial.print("handleNewMessages ");
  if (debug) Serial.println(numNewMessages);

  for (int i = 0; i < numNewMessages; i++)
  {
    String chat_id = bot.messages[i].chat_id;
    String text = bot.messages[i].text;
    String from_name = bot.messages[i].from_name;
    if (from_name == "") from_name = "Guest";    

    // die Eigenschaften der Struktur telegramMessage des Objekts UniversalTelegramBot ausgeben
    // von: https://github.com/witnessmenow/Universal-Arduino-Telegram-Bot/blob/master/src/UniversalTelegramBot.h
    // debug auf true zum Auslesen

    if (debug) 
    {
      Serial.print("text: ");
      Serial.println(text);
      
      Serial.print("chat_id: ");
      Serial.println(chat_id);   

      String chat_title = bot.messages[i].chat_title;
      Serial.print("chat_title: ");
      Serial.println(chat_title);
      
      String from_id = bot.messages[i].from_id;
      Serial.print("from_id: ");
      Serial.println(from_id);

      Serial.print("from_name: ");
      Serial.println(from_name);

      String date = bot.messages[i].date;
      Serial.print("date: ");
      Serial.println(date);

      String type = bot.messages[i].type;
      Serial.print("type: ");
      Serial.println(type);

      String file_caption = bot.messages[i].file_caption;
      Serial.print("file_caption: ");
      Serial.println(file_caption);

      String file_path = bot.messages[i].file_path;
      Serial.print("file_path: ");
      Serial.println(file_path);

      String file_name = bot.messages[i].file_name;
      Serial.print("file_name: ");
      Serial.println(file_name);

      //    Bool hasDocument = bot.messages[i].hasDocument;
      //    Serial.print("hasDocument: ");
      //    Serial.println(String(hasDocument));

      int file_size = bot.messages[i].file_size;
      Serial.print("file_size: ");
      Serial.println(String(file_size));

      Serial.print("trusted_chat_id1: ");
      Serial.println(trusted_chat_id1);
      
      Serial.print("trusted_chat_id2: ");
      Serial.println(trusted_chat_id2);    
      
      Serial.print("temp_trusted_chat_id: ");
      Serial.println(temp_trusted_chat_id);
      
      Serial.print("temp_trusted_from_name: ");
      Serial.println(temp_trusted_from_name);
    }

      /*
      
      die paar fehlen noch:
      
      struct telegramMessage {
      ...
        float longitude;
        float latitude;
        int update_id;
        int message_id;  

        int reply_to_message_id;
        String reply_to_text;
        String query_id;
      };
      */

  // Anna (1234567890 bzw trusted_chat_id1) oder Berta (0987654321 bzw trusted_chat_id2) oder temp. chat_id (initial Anna) oder tem_trusted_from_name (initial md5(Anna))
    if ((chat_id == trusted_chat_id1) || (chat_id == trusted_chat_id2) || (chat_id == temp_trusted_chat_id) || ((from_name == temp_trusted_from_name) && (from_name != "")))
    {
      if (debug) Serial.print("chat_id OK - Befehlsabfrage...\n");
          
      if ((text == "/info") || (text == "/help"))
      {
        String help = "Hallo " + from_name + ".\n\n";
        help += "/info oder /help: Diesen Text zeigen\n";
        help += "/debug : Die seriellen Ausgaben in der IDE umschalten\n(Standard: aus. Code: sets debug = !debug)\n";
        help += "/open_time:<ms> : Setzt (bis zum nächsten Reboot) die Öffnungszeit in Millisekunden (max. 10000)\n";
        help += "/chat_id:<Chat-ID> : Berechtigt (bis zum nächsten Reboot) zusätzlich diese Chat-ID für Kommandos\n";
        help += "/from_name:<Telegram-Name> : Berechtigt (bis zum nächsten Reboot) zusätzlich diesen Telegram-Namen für Kommandos (leer=nicht erlaubt)\n";
        help += "/open : Tür öffnen für " + String(relaisDelay) + " Millisekunden\n";
        help += "/open1 : Tür eine Sekunden lang öffnen\n";
        help += "/open_in_10 : Tür nach 10 Sekunden öffnen für " + String(relaisDelay) + " Millisekunden\n";
        help += "/open:<ms> : Tür für <ms> Millisekunden öffnen (max 10000)\n";
        // welcome += "chat_id: " + chat_id;
        if (debug) Serial.print("help: \n");
        if (debug) Serial.println(help);
        bot.sendMessage(chat_id, help, "");
      }
    
      if (text == "/open")
      {
        String command = "Tür öffnen für " + String(relaisDelay) + " ms...";      
        bot.sendMessage(chat_id, command, "");       
        digitalWrite(pinRelais1, LOW); // turn the Relais on
        delay(relaisDelay);
        digitalWrite(pinRelais1, HIGH); // turn the Relais off again
        // command = "Relais was ON for " + String(relaisDelay) + " ms\n\nTo open press: \n/open";      
        // bot.sendMessage(chat_id, command, "");      
        // String keyboardJson = "[[\"/help\", \"/open\"],[\"/open_in_10\", \"/open1\"]]";
        bot.sendMessageWithReplyKeyboard(chat_id, "Für alle Befehle auf /help tippen...", "", keyboardJson, true);
      }
      if (text == "/open1")
      {
        String command = "Tür eine Sekunde öffnen ...";      
        bot.sendMessage(chat_id, command, "");       
        digitalWrite(pinRelais1, LOW); // turn the Relais on
        delay(1000);
        digitalWrite(pinRelais1, HIGH); // turn the Relais off again
        // command = "Relais was ON for " + String(relaisDelay) + " ms\n\nTo open press: \n/open";      
        // bot.sendMessage(chat_id, command, "");      
        // String keyboardJson = "[[\"/help\", \"/open\"],[\"/open_in_10\", \"/open1\"]]";
        bot.sendMessageWithReplyKeyboard(chat_id, "Für alle Befehle auf /help tippen...", "", keyboardJson, true);
      }
      // ToDo: 2022-04-14: noch fertig stellen und testen:
      if (text.substring(0, 6) == "/open:")
      {
        int length = text.length();
        

        String str_open_length = text.substring(6, length);
        if (isNumber(str_open_length))
        {
          int open_length = str_open_length.toInt();
          // nicht kleiner als 100 ms und nicht groesser als 10000 ms
          if (open_length < 100 || open_length > 10000) open_length = relaisDelay;
          String command = "Tür " + String(open_length) + " Millisekunden öffnen ..."; 
          bot.sendMessage(chat_id, command, "");
          digitalWrite(pinRelais1, LOW); // turn the Relais on
          delay(open_length);
          digitalWrite(pinRelais1, HIGH); // turn the Relais off again
          // command = "Relais was ON for " + String(relaisDelay) + " ms\n\nTo open press: \n/open";      
          // bot.sendMessage(chat_id, command, "");      
          // String keyboardJson = "[[\"/help\", \"/open\"],[\"/open_in_10\", \"/open1\"]]";
          bot.sendMessageWithReplyKeyboard(chat_id, "Für alle Befehle auf /help tippen...", "", keyboardJson, true);

        }
        else
        {
          // String keyboardJson = "[[\"/help\", \"/open\"],[\"/open_in_10\", \"/open1\"]]";
          bot.sendMessageWithReplyKeyboard(chat_id, "/open:<ms> - <ms> muss eine Zahl sein!", "", keyboardJson, true);
        }

        
      }
      if (text == "/open_in_10")
      {
        String command = "Tür in 10 Sekunden für " + String(relaisDelay) + " Millisekunden öffnen...";     
        bot.sendMessage(chat_id, command, "");   
        // 10 Sek. warten
        delay(10000);     
        digitalWrite(pinRelais1, LOW); // turn the Relais on
        delay(relaisDelay);
        digitalWrite(pinRelais1, HIGH); // turn the Relais off again
        // command = "Relais was ON for " + String(relaisDelay) + " ms\n\nTo open press: \n/open";      
        // bot.sendMessage(chat_id, command, "");      
        // String keyboardJson = "[[\"/help\", \"/open\"],[\"/open_in_10\", \"/open1\"]]";
        bot.sendMessageWithReplyKeyboard(chat_id, "Für alle Befehle auf /help tippen...", "", keyboardJson, true);
      }

      // temporaere chat_id zulassen
               
      if (text.substring(0, 9) == "/chat_id:")
      {
        if (debug) Serial.print("text.substring(0,9): ");
        if (debug) Serial.println(text.substring(0, 9));
        int length = text.length();
        temp_trusted_chat_id = text.substring(9, length);
        if (debug) Serial.print("length: ");
        if (debug) Serial.println(String(length));
        if (debug) Serial.print("temp_trusted_chat_id: ");
        if (debug) Serial.println(temp_trusted_chat_id);
        String command = "Allow commands from chat_id: " + temp_trusted_chat_id;      
        bot.sendMessage(chat_id, command, "");       
      }
      if (text.substring(0, 11) == "/from_name:")
      {
        int length = text.length();
        // wenn leer, also length = 11 dann wird der temp. from_name (temp_trusted_from_name) geleert (initial der md5 von Anna)
        String command = "";
        if (length == 11)
        {
          temp_trusted_from_name = "";
          String command = "from_name geleert, from_name nicht mehr aktiv"; 
        }
        else
        {
          temp_trusted_from_name = text.substring(11, length);
          String command = "Befehle (bis Reboot) erlauben von Telegram-Name: " + temp_trusted_from_name;           
        }        
        if (debug) Serial.print("length: ");
        if (debug) Serial.println(String(length));
        if (debug) Serial.print("temp_trusted_from_name: ");
        if (debug) Serial.println(temp_trusted_from_name);     
        bot.sendMessage(chat_id, command, "");       
      }     
      if (text.substring(0, 11) == "/open_time:")
      {
        String command = "";
        int length = text.length();
        String temp_open_time = text.substring(11, length);
        if (debug) Serial.print("length: ");
        if (debug) Serial.println(String(length));
        if (debug) Serial.print("temp_open_time: ");
        if (debug) Serial.println(temp_open_time);
        if (isNumber(temp_open_time))
        {
          int tempRelaisDelay = temp_open_time.toInt();
          if (tempRelaisDelay > relaisMaxDelay) relaisDelay = relaisMaxDelay; // max delay 
          else if (tempRelaisDelay < 100) relaisDelay = relaisDelay; // unchanged if less 100 ms
          else relaisDelay = tempRelaisDelay;
          command = "open_time now (till next reboot): " + String(relaisDelay); 
          if (debug) Serial.print(command);
        }
        else
        {
          command = "open_time must be a number!"; 
          if (debug) Serial.print("temp_open_time is not a number! command: " + command);
        }
        bot.sendMessage(chat_id, command, "");
      }
      if (text == "/debug")
      {
        debug = !debug;
        if (debug) 
        {
          bot.sendMessage(chat_id, "Debug Nachrichten zum Seriellen Monitor aktiviert (debug = true)", "");
          Serial.print("Debug enabled");
        }
        else 
        {
          bot.sendMessage(chat_id, "Debug Nachrichten zum Seriellen Monitor deaktiviert (debug = false)", "");
        }
      }
      // Sendet Debug Nachrichten (natuerlich nur an Anna)
      if (debug) 
      {
        String debugMessage = "debug:\n";
        debugMessage += "from_name: " + from_name;
        String from_id = bot.messages[i].from_id;
        debugMessage += "\nfrom_id: " + from_id;
        debugMessage += "\nchat_id: " + chat_id;        
        debugMessage += "\ntemp_trusted_from_name: " + temp_trusted_from_name;
        debugMessage += "\ntemp_trusted_chat_id: " + temp_trusted_chat_id;
        debugMessage += "\ntrusted_chat_id1: " + trusted_chat_id1;
        debugMessage += "\ntrusted_chat_id2: " + trusted_chat_id2;
        debugMessage += "\ntext: " + text;
        bot.sendMessage(trusted_chat_id1, debugMessage, "");
      }
    }
    else
    {
      // wrong chat_id or from_name makes delay 
      if (debug) Serial.print("from_name: ");
      if (debug) Serial.println(from_name);
      if (debug) Serial.print("chat_id: ");
      if (debug) Serial.println(chat_id);        
      if (debug) Serial.print("wrong chat_id / from_name - delay...");
      if (debug) 
      {
        String debugMessage = "debug\nwrong chat_id / from_name - delay\n";
        debugMessage += "from_name: " + from_name;
        String from_id = bot.messages[i].from_id;
        debugMessage += "\nfrom_id: " + from_id;
        debugMessage += "\nchat_id: " + chat_id;        
        debugMessage += "\ntemp_trusted_from_name: " + temp_trusted_from_name;
        debugMessage += "\ntemp_trusted_chat_id: " + temp_trusted_chat_id;
        debugMessage += "\ntrusted_chat_id1: " + trusted_chat_id1;
        debugMessage += "\ntrusted_chat_id2: " + trusted_chat_id2;
        debugMessage += "\text: " + text;
        bot.sendMessage(trusted_chat_id1, debugMessage, "");
      }      
      delay(nagDelay);
    }
  }
}
// 2022-05-12: noch ganz primitiv implementiert, wenn HIGH auf dem D2 Pin (GPIO4)
// ToDo: noch genauer differenzieren an wen geschickt wird, evtl. mit Parameter von klingel()
// evtl. noch fuer Klingel Code die Tuer oeffnen, dann aber die Klingel unterbrechen, also per Relais als weiteren Ausgang
void klingel()
{
  // Nachricht an Anna (hartcodiert, noch)
  bot.sendMessage("1234567890", "Es hat geklingelt!", "");
}
void bot_setup()
{
// 2022-05-12: von SetMyCommands inspiriert, siehe:
// https://github.com/witnessmenow/Universal-Arduino-Telegram-Bot/blob/master/examples/ESP8266/SetMyCommands/SetMyCommands.ino 
// die Befehle werden beim Bot selbst hinterlegt, daher kann man sie auch per anderem ESP8266 hochladen und sie wirken auch
// fuer das NodeMCU Tueroeffner, das man gar nicht damit aktualisieren muss.
// Links in der Eingabezeile sieht man dann ein Menue zum Hochklappen mit den Befehlen
  const String commands = F("["
                            "{\"command\":\"/help\",  \"description\":\"Alle Befehle mit Erklärung anzeigen\"},"
                            "{\"command\":\"/debug\",  \"description\":\"Serielle Ausgabe an/aus und Debug an Anna\"},"
                            "{\"command\":\"/open_in_10\",  \"description\":\"Tür in 10s öffnen (3s)\"},"
                            "{\"command\":\"/open1\", \"description\":\"Tür öffnen (1s)\"},"
                            "{\"command\":\"/open\",\"description\":\"Tür öffnen (3s)\"}" // no comma on last command
                            "]");
  bot.setMyCommands(commands);  
}

void setup()
{
  // muss auch wenn debug aus ist aktiviert werden, sonst kann man nicht mit /debug umschalten
  Serial.begin(115200);
  Serial.println();
  
  // LED auskommentiert, nicht mehr benoetigt
  // pinMode(ledPin, OUTPUT); // initialize digital ledPin as an output.
  // delay(10);
  // digitalWrite(ledPin, HIGH); // initialize pin as off (active LOW)
  // Anmerkung: 2022-04-06: von: https://www.smarthome-tricks.de/esp8266/relais-schalten/
  pinMode(pinRelais1 , OUTPUT);
  digitalWrite(pinRelais1, HIGH); // initialize pin as off (active LOW)

  // 2022-05-12: schon mal den Rohbau fuer die Klingelabfrage:
  pinMode(pinKlingel, INPUT);
  
  // attempt to connect to Wifi network:
  configTime(0, 0, "pool.ntp.org");      // get UTC time via NTP
  secured_client.setTrustAnchors(&cert); // Add root certificate for api.telegram.org
  if (debug) Serial.print("Connecting to Wifi SSID ");
  if (debug) Serial.print(WIFI_SSID);
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  while (WiFi.status() != WL_CONNECTED)
  {
    if (debug) Serial.print(".");
    delay(500);
  }
  if (debug) Serial.print("\nWiFi connected. IP address: ");
  if (debug) Serial.println(WiFi.localIP());

  // Check NTP/Time, usually it is instantaneous and you can delete the code below.
  if (debug) Serial.print("Retrieving time: ");
  time_t now = time(nullptr);
  while (now < 24 * 3600)
  {
    if (debug) Serial.print(".");
    delay(100);
    now = time(nullptr);
  }
  if (debug) Serial.println(now);

  // String keyboardJson = "[[\"/help\", \"/open\"],[\"/open_in_10\", \"/open1\"]]";
  bot.sendMessageWithReplyKeyboard(trusted_chat_id1, "NodeMCU: tueroeffner.ino Start...", "", keyboardJson, true);
   
//  String startup = "NodeMCU: tueroeffner.ino - Startup\n\nFor info press:\n/info\n\nTo open press:\n/open";
//  bot.sendMessage("1234567890", startup, "");
  bot_setup();
}

void loop()
{
  // millis ist die Zeit in ms seit dem letzten Reboot. bot_lasttime wird unten auf millis gesetzt und sobald millis() eine Sekunde (BOT_MTBS) weiter ist, wird das if betreten
  if (millis() - bot_lasttime > BOT_MTBS)
  {
    int numNewMessages = bot.getUpdates(bot.last_message_received + 1);

    while (numNewMessages)
    {
      if (debug) Serial.println("got response");
      handleNewMessages(numNewMessages);
      numNewMessages = bot.getUpdates(bot.last_message_received + 1);
    }

    bot_lasttime = millis();
  } 
  else
  {
    // 2022-05-12: den Eingang pruefen, wenn auf Masse, dann Funktion klingel() aufrufen
    // ToDo: genauer die Bedingung pruefen und auf dem Board ueber einen Widerstand gg Plus oder Masse eindeutig setzen
    /*
   das funktioniert noch nicht so, muss noch ein Widerstand rein, dass der Eingang auch def. ist, daher erst mal raus
    if (digitalRead(pinKlingel) == LOW) 
    {
      klingel();
    }
    */
  } 

}

allerdings ist pastebin schon sehr dauerhaft bisher, da ist noch nichts verschwunden.

Hier das Schaltbild, viel ist es ja nicht.

Was sagt den der serielle Monitor, wenn debug aktiviert ist und der Fehler auftritt ?

Das kann ich nicht sagen, weil ich den NodeMCU ja dauerhaft im Einsatz habe und nicht am PC hängen.
Der spinnt ja auch nicht gleich, sondern erst nach Tagen.

Ich müsste es etwas umprogrammieren und debug zum Bot schicken, dann könnte ich es evtl. lesen.

Als erstes müsste ich mal immer, wenn er offline ging und dann wieder online geht eine Nachricht schicken, vielleicht ist das ja oft und hat mit dem Fehler auch zu tun.
Also jede Sekunde nicht nur den Bot Nachrichtenspeicher auslesen, sondern auch
(WiFi.status() == WL_CONNECTED) prüfen. Falls false, beim nächsten Mal wenn true eine Nachricht etwa "NodeMCU wieder online. Offline am x seit y Uhr." schicken.

Naja, das wäre doch das Erste was man machen sollte.
Wenn ein Programm dies schon bietet, ist es doch der einfachste Weg.
Alles andere ist doch nur raten.

Und ob das mit dem Bot dann noch funktioniert, bezweifle ich.
Wenn de ESP hängt, geht nix mehr.

Der einfachste Weg wäre vermutlich mit einem Zeitschalter nachts :smirk:

Den Fehler umgehen und ignorieren ?

Nicht elegant und auf Dauer unbefriedigend.
Aber wie kann ich denn mit serial debug überhaupt sehen, ob mein RAM überläuft oder so was in die Richtung?
Ich bezweifle, dass meine bisherigen Ausgaben überhaupt was bringen...

Du arbeitest viel mit Strings die sich ändern. Da diese immer zusammenhängend im RAM liegen, fragmentiert der RAM mit der Zeit. Es muss immer wieder eine zusammenhängend freie Stelle im RAM gefunden werden. Wenn keine freie Stelle mehr gefunden wird, hängt sich das System auf.

1 Like

Klingt einleuchtend, aber was kann man da machen?
Würde da ein DeepSleep und wieder Aufwachen (nach 1 Sekunde) helfen?

Noch was fallt mir ein:

In meiner Deklaration sind zwei Fehler gemeldet (nur in der Arduino 2 IDE, in der 1 nicht):

#include <ESP8266WiFi.h>

In included file: typedef redefinition with different types ('int' vs '_ssize_t' (aka 'long long'))clang(redefinition_different_typedef)
arch.h(202, 13): Error occurred here
types.h(185, 18): Previous definition is here

und:

#include <UniversalTelegramBot.h>

In included file: use of undeclared identifier 'char16_t'clang(undeclared_var_use)
char_traits.h(706, 24): Error occurred here

Die Header-Dateien kommen allerdings aus der Bibliothek aus Github, da habe ich ja gar nichts geändert.
Könnte der Fehler vielleicht auch daran liegen?
Aber dann dürfte es doch überhaupt erst gar nicht kompilieren...

Der DeepSleep kommt einem Reset gleich, was den kompletten RAM wieder frei gibt. Dies würde das Problem des Fragmentieren, wenn es der Auslöser ist, beheben.

Anderseits könntest du CharArrays nutzen und diesen ein ausreichende Länge geben. Da die Länge dann immer gleich bleibt, tritt die Fragmentierung dadurch nicht auf.

Schwieriger, aber nicht unmöglich, die Strings auf fester Länge halten. Würde ich aber nicht tun.

Ich denke ein täglicher Reset sollte dein String Problem lösen.

1 Like

Nicht das eigentliche Problem lösen, sondern nur die Auswirkungen vermindern.

Gruß Tommy

Also Kabel legen von D0 auf RST wie hier beschrieben:

ESP8266 Deep Sleep with Arduino IDE (NodeMCU)

und mit zB: ESP.deepSleep(1e5); eine Zehntelsekunde Schlafenlegen (oder noch kürzer) und dann bootet er wieder neu.
Die Zeit zum Schlafengehen muss ich aber dann erst noch mit der NTPClient Bibliothek holen.

Nunja, das Problem besteht vermutlich darin das der RAM fragmentiert. Dieses Problem kann man mit einem Reset lösen, da nach dem Reset der RAM wieder aufgeräumt ist.

Natürlich kann man auch die Ursache des fragmentierens beheben. Dies kann aber auch etwas aufwendiger sein. Die Frage ist was man will. Eine schnelle Lösung. Oder eine ordentliche Lösung.

Dann eher eine schnelle Pseudolösung oder eine Lösung.
Ein Reset als Lösung kaschiert in meinen Augen eigentlich nur eine schlechte Programmierung, die man nicht verbessern will.

Gruß Tommy

1 Like