Firebase Http Functions Reading Get Url Query Parameters

Firebase Realtime Database Arduino Library for ESP32

DOI

Google's Firebase Realtime Database Arduino Library for ESP32 v3.xv.5

This library supports ESP32 MCU from Espressif. The post-obit are platforms in which libraries are also available.

  • ESP8266 Firebase Arduino library

  • Arduino MKR WiFi 1010, Arduino MKR VIDOR 4000 and Arduino UNO WiFi Rev.2

  • Arduino WiFi Shield 101 and Arduino MKR1000 WIFI

New library for ESP8266 and ESP32 is available

The Firebase Client for ESP8266 and ESP32 supports Cloud Firestore, Firebase Storage, Google Cloud Storage and new API Cloud Messaging and Cloud Functions for Firebase is now available.

Delight try it here https://github.com/mobizt/Firebase-ESP-Client

Tested Devices

  • NodeMCU-32
  • WEMOS LOLIN32
  • TTGO T8 V1.8

About ESP32 boards are supported unless Sparkfun ESP32 Thing (old version) is not recommended due to it built with non-standard 26 MHz clock on board instead of 40 MHz which causes the bugs and unstable network connection.

Other Arduino Devices supported using external Clients.

Since version 3.14.4, library allows y'all to use external Arduino Clients network interfaces e.chiliad. WiFiClient, EthernetClient and GSMClient, the Arduino supported devices that have enough flash size (> 128k) and memory can now use this library.

To utilize external Client, encounter the ExternalClient examples.

The hallmark with OAuth2.0 and custom auth tokens, RTDB error queue and downloadFileOTA features are not supported for other Arduino devices using external Clients.

The flash and SD filesystems supports depend on the devices and third party filesystems libraries installed.

Features

  • Consummate and secure Firebase RTDB's Rest APIs Client

  • Supports database read, store, update, delete and value changes listener

  • Supports Test Mode (No Auth)

  • Supports Firmware OTA updates

  • Supports Firebase Cloud Messaging.

  • Born JSON editor and deserializer.

  • Supports external Heap via PSRAM.

  • Supports ethernet using LAN8720, TLK110 and IP101 Ethernet modules.

Basic Examples

Don't be confused with other Firebase Arduino libraries, this library has dissimilar working functions, the post-obit examples provide the basic usages.

ESP32 | Flutter | FIREBASE - Temperature & Humidity Bank check App

Serverless IoTs with Firebase Realtime Database and ESP32 - Office ane

Serverless IoTs with Firebase Realtime Database and ESP32 - Part 2

Dependencies

This library required ESP32 Core SDK version 1.0.1 or above.

For Arduino IDE, ESP32 Core SDK tin be installed through Boards Manager.

For PlatfoemIO IDE, ESP32 Core SDK tin be installed through PIO Habitation > Platforms > Espressif 32.

Installation

Using Library Manager

At Arduino IDE, become to carte Sketch -> Include Library -> Manage Libraries...

In Library Director Window, search "firebase" in the search form then select "Firebase ESP32 Client"

Click "Install" button.

For PlatformIO IDE, using the following command.

pio lib install "Firebase ESP32 Client"

Or at PIO Home -> Library -> Registry then search Firebase ESP32 Client.

More on PlatformIO...

Manual installation

For Arduino IDE, download nix file from the repository (Github folio) by select Clone or download dropdown at the peak of repository, select Download Aught

From Arduino IDE, select carte du jour Sketch -> Include Library -> Add .ZIP Library....

Cull Firebase-ESP32-master.zip that previously downloaded.

Get to menu Files -> Examples -> Firebase-ESP32-chief and choose one from examples.

For PlatformIO, in folder "lib", create new folder named "Firebase-ESP32" and add these files in that binder.

Usages

See all examples for consummate usages.

See function description for all available functions.

Initialization

                              //Include WiFi.h              #include                              <WiFi.h>                                            //Include Firebase ESP32 library (this library)              #include                              <FirebaseESP32.h>                                            //Define the Firebase Data object              FirebaseData fbdo;                              //                Define the FirebaseAuth information for authentication data              FirebaseAuth auth;                              //                Define the FirebaseConfig data for config information              FirebaseConfig config;                              //                Assign the project host and api fundamental (required)              config.host = FIREBASE_HOST;  config.api_key = API_KEY;                              //                Assign the user sign in credentials              auth.user.email = USER_EMAIL;  auth.user.countersign = USER_PASSWORD;                              //Initialize the library with the Firebase authen and config.              Firebase.begin(&config, &auth);                              //Optional, prepare AP reconnection in setup()              Firebase.reconnectWiFi(true);                              //Optional, gear up number of mistake retry              Firebase.setMaxRetry(fbdo,              3);                              //Optional, fix number of error resumable queues              Firebase.setMaxErrorQueue(fbdo,              30);                              //Optional, use archetype HTTP GET and POST requests.                                            //This option allows get and delete functions (PUT and DELETE HTTP requests) works for                                            //device connected backside the Firewall that allows only Get and Post requests.                            Firebase.enableClassicRequest(fbdo,              true);                              //Optional, set the size of HTTP response buffer                              //Forbid out of memory for big payload just data may exist truncated and can't determine its type.              fbdo.setResponseSize(8192);                              //minimum size is 4096 bytes            

Memory Options for ESP32

In ESP32 module that has PSRAM installed, you lot can enable it and fix the library to apply this external memory instead.

Arduino IDE

To enable PSRAM in ESP32 module.

Enable PSRAM in ESP32

PlatformIO IDE

In PlatformIO on VSCode or Atom IDE, add the following build_flags in your projection's platformio.ini file.

              build_flags              = -DBOARD_HAS_PSRAM -mfix-esp32-psram-enshroud-outcome

Once the external Heap memory was enabled in IDE, to allow the library to use the external retentivity, you lot can set it in FirebaseFS.h past define this macro.

#ascertain              FIREBASE_USE_PSRAM            

Authentication

This library supports many types of authentications.

See other authentication examples for more authentication methods.

Some hallmark methods require the token generaion and exchanging process which take more than time than using the legacy token.

The system time must be prepare earlier authenticate using the custom and OAuth2.0 tokens or when the root certificate was set for information transfer.

The authentication with custom and OAuth2.0 tokens takes the time, several seconds in overall process which included the NTP time conquering (system time setup), JWT token generation and signing process.

By setting the arrangement time prior to calling the Firebase.begin , the internal NTP time acquisition process will be ignored.

You can set the organization time using the RTC chip or manually past calling Firebase.setSystemTime .

While authenticate using E-mail and countersign, the process volition exist perform faster because no token generation and time setup required.

The authenticate using the legacy token (database hole-and-corner) does non accept these filibuster time because the token is ready to use.

Speed of information transfer

This library focuses on the user privacy and user data protection which follows Google authentication processes. Setting the security rules to allow public access read and write, is non recommended even the data transmision time in this case was significantly reduced as it does not crave whatever auth token then the overall information size was reduced, just anyone tin steal, modify, or delete data in your database.

Once the auth token is importance and when it was created and ready for hallmark process, the data manual time will depend on the time used in SSL/TLS handshake procedure (but for new session opening), the size of http header (included auth token size) and payload to be transmitted and the SSL customer buffer reserved size especially in ESP8266.

The legacy token size is relatively modest, only 40 bytes, result in smallest header to send, while the size of id token generated using Email/Password is quite large, approx. 900 bytes. result in larger header to send.

There is a compromise between the speed of data transfer and the Rx/Tx buffer which and so reduced the free memory bachelor specially in ESP8266.

When the reserved SSL client Rx/Tx buffer is smaller than the size of information to be transmitted, the data need to exist sent every bit multiple chunks which required more transmission time.

This affected peculiarly in ESP8266 which has the express free memory.

To speed up the information transmission in ESP8266, the larger reserved Rx/Tx buffer size is necessary.

The reserved SSL Rx/Tx buffer size in ESP8266 tin can be set up through the function <Firebase Data object>.setBSSLBufferSize, due east.g. fbdo.setBSSLBufferSize(2048, 2048);

The larger BearSSL buffer reserved for ESP8266, the lower free retentivity available as long as the session opened (server connection).

Therefore the fourth dimension for data transfer will exist varied from approx. neary 200 ms to 500 ms based on the reserved SSL client Rx/Tx buffer size and the size of data to transmit.

In ESP8266, when the free memory and speed are concerned, the legacy token should be used instead of other authentication to reduce the header size and the lower SSL Rx/Tx buffer i.eastward. 1024 for Rx and 512 for Tx are enough.

When the session was reused (in this library), the SSL handshake process will exist ignored in the subsequence requests.

The session was shut when the host or ip changes or server closed or the session timed out in 3 minutes.

When the new session need to be opened, the SSL handshake volition be processed again and used the fourth dimension approx i - 2 seconds to exist done.

For mail (push) or put (set) request in RTDB, to speed upward the data transfer, use pushAsync or setAsync instead.

With pushAsync and setAsync, the payload response volition exist ignored and the adjacent data volition be processed immediately.

Access in Test Style (No Auth)

In Examination Style, token generation will exist ignored and no hallmark practical to the request.

You can admission RTDB database in Test Mode by set the security rules similar this.

{              "rules": {              ".read":              true,              ".write":              true              } }

And fix the config.signer.test_mode = truthful;, come across TestMode.ino example.

The authenication credentials and prerequisites

To use Email/Countersign sign-in authentication as in the examples, the Email/Password Sign-in provider must exist enabled.

Enable Email/Password Sign-in provider

Enable Email/Password Sign-in provider

Add E-mail and password for outset user in your project so use this Email and password to sign in.

Enable Email/Password Sign-in provider

To utilize Anonymous sign-in, the Anonymous Sign-in provider must be enabled by follow the beneath steps.

Enable Anonymous Sign-in provider

Enable Anonymous Sign-in provider

Enable Anonymous Sign-in provider

To get API Primal used in Email/Password sign-in

API Key

To get the Service accounts primal JSON file used in Custom and OAuth2.0 tokens athentications.

Service Account Key File

For RTDB usages, create new real-time database (if not setup notwithstanding)

Firebase Host

Firebase Host

Firebase Host

Edit the default database rules as following

Firebase Host

{              "rules": {              ".read":                              "auth != nil"              ,              ".write":                              "auth != null"                            } }

This certificate provides the RTDB security rules details.

The Firebase RTDB security rules are JSON-based rules which information technology should valid to used with this library RTDB functions that involved the security rules modification and reading, otherwise the rules wont be inverse or read by these functions.

To get the database URL and secret (legacy token).

Firebase Host

Firebase Auth

For server SSL authentication past providing the server root certificate.

Server SSL document verification is the process to ensure that the server that client is being connected is a trusted (valid) server instead of fake server.

The Google's GlobalSign R2 root certificate can be download from https://pki.goog/repository/

Select the .PEM (base-64 encoded string) or .DER (binary) file to download.

From the test as of July 2021, GlobalSign Root CA was missing from Google server, the certificate chain, GTS Root R1 can be used instead of root certificate.

Firebase Host

Beneath is how to assign the certificate data for server verification.

                              /*                In case the document data was used                */                            config.cert.information = rootCACert;                              //Or custom set the root document for each FirebaseData object              fbdo.setCert(rootCACert);                              /*                Or assign the document file                */                                            /** From the test as of July 2021, GlobalSign Root CA was missing from Google server                              * equally described in a higher place, GTS Root R1 (gsr1.pem or gsr1.der) can be used instead.                              * ESP32 Arduino SDK supports PEM format merely even mBedTLS supports DER format also.                              * ESP8266 SDK supports both PEM and DER format certificates.                              */                                            //config.cert.file = "/gsr1.pem";                              //config.cert.file_storage = StorageType::Wink;   //or StorageType::SD            

Excludes the unused classes to relieve retentiveness

The internal classes, RTDB and FCM in this library can be excluded or disabled to save retention usage through FirebaseFS.h.

By comment the following macros.

ENABLE_RTDB

ENABLE_FCM

To disable OTA update, comment this macro.

              ENABLE_OTA_FIRMWARE_UPDATE                          

Read Data

Data at a specific node in Firebase RTDB tin be read through these go functions.

The functions included get, getInt, getFloat, getDouble, getBool, getString, getJSON, getArray, getBlob, getFile.

These functions return boolean value indicates the success of the operation which will exist true if all of the following conditions were met.

  • Server returns HTTP status code 200

  • The information types matched betwixt request and response.

For generic become, use Firebase.get(fbdo, <path>).

And bank check its blazon with fbdo.dataType() or fbdo.dataTypeEnum() and cast the value from it e.thousand. fbdo.to<int>(), fbdo.to<std::string>().

The data blazon of returning payload can be adamant by fbdo.dataType() which returns String or fbdo.dataTypeEnum() returns enum value.

The String of type returns from fbdo.dataType() tin be string, boolean, int, bladder, double, json, array, blob, file and null.

The enum value type, fb_esp_rtdb_data_type returns from fbdo.dataTypeEnum() can be fb_esp_rtdb_data_type_null (1), fb_esp_rtdb_data_type_integer, fb_esp_rtdb_data_type_float, fb_esp_rtdb_data_type_double, fb_esp_rtdb_data_type_boolean, fb_esp_rtdb_data_type_string, fb_esp_rtdb_data_type_json, fb_esp_rtdb_data_type_array, fb_esp_rtdb_data_type_blob, and fb_esp_rtdb_data_type_file (10)

The database information's payload (response) can be read or admission through the casting value from FirebaseData object with to<type>() functions (since v2.4.0).

  • String due south = fbdo.to<String>();

  • std::cord _s = fbdo.to<std::string>();

  • const char *str = fbdo.to<const char *>();

  • bool b = fbdo.to<bool>();

  • int16_t _i = fbdo.to<int16_t>();

  • int i = fbdo.to<int>();

  • double d = fbdo.to<double>();

  • float f = fbdo.to<float>();

  • FirebaseJson *json = fbdo.to<FirebaseJson *>(); or

  • FirebaseJson &json = fbdo.to<FirebaseJson>();

  • FirebaseJsonArray *arr = fbdo.to<FirebaseJsonArray *>(); or

  • FirebaseJsonArray &arr = fbdo.to<FirebaseJsonArray>();

  • std::vector<uint8_t> *blob = fbdo.to<std::vector<uint8_t> *>();

  • File file = fbdo.to<File>();

Or through the legacy methods

  • int i = fbdo.intData();

  • float f = fbdo.floatData();

  • double d = fbdo.doubleData();

  • bool b = fbdo.boolData();

  • String s = fbdo.stringData();

  • String js = fbdo.jsonString();

  • FirebaseJson &json = fbdo.jsonObject();

  • FirebaseJson *jsonPtr = fbdo.jsonObjectPtr();

  • FirebaseJsonArray &arr = fbdo.jsonArray();

  • FirebaseJsonArray *arrPtr = fbdo.jsonArrayPtr();

  • std::vector<uint8_t> blob = fbdo.blobData();

  • File file = fbdo.fileStream();

Read the information which its type does not match the data blazon in the database from above functions will return empty (string, object or array).

BLOB and file stream data are stored as special base64 encoded cord which are only supported and implemented by this library.

The encoded base64 string will be prefixed with some header cord ("file,base64," and "blob,base64,") for data blazon manipulation.

The post-obit instance showed how to read integer value from node "/examination/int".

              if              (Firebase.getInt(fbdo,                              "/examination/int"              )) {              if              (fbdo.dataTypeEnum() == fb_esp_rtdb_data_type_integer) {       Series.println(fbdo.to<int>());     }    }              else              {     Series.println(fbdo.errorReason());   }

Store Data

To store data at a specific node in Firebase RTDB, utilize these set functions.

The role included set, setInt, setFloat, setDouble, setBool, setString, setJSON, setArray, setBlob and setFile.

For faster sending data, non-waits or async fashion functions are available eastward.m. setAsync, setIntAsync, setFloatAsync, setDoubleAsync, setBoolAsync, setStringAsync, setJSONAsync, setArrayAsync, setBlobAsync and setFileAsync.

For generic set, employ Firebase.set(fbdo, <path>, <whatever variable or value>).

These async functions will ignore the server responses.

The above functions return boolean value indicates the success of the functioning which will exist true if all of the following weather matched.

  • Server returns HTTP status code 200

  • The information types matched between asking and response.

Only setBlob and setFile functions that make a silent request to Firebase server, thus no payload response returned.

The priority, virtual node ".priority" of each database node can exist set through Firebase'southward set up functions.

The priority value tin be used in a query or filtering the children's data under a defined node.

Priority option was removed from File and Blob functions since v2.4.0.

ETag (unique identifier value) assigned to Firebase's prepare functions is used as provisional checking.

If defined Etag is non matched the divers path's ETag, the fix functioning will neglect with effect 412 Precondition Failed.

ETag at any node can be read through Firebase.getETag. ETag value changed upon the data was gear up or delete.

The server'south Timestamp can be stored in the database through Firebase.setTimestamp.

The returned Timestamp value can get from fbdo.to<int>().

The file systems for wink and sd memory tin can be changed in FirebaseFS.h.

The post-obit example showed how to store file data to flash retention at node "/examination/file_data".

              if              (Firebase.getFile(fbdo, StorateType::FLASH,                              "/test/file_data"              ,                              "/examination.txt"              )) {                              //Flash.begin(); //not need to brainstorm over again due to it has been called in function.              File file = DEFAULT_FLASH_FS.open(                "/exam.txt"              ,                              "r"              );              while              (file.available())   {          Serial.print(file.read(), HEX);        }       file.shut();   Series.println();  }              else              {   Series.println(fbdo.fileTransferError()); }

Append Information

To suspend new data to a specific node in Firebase RTDB, utilize these push functions.

The function included push, pushInt, pushFloat, pushDouble, pushBool, pushString, pushJSON, pushArray, pushBlob, and pushFile.

For faster sending data, non-waits or async style functions are bachelor due east.g. pushAsync, pushIntAsync, pushFloatAsync, pushDoubleAsync, pushBoolAsync, pushStringAsync, pushJSONAsync, pushArrayAsync, pushBlobAsync and pushFileAsync.

These functions return boolean value indicates the success of the performance.

The unique primal of a new appended node can be determined from fbdo.pushName().

As set functions, the Firebase's push button functions support priority.

ETag was not bachelor after push unless read the ETag at that new appended unique fundamental later with Firebase.getETag.

The server's Timestamp can exist appended in the database through Firebase.pushTimestamp.

The unique key of Timestamp tin can be determined after Timestamp was appended.

The following instance showed how to append new information (using FirebaseJson object) to node "/test/append.

FirebaseJson json; FirebaseJson json2;  json2.set(                "child_of_002"              ,              123.456); json.set up(                "parent_001"              ,                              "parent 001 text"              ); json.set(                "parent 002"              , json2);              if              (Firebase.pushJSON(fbdo,                              "/test/append"              , json)) {    Serial.println(fbdo.dataPath());    Series.println(fbdo.pushName());    Serial.println(fbdo.dataPath() +                              "/"              + fbdo.pushName());  }              else              {   Serial.println(fbdo.errorReason()); }

Patch Information

Firebase's update functions used to patch or update new or existing data at the defined node.

These functions, updateNode and updateNodeSilent are bachelor and work with JSON object (FirebaseJson object only).

For faster sending data, not-waits or async way functions are available east.k. updateNodeAsync, and updateNodeSilentAsync.

If any key name provided at a defined node in JSON object has not existed, a new central volition be created.

The server returns JSON data payload which was successfully patched.

Render of large JSON payload will cost the network data, alternative role updateNodeSilent or updateNodeSilentAsync should exist used to salvage the network data.

The following example showed how to patch data at "/exam".

FirebaseJson updateData; FirebaseJson json; json.prepare(                "_data2"              ,                "_value2"              ); updateData.set(                "data1"              ,                "value1"              ); updateData.set(                "data2"              , json);              if              (Firebase.updateNode(fbdo,                              "/test/update"              , updateData)) {    Serial.println(fbdo.dataPath());    Serial.println(fbdo.dataType());    Serial.println(fbdo.jsonString());   }              else              {   Serial.println(fbdo.errorReason()); }

Delete Data

The following example showed how to delete data and its children at "/examination/suspend"

Firebase.deleteNode(fbdo,                              "/exam/append"              );

Filtering Data

To filter or query the data, the following query parameters are bachelor through the QueryFilter class.

These parameters are orderBy, limitToFirst, limitToLast, startAt, endAt, and equalTo.

To filter data, parameter orderBy should be assigned.

Use "$key" equally the orderBy parameter if the key of kid nodes was used for the query.

Use "$value" as the orderBy parameter if the value of kid nodes was used for the query.

Employ key (or full path) of kid nodes as the orderBy parameter if all values of the specific key were used for the query.

Use "$priority" as orderBy parameter if child nodes's "priority" was used for query.

The to a higher place orderBy parameter can be combined with the following parameters for express and ranged the queries.

QueryFilter.limitToFirst - The full children (number) to filter from the first child.

QueryFilter.limitToLast - The total last children (number) to filter.

QueryFilter.startAt - Starting value of range (number or cord) of query upon orderBy param.

QueryFilter.endAt - Ending value of range (number or cord) of query upon orderBy param.

QueryFilter.equalTo - Value (number or string) matches the orderBy param

The following case showed how to use queries parameter in QueryFilter class to filter the data at node "/test/data"

                              //Assume that children that accept key "sensor" are under "/test/data"                              //Instantiate the QueryFilter grade              QueryFilter query;                              //Build query using specified kid node fundamental "sensor" nether "/exam/data"              query.orderBy(                "sensor"              );                              //Query any child that its value begins with 2 (number), causeless that its information blazon is float or integer              query.startAt(2);                              //Query any child that its value ends with viii (number), assumed that its data blazon is float or integer              query.endAt(8);                              //Limit the maximum query effect to return but the last 5 nodes              query.limitToLast(v);              if              (Firebase.getJSON(fbdo,                              "/test/data"              , query)) {                              //Success, then try to read the JSON payload value              Serial.println(fbdo.jsonString()); }              else              {                              //Failed to get JSON data at defined database path, impress out the error reason              Serial.println(fbdo.errorReason()); }                              //Clear all query parameters              query.clear();

Server Information Changes Listener with Server-Sent Events or HTTP Streaming

This library uses HTTP Become request with text/event-stream header to make HTTP streaming connection.

The Firebase's functions that involved the stream operations are beginStream, beginMultiPathStream, setStreamCallback, setMultiPathStreamCallback and/or readStream.

Part beginStream is to subscribe to the data changes at a defined node.

Function beginMultiPathStream is to subscribe to the information changes at a defined parent node path with multiple kid nodes value parsing and works with setMultiPathStreamCallback.

Part setStreamCallback is to assign the callback function that accepts the FirebaseStream course as parameter.

Function setMultiPathStreamCallback is to assign the callback function that accepts the MultiPathStream grade equally parameter.

The FirebaseStream contains stream's outcome/data payloadd and interface function calls are like to FirebaseData object.

The MultiPathStream contains stream's effect/data payload for various child nodes.

To polling the stream'south effect/information payload manually, use readStream in loop().

Function readStream used in the loop() job to continuously read the stream's event and data.

Since polling the stream's event/information payload with readStream, use fbdo.streamAvailable to bank check if stream event/data payoad is available.

Office fbdo.streamAvailable returned true when new stream's event/data payload was available.

When new stream payload was available, its data and result can exist accessed from FirebaseData object functions.

Office endStream ends the stream operation.

Note that, when using the shared FirebaseData object for stream and CRUD usages(normal operation to create,read, update and delete data), the stream connection will exist interrupted (airtight) to connect in other HTTP mode, the stream volition be resumed (open) later the CRUD usages.

For the to a higher place case, yous need to provide the idle time for FirebaseData object to established the streaming connection and received the stream payload. The changes on the server at the streaming node path during the stream interruption will be missed.

To avert this sitation, don't share the usage of stream's FirebaseData object, some other FirebaseData object should be used.

In add-on, delay function used in the same loop of readStream() will defer the streaming, the server data changes may be missed.

Keep in mind that FirebaseData object volition create the SSL client within of HTTPS data transaction and uses large memory.

The following example showed how to subscribe to the information changes at node "/exam/data" with a callback function.

                              //In setup(), set the stream callback role to handle data                              //streamCallback is the role that called when database data changes or updates occurred                              //streamTimeoutCallback is the office that called when the connection betwixt the server                                            //and client was timeout during HTTP stream              Firebase.setStreamCallback(fbdo, streamCallback, streamTimeoutCallback);                              //In setup(), set the streaming path to "/test/data" and begin stream connection              if              (!Firebase.beginStream(fbdo,                              "/test/information"              )) {                              //Could not brainstorm stream connection, and so impress out the error detail              Serial.println(fbdo.errorReason()); }                              //Global function that handles stream data              void              streamCallback(StreamData data) {                              //Print out all information              Serial.println(                "Stream Data..."              );   Serial.println(data.streamPath());   Serial.println(data.dataPath());   Serial.println(data.dataType());                              //Print out the value                              //Stream data can be many types which can be determined from part dataType              if              (information.dataTypeEnum() == fb_esp_rtdb_data_type_integer)       Series.println(information.to<int>());              else              if              (information.dataTypeEnum() == fb_esp_rtdb_data_type_float)       Serial.println(information.to<float>(),              5);              else              if              (information.dataTypeEnum() == fb_esp_rtdb_data_type_double)              printf(                "%.9lf\northward                "              , data.to<double>());              else              if              (information.dataTypeEnum() == fb_esp_rtdb_data_type_boolean)       Serial.println(data.to<bool>()?                              "true"                            :                              "false"              );              else              if              (data.dataTypeEnum() == fb_esp_rtdb_data_type_string)       Serial.println(data.to<String>());              else              if              (information.dataTypeEnum() == fb_esp_rtdb_data_type_json)   {       FirebaseJson *json = data.to<FirebaseJson *>();       Serial.println(json->raw());   }              else              if              (data.dataTypeEnum() == fb_esp_rtdb_data_type_array)   {       FirebaseJsonArray *arr = data.to<FirebaseJsonArray *>();       Series.println(arr->raw());   }  }                              //Global function that notifies when stream connection lost                              //The library volition resume the stream connection automatically              void              streamTimeoutCallback(bool              timeout) {              if(timeout){                              //Stream timeout occurred              Serial.println(                "Stream timeout, resume streaming..."              );   }   }            

For multiple paths stream, see the MultiPath_stream case.

The following instance showed how to subscribe to the stream changes at "/exam/information" and read the stream manually.

                              //In setup(), set the streaming path to "/test/data" and begin stream connection              if              (!Firebase.beginStream(fbdo,                              "/test/data"              )) {   Series.println(fbdo.errorReason()); }                              //In loop()              if              (!Firebase.readStream(fbdo)) {   Serial.println(fbdo.errorReason()); }              if              (fbdo.streamTimeout()) {   Serial.println(                "Stream timeout, resume streaming..."              );   Serial.println(); }              if              (fbdo.streamAvailable()) {              if              (fbdo.dataTypeEnum() == fb_esp_rtdb_data_type_integer)     Serial.println(fbdo.to<int>());              else              if              (fbdo.dataTypeEnum() == fb_esp_rtdb_data_type_float)     Serial.println(fbdo.to<float>(),              5);              else              if              (fbdo.dataTypeEnum() == fb_esp_rtdb_data_type_double)              printf(                "%.9lf\n                "              , fbdo.to<double>());              else              if              (fbdo.dataTypeEnum() == fb_esp_rtdb_data_type_boolean)     Serial.println(fbdo.to<bool>() ?                              "true"                            :                              "false"              );              else              if              (fbdo.dataTypeEnum() == fb_esp_rtdb_data_type_string)     Serial.println(fbdo.to<Cord>());              else              if              (fbdo.dataTypeEnum() == fb_esp_rtdb_data_type_json)   {       FirebaseJson *json = fbdo.to<FirebaseJson *>();       Serial.println(json->raw());   }              else              if              (fbdo.dataTypeEnum() == fb_esp_rtdb_data_type_array)   {       FirebaseJsonArray *arr = fbdo.to<FirebaseJsonArray *>();       Serial.println(arr->raw());   }      }

Fill-in and Restore Information

This library allows data backup and restores at a defined path.

The backup file will store in SD/SDMMC carte or flash retentiveness.

The file systems for flash and SD memory can exist inverse via FirebaseFS.h.

Due to SD library used, only 8.3 DOS format file proper noun supported.

The maximum eight characters for a file name and three characters for file extension.

The database restoration returned completed status only when Firebase server successfully updates the data.

Whatever failed operation will non affect the database (no updates or changes).

The post-obit instance showed how to backup all database data at "/" and restore.

              String backupFileName;              if              (!Firebase.backup(fbdo, StorateType::SD,                              "/"              ,                              "/backup.txt"              ))  {    Serial.println(fbdo.fileTransferError());  }              else              {    Serial.println(fbdo.getBackupFilename());    Serial.println(fbdo.getBackupFileSize());    backupFileName = fbdo.getBackupFilename();   }                              //Begin restore backed dup data dorsum to database              if              (!Firebase.restore(fbdo, StorateType::SD,                              "/"              , backupFileName))   {     Serial.println(fbdo.fileTransferError());   }              else              {     Series.println(fbdo.getBackupFilename());   }

Database Error Treatment

When read store, append and update operations were failed due to buffer overflow and network problems.

These operations can retry and queued subsequently the retry amount was reached the maximum retry set in function setMaxRetry.

                              //fix maximum retry amount to 3              Firebase.setMaxRetry(fbdo,              three);

The function setMaxErrorQueue limits the maximum queues in Error Queue collection.

The full of queue drove can exist checked through role isErrorQueueFull.

                              //gear up maximum queues to ten              Firebase.setMaxErrorQueue(fbdo,              10);                              //determine whether Error Queue drove is total or not              Firebase.isErrorQueueFull(fbdo);

This library provides 2 approaches to run or procedure Error Queues with two functions.

  • beginAutoRunErrorQueue
  • processErrorQueue

The function beginAutoRunErrorQueue volition run or process queues automatically and can be called once.

While function processErrorQueue volition run or process queues and should phone call within the loop().

With office beginAutoRunErrorQueue, you lot tin assigned callback function that accept QueueInfo object every bit parameter.

Which contains all information about being processed queue, number of remaining queues and Error Queue collection status.

Otherwise, Error Queues can be tracked manually with the following functions.

Part getErrorQueueID volition return the unsigned integer presents the id of the queue which will keep using after.

Use getErrorQueueID and isErrorQueueExisted to bank check whether this queue id is still existed or not.

If Error Queue ID does not exist in Error Queues collection, that queue is already done.

The post-obit example showed how to run Error Queues automatically and track the status with the callback function.

                              //In setup()                              //Set the maximum Firebase Mistake Queues in collection (0 - 255).                              //Firebase read/store operation causes by network problems and buffer overflow will exist                                            //added to Firebase Error Queues collection.              Firebase.setMaxErrorQueue(fbdo,              10);                              //Brainstorm to run Mistake Queues in Fault Queue collection                            Firebase.beginAutoRunErrorQueue(fbdo, callback);                              //Employ to stop the auto run queues                              //Firebase.endAutoRunErrorQueue(fbdo);              void              errorQueueCallback              (QueueInfo queueinfo){              if              (queueinfo.isQueueFull())   {     Serial.println(                "Queue is full"              );   }    Serial.impress(                "Remaining queues:                "              );   Serial.println(queueinfo.totalQueues());    Serial.print(                "Beingness processed queue ID:                "              );   Serial.println(queueinfo.currentQueueID());      Series.impress(                "Data blazon:"              );   Series.println(queueinfo.dataType());     Serial.impress(                "Method:                "              );   Serial.println(queueinfo.firebaseMethod());    Serial.impress(                "Path:                "              );   Series.println(queueinfo.dataType());    Serial.println(); }

The following instance showed how to run Error Queues and track its status manually.

                              //In setup()                              //Set the maximum Firebase Error Queues in collection (0 - 255).                              //Firebase read/shop operation causes past network problems and buffer overflow will be added to                                            //Firebase Fault Queues drove.              Firebase.setMaxErrorQueue(fbdo,              10);                              //All of the following are in loop()              Firebase.processErrorQueue(fbdo);                              //Detrnine the queue condition              if              (Firebase.isErrorQueueFull(fbdo)) {   Serial.println(                "Queue is total"              ); }                              //Remaining Error Queues in Error Queue collection              Serial.print(                "Remaining queues:                "              ); Serial.println(Firebase.errorQueueCount(fbdo));                              //Assumed that queueID is unsigned integer assortment of queue that added to Error Queue drove                                            //when mistake and employ Firebase.getErrorQueueID to get this Fault Queue id.              for              (uint8_t              i =              0; i < LENGTH_OF_QUEUEID_ARRAY; i++) {   Serial.impress(                "Error Queue                "              );   Serial.impress(queueID[i]);              if              (Firebase.isErrorQueueExisted(fbdo, queueID[i]))     Serial.println(                "                is queuing"              );              else              Serial.println(                "                is done"              ); } Serial.println();

Error Queues can be saved as a file in SD carte or Wink memory with function saveErrorQueue.

Error Queues store as a file tin can be restored to Error Queue collection with function restoreErrorQueue.

Two types of storage can exist assigned with these functions, StorageType::FLASH and StorageType::SD.

Read data (become) operation is not support queues restore

The following example showed how to restore and save Fault Queues in /examination.txt file.

                              //To restore Error Queues              if              (Firebase.errorQueueCount(fbdo,                              "/test.txt"              , StorageType::Wink) >              0) {     Firebase.restoreErrorQueue(fbdo,                              "/exam.txt"              , StorageType::FLASH);     Firebase.deleteStorageFile(                "/exam.txt"              , StorageType::FLASH); }                              //To relieve Error Queues to file              Firebase.saveErrorQueue(fbdo,                              "/examination.txt"              , StorageType::FLASH);            

FireSense, The Programmable Data Logging and IO Command (Add On)

This add on library is for the advance usages and works with Firebase RTDB.

With this add on library, y'all can remotely program your device to control its IOs or do some job or call predefined functions on the fly.

This allows you to alter your device behaviour and functions without to flash a new firmware via serial or OTA.

See examples/FireSense for the usage.

For FireSense part description, meet src/addons/FireSense/README.md.

Firebase Cloud Messaging (FCM)

2 types of FCM message data can be sent using this library e.1000. notification and custom information.

These two types of data tin send all together or separately.

Function Firebase.sendMessage volition send a message to i recipient.

Function Firebase.broadcastMessage volition broadcast or ship a message to multiple recipients.

Part Firebase.sendTopic will send a message to whatever recipient who subscribed to the topic.

The FCM message itself offers a wide range of messaging options and capabilities for diverse recipient device platforms.

For Android, iOS and web platforms, these basic options can be prepare and piece of work for all platforms.

Function fbdo.fcm.begin used to assign the server central of your Firebase project.

Function fbdo.fcm.addDeviceToken used to add recipient registered device token which wants to ship message to.

Functions fbdo.fcm.removeDeviceToken and fbdo.fcm.clearDeviceToken used to remove or clear recipient device.

For the notification message, title, body, icon (optional), and click_action (optional) can be ready through fbdo.fcm.setNotifyMessage.

And clear these notify message data with fbdo.fcm.clearNotifyMessage.

For the information message, provide your custom data as JSON object (FirebaseJson object or cord) to fbdo.fcm.setDataMessage which can exist clear with fbdo.fcm.clearDataMessage.

The other options are priority, collapse central, Fourth dimension to Live of the message and topic to send messages to, can be gear up from the post-obit functions.

Call fbdo.fcm.setPriority for priority ("normal" or "high"), fbdo.fcm.setCollapseKey for collapse key setup, fbdo.fcm.setTimeToLive for life bridge of message setup between 0 sec. to two,419,200 sec. (or iv weeks), and fbdo.fcm.setTopic for assigning the topic that message to send to.

The post-obit example showed how to transport FCM message.

                              //Provide your Firebase project's server fundamental here              fbdo.fcm.begin(FIREBASE_FCM_SERVER_KEY);                              //Prvide one or more the recipient registered token or instant ID token              fbdo.fcm.addDeviceToken(FIREBASE_FCM_DEVICE_TOKEN);                              //Provide the priority (optional)              fbdo.fcm.setPriority(                "normal"              );                              //Provide the fourth dimension to live (optional)              fbdo.fcm.setTimeToLive(5000);                              //Set up the notification message data              fbdo.fcm.setNotifyMessage(                "Notification"              ,                              "Hello World!"              ,                              "firebase-logo.png"              ,                              "http://world wide web.google.com"              );                              //Gear up the custom message data              fbdo.fcm.setDataMessage(                "{\"myData\":\"myValue\"}"              );                              //Send message to one recipient with inddex 1 (index starts from 0)              if              (Firebase.sendMessage(fbdo,              1)) {                              //Success, print the result returned from server              Serial.println(fbdo.fcm.getSendResult()); }              else              {                              //Failed, print the fault reason              Serial.println(fbdo.errorReason()); }

Create, Edit, Serializing and Deserializing the JSON Objects

This library has built-in FirebaseJson Arduino library, the easiest JSON parser, builder and editor.

FirebaseJson usages are so simple every bit you read, store and update(edit) the JSON node in Firebase RTDB.

It doesn't apply the recursive call to parse or deserialize complex or nested JSON objects and arrays.

This makes the library tin utilise with a limited memory device.

Since you declare the FirebaseJson or FirebaseJsonArray object, use the functions setJsonData, setJsonArrayData, add, set and remove to build or edit the JSON/Array object and use get to parse the node's contents.

Divers the relative path of the specific node to add, set, remove and become functions to add, ready, remove and get its contents.

Part FirebaseJson.setJsonData is to deserialize the JSON string to JSON object.

In addition, office FirebaseJson.readFrom tin can be used to read the streaming JSON contents from WiFi/Ethernet Client, File and Harware Series and serialize information technology as the streaming content contains valid JSON data.

Function FirebaseJson.add is used to add the new node with the contents due east.g. Cord, Number (int and double), Boolean, Array and Object to the divers node.

Function FirebaseJson.set up is used for edit, overwrite, create new (if not exist) node with contents e.g. String, Number (int and double), Boolean, Assortment and Object at the defined relative path and node.

Role FirebaseJson.go is used for parsing or deserializee the JSON object and assortment. The deserialized or parsed result will keep in FirebaseJsonData object which tin be casted to whatever blazon of value or variable due east.g string, bool, int, bladder, double by using FirebaseJsonData.to<type>.

The casting from FirebaseJsonData to FirebaseJson and FirebaseJsonArray objects is different, by using FirebaseJsonData.getJSON(FirebaseJson) and FirebaseJsonData.getArray(FirebaseJsonArray).

Function FirebaseJson.search is used for searching the elements in JSON object and array. The search function supports criterias which can exist set using FirebaseJson::SearchCriteria data.

The search function returns the number of items or elements found.

The SearchCriteria data consisted of the backdrop east.1000. path, value, depth, endDepth, and searchAll.

The path holding is the key proper noun or path to search which can utilise the wildcard * for path to be whatsoever key or name at that depth and so on.

The value belongings can exist used with or without path consignment.

The depth property is begin depth to search, default value is 0.

The endDepth property is the cease depth to search, default value is -1 for unlimited end depth.

The searchAll property, when gear up to true, is to search all occurrences of elements found and search outcome stores in FirebaseJsonData object volition be assortment of all items found. The actual full path of search can be obtained by FirebaseJsonData.searchPath which will be serialized array string of all paths for all elements found from search.

When searchAll property is false (default), the first occurrence will be set to the result which tin exist any value type.

The search path from FirebaseJsonData.searchPath will be string of the element or item full path.

The search result will keep in FirebaseJsonData object which later tin can cast to any type (always be an array in case of searchAll holding is truthful) by using FirebaseJsonData.to<blazon>.

Function FirebaseJson.remove is used to remove the node and all its children'south contents at the defined relative path and node.

Function FirebaseJson.toString is used for serializeing the JSON object to writable objects east.g. char assortment, Arduino String, C/C++ string, WiFi/Ethernet Client and Hardware/Software Serial.

Function FirebaseJson.serializedBufferLength is used for calculating the serialized buffer size that required for reserved buffer in serialization.

Function FirebaseJson.responseCode is used to get the http code response header while read the WiFi/Ethernet Client using FirebaseJson.toString.

Functions FirebaseJson.iteratorBegin, FirebaseJson.iteratorGet and FirebaseJson.iteratorEnd are used to parse all JSON object contents as a list which can be iterated with index.

Function FirebaseJson.articulate is used to articulate JSON object contents.

Function FirebaseJson.setFloatDigits is for float number precision when serialized to string.

Function FirebaseJson.setDoubleDigits is for double number precision when serialized to string.

Function FirebaseJsonArray.add is used for adding the new contents e.chiliad. Cord, Number (int and double), Boolean, Array and Object to JSON assortment.

Function FirebaseJsonArray.fix is for edit, overwrite, create new (if not exist) contents e.g. String, Number (int and double), Boolean, Array and Object at the divers relative path or defined index of JSON assortment.

Function FirebaseJsonArray.get and FirebaseJsonArray.searchpiece of work in the aforementioned mode every bit FirebaseJson objects

Part FirebaseJsonArray.remove is used to remove the assortment's contents at the defined relative path or defined index of JSON array.

Role FirebaseJsonArray.toString is used for serializeing the JSON array object to writable objects e.one thousand. char assortment, Arduino String, C/C++ cord, WiFi/Ethernet Client and Hardware/Software Serial.

Function FirebaseJsonArray.serializedBufferLength is used for calculating the serialized buffer size that required for reserved buffer in serialization.

Function FirebaseJsonArray.responseCode is used to become the http lawmaking response header while read the WiFi/Ethernet Customer using FirebaseJson.toString.

Function FirebaseJsonArray.articulate is used to articulate JSON array object contents.

Function FirebaseJsonArray.setFloatDigits is for float number precision when serialized to string.

Function FirebaseJsonArray.setDoubleDigits is for double number precision when serialized to string.

Meet examples/FirebaseJson for the usage.

For FirebaseJson part description, see FirebaseJSON object Functions.

The following example shows how to use FirebaseJson.

                              //Declare FirebaseJson object (global or local)              FirebaseJson json;                              //Add together name with value Living Room to JSON object              json.add(                "name"              ,                              "Living Room"              );                              //Add temp1 with value 120 and temp1 with xl to JSON object                              //Note: temp2 is non the kid of temp1 equally in previous version.              json.add(                "temp1"              ,              120).add(                "temp2"              ,              40);                              //Add nested child contents directly              json.set(                "unit of measurement/temp1"              ,                              "Farenheit"              ); json.prepare(                "unit of measurement/temp2"              ,                              "Celcius"              );                              //Deserialize to serial with prettify option              json.toString(Series,              truthful); Serial.println(); Serial.println();                              /**              This is the result of the above code                            {                              "proper noun": "Living Room",                              "temp1": 120,                              "temp2": 40,                              "unit of measurement": {                              "temp1": "Farenheit",                              "temp2": "Celcius"                              }              }                              */                                            //To set assortment to the higher up JSON using FirebaseJson straight                              //Set (add) assortment indexes 0,1,ii,v,seven under temp1, the original value volition be replaced with new one.              json.ready(                "temp1/[0]"              ,              47); json.set(                "temp1/[1]"              ,              28); json.set(                "temp1/[2]"              ,              34); json.ready(                "temp1/[5]"              ,              23);                              //nix will be created at assortment index three,iv due to it's non yet assigned              json.set(                "temp1/[7]"              ,              25);                              //null will be created at array index half dozen                              //Print out every bit prettify cord              json.toString(Series,              true); Serial.println(); Serial.println();                              /**              The result of the to a higher place code                            {                              "name": "Living Room",                              "temp1": [                              47,                              28,                              34,                              naught,                              zip,                              23,                              null,                              25                              ],                              "temp2": 40,                              "unit": {                              "temp1": "Farenheit",                              "temp2": "Celcius"                              }                              }                              */                                            //Effort to remove temp1 assortment at index 1              json.remove(                "temp1/[1]"              );                              //Try to remove temp2              json.remove(                "temp2"              );                              //Print out as prettify string              json.toString(Serial,              true); Serial.println(); Serial.println();                              /**              The effect of the above code                            {                              "name": "Living Room",                              "temp1": [                              47,                              34,                              nothing,                              null,                              23,                              zero,                              25                              ],                              "unit": {                              "temp1": "Farenheit",                              "temp2": "Celcius"                              }              }                              */                                            //At present parse/read the contents from specific node unit/temp2                              //FirebaseJsonData is required to keep the parse results which can exist accessed afterwards              FirebaseJsonData upshot;  json.go(upshot,                              "unit of measurement/temp2"              );              if              (result.success) {                              //Print type of parsed data e.k string, int, double, bool, object, array, zero and undefined              Series.println(result.type);                              //Print its content e.1000.cord, int, double, bool whereas object, array and zippo too tin access as string              Serial.println(result.to<String>());                              //Series.println(result.to<int>());                              //Serial.println(effect.to<bool>());                              //Series.println(result.to<bladder>());                              //Serial.println(result.to<double>());              }                              //The to a higher place lawmaking will show                              /**              string              Celcius                              */                                            //To become the array temp from FirebaseJson              json.get(result,                              "temp1"              );                              //Gear up FirebaseJsonArray to take the assortment from FirebaseJson              FirebaseJsonArray arr;                              //Get array data              result.go<FirebaseJsonArray>(arr);                              //Call get with FirebaseJsonData to parse the array at defined index i              for              (size_t              i =              0; i < arr.size(); i++) {                              //upshot now used as temporary object to get the parse results              arr.go(result, i);                              //Print its value              Serial.print(                "Assortment index:                "              );   Serial.print(i);   Series.impress(                ", type:                "              );   Series.print(result.type);   Serial.print(                ", value:                "              );   Serial.println(result.to<String>()); }                              /**              The result of above lawmaking              Array alphabetize: 0, type: int, value: 47              Assortment index: 1, blazon: int, value: 34              Array index: 2, type: goose egg, value: null              Array index: iii, type: null, value: nothing              Array alphabetize: 4, type: int, value: 23              Array index: 5, type: zero, value: naught              Assortment index: vi, blazon: int, value: 25                              */                          

The post-obit example shows how to use FirebaseJsonArray.

                              //Declare FirebaseJsonArray object (global or local)              FirebaseJsonArray arr;                              //Add some data              arr.add(                "assistant"              ); arr.add(                "mango"              ); arr.add(                "coconut"              );                              //Change the array contents              arr.fix(                "[1]/food"              ,                              "salad"              ); arr.ready(                "[1]/sweet"              ,                              "cake"              ); arr.set up(                "[1]/titbit"              ,                              "snack"              ); arr.set(                "[2]"              ,                              "apple"              );                              //                or arr.prepare(2, "apple");              arr.ready(                "[four]/[0]/[1]/amount"              ,              20);                              //Print out array equally prettify string              arr.toString(Series,              true); Series.println(); Series.println();                              /**              This is the event of the above code                            [                              "banana",                              {                              "nutrient": "salad",                              "sweet": "cake",                              "appetizer": "snack"                              },                              "apple",                              null,                              [                              [                              aught,                              {                              "corporeality": 20                              }                              ]                              ]              ]                              */                                            //Remove array content at /4/0/1/amount              arr.remove(                "[4]/[0]/[1]/corporeality"              );                              //Print out as prettify cord              arr.toString(Serial,              true); Serial.println(); Serial.println();                              /**              The upshot of the in a higher place code                            [                              "banana",                              {                              "food": "salad",                              "sugariness": "block",                              "appetizer": "snack"                              },                              "apple tree",                              nada,                              [                              [                              null                              ]                              ]              ]                                            */                                            //At present parse/read the assortment contents at some index              FirebaseJsonData event;  arr.go(consequence,                              "[1]/food"              );              if(result.success) {                              //Blazon of parsed data              Serial.println(result.type);                              //Its value              Serial.println(effect.to<String>());                              //Serial.println(result.to<int>());                              //Serial.println(consequence.to<bool>());                              //Serial.println(upshot.to<float>());                              //Serial.println(issue.to<double>());              }                              //The above lawmaking will show                              /**              string              salad                              */                                            //To become the JSON object at array index 1 from FirebaseJsonArray              arr.go(upshot,                              "[1]"              );                //                or arr.get(result, 1);                              //Fix FirebaseJson to take the JSON object from FirebaseJsonArray              FirebaseJson json;                              //Go FirebaseJson data              result.get<FirebaseJson>(json);                              //Parse the JSON object as list                              //Become the number of items              size_t              len = json.iteratorBegin(); FirebaseJson::IteratorValue value;              for              (size_t              i =              0; i < len; i++) {     value = json.valueAt(i);     Serial.printf(                "%d, Blazon: %s, Proper noun: %due south, Value: %south\north                "              , i, value.type              == FirebaseJson::JSON_OBJECT ?                              "object"                            :                              "array"              , value.central.c_str(), value.value.c_str()); }                              //Clear all list to free memory              json.iteratorEnd();                              /**              The issue of the in a higher place lawmaking                            0, Type: object, Key: food, Value: salad              1, Blazon: object, Key: sweet, Value: block              2, Type: object, Cardinal: appetizer, Value: snack                                            */                          

License

The MIT License (MIT)

Copyright (C) 2022 K. Suwatchai (Mobizt)

Permission is hereby granted, free of accuse, to any person returning a re-create of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to let persons to whom the Software is furnished to do so, subject field to the following weather condition:

The above copyright find and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "Equally IS", WITHOUT WARRANTY OF Whatever KIND, Limited OR Implied, INCLUDING Simply NOT Limited TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A Item PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS Exist LIABLE FOR ANY Merits, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE Apply OR OTHER DEALINGS IN THE SOFTWARE.

millertherited51.blogspot.com

Source: https://github.com/mobizt/Firebase-ESP32

0 Response to "Firebase Http Functions Reading Get Url Query Parameters"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel