mobizt / Firebase-ESP-Client

[DEPRECATED]🔥Firebase Arduino Client Library for ESP8266, ESP32 and RP2040 Pico. The complete, fast, secured and reliable Firebase Arduino client library that supports RTDB, Cloud Firestore, Firebase and Google Cloud Storage, Cloud Messaging and Cloud Functions for Firebase.
MIT License
471 stars 100 forks source link

No more processes #596

Closed sudilacf closed 10 months ago

sudilacf commented 10 months ago

tcpWrite(): fail on fd 59, errno: 11, "No more processes

how to fix this problem?

mobizt commented 10 months ago

You should create minimal code that reproduces the issue.

The issue is about the bugs in ESP32 WiFiClient core library when the session was reused while the connection was terminated by server.

  1. You should not use async functions.
  2. Firebase closes the session in 50 seconds even the session was kept alive for reuse. Then call fbdo.clear() after the session was opened (server connected) longer than 50 seconds.
sudilacf commented 10 months ago

so I need to call fbdo.clear() after using get/set function?

mobizt commented 10 months ago

No, it's not necessary, it depends on your code which FirebaseData object may be used incorrectly, and I suggest based on the error.

If FirebaseData object used for stream with callback, you should not reuse it for other functions. If you use, xxxAsync, please avoid using it.

mobizt commented 10 months ago

Minimal?

sudilacf commented 10 months ago

Minimal?

Im using 3 FirebaseData object two for MultiStream and one fbdo

void feedStreamCallback(MultiPathStream data) {

  Serial.printf("Feed:\nLength: %d\nMax: %d\n", data.payloadLength(), data.maxPayloadLength());

  if(data.get("/now")) {

    if(data.value.equals("true")) {

      if(Firebase.RTDB.setBool(&fbdo, "/feed/now", false)) {

        if(addToHistory(&fbdo)) {

          if(Firebase.RTDB.setString(&fbdo, "/settings/push_key", fbdo.pushName())) {

            feed();

          }

        }

      }

    }

  }

  if(data.get("/offset")) {

    scheduleOffset = data.value.toInt();

  }

  if(data.get("/on")) {

    scheduleOn = data.value;

  }

}

void settingsStreamCallback(MultiPathStream data) {

  Serial.printf("Settings:\nLength: %d\nMax: %d\n", data.payloadLength(), data.maxPayloadLength());

  if(data.get("/push_key")) {

    if(Firebase.RTDB.getJSON(&fbdo, "/history/" + data.value)) {

      json = fbdo.jsonObject();

    } else {

      lcd.clear();
      lcd.print("Last fed:");
      lcd.setCursor(0, 1);
      lcd.print("No data to show");

    }

  }

}
mobizt commented 10 months ago

No, minimal does not mean the fraction of code.

You should create minimal, clean without third party libraries but complete that reproduces the issue and post here instead of your code.

I can't verify or debug your complex code.

mobizt commented 10 months ago

Did you know this will cause memory leaks?

Firebase.RTDB.setString(new FirebaseData()...

When you dynamically allocated the FirebaseData with new without using delete.

mobizt commented 10 months ago

The FirebaseData object is not only contains data but SSL Client and its resource which you should defined it locally or globally whenever you used it in usage scope.

sudilacf commented 10 months ago

this is the summarization of my code:

#include <WiFi.h>
#include <TimeLib.h>
#include <WiFiUdp.h>
#include <NTPClient.h>
#include <Firebase_ESP_Client.h>

int scheduleOffset;
String scheduleOn;

FirebaseData fbdo;
FirebaseData feedStream;
FirebaseData settingsStream;
FirebaseAuth auth;
FirebaseConfig config;
FirebaseJson json;
FirebaseJsonData result;

WiFiUDP clientUDP;
NTPClient timeClient(clientUDP, "asia.pool.ntp.org", 3600 * 8);

void feedStreamCallback(MultiPathStream data);
void settingsStreamCallback(MultiPathStream data);
void streamTimeoutCallback(bool);

void setup() {

    Serial.begin(115200);

    WiFi.begin("WIFISSID", "PASSWORD");
    while (WiFi.status() != WL_CONNECTED)
    {
        Serial.print(".");
        delay(500);
    }
    Serial.println("connected");

    config.database_url = "";
    config.signer.tokens.legacy_token = "";

    Firebase.reconnectNetwork(true);
    fbdo.setBSSLBufferSize(2048, 1024);
    feedStream.setBSSLBufferSize(2048, 1024);
    settingsStream.setBSSLBufferSize(2048, 1024);
    Firebase.begin(&config, &auth);
    feedStream.keepAlive(5, 5, 1);
    settingsStream.keepAlive(5, 5, 1);

    if(!Firebase.RTDB.beginMultiPathStream(&feedStream, "/feed")) {
        Serial.printf("Failed to begin stream %s\n", feedStream.errorReason().c_str());
        return;
    }

    if(!Firebase.RTDB.beginMultiPathStream(&settingsStream, "/settings")) {
        Serial.printf("Failed to begin stream %s\n", settingsStream.errorReason().c_str());
        return;
    }

    Firebase.RTDB.setMultiPathStreamCallback(&feedStream, feedStreamCallback, streamTimeoutCallback);
    Firebase.RTDB.setMultiPathStreamCallback(&settingsStream, settingsStreamCallback, streamTimeoutCallback);

}

void loop() {

    if (!Firebase.ready())
        return;

    timeClient.update();

    json.get(result, "month");
    String monthStr(result.to<int>());
    json.get(result, "day");
    String dayStr(result.to<int>());
    json.get(result, "year");
    String yearStr(result.to<int>());
    json.get(result, "hour");
    String hourStr(result.to<int>());
    json.get(result, "minute");
    String minuteStr(result.to<int>());
    json.get(result, "meridian");
    String meridian(result.to<String>());
    String lastFed = monthStr + "/" + dayStr + "/" + yearStr + " " + hourStr + ":" + minuteStr + ":00 " + meridian;

    if(!scheduleOn.isEmpty() && !scheduleOn.equals(lastFed) && getTimeOffset(0).equals(scheduleOn)) {

        if(addToHistory(&fbdo)) {

            if(Firebase.RTDB.setString(new FirebaseData(), "/settings/push_key", fbdo.pushName())){

            if(Firebase.RTDB.setString(new FirebaseData(), "/feed/on", getTimeOffset(scheduleOffset))) {

                feed();

            }

            }

        }

    }

}

void feedStreamCallback(MultiPathStream data) {

  Serial.printf("Feed:\nLength: %d\nMax: %d\n", data.payloadLength(), data.maxPayloadLength());

  if(data.get("/now")) {

    if(data.value.equals("true")) {

      if(Firebase.RTDB.setBool(&fbdo, "/feed/now", false)) {

        if(addToHistory(&fbdo)) {

          if(Firebase.RTDB.setString(&fbdo, "/settings/push_key", fbdo.pushName())) {

            feed();

          }

        }

      }

    }

  }

  if(data.get("/offset")) {

    scheduleOffset = data.value.toInt();

  }

  if(data.get("/on")) {

    scheduleOn = data.value;

  }

}

void settingsStreamCallback(MultiPathStream data) {

  Serial.printf("Settings:\nLength: %d\nMax: %d\n", data.payloadLength(), data.maxPayloadLength());

  if(data.get("/push_key")) {

    if(Firebase.RTDB.getJSON(&fbdo, "/history/" + data.value)) {

      json = fbdo.jsonObject();

    }

  }

}

void feed() {

  //rotate servo

}

bool addToHistory(FirebaseData *fbdo) {

    const char *weekday_names[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
    const char *month_names[] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
    unsigned long epochTime = timeClient.getEpochTime();
    const char *meridian = isAM(epochTime) ? "AM" : "PM";
    FirebaseJson json;

    json.set("week_day_name", weekday_names[weekday(epochTime) - 1]);
    json.set("year", year(epochTime));
    json.set("month", month(epochTime));
    json.set("month_name", month_names[month(epochTime) - 1]);
    json.set("day", day(epochTime));
    json.set("hour", hourFormat12(epochTime));
    json.set("minute", minute(epochTime));
    json.set("second", second(epochTime));
    json.set("meridian", meridian);
    json.set("epoch_time", epochTime);

    return Firebase.RTDB.pushJSON(fbdo, "/history", &json);

}
mobizt commented 10 months ago

Please read my previous comment, your code causes memory leaks and will not work properly.

sudilacf commented 10 months ago

The FirebaseData object is not only contains data but SSL Client and its resource which you should defined it locally or globally whenever you used it in usage scope.

which FirebaseData do you mean?

mobizt commented 10 months ago

Already told in my previous comment.

mobizt commented 10 months ago

Did you know this will cause memory leaks?

Firebase.RTDB.setString(new FirebaseData()...

When you dynamically allocated the FirebaseData with new without using delete.

sudilacf commented 10 months ago

Did you know this will cause memory leaks? Firebase.RTDB.setString(new FirebaseData()... When you dynamically allocated the FirebaseData with new without using delete.

Ow I see, I'll try to remove it and test again. thanks

sudilacf commented 10 months ago

sir I got another problem

tcpWrite(): fail on fd 51, errno: 128, "Socket is not connected"

what causes this? can I use keepAlive() on my fbdo object and will it fix? cuz I only used keepAlive() on my stream.

mobizt commented 10 months ago

The same reason, the connection terminated by server which WiFiClient does not handle this properly as a bug in ESP32 WiFiClient library.

To be fix, the WiFiClient should be closed the connection on its end as server is gone instead of just give the error and still vaiting the data in the infinite loop without closing the session.

Now you should update the library by download the zip file from library repository.

sudilacf commented 10 months ago

I think I fixed it after removing Firebase.reconnectNetwork(true) cuz I have code for internet reconnection.

btw, can you send me the link of WiFiClient lib pls, I cant find it.

mobizt commented 10 months ago

No, it's internally implemented, and you should update the library.

Anyway, you should follow the example and read the comment first. https://github.com/mobizt/Firebase-ESP-Client/blob/a3701a04f0d1f82955a75140729100554e5fc0a2/examples/RTDB/Basic/Basic.ino#L118-L119

sudilacf commented 10 months ago

But I'm using the latest version of library 4.4.8, shall I download it here in github instead in platform IO?

And yes, already read that.

mobizt commented 10 months ago

I just update the library and it takes several hours for Arduino Library Manager to update.

In PlatformIO, you can update it now.

sudilacf commented 10 months ago

Thanks bro