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 #93

Closed mars000 closed 4 years ago

mars000 commented 4 years ago

thanks for pulling together a great library. Wonder - why is it (at startup especially) it can take 2-3 times longer to do a setString vs setInteger ? what is going on under the hood.

Also - any way to make setString, setInt non blocking ?

kind regards

mobizt commented 4 years ago

It's not different in term of operation between that functions.

The time consumed for operation based on the network situation.

mobizt commented 4 years ago

The client should take care of and wait for the server response to be finished with the timeout to ensure the success of the request.

The time consuming then vary depending on the time used in request , response and SSL/TLS handshake.

If you are using different Firebase Data object for streaming and reading/storing data, the connection between server and client is kept alive and the time consuming for the request and response will be significantly reduced (use approx. 200 - 300 ms per request).

mars000 commented 4 years ago

thank you mobizt for the quick and helpful response.

A few questions:

  1. Is there a non blocking way of writing to firebase ?
  2. How long does the websocket stay open (I assume its a keepalive and stays open for as long as the app is running and internet connected via wifi) ?
  3. I've edited slightly your Blynk example. Given your above advice I'm using different Firebase data objects for each Stream and write - is this best practice for making it fast as possible ?

My code below (modified from your ;-))


/*
 * Created by K. Suwatchai (Mobizt)
 * 
 * Email: k_suwatchai@hotmail.com
 * 
 * Github: https://github.com/mobizt
 * 
 * Copyright (c) 2020 mobizt
 * 
 * This example is for the beginner
 *
*/

#include <WiFi.h>
#include <FirebaseESP32.h>
#include <Ticker.h>

//1. Change the following info
#define FIREBASE_HOST "https://esp32-flutter-firebase-ec9c6.firebaseio.com/"
#define FIREBASE_AUTH "xxxxx"
#define WIFI_SSID "xxx"
#define WIFI_PASSWORD "xxx"

Ticker sendMessage1;
Ticker sendMessage2;

//Debug Blynk to serial port
#define BLYNK_PRINT Serial

#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>

//Auth token for your Blynk app project
#define BLYNK_AUTH "YOUR_BLYNK_APP_PROJECT_AUTH_TOKEN"

//Define FirebaseESP32 data objects
FirebaseData firebaseData0;
FirebaseData firebaseData1;
FirebaseData firebaseData2;
FirebaseData firebaseData3;

String path0 = "/Blynk_Test";
String path = "/Blynk_Test/Int";
String path1 = "/Blynk_Test/String";

//D4 or GPIO2 on Wemos D1 mini
uint8_t BuiltIn_LED = 2;

void printResult(FirebaseData &data);
void printResult(StreamData &data);

/*
Blynk app Widget setup 
**********************
1. Button Widget (Switch type), Output -> Virtual pin V1
2. LED Widget, Input -> Virtual pin V2
*/

WidgetLED led(V4);

void streamCallback1(StreamData data)
{

  Serial.println("Stream Data [1] available...");
  Serial.println("STREAM PATH: " + data.streamPath());
  Serial.println("EVENT PATH: " + data.dataPath());
  Serial.println("DATA TYPE: " + data.dataType());
  Serial.println("EVENT TYPE: " + data.eventType());
  Serial.print("VALUE: ");
  printResult(data);
  Serial.println();
}

void streamCallback0(StreamData data)
{

  Serial.println("Stream Data [0] available...");
  Serial.println("STREAM PATH: " + data.streamPath());
  Serial.println("EVENT PATH: " + data.dataPath());
  Serial.println("DATA TYPE: " + data.dataType());
  Serial.println("EVENT TYPE: " + data.eventType());
  Serial.print("VALUE: ");
  printResult(data);
  Serial.println();
}

void streamTimeoutCallback(bool timeout)
{
  if (timeout)
  {
    Serial.println();
    Serial.println("Stream timeout, resume streaming...");
    Serial.println();
  }
}

void setup()
{

  Serial.begin(115200);

  pinMode(BuiltIn_LED, OUTPUT);

  WiFi.begin("xxx", "xxx);
  Serial.print("Connecting to Wi-Fi");
  while (WiFi.status() != WL_CONNECTED)
  {
    Serial.print(".");
    delay(300);
  }
  Serial.println();
  Serial.print("Connected with IP: ");
  Serial.println(WiFi.localIP());
  Serial.println();

  Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH);
  Firebase.reconnectWiFi(true);

  if (!Firebase.beginStream(firebaseData1, path))
  {
    Serial.println("------------------------------------");
    Serial.println("firebase1 -> Can't begin stream connection...");
    Serial.println("REASON: " + firebaseData1.errorReason());
    Serial.println("------------------------------------");
    Serial.println();
  }

  if (!Firebase.beginStream(firebaseData0, path0))
  {
    Serial.println("------------------------------------");
    Serial.println("firsbase0 -> Can't begin stream connection...");
    Serial.println("REASON: " + firebaseData0.errorReason());
    Serial.println("------------------------------------");
    Serial.println();
  }

  Firebase.setStreamCallback(firebaseData1, streamCallback1, streamTimeoutCallback);
  Firebase.setStreamCallback(firebaseData0, streamCallback0, streamTimeoutCallback);

  // auth = garage gate
  Blynk.config("xxx", "blynk.xxx.com", 80);
  Blynk.connect();
}

void loop()
{
  Blynk.run();

  /*  if (!Firebase.readStream(firebaseData1))
  {
    Serial.println("------------------------------------");
    Serial.println("firebaseData1 -> Can't read stream data...");
    Serial.println("REASON: " + firebaseData1.errorReason());
    Serial.println("------------------------------------");
    Serial.println();
  }

  if (!Firebase.readStream(firebaseData0))
  {
    Serial.println("------------------------------------");
    Serial.println("firebaseData0 -> Can't read stream data...");
    Serial.println("REASON: " + firebaseData0.errorReason());
    Serial.println("------------------------------------");
    Serial.println();
  }

  if (firebaseData1.streamTimeout())
  {
    Serial.println("Stream timeout, resume streaming...");
    Serial.println();
  }

  if (firebaseData1.streamAvailable())
  {
    Serial.println("------------------------------------");
    Serial.println("Stream Data available...");
    Serial.println("STREAM PATH: " + firebaseData1.streamPath());
    Serial.println("EVENT PATH: " + firebaseData1.dataPath());
    Serial.println("DATA TYPE: " + firebaseData1.dataType());
    Serial.println("EVENT TYPE: " + firebaseData1.eventType());
    Serial.print("VALUE: ");
    if (firebaseData1.dataType() == "int")
    {

      Serial.println(firebaseData1.intData());
      if (firebaseData1.intData() == 0)
      {
        Blynk.virtualWrite(V11, LOW);
        //   led.off();
      }
      else if (firebaseData1.intData() == 1)
      {
        Blynk.virtualWrite(V11, HIGH);
        //  led.on();
      }
    } 
  }

  if (firebaseData0.streamAvailable())
  {
    Serial.println("------------------------------------");
    Serial.println("Stream Data available...");
    Serial.println("STREAM PATH: " + firebaseData0.streamPath());
    Serial.println("EVENT PATH: " + firebaseData0.dataPath());
    Serial.println("DATA TYPE: " + firebaseData0.dataType());
    Serial.println("EVENT TYPE: " + firebaseData0.eventType());
    Serial.print("VALUE: ");
    if (firebaseData0.dataType() == "int")
    {

      Serial.println(firebaseData0.intData());
      if (firebaseData1.intData() == 0)
      {
        Blynk.virtualWrite(V11, LOW);
        //   led.off();
      }
      else if (firebaseData0.intData() == 1)
      {
        Blynk.virtualWrite(V11, HIGH);
        //  led.on();
      }
    }

    if (firebaseData0.dataType() == "string")
    {

      Serial.println(firebaseData0.stringData());
    }

    if (firebaseData0.dataType() == "json")
    {

    FirebaseJson &json = firebaseData0.jsonObject();
    //Print all object data
    Serial.println("Pretty printed JSON data:");
    String jsonStr;
    json.toString(jsonStr, true);
    Serial.println(jsonStr);
    //  }

    Serial.println("------------------------------------");
    Serial.println();
  } */
}

BLYNK_WRITE(V11)
{
  static bool already_called = false;
  static int counter = 0;
  int pinValue = param.asInt(); // assigning incoming value from pin V1 to a variable

  if (pinValue == 0)
  {
    led.off();
    already_called = false;
  }
  if (pinValue == 1)
  {
    led.on();

    if (already_called == false)
    {
      Serial.println("------------------------------------");
      Serial.println("Set integer...");
      //Also can use Firebase.set instead of Firebase.setInt
      if (Firebase.setInt(firebaseData2, path, pinValue))
      {
        Serial.println("int PASSED");
        Serial.println("PATH: " + firebaseData2.dataPath());
        Serial.println("TYPE: " + firebaseData2.dataType());
        Serial.print("VALUE: ");

        if (firebaseData2.dataType() == "int")
          Serial.println(firebaseData2.intData());
        Serial.println("------------------------------------");
        Serial.println();
        already_called = true;
      }
      else
      {
        Serial.println("FAILED");
        Serial.println("REASON: " + firebaseData2.errorReason());
        Serial.println("------------------------------------");
        Serial.println();
      }

      Serial.println("Set string..");
      String mess = "Pressed @ " + String(millis());
      if (Firebase.setString(firebaseData3, path1, mess))
      {
        Serial.println("String PASSED");
        Serial.println("PATH: " + firebaseData3.dataPath());
        Serial.println("TYPE: " + firebaseData3.dataType());
        Serial.print("VALUE: ");

        if (firebaseData3.dataType() == "string")
          Serial.println(firebaseData3.stringData());
        Serial.println("------------------------------------");
        Serial.println();
        already_called = true;
      }

      else
      {
        Serial.println("FAILED");
        Serial.println("REASON: " + firebaseData2.errorReason());
        Serial.println("------------------------------------");
        Serial.println();
      }
    }
  }
}

void printResult(StreamData &data)
{

  if (data.dataType() == "int")
    Serial.println(data.intData());
  else if (data.dataType() == "float")
    Serial.println(data.floatData(), 5);
  else if (data.dataType() == "double")
    printf("%.9lf\n", data.doubleData());
  else if (data.dataType() == "boolean")
    Serial.println(data.boolData() == 1 ? "true" : "false");
  else if (data.dataType() == "string" || data.dataType() == "null")
    Serial.println(data.stringData());
  else if (data.dataType() == "json")
  {
    Serial.println();
    FirebaseJson *json = data.jsonObjectPtr();
    //Print all object data
    Serial.println("Pretty printed JSON data:");
    String jsonStr;
    json->toString(jsonStr, true);
    Serial.println(jsonStr);
    Serial.println();
    Serial.println("Iterate JSON data:");
    Serial.println();
    size_t len = json->iteratorBegin();
    String key, value = "";
    int type = 0;
    for (size_t i = 0; i < len; i++)
    {
      json->iteratorGet(i, type, key, value);
      Serial.print(i);
      Serial.print(", ");
      Serial.print("Type: ");
      Serial.print(type == FirebaseJson::JSON_OBJECT ? "object" : "array");
      if (type == FirebaseJson::JSON_OBJECT)
      {
        Serial.print(", Key: ");
        Serial.print(key);
      }
      Serial.print(", Value: ");
      Serial.println(value);
    }
    json->iteratorEnd();
  }
  else if (data.dataType() == "array")
  {
    Serial.println();
    //get array data from FirebaseData using FirebaseJsonArray object
    FirebaseJsonArray *arr = data.jsonArrayPtr();
    //Print all array values
    Serial.println("Pretty printed Array:");
    String arrStr;
    arr->toString(arrStr, true);
    Serial.println(arrStr);
    Serial.println();
    Serial.println("Iterate array values:");
    Serial.println();

    for (size_t i = 0; i < arr->size(); i++)
    {
      Serial.print(i);
      Serial.print(", Value: ");

      FirebaseJsonData *jsonData = data.jsonDataPtr();
      //Get the result data from FirebaseJsonArray object
      arr->get(*jsonData, i);
      if (jsonData->typeNum == FirebaseJson::JSON_BOOL)
        Serial.println(jsonData->boolValue ? "true" : "false");
      else if (jsonData->typeNum == FirebaseJson::JSON_INT)
        Serial.println(jsonData->intValue);
      else if (jsonData->typeNum == FirebaseJson::JSON_DOUBLE)
        printf("%.9lf\n", jsonData->doubleValue);
      else if (jsonData->typeNum == FirebaseJson::JSON_STRING ||
               jsonData->typeNum == FirebaseJson::JSON_NULL ||
               jsonData->typeNum == FirebaseJson::JSON_OBJECT ||
               jsonData->typeNum == FirebaseJson::JSON_ARRAY)
        Serial.println(jsonData->stringValue);
    }
  }
}
mobizt commented 4 years ago

1. As I post above you need (essential) to take care of the request response. Non block for server request in not make sense and useless. You can use async or non block for server side but the client should wait for complete response.

If you implement your own the tcp/udp server communication, you can implement non block on your client side but no guarantee of packet received ordering sequence and the lost of packets.

2. It's not the web socket. it is the http request on secure port (443) sent to sever with the header that the connection should keep alive and server should not close it after sent the response. The connection is kept alive as long as both client and server are on the internet.

  1. I have answered this in many opened issues and also wrote the comment in the stream examples for long time.

mobizt commented 4 years ago

If you've found the unacceptable latency or network round trip delay in your device, the problem may be at the router or AP.

mars000 commented 4 years ago

thanks for your answers - they assist a great deal in my understanding how to best use your very useful library.