mobizt / Firebase-ESP32

[DEPRECATED]🔥 Firebase RTDB Arduino Library for ESP32. The complete, fast, secured and reliable Firebase Arduino client library that supports CRUD (create, read, update, delete) and Stream operations.
MIT License
415 stars 118 forks source link

HELP StreamData limit Esp32 #62

Closed opit7 closed 4 years ago

opit7 commented 4 years ago

Hello, is there a limit on how many StreamData instances can be initalized ? Because as soon as i use more than two for a stream with callback functions the streams stop working.

// basics
  Firebase.begin(this->config.FIREBASE_ID.c_str(), this->config.FIREBASE_SECRET.c_str());
  Firebase.reconnectWiFi(true);
  Firebase.setMaxRetry(firebaseData, 3);
  Firebase.setMaxErrorQueue(firebaseData, 30);
  Firebase.enableClassicRequest(firebaseData, true);

  // check connection
  Firebase.getBool(firebaseData, "/online") ? Serial.println("[INFO] Firebase initialized") : Serial.println("[ERROR] Firebase error: " + firebaseData.errorReason());
  if (firebaseData.dataType() == "boolean")
  {
    firebaseData.boolData() ? Serial.println("[INFO] Firebase database is online") : Serial.println("[INFO] Firebase database is offline");
    Firebase.setBool(firebaseData, this->config.FIREBASE_PATH + "/online", true);
  }

  /**** setup streams ****/
  // fbOnPing
  if (!Firebase.beginStream(test, (this->config.FIREBASE_PATH + "/cmd/ping").c_str()))
    Serial.println("[Error] Stream: " + test.errorReason());
  Firebase.setStreamCallback(test, fbOnPing, fbOnPingTimeout);

  // fbOnImpulse
  if (!Firebase.beginStream(fbDOnImpulse, (this->config.FIREBASE_PATH + "/cmd/impulse").c_str()))
    Serial.println("[Error] Stream: " + fbDOnImpulse.errorReason());
  Firebase.setStreamCallback(fbDOnImpulse, fbOnImpulse, fbOnImpulseTimeout);

  // fbOnLight
  if (!Firebase.beginStream(fbDOnLight, (this->config.FIREBASE_PATH + "/cmd/light").c_str()))
    Serial.println("[Error] Stream: " + fbDOnLight.errorReason());
  Firebase.setStreamCallback(fbDOnLight, fbOnLight, fbOnLightTimeout);

  Serial.println("[INFO] setupFirebase done");

image

Is this the wrong way to initialize multiple callback streams?

What am I missing? Any help is appreciated!

mobizt commented 4 years ago

You are using too many FirebaseData objects.

Each FirebaseData object has a WiFi Client instance that consumes a large amount of ram due to memory used by SSL/TLS provider ( mbedTLS library).

When the free heap is less than 100k, the WiFi Client can't establish the SSL connection.

You can use only one FirebaseData object for the stream which the stream path is the parent node of children nodes that you want to track the change e.g. Firebase.beginStream(firebaseData2, this->config.FIREBASE_PATH + "/cmd")

Assume that firebaseData2 used for the stream.

You can check data.dataPath()to determine which child node value has changed.

Assume data is the StreamData object in a stream callback function.

For your case, dataPath will return /impulse, /ping and /light.

If the value of many child nodes changes at the same time the path returns from firebaseData2.dataPath()` will be / and the stream data will be JSON object which you need to parse the child node to check its value. Then compare this child node value with its old value to determine the value changes.

Assume that streamCallback is the stream callback function.

Here is an example.


//global variable
FirebaseData firebaseData2;

//in setup
Firebase.beginStream(firebaseData2, this->config.FIREBASE_PATH + "/cmd");
Firebase.setStreamCallback(firebaseData2, streamCallback, streamTimeoutCallback);

void streamCallback(StreamData data)
{
    if (data.dataType() == "json")
    {
        //Multiple nodes values changed

        FirebaseJson &json = data.jsonObject();
        FirebaseJsonData jsonData;
        //Parse each node value
       json.get(jsonData, "/impulse");
       if (jsonData.success)
       {
         //Success when node "/impulse" existed in JSON object (stream data)
         //Get the value and compare with old value
         int myInt = jsonData.intValue;
         //double myDouble = jsonData.doubleValue;
         //bool myBool = jsonData.boolValue;
         //String myStr = jsonData.stringValue;
       }

       json.get(jsonData, "/ping");
       if (jsonData.success)
       {
          int myInt = jsonData.intValue;
          //double myDouble = jsonData.doubleValue;
          //bool myBool = jsonData.boolValue;
          //String myStr = jsonData.stringValue;
       }

       json.get(jsonData, "/light");
       if (jsonData.success)
       {
         int myInt = jsonData.intValue;
         //double myDouble = jsonData.doubleValue;
         //bool myBool = jsonData.boolValue;
         //String myStr = jsonData.stringValue;
       }

    }
    else 
    {
       //One a node value changes
       //The stream data type can be any of int, boolean, float, double, string, json, array, and null

       if(data.dataPath() == "/impulse")
       {
          //Handle your /impulse data here
      }
      else if(data.dataPath() == "/ping")
      {
         //Handle your /ping data here
      }
      else if(data.dataPath() == "/light")
      {
         //Handle your /light data here
      }   

    }

}

void streamTimeoutCallback (bool timeout)
{

}
mobizt commented 4 years ago

Now the library v 3.6.8 (on Github) supports multiple paths stream.

You can update and try this example.