There Was an Unknown Error While Processing the Request Try Again Firebase
Firebase Realtime Database Arduino Library for ESP8266
This library supports ESP8266 MCU from Espressif. The following are platforms in which libraries are also available.
-
ESP32 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 unified version for ESP8266 and ESP32 with Deject Storage and new Cloud Messaging supported is now available.
Please attempt information technology here https://github.com/mobizt/Firebase-ESP-Client
Tested Devices
- Wemos D1 Mini
- NodeMCU
- ESP-12F
- LinkNode
Other Arduino Devices supported using external Clients.
Since version iii.viii.iv, library allows you to use external Arduino Clients network interfaces eastward.1000. WiFiClient, EthernetClient and GSMClient, the Arduino supported devices that have plenty wink size (> 128k) and retentivity can now use this library.
To use external Client, run into the ExternalClient examples.
The authentication 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'southward Residual APIs Client
-
Supports database read, store, update, delete and value changes listener
-
Supports Test Style (No Auth)
-
Supports Firmware OTA updates
-
Supports Firebase Cloud Messaging.
-
Built-in JSON editor and deserializer.
-
Supports external Heap via SRAM/PSRAM.
-
Supports ethernet using ENC28J60, W5100 and W5500 Ethernet modules.
Known bugs
From known bugs of BearSSL library in ESP8266 Arduino Cadre SDK version 2.six.1.
If you're using this SDK version, please update the ESP8266 Arduino Core SDK to version two.half-dozen.two or newer.
Basic Examples
Don't exist confused with other Firebase Arduino libraries, this library has different working functions, the following examples provide the basic usages.
IoT using Firebase and NodeMCU © CC By-NC-SA
ESP32 | Palpitate | FIREBASE - Temperature & Humidity Bank check App <-- *For ESP32 which similar to ESSP8266 unless the include header file, utilise #include <FirebaseESP8266.h> instead
Serverless IoTs with Firebase Realtime Database and ESP8266 - Part 1
Serverless IoTs with Firebase Realtime Database and ESP8266 - Office 2
Dependencies
This library required ESP8266 Core SDK version 2.6.2 and above.
For Arduino IDE, ESP8266 Core SDK tin can exist installed through Boards Manager.
For PlatfoemIO IDE, ESP8266 Core SDK can be installed through PIO Home > Platforms > Espressif 8266.
Installation
Using Library Manager
At Arduino IDE, go to bill of fare Sketch -> Include Library -> Manage Libraries...
In Library Manager Window, search "firebase" in the search grade so select "Firebase ESP8266 Customer".
Click "Install" button.
For PlatformIO IDE, using the following command.
pio lib install "Firebase ESP8266 Customer""
Or at PIO Habitation -> Libraries -> Registry then search Firebase ESP8266 Customer.
If you ever installed this library in Global storage in PlatformIO version prior to v2.0.0 and y'all have updated the PlatformIO to v2.0.0 and later, the global library installation was non available, the sources files of old library version still be able to search by the library dependency finder (LDF), you needed to remove the library from folder C:\Users\<UserName>\.platformio\lib to prevent unexpected behavior when compile and run.
Transmission installation
For Arduino IDE, download nada file from the repository (Github page) by select Code dropdown at the meridian of repository, select Download Zero
From Arduino IDE, select carte Sketch -> Include Library -> Add together .ZIP Library....
Choose Firebase-ESP8266-master.zip that previously downloaded.
Rename Firebase-ESP8266-master folder to Firebase_ESP8266_Client.
Go to menu Files -> Examples -> Firebase-ESP8266-master and choose one from examples.
For PlatformIO, in folder "lib", create new binder named "Firebase-ESP8266" and add these files in that folder.
Important Note for Manual Installation in Arduino IDE
Folder renaming to Firebase_ESP8266_Client was required for making the library can be updated via Library Manager without problems.
Without folder renaming, when you update the library via Library Manager, library will be updated to the some other folder named Firebase_ESP8266_Client which leads to compilation error when there are ii different versions of library constitute in the libraries binder and can cause the conflicts when file structures and functions changed in the newer version.
For example, the library version 3.seven.5 and before were installed manually past downloading Zip file and extracted to Firebase-ESP8266-chief binder. If the library was afterwards updated to v3.viii.2 and newer via Library Manager, the compilation error will have place because the newer version files structures and functions changed and compiler is trying to compile these ii versions of source files together.
In this case, you need to delete Firebase-ESP8266-master folder from libraries binder.
Usages
See all examples for complete usages.
Encounter office clarification for all bachelor functions.
Initialization
// Include ESP8266WiFi.h #include <ESP8266WiFi.h> // Include Firebase ESP8266 library (this library) #include <FirebaseESP8266.h> // Ascertain the Firebase Data object FirebaseData fbdo; // Define the FirebaseAuth data for authentication information FirebaseAuth auth; // Define the FirebaseConfig information for config data FirebaseConfig config; // Assign the project host and api key (required) config.host = FIREBASE_HOST; config.api_key = API_KEY; // Assign the user sign in credentials auth.user.email = USER_EMAIL; auth.user.password = USER_PASSWORD; // Initialize the library with the Firebase authen and config. Firebase.begin(&config, &auth); // Optional, gear up AP reconnection in setup() Firebase.reconnectWiFi(truthful); // Optional, set up number of error retry Firebase.setMaxRetry(fbdo, 3); // Optional, set number of error resumable queues Firebase.setMaxErrorQueue(fbdo, 30); // Optional, utilise classic HTTP GET and Mail requests. // This selection allows go and delete functions (PUT and DELETE HTTP requests) works for // device connected behind the Firewall that allows simply Get and Post requests. Firebase.enableClassicRequest(fbdo, true); // Optional, prepare the size of BearSSL WiFi to receive and transmit buffers // Firebase may non back up the data transfer fragmentation, you may need to reserve the buffer to match // the data to exist transported. fbdo.setBSSLBufferSize(1024, 1024); // minimum size is 512 bytes, maximum size is 16384 bytes // Optional, ready the size of HTTP response buffer // Preclude out of memory for large payload but information may be truncated and can't determine its type. fbdo.setResponseSize(1024); // minimum size is 1024 bytes See other authentication examples for more than sign in methods.
Memory Options for ESP8266
When yous update the ESP8266 Arduino Core SDK to v3.0.0, the retentiveness can be configurable from IDE.
Y'all can choose the Heap memory betwixt internal and external retention bit from IDE e.1000. Arduino IDE and PlatformIO on VSCode or Cantlet IDE.
Arduino IDE
For ESP8266 devices that don't not have external SRAM/PSRAM flake installed, cull the MMU option 3, 16KB enshroud + 48KB IRAM and 2nd Heap (shared).
For ESP8266 devices that have external 23LC1024 SRAM chip installed, cull the MMU option five, 128K External 23LC1024.
For ESP8266 devices that accept external ESP-PSRAM64 chip installed, choose the MMU option six, 1M External 64 MBit PSRAM.
PlatformIO IDE
The MMU options can be selected from build_flags in your project's platformio.ini file
For ESP8266 devices that don't non have external SRAM/PSRAM chip installed, add build flag as below.
[env:d1_mini] platform = espressif8266 build_flags = -D PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48_SECHEAP_SHARED board = d1_mini framework = arduino monitor_speed = 115200 For ESP8266 devices that have external 23LC1024 SRAM chip installed, add build flag every bit below.
[env:d1_mini] platform = espressif8266 ;128K External 23LC1024 build_flags = -D PIO_FRAMEWORK_ARDUINO_MMU_EXTERNAL_128K board = d1_mini framework = arduino monitor_speed = 115200 For ESP8266 devices that accept external ESP-PSRAM64 bit installed, add together build flag as below.
[env:d1_mini] platform = espressif8266 ;1M External 64 MBit PSRAM build_flags = -D PIO_FRAMEWORK_ARDUINO_MMU_EXTERNAL_1024K board = d1_mini framework = arduino monitor_speed = 115200 ESP8266 andd SRAM/PSRAM Chip connection
Most ESP8266 modules don't take the built-in SRAM/PSRAM on board. External memory fleck connectedness tin can exist done via SPI port equally beneath.
23LC1024/ESP-PSRAM64 ESP8266 CS (Pin 1) GPIO15 SCK (Pin 6) GPIO14 MOSI (Pin 5) GPIO13 MISO (Pin 2) GPIO12 /Hold (Pin 7 on 23LC1024 only) 3V3 Vcc (Pivot 8) 3V3 Vcc (Pin 4) GND Once the external Heap memory was selected in IDE, to allow the library to apply the external memory, you can set it in FirebaseFS.h by define this macro.
#ascertain FIREBASE_USE_PSRAM This macro was defined by default when y'all installed or update the library.
Hallmark
This library supports many types of authentications.
See other authentication examples for more hallmark methods.
Some authentication methods require the token generaion and exchanging process which take more than time than using the legacy token.
The system time must be ready before 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 fourth dimension, several seconds in overall process which included the NTP time conquering (system time setup), JWT token generation and signing process.
By setting the organisation time prior to calling the Firebase.begin , the internal NTP time acquisition process volition exist ignored.
You tin can set the organization time using the RTC bit or manually past calling Firebase.setSystemTime .
While authenticate using Electronic mail and password, the process volition exist perform faster because no token generation and time setup required.
The cosign using the legacy token (database secret) does not accept these filibuster time because the token is prepare to use.
Speed of data transfer
This library focuses on the user privacy and user data protection which follows Google authentication processes. Setting the security rules to let public access read and write, is not recommended fifty-fifty the data transmision fourth dimension in this instance was significantly reduced as it does non require whatever auth token and so the overall data size was reduced, just anyone tin steal, modify, or delete data in your database.
Once the auth token is importance and when information technology was created and ready for hallmark process, the data transmission time volition depend on the time used in SSL/TLS handshake process (only 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 small, only twoscore 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 transport.
There is a compromise betwixt the speed of data transfer and the Rx/Tx buffer which then reduced the complimentary memory available especially in ESP8266.
When the reserved SSL customer Rx/Tx buffer is smaller than the size of data to be transmitted, the data demand to be sent equally multiple chunks which required more transmission time.
This afflicted peculiarly in ESP8266 which has the limited free memory.
To speed up the data transmission in ESP8266, the larger reserved Rx/Tx buffer size is necessary.
The reserved SSL Rx/Tx buffer size in ESP8266 can be set through the function <Firebase Data object>.setBSSLBufferSize, e.g. fbdo.setBSSLBufferSize(2048, 2048);
The larger BearSSL buffer reserved for ESP8266, the lower gratis memory bachelor as long as the session opened (server connection).
Therefore the time for information 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 exist used instead of other authentication to reduce the header size and the lower SSL Rx/Tx buffer i.e. 1024 for Rx and 512 for Tx are enough.
When the session was reused (in this library), the SSL handshake procedure will be ignored in the subsequence requests.
The session was close when the host or ip changes or server closed or the session timed out in three minutes.
When the new session need to be opened, the SSL handshake volition be processed again and used the time approx i - two seconds to be done.
For post (push) or put (fix) asking in RTDB, to speed up the data transfer, use pushAsync or setAsync instead.
With pushAsync and setAsync, the payload response will be ignored and the adjacent data will be processed immediately.
Admission in Test Style (No Auth)
In Test Mode, token generation volition be ignored and no authentication applied to the request.
You can access RTDB database in Test Style by set the security rules like this.
{ "rules": { ".read": true, ".write": true } } And ready the config.signer.test_mode = true;, see TestMode.ino example.
The authenication credentials and prerequisites
To use Electronic mail/Password sign-in authentication every bit in the examples, the Email/Password Sign-in provider must be enabled.
Add Email and password for first user in your project so use this Email and password to sign in.
To apply Bearding sign-in, the Bearding Sign-in provider must exist enabled past follow the below steps.
To get API Key used in Electronic mail/Countersign sign-in
To get the Service accounts primal JSON file used in Custom and OAuth2.0 tokens athentications.
For RTDB usages, create new real-fourth dimension database (if not setup all the same)
Edit the default database rules equally post-obit
{ "rules": { ".read": "auth != null" , ".write": "auth != null" } } To get the database URL and secret (legacy token).
For server SSL authentication past providing the server root certificate.
Server SSL certificate verification is the procedure 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 document tin be download from https://pki.goog/repository/
Select the .PEM (base-64 encoded string) or .DER (binary) file to download.
From the test every bit of July 2021, GlobalSign Root CA was missing from Google server, the certificate chain, GTS Root R1 tin exist used instead of root certificate.
Below is how to assign the certificate data for server verification.
/* In example the certificate data was used */ config.cert.data = rootCACert; // Or custom fix the root document for each FirebaseData object fbdo.setCert(rootCACert); /* Or assign the document file */ /** From the examination as of July 2021, GlobalSign Root CA was missing from Google server * as described higher up, GTS Root R1 (gsr1.pem or gsr1.der) can be used instead. * ESP32 Arduino SDK supports PEM format only fifty-fifty mBedTLS supports DER format besides. * 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 save memory
The internal classes, RTDB and FCM in this library can exist excluded or disabled to save retentivity 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 can exist read through these get functions.
The functions included go, getInt, getFloat, getDouble, getBool, getString, getJSON, getArray, getBlob, getFile.
These functions return boolean value indicates the success of the operation which will be true if all of the following conditions were met.
-
Server returns HTTP status code 200
-
The data types matched between request and response.
For generic get, employ Firebase.get(fbdo, <path>).
And check its type with fbdo.dataType() or fbdo.dataTypeEnum() and cast the value from it e.g. fbdo.to<int>(), fbdo.to<std::string>().
The data type of returning payload can be determined by fbdo.dataType() which returns String or fbdo.dataTypeEnum() returns enum value.
The String of type returns from fbdo.dataType() tin can be string, boolean, int, float, double, json, array, blob, file and null.
The enum value type, fb_esp_rtdb_data_type returns from fbdo.dataTypeEnum() tin can be fb_esp_rtdb_data_type_null (one), 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 (x)
The database data's payload (response) tin can be read or access through the casting value from FirebaseData object with to<type>() functions (since v2.4.0).
-
String s = fbdo.to<String>(); -
std::string _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 data which its type does non match the data type in the database from above functions will return empty (string, object or array).
BLOB and file stream data are stored as special base64 encoded string which are just supported and implemented by this library.
The encoded base64 cord will be prefixed with some header string ("file,base64," and "blob,base64,") for information type manipulation.
The following example showed how to read integer value from node "/test/int".
if (Firebase.getInt(fbdo, "/exam/int" )) { if (fbdo.dataTypeEnum() == fb_esp_rtdb_data_type_integer) { Serial.println(fbdo.to<int>()); } } else { Serial.println(fbdo.errorReason()); } Store Data
To store data at a specific node in Firebase RTDB, use these set functions.
The function included set, setInt, setFloat, setDouble, setBool, setString, setJSON, setArray, setBlob and setFile.
For faster sending data, non-waits or async mode functions are available due east.g. setAsync, setIntAsync, setFloatAsync, setDoubleAsync, setBoolAsync, setStringAsync, setJSONAsync, setArrayAsync, setBlobAsync and setFileAsync.
For generic prepare, apply Firebase.set up(fbdo, <path>, <any variable or value>).
These async functions will ignore the server responses.
The above functions return boolean value indicates the success of the operation which will be true if all of the following conditions matched.
-
Server returns HTTP status lawmaking 200
-
The information types matched between asking and response.
Merely 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 tin be set through Firebase'southward set functions.
The priority value can exist 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 set functions is used as provisional checking.
If defined Etag is not matched the divers path's ETag, the set operation will fail with upshot 412 Precondition Failed.
ETag at whatever node can be read through Firebase.getETag. ETag value changed upon the information was prepare or delete.
The server's Timestamp tin can exist stored in the database through Firebase.setTimestamp.
The returned Timestamp value can get from fbdo.to<int>().
The file systems for flash and sd memory tin be inverse in FirebaseFS.h.
The following example showed how to store file data to flash memory at node "/test/file_data".
if (Firebase.getFile(fbdo, StorateType::FLASH, "/test/file_data" , "/examination.txt" )) { // FLASH.begin(); // not need to begin over again due to it has been called in function. File file = DEFAULT_FLASH_FS.open( "/test.txt" , "r" ); while (file.available()) { Serial.impress(file.read(), HEX); } file.close(); Serial.println(); } else { Serial.println(fbdo.fileTransferError()); } Append Information
To append new data to a specific node in Firebase RTDB, use 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 mode functions are available e.1000. pushAsync, pushIntAsync, pushFloatAsync, pushDoubleAsync, pushBoolAsync, pushStringAsync, pushJSONAsync, pushArrayAsync, pushBlobAsync and pushFileAsync.
These functions return boolean value indicates the success of the operation.
The unique primal of a new appended node can be adamant from fbdo.pushName().
Every bit set up functions, the Firebase's push functions support priority.
ETag was not available after button unless read the ETag at that new appended unique cardinal later with Firebase.getETag.
The server's Timestamp can be appended in the database through Firebase.pushTimestamp.
The unique primal of Timestamp can be adamant after Timestamp was appended.
The post-obit example showed how to suspend new data (using FirebaseJson object) to node "/test/append.
FirebaseJson json; FirebaseJson json2; json2.gear up( "child_of_002" , 123.456); json.set( "parent_001" , "parent 001 text" ); json.set( "parent 002" , json2); if (Firebase.pushJSON(fbdo, "/test/suspend" , json)) { Series.println(fbdo.dataPath()); Serial.println(fbdo.pushName()); Serial.println(fbdo.dataPath() + "/" + fbdo.pushName()); } else { Serial.println(fbdo.errorReason()); } Patch Data
Firebase's update functions used to patch or update new or existing information at the divers node.
These functions, updateNode and updateNodeSilent are bachelor and work with JSON object (FirebaseJson object only).
For faster sending data, non-waits or async mode functions are bachelor e.g. updateNodeAsync, and updateNodeSilentAsync.
If any cardinal proper noun provided at a defined node in JSON object has not existed, a new primal will exist created.
The server returns JSON information payload which was successfully patched.
Render of large JSON payload will cost the network data, culling function updateNodeSilent or updateNodeSilentAsync should be used to save the network data.
The post-obit example showed how to patch data at "/test".
FirebaseJson updateData; FirebaseJson json; json.ready( "_data2" , "_value2" ); updateData.gear up( "data1" , "value1" ); updateData.set( "data2" , json); if (Firebase.updateNode(fbdo, "/examination/update" , updateData)) { Serial.println(fbdo.dataPath()); Serial.println(fbdo.dataType()); Serial.println(fbdo.jsonString()); } else { Series.println(fbdo.errorReason()); } Delete Data
The following instance showed how to delete data and its children at "/examination/append"
Firebase.deleteNode(fbdo, "/test/append" ); Filtering Information
To filter or query the data, the following query parameters are available through the QueryFilter class.
These parameters are orderBy, limitToFirst, limitToLast, startAt, endAt, and equalTo.
To filter information, parameter orderBy should be assigned.
Use "$key" equally the orderBy parameter if the key of child nodes was used for the query.
Use "$value" as the orderBy parameter if the value of child nodes was used for the query.
Use primal (or full path) of child nodes every bit the orderBy parameter if all values of the specific central were used for the query.
Use "$priority" as orderBy parameter if child nodes'south "priority" was used for query.
The above orderBy parameter can exist combined with the following parameters for limited and ranged the queries.
QueryFilter.limitToFirst - The total 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 string) of query upon orderBy param.
QueryFilter.endAt - Catastrophe value of range (number or string) 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 grade to filter the data at node "/test/data"
// Presume that children that have key "sensor" are under "/test/data" // Instantiate the QueryFilter class QueryFilter query; // Build query using specified child node fundamental "sensor" under "/test/data" query.orderBy( "sensor" ); // Query whatever kid that its value begins with two (number), assumed that its data type is float or integer query.startAt(2); // Query any kid that its value ends with 8 (number), assumed that its data type is bladder or integer query.endAt(8); // Limit the maximum query event to render simply the last 5 nodes query.limitToLast(5); if (Firebase.getJSON(fbdo, "/test/data" , query)) { // Success, then try to read the JSON payload value Series.println(fbdo.jsonString()); } else { // Failed to get JSON data at defined database path, print out the mistake reason Series.println(fbdo.errorReason()); } // Clear all query parameters query.articulate(); Server Data Changes Listener with Server-Sent Events or HTTP Streaming
This library uses HTTP GET request with text/consequence-stream header to make HTTP streaming connexion.
The Firebase'south functions that involved the stream operations are beginStream, beginMultiPathStream, setStreamCallback, setMultiPathStreamCallback and/or readStream.
Function beginStream is to subscribe to the data changes at a defined node.
Office beginMultiPathStream is to subscribe to the data changes at a defined parent node path with multiple kid nodes value parsing and works with setMultiPathStreamCallback.
Function setStreamCallback is to assign the callback function that accepts the FirebaseStream class as parameter.
Function setMultiPathStreamCallback is to assign the callback function that accepts the MultiPathStream class as parameter.
The FirebaseStream contains stream'due south event/data payloadd and interface function calls are similar to FirebaseData object.
The MultiPathStream contains stream's issue/information payload for various child nodes.
To polling the stream's event/data payload manually, use readStream in loop().
Function readStream used in the loop() task to continuously read the stream'due south event and data.
Since polling the stream'due south event/data payload with readStream, use fbdo.streamAvailable to check if stream event/data payoad is bachelor.
Function fbdo.streamAvailable returned truthful when new stream'south event/data payload was bachelor.
When new stream payload was available, its data and event tin can be accessed from FirebaseData object functions.
Function endStream ends the stream operation.
Note that, when using the shared FirebaseData object for stream and Grime usages(normal operation to create,read, update and delete data), the stream connection will be interrupted (closed) to connect in other HTTP way, the stream volition be resumed (open) later on the CRUD usages.
For the in a higher place example, you need to provide the idle time for FirebaseData object to established the streaming connexion and received the stream payload. The changes on the server at the streaming node path during the stream interruption will be missed.
To avoid this sitation, don't share the usage of stream's FirebaseData object, another FirebaseData object should exist used.
In improver, delay function used in the same loop of readStream() will defer the streaming, the server data changes may be missed.
Keep in heed that FirebaseData object will create the SSL client within of HTTPS information transaction and uses large memory.
The following case showed how to subscribe to the data changes at node "/test/data" with a callback function.
// In setup(), set the stream callback function to handle information // streamCallback is the role that called when database data changes or updates occurred // streamTimeoutCallback is the function that called when the connection between the server // and client was timeout during HTTP stream Firebase.setStreamCallback(fbdo, streamCallback, streamTimeoutCallback); // In setup(), fix the streaming path to "/test/information" and begin stream connexion if (!Firebase.beginStream(fbdo, "/test/data" )) { // Could not begin stream connection, then print out the mistake particular Series.println(fbdo.errorReason()); } // Global function that handles stream data void streamCallback(StreamData data) { // Impress out all information Series.println( "Stream Data..." ); Serial.println(information.streamPath()); Series.println(data.dataPath()); Serial.println(data.dataType()); // Impress out the value // Stream information can be many types which tin can be determined from part dataType if (data.dataTypeEnum() == fb_esp_rtdb_data_type_integer) Series.println(data.to<int>()); else if (data.dataTypeEnum() == fb_esp_rtdb_data_type_float) Series.println(information.to<float>(), 5); else if (data.dataTypeEnum() == fb_esp_rtdb_data_type_double) printf( "%.9lf\northward " , information.to<double>()); else if (data.dataTypeEnum() == fb_esp_rtdb_data_type_boolean) Serial.println(information.to<bool>()? "true" : "false" ); else if (data.dataTypeEnum() == fb_esp_rtdb_data_type_string) Serial.println(data.to<Cord>()); else if (data.dataTypeEnum() == fb_esp_rtdb_data_type_json) { FirebaseJson *json = data.to<FirebaseJson *>(); Series.println(json->raw()); } else if (information.dataTypeEnum() == fb_esp_rtdb_data_type_array) { FirebaseJsonArray *arr = data.to<FirebaseJsonArray *>(); Serial.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 authentication except for legacy token, Firebase.gear up() should be called repeatedly // in loop() to handle authentication tasks. void loop() { if (Firebase.gear up()) { // Firebase is set up to apply now. } }
For multiple paths stream, see the MultiPath_stream example.
The post-obit example showed how to subscribe to the stream changes at "/test/information" and read the stream manually.
// In setup(), set up the streaming path to "/test/information" and brainstorm stream connection if (!Firebase.beginStream(fbdo, "/examination/data" )) { Serial.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) Series.println(fbdo.to<float>(), v); else if (fbdo.dataTypeEnum() == fb_esp_rtdb_data_type_double) printf( "%.9lf\north " , fbdo.to<double>()); else if (fbdo.dataTypeEnum() == fb_esp_rtdb_data_type_boolean) Serial.println(fbdo.to<bool>() ? "true" : "simulated" ); else if (fbdo.dataTypeEnum() == fb_esp_rtdb_data_type_string) Serial.println(fbdo.to<String>()); else if (fbdo.dataTypeEnum() == fb_esp_rtdb_data_type_json) { FirebaseJson *json = fbdo.to<FirebaseJson *>(); Series.println(json->raw()); } else if (fbdo.dataTypeEnum() == fb_esp_rtdb_data_type_array) { FirebaseJsonArray *arr = fbdo.to<FirebaseJsonArray *>(); Serial.println(arr->raw()); } } // For authentication except for legacy token, Firebase.gear up() should exist chosen repeatedly // in loop() to handle authentication tasks. void loop() { if (Firebase.ready()) { // Firebase is ready to use now. } } Fill-in and Restore Data
This library allows data backup and restores at a defined path.
The backup file will shop in SD/SDMMC carte or wink retentiveness.
The file systems for wink and SD retention tin can be changed via FirebaseFS.h.
Due to SD library used, only 8.3 DOS format file name supported.
The maximum eight characters for a file proper noun and 3 characters for file extension.
The database restoration returned completed status but when Firebase server successfully updates the data.
Whatever failed performance will not affect the database (no updates or changes).
The following instance showed how to backup all database information at "/" and restore.
Cord 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(); } // Brainstorm restore backed dup data back to database if (!Firebase.restore(fbdo, StorateType::SD, "/" , backupFileName)) { Serial.println(fbdo.fileTransferError()); } else { Serial.println(fbdo.getBackupFilename()); } Database Error Handling
When read store, append and update operations were failed due to buffer overflow and network problems.
These operations can retry and queued after the retry amount was reached the maximum retry set in function setMaxRetry.
// ready maximum retry amount to 3 Firebase.setMaxRetry(fbdo, three); The function setMaxErrorQueue limits the maximum queues in Error Queue collection.
The full of queue collection tin be checked through function isErrorQueueFull.
// set maximum queues to x Firebase.setMaxErrorQueue(fbdo, 10); // make up one's mind whether Fault Queue collection is full or not Firebase.isErrorQueueFull(fbdo); This library provides two approaches to run or procedure Mistake Queues with two functions.
-
beginAutoRunErrorQueue -
processErrorQueue
The office beginAutoRunErrorQueue will run or process queues automatically and can be called once.
While function processErrorQueue volition run or process queues and should call inside the loop().
With function beginAutoRunErrorQueue, you tin can assigned callback function that have QueueInfo object as parameter.
Which contains all information about existence processed queue, number of remaining queues and Error Queue collection condition.
Otherwise, Mistake Queues can be tracked manually with the following functions.
Part getErrorQueueID volition render the unsigned integer presents the id of the queue which volition keep using later.
Employ getErrorQueueID and isErrorQueueExisted to check whether this queue id is still existed or not.
If Mistake Queue ID does not exist in Mistake Queues collection, that queue is already done.
The following example showed how to run Error Queues automatically and rail the status with the callback role.
// In setup() // Prepare the maximum Firebase Error Queues in drove (0 - 255). // Firebase read/store operation causes past network issues and buffer overflow will exist // added to Firebase Error Queues drove. Firebase.setMaxErrorQueue(fbdo, 10); // Begin to run Error Queues in Fault Queue collection Firebase.beginAutoRunErrorQueue(fbdo, callback); // Use to stop the auto run queues // Firebase.endAutoRunErrorQueue(fbdo); void errorQueueCallback (QueueInfo queueinfo){ if (queueinfo.isQueueFull()) { Serial.println( "Queue is full" ); } Series.print( "Remaining queues: " ); Serial.println(queueinfo.totalQueues()); Serial.print( "Being processed queue ID: " ); Serial.println(queueinfo.currentQueueID()); Serial.print( "Data type:" ); Serial.println(queueinfo.dataType()); Serial.print( "Method: " ); Serial.println(queueinfo.firebaseMethod()); Series.print( "Path: " ); Serial.println(queueinfo.dataType()); Serial.println(); } The following instance showed how to run Error Queues and runway its status manually.
// In setup() // Set the maximum Firebase Fault Queues in collection (0 - 255). // Firebase read/store functioning causes past network problems and buffer overflow will be added to // Firebase Error Queues drove. Firebase.setMaxErrorQueue(fbdo, ten); // All of the post-obit are in loop() Firebase.processErrorQueue(fbdo); // Detrnine the queue condition if (Firebase.isErrorQueueFull(fbdo)) { Serial.println( "Queue is full" ); } // Remaining Error Queues in Mistake Queue collection Serial.print( "Remaining queues: " ); Serial.println(Firebase.errorQueueCount(fbdo)); // Assumed that queueID is unsigned integer array of queue that added to Error Queue collection // when error and apply Firebase.getErrorQueueID to get this Error Queue id. for (uint8_t i = 0; i < LENGTH_OF_QUEUEID_ARRAY; i++) { Series.impress( "Error Queue " ); Series.print(queueID[i]); if (Firebase.isErrorQueueExisted(fbdo, queueID[i])) Serial.println( " is queuing" ); else Serial.println( " is done" ); } Serial.println(); Error Queues tin can be saved as a file in SD card or Wink retentivity with function saveErrorQueue.
Mistake Queues store equally a file tin exist restored to Error Queue collection with part restoreErrorQueue.
Two types of storage can be assigned with these functions, StorageType::FLASH and StorageType::SD.
Read data (go) operation is not back up queues restore
The following case showed how to restore and salve Fault Queues in /test.txt file.
// To restore Error Queues if (Firebase.errorQueueCount(fbdo, "/test.txt" , StorageType::FLASH) > 0) { Firebase.restoreErrorQueue(fbdo, "/test.txt" , StorageType::Flash); Firebase.deleteStorageFile( "/examination.txt" , StorageType::FLASH); } // To salve Error Queues to file Firebase.saveErrorQueue(fbdo, "/test.txt" , StorageType::Flash); FireSense, The Programmable Information Logging and IO Control (Add together On)
This add on library is for the accelerate usages and works with Firebase RTDB.
With this add on library, you tin can remotely program your device to control its IOs or do some task or phone 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.
Run into examples/FireSense for the usage.
For FireSense part description, meet src/addons/FireSense/README.doc.
Firebase Cloud Messaging (FCM)
Ii types of FCM message information tin be sent using this library e.g. notification and custom data.
These two types of data can transport all together or separately.
Function Firebase.sendMessage volition send a message to one recipient.
Function Firebase.broadcastMessage will broadcast or transport a message to multiple recipients.
Role Firebase.sendTopic will send a message to any recipient who subscribed to the topic.
The FCM message itself offers a broad range of messaging options and capabilities for diverse recipient device platforms.
For Android, iOS and web platforms, these basic options tin can be set and work for all platforms.
Function fbdo.fcm.begin used to assign the server fundamental of your Firebase project.
Function fbdo.fcm.addDeviceToken used to add recipient registered device token which wants to ship bulletin 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 set up through fbdo.fcm.setNotifyMessage.
And clear these notify message data with fbdo.fcm.clearNotifyMessage.
For the information bulletin, provide your custom data as JSON object (FirebaseJson object or string) to fbdo.fcm.setDataMessage which can be clear with fbdo.fcm.clearDataMessage.
The other options are priority, collapse key, Time to Live of the bulletin and topic to send messages to, can be ready from the following functions.
Telephone call fbdo.fcm.setPriority for priority ("normal" or "loftier"), fbdo.fcm.setCollapseKey for collapse key setup, fbdo.fcm.setTimeToLive for life bridge of message setup between 0 sec. to 2,419,200 sec. (or 4 weeks), and fbdo.fcm.setTopic for assigning the topic that message to send to.
The post-obit example showed how to send FCM message.
// Provide your Firebase project's server key hither fbdo.fcm.begin(FIREBASE_FCM_SERVER_KEY); // Prvide 1 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 time to alive (optional) fbdo.fcm.setTimeToLive(5000); // Set the notification bulletin data fbdo.fcm.setNotifyMessage( "Notification" , "Hello Globe!" , "firebase-logo.png" , "http://www.google.com" ); // Set the custom message data fbdo.fcm.setDataMessage( "{\"myData\":\"myValue\"}" ); // Transport message to ane recipient with inddex i (index starts from 0) if (Firebase.sendMessage(fbdo, 1)) { // Success, print the result returned from server Series.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 as you read, store and update(edit) the JSON node in Firebase RTDB.
It doesn't utilize the recursive telephone call to parse or deserialize complex or nested JSON objects and arrays.
This makes the library tin use with a limited retentivity 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 apply get to parse the node's contents.
Defined the relative path of the specific node to add, prepare, remove and get functions to add together, ready, remove and get its contents.
Role FirebaseJson.setJsonData is to deserialize the JSON cord to JSON object.
In addition, function FirebaseJson.readFrom can be used to read the streaming JSON contents from WiFi/Ethernet Client, File and Harware Serial and serialize it as the streaming content contains valid JSON data.
Part FirebaseJson.add is used to add the new node with the contents e.g. String, Number (int and double), Boolean, Assortment and Object to the defined node.
Function FirebaseJson.set is used for edit, overwrite, create new (if not exist) node with contents e.g. String, Number (int and double), Boolean, Array and Object at the defined relative path and node.
Part FirebaseJson.get is used for parsing or deserializee the JSON object and array. The deserialized or parsed outcome will continue in FirebaseJsonData object which tin can be casted to any type of value or variable east.g string, bool, int, bladder, double by using FirebaseJsonData.to<type>.
The casting from FirebaseJsonData to FirebaseJson and FirebaseJsonArray objects is unlike, by using FirebaseJsonData.getJSON(FirebaseJson) and FirebaseJsonData.getArray(FirebaseJsonArray).
Function FirebaseJson.remove is used to remove the node and all its children's contents at the defined relative path and node.
Function FirebaseJson.toString is used for serializeing the JSON object to writable objects e.yard. char array, Arduino String, C/C++ string, WiFi/Ethernet Client and Hardware/Software Serial.
Office 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 Customer 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 alphabetize.
Office FirebaseJson.clear 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 cord.
Function FirebaseJsonArray.add is used for adding the new contents e.g. String, Number (int and double), Boolean, Assortment and Object to JSON array.
Role FirebaseJsonArray.set is for edit, overwrite, create new (if not exist) contents e.yard. String, Number (int and double), Boolean, Array and Object at the defined relative path or defined index of JSON assortment.
Office FirebaseJsonArray.get and FirebaseJsonArray.searchwork in the same way every bit FirebaseJson objects
Function FirebaseJsonArray.remove is used to remove the array'south contents at the defined relative path or divers index of JSON assortment.
Part FirebaseJsonArray.toString is used for serializeing the JSON array object to writable objects east.m. char assortment, Arduino String, C/C++ cord, WiFi/Ethernet Customer 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 go the http lawmaking response header while read the WiFi/Ethernet Customer using FirebaseJson.toString.
Function FirebaseJsonArray.clear is used to clear JSON assortment object contents.
Office FirebaseJsonArray.setFloatDigits is for float number precision when serialized to string.
Function FirebaseJsonArray.setDoubleDigits is for double number precision when serialized to string.
Come across examples/FirebaseJson for the usage.
For FirebaseJson function 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 together( "proper name" , "Living Room" ); // Add temp1 with value 120 and temp1 with forty to JSON object // Note: temp2 is non the child of temp1 as in previous version. json.add together( "temp1" , 120).add( "temp2" , 40); // Add nested child contents straight json.ready( "unit of measurement/temp1" , "Farenheit" ); json.fix( "unit of measurement/temp2" , "Celcius" ); // Deserialize to serial with prettify option json.toString(Serial, true); Serial.println(); Serial.println(); /** This is the result of the above code { "proper name": "Living Room", "temp1": 120, "temp2": 40, "unit": { "temp1": "Farenheit", "temp2": "Celcius" } } */ // To set array to the in a higher place JSON using FirebaseJson directly // Set (add) array indexes 0,1,two,5,vii under temp1, the original value will exist replaced with new 1. json.prepare( "temp1/[0]" , 47); json.set( "temp1/[one]" , 28); json.ready( "temp1/[2]" , 34); json.set( "temp1/[5]" , 23); // null will be created at array index 3,4 due to it's not withal assigned json.set( "temp1/[seven]" , 25); // nothing will exist created at array index 6 // Print out equally prettify cord json.toString(Serial, true); Serial.println(); Series.println(); /** The result of the in a higher place lawmaking { "name": "Living Room", "temp1": [ 47, 28, 34, nix, null, 23, null, 25 ], "temp2": 40, "unit": { "temp1": "Farenheit", "temp2": "Celcius" } } */ // Try to remove temp1 array at index one json.remove( "temp1/[1]" ); // Try to remove temp2 json.remove( "temp2" ); // Print out every bit prettify cord json.toString(Serial, true); Serial.println(); Serial.println(); /** The consequence of the to a higher place code { "name": "Living Room", "temp1": [ 47, 34, zip, cypher, 23, naught, 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 after FirebaseJsonData outcome; json.get(result, "unit/temp2" ); if (effect.success) { // Print type of parsed information e.g string, int, double, bool, object, assortment, null and undefined Serial.println(upshot.type); // Print its content due east.g.string, int, double, bool whereas object, array and cypher also can access every bit string Serial.println(consequence.to<String>()); // Serial.println(result.to<int>()); // Series.println(upshot.to<bool>()); // Serial.println(result.to<float>()); // Series.println(result.to<double>()); } // The in a higher place code will show /** cord Celcius */ // To get the assortment temp from FirebaseJson json.get(result, "temp1" ); // Prepare FirebaseJsonArray to take the array from FirebaseJson FirebaseJsonArray arr; // Go array information 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++) { // result at present used as temporary object to become the parse results arr.get(issue, i); // Impress its value Series.print( "Array index: " ); Serial.print(i); Serial.print( ", type: " ); Serial.print(result.type); Serial.print( ", value: " ); Serial.println(issue.to<String>()); } /** The result of above code Array index: 0, type: int, value: 47 Assortment index: 1, type: int, value: 34 Array index: 2, type: null, value: zip Array index: 3, blazon: nada, value: null Array index: 4, type: int, value: 23 Array index: v, type: null, value: null Array index: 6, type: int, value: 25 */
The post-obit case shows how to apply FirebaseJsonArray.
// Declare FirebaseJsonArray object (global or local) FirebaseJsonArray arr; // Add some data arr.add( "banana" ); arr.add together( "mango" ); arr.add( "coconut" ); // Change the array contents arr.set( "[1]/nutrient" , "salad" ); arr.ready( "[1]/sweet" , "cake" ); arr.ready( "[1]/appetizer" , "snack" ); arr.gear up( "[2]" , "apple" ); // or arr.prepare(2, "apple"); arr.set( "[iv]/[0]/[i]/amount" , 20); // Print out array as prettify string arr.toString(Serial, true); Serial.println(); Serial.println(); /** This is the result of the above code [ "banana", { "nutrient": "salad", "sweet": "cake", "appetizer": "snack" }, "apple tree", null, [ [ null, { "amount": 20 } ] ] ] */ // Remove array content at /four/0/1/amount arr.remove( "[4]/[0]/[1]/amount" ); // Print out as prettify string arr.toString(Serial, true); Serial.println(); Serial.println(); /** The event of the above code [ "banana", { "food": "salad", "sweet": "cake", "titbit": "snack" }, "apple", null, [ [ null ] ] ] */ // Now parse/read the assortment contents at some index FirebaseJsonData result; arr.get(issue, "[1]/food" ); if(result.success) { // Blazon of parsed data Serial.println(result.type); // Its value Serial.println(result.to<String>()); // Serial.println(result.to<int>()); // Series.println(result.to<bool>()); // Series.println(consequence.to<bladder>()); // Serial.println(effect.to<double>()); } // The higher up code will show /** string salad */ // To get the JSON object at array index 1 from FirebaseJsonArray arr.go(result, "[one]" ); // or arr.get(result, ane); // Set up FirebaseJson to take the JSON object from FirebaseJsonArray FirebaseJson json; // Become 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); Series.printf( "%d, Type: %s, Name: %s, Value: %s\north " , i, value.type == FirebaseJson::JSON_OBJECT ? "object" : "array" , value.fundamental.c_str(), value.value.c_str()); } // Clear all list to free memory json.iteratorEnd(); /** The result of the to a higher place lawmaking 0, Blazon: object, Key: food, Value: salad one, Type: object, Central: sweet, Value: cake 2, Blazon: object, Key: titbit, Value: snack */ License
The MIT License (MIT)
Copyright (C) 2022 One thousand. Suwatchai (Mobizt)
Permission is hereby granted, costless of charge, to whatsoever person returning a copy 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 permit persons to whom the Software is furnished to practice and so, subject to the post-obit weather condition:
The higher up copyright discover and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF Any KIND, EXPRESS OR Implied, INCLUDING Only NOT Limited TO THE WARRANTIES OF MERCHANTABILITY, Fettle FOR A Item PURPOSE AND NONINFRINGEMENT. IN NO Issue SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY Claim, 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 Utilize OR OTHER DEALINGS IN THE SOFTWARE.
Source: https://github.com/mobizt/Firebase-ESP8266
0 Response to "There Was an Unknown Error While Processing the Request Try Again Firebase"
Post a Comment