diff --git a/README.md b/README.md index e096744e..b80c4dd2 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.4390794.svg)](https://doi.org/10.5281/zenodo.4390794) -Google's Firebase Realtime Database Arduino Library for ESP8266 v 3.1.9 +Google's Firebase Realtime Database Arduino Library for ESP8266 v 3.1.12 This library supports ESP8266 MCU from Espressif. The following are platforms in which libraries are also available. @@ -221,7 +221,11 @@ See [Other authentication examples](/examples/Authentications) for more authenti Some authentication methods need the token generaion and exchanging process which take more time than using the legacy token. -The authentication with custom and OAuth2.0 tokens take the time in overall process included NTP time acquisition, JWT token generation and signing, more than 10 seconds in ESP8266 and 1 or 2 seconds in ESP32. +The authentication with custom and OAuth2.0 tokens takes the time, several seconds in overall process included NTP time acquisition, JWT token generation and signing. + +Set the system time prior to calling the Firebase.begin to skip the internal NTP time acquisition process. + +To set the system time with RTC or timestamp, use **`Firebase.setSystemTime`**. While using Email and password sign-in which use in the id token generation process takes minimum time. diff --git a/examples/Authentications/Access_Token_from_File/Access_Token_from_File.ino b/examples/Authentications/Access_Token_from_File/Access_Token_from_File.ino index 96b48601..edc81276 100644 --- a/examples/Authentications/Access_Token_from_File/Access_Token_from_File.ino +++ b/examples/Authentications/Access_Token_from_File/Access_Token_from_File.ino @@ -1,34 +1,47 @@ /** * Created by K. Suwatchai (Mobizt) - * + * * Email: k_suwatchai@hotmail.com - * + * * Github: https://github.com/mobizt - * + * * Copyright (c) 2021 mobizt * */ -/** This example will show how to authenticate as admin using +/** This example will show how to authenticate as admin using * the Service Account file to create the access token to sign in internally. - * - * The library will connect to NTP server to get the time (in case your device time was not set) + * + * The library will connect to NTP server to get the time (in case your device + * time was not set) * and waiting for the time to be ready. - * - * If the waiting is timed out and the system time is not ready, the custom and OAuth2.0 acces tokens generation will fail - * because of invalid expiration time in JWT token that used in the id/access token request. + * + * If the waiting is timed out and the system time is not ready, the custom and + * OAuth2.0 acces tokens generation will fail + * because of invalid expiration time in JWT token that used in the id/access + * token request. */ +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) #include #include +#endif + +//Provide the token generation process info. +#include "addons/TokenHelper.h" +//Provide the RTDB payload printing info and other helper functions. +#include "addons/RTDBHelper.h" /* 1. Define the WiFi credentials */ #define WIFI_SSID "WIFI_AP" #define WIFI_PASSWORD "WIFI_PASSWORD" -/* 2. Define the Firebase project host name (required) */ -#define FIREBASE_HOST "PROJECT_ID.firebaseio.com" +/* 2. If work with RTDB, define the RTDB URL */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app /* 3. Define the Firebase Data object */ FirebaseData fbdo; @@ -39,21 +52,6 @@ FirebaseAuth auth; /* 5. Define the FirebaseConfig data for config data */ FirebaseConfig config; -/* The calback function to print the token generation status */ -void tokenStatusCallback(TokenInfo info); - -/* The function to print the operating results */ -void printResult(FirebaseData &data); - -/* The helper function to get the token status string */ -String getTokenStatus(struct token_info_t info); - -/* The helper function to get the token type string */ -String getTokenType(struct token_info_t info); - -/* The helper function to get the token error string */ -String getTokenError(struct token_info_t info); - String path = "/Test"; unsigned long dataMillis = 0; int count = 0; @@ -61,45 +59,61 @@ int count = 0; void setup() { - Serial.begin(115200); + Serial.begin(115200); - WiFi.begin(WIFI_SSID, WIFI_PASSWORD); - Serial.print("Connecting to Wi-Fi"); - while (WiFi.status() != WL_CONNECTED) - { - Serial.print("."); - delay(300); - } - Serial.println(); - Serial.print("Connected with IP: "); - Serial.println(WiFi.localIP()); - Serial.println(); + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + Serial.print("Connecting to Wi-Fi"); + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Assign the certificate file (optional) */ + config.cert.file = "/gsr2.pem"; + config.cert.file_storage = StorageType::FLASH; //or StorageType::SD - /* Assign the certificate file (optional) */ - config.cert.file = "/gsr2.pem"; - config.cert.file_storage = StorageType::FLASH; //Don't assign number, use struct instead + /* The file systems for flash and SD/SDMMC can be changed in FirebaseFS.h. */ - /* Assign the project host (required) */ - config.host = FIREBASE_HOST; + /* Assign the sevice account JSON file and the file storage type (required) */ + config.service_account.json.path = "/service_account_file.json"; //change this for your json file + config.service_account.json.storage_type = StorageType::FLASH; //or StorageType::SD - /* Assign the sevice account JSON file and the file storage type (required) */ - config.service_account.json.path = "/service_account_file.json"; //change this for your json file - config.service_account.json.storage_type = StorageType::FLASH; //Don't assign number, use struct instead + /** The user UID set to empty to sign in as admin */ + auth.token.uid = ""; - /** The user UID set to empty to sign in as admin */ - auth.token.uid = ""; + /* Assign the RTDB URL */ + config.database_url = DATABASE_URL; - Firebase.reconnectWiFi(true); + /** The scope of the OAuth2.0 authentication + * If you wan't this access token for others Google Cloud Services. + */ + //config.signer.tokens.scope = "Google Scope 1 Url, Google Scope 2 Url,.."; - /** Assign the callback function for the long running token generation task */ - config.token_status_callback = tokenStatusCallback; + Firebase.reconnectWiFi(true); - /** Assign the maximum retry of token generation */ - config.max_token_generation_retry = 5; + /* Assign the callback function for the long running token generation task */ + config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h - /* Now we start to signin using access token */ + /** Assign the maximum retry of token generation */ + config.max_token_generation_retry = 5; - /** Initialize the library with the Firebase authen and config. + /** To set system time with the timestamp from RTC + * The internal NTP server time acquisition + * of token generation process will be skipped, + * if the system time is already set. + * + * sec is the seconds from midnight Jan 1, 1970 + */ + //Firebase.setSystemTime(sec); + + /* Now we start to signin using access token */ + + /** Initialize the library with the Firebase authen and config. * * The device time will be set by sending request to the NTP server * befor token generation and exchanging. @@ -108,262 +122,42 @@ void setup() * * Theses process may take time to complete. */ - Firebase.begin(&config, &auth); + Firebase.begin(&config, &auth); - /* The access token (C++ string) can be accessed from config.signer.tokens.access_token. */ + /* The access token (C++ string) can be accessed from config.signer.tokens.access_token. */ } void loop() { - if (millis() - dataMillis > 5000) - { - dataMillis = millis(); - - /* Get the token status */ - TokenInfo info = Firebase.authTokenInfo(); - if (info.status == token_status_ready) - { - Serial.println("------------------------------------"); - Serial.println("Set int test..."); - - if (Firebase.set(fbdo, path + "/int", count++)) - { - Serial.println("PASSED"); - Serial.println("PATH: " + fbdo.dataPath()); - Serial.println("TYPE: " + fbdo.dataType()); - Serial.println("ETag: " + fbdo.ETag()); - Serial.print("VALUE: "); - printResult(fbdo); - Serial.println("------------------------------------"); - Serial.println(); - } - else - { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); - Serial.println("------------------------------------"); - Serial.println(); - } - } - } -} - -void tokenStatusCallback(TokenInfo info) -{ - /** fb_esp_auth_token_status enum - * token_status_uninitialized, - * token_status_on_initialize, - * token_status_on_signing, - * token_status_on_request, - * token_status_on_refresh, - * token_status_ready, - * token_status_error - */ - if (info.status == token_status_error) - { - Serial.printf("Token info: type = %s, status = %s\n", getTokenType(info).c_str(), getTokenStatus(info).c_str()); - Serial.printf("Token error: %s\n", getTokenError(info).c_str()); - } - else - { - Serial.printf("Token info: type = %s, status = %s\n", getTokenType(info).c_str(), getTokenStatus(info).c_str()); - } -} - -void printResult(FirebaseData &data) -{ + if (millis() - dataMillis > 5000) + { + dataMillis = millis(); - if (data.dataType() == "int") - Serial.println(data.intData()); - else if (data.dataType() == "float") - Serial.println(data.floatData(), 5); - else if (data.dataType() == "double") - printf("%.9lf\n", data.doubleData()); - else if (data.dataType() == "boolean") - Serial.println(data.boolData() == 1 ? "true" : "false"); - else if (data.dataType() == "string") - Serial.println(data.stringData()); - else if (data.dataType() == "json") + if (Firebase.ready()) { + Serial.println("------------------------------------"); + Serial.println("Set int test..."); + + String node = path + "/int"; + + if (Firebase.set(fbdo, node.c_str(), count++)) + { + Serial.println("PASSED"); + Serial.println("PATH: " + fbdo.dataPath()); + Serial.println("TYPE: " + fbdo.dataType()); + Serial.println("ETag: " + fbdo.ETag()); + Serial.print("VALUE: "); + printResult(fbdo); //see addons/RTDBHelper.h + Serial.println("------------------------------------"); Serial.println(); - FirebaseJson &json = data.jsonObject(); - //Print all object data - Serial.println("Pretty printed JSON data:"); - String jsonStr; - json.toString(jsonStr, true); - Serial.println(jsonStr); - Serial.println(); - Serial.println("Iterate JSON data:"); + } + else + { + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + Serial.println("------------------------------------"); Serial.println(); - size_t len = json.iteratorBegin(); - String key, value = ""; - int type = 0; - for (size_t i = 0; i < len; i++) - { - json.iteratorGet(i, type, key, value); - Serial.print(i); - Serial.print(", "); - Serial.print("Type: "); - Serial.print(type == FirebaseJson::JSON_OBJECT ? "object" : "array"); - if (type == FirebaseJson::JSON_OBJECT) - { - Serial.print(", Key: "); - Serial.print(key); - } - Serial.print(", Value: "); - Serial.println(value); - } - json.iteratorEnd(); + } } - else if (data.dataType() == "array") - { - Serial.println(); - //get array data from FirebaseData using FirebaseJsonArray object - FirebaseJsonArray &arr = data.jsonArray(); - //Print all array values - Serial.println("Pretty printed Array:"); - String arrStr; - arr.toString(arrStr, true); - Serial.println(arrStr); - Serial.println(); - Serial.println("Iterate array values:"); - Serial.println(); - for (size_t i = 0; i < arr.size(); i++) - { - Serial.print(i); - Serial.print(", Value: "); - - FirebaseJsonData &jsonData = data.jsonData(); - //Get the result data from FirebaseJsonArray object - arr.get(jsonData, i); - if (jsonData.typeNum == FirebaseJson::JSON_BOOL) - Serial.println(jsonData.boolValue ? "true" : "false"); - else if (jsonData.typeNum == FirebaseJson::JSON_INT) - Serial.println(jsonData.intValue); - else if (jsonData.typeNum == FirebaseJson::JSON_FLOAT) - Serial.println(jsonData.floatValue); - else if (jsonData.typeNum == FirebaseJson::JSON_DOUBLE) - printf("%.9lf\n", jsonData.doubleValue); - else if (jsonData.typeNum == FirebaseJson::JSON_STRING || - jsonData.typeNum == FirebaseJson::JSON_NULL || - jsonData.typeNum == FirebaseJson::JSON_OBJECT || - jsonData.typeNum == FirebaseJson::JSON_ARRAY) - Serial.println(jsonData.stringValue); - } - } - else if (data.dataType() == "blob") - { - - Serial.println(); - - for (size_t i = 0; i < data.blobData().size(); i++) - { - if (i > 0 && i % 16 == 0) - Serial.println(); - - if (i < 16) - Serial.print("0"); - - Serial.print(data.blobData()[i], HEX); - Serial.print(" "); - } - Serial.println(); - } - else if (data.dataType() == "file") - { - - Serial.println(); - - File file = data.fileStream(); - int i = 0; - - while (file.available()) - { - if (i > 0 && i % 16 == 0) - Serial.println(); - - int v = file.read(); - - if (v < 16) - Serial.print("0"); - - Serial.print(v, HEX); - Serial.print(" "); - i++; - } - Serial.println(); - file.close(); - } - else - { - Serial.println(data.payload()); - } -} - -/* The helper function to get the token type string */ -String getTokenType(struct token_info_t info) -{ - switch (info.type) - { - case token_type_undefined: - return "undefined"; - - case token_type_legacy_token: - return "legacy token"; - - case token_type_id_token: - return "id token"; - - case token_type_custom_token: - return "custom token"; - - case token_type_oauth2_access_token: - return "OAuth2.0 access token"; - - default: - break; - } - return "undefined"; -} - -/* The helper function to get the token status string */ -String getTokenStatus(struct token_info_t info) -{ - switch (info.status) - { - case token_status_uninitialized: - return "uninitialized"; - - case token_status_on_initialize: - return "on initializing"; - - case token_status_on_signing: - return "on signing"; - - case token_status_on_request: - return "on request"; - - case token_status_on_refresh: - return "on refreshing"; - - case token_status_ready: - return "ready"; - - case token_status_error: - return "error"; - - default: - break; - } - return "uninitialized"; -} - -/* The helper function to get the token error string */ -String getTokenError(struct token_info_t info) -{ - String s = "code: "; - s += String(info.error.code); - s += ", message: "; - s += info.error.message.c_str(); - return s; -} + } +} \ No newline at end of file diff --git a/examples/Authentications/Anonymous_Signin/Anonymous_Signin.ino b/examples/Authentications/Anonymous_Signin/Anonymous_Signin.ino index 7d898c40..e8171def 100644 --- a/examples/Authentications/Anonymous_Signin/Anonymous_Signin.ino +++ b/examples/Authentications/Anonymous_Signin/Anonymous_Signin.ino @@ -20,17 +20,24 @@ * different UID every time you run this example. */ +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) #include #include +#endif + +//Provide the token generation process info. +#include "addons/TokenHelper.h" +//Provide the RTDB payload printing info and other helper functions. +#include "addons/RTDBHelper.h" /* 1. Define the WiFi credentials */ #define WIFI_SSID "WIFI_AP" #define WIFI_PASSWORD "WIFI_PASSWORD" -/* 2. Define the Firebase project host name (required) */ -#define FIREBASE_HOST "PROJECT_ID.firebaseio.com" - -/** 3. Define the API key +/** 2. Define the API key * * The API key can be obtained since you created the project and set up * the Authentication in Firebase console. @@ -40,7 +47,10 @@ * The API key also available by click at the link APPLICATION SETUP DETAILS. * */ -#define API_KEY "WEB_API_KEY" +#define API_KEY "API_KEY" + +/* 3. If work with RTDB, define the RTDB URL */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app /* 4. Define the Firebase Data object */ FirebaseData fbdo; @@ -51,18 +61,6 @@ FirebaseAuth auth; /* 6. Define the FirebaseConfig data for config data */ FirebaseConfig config; -/* The function to print the operating results */ -void printResult(FirebaseData &data); - -/* The helper function to get the token status string */ -String getTokenStatus(struct token_info_t info); - -/* The helper function to get the token type string */ -String getTokenType(struct token_info_t info); - -/* The helper function to get the token error string */ -String getTokenError(struct token_info_t info); - String path = ""; unsigned long dataMillis = 0; int count = 0; @@ -85,10 +83,12 @@ void setup() Serial.println(WiFi.localIP()); Serial.println(); - /* Assign the project host and API key (required) */ - config.host = FIREBASE_HOST; + /* Assign the API key (required) */ config.api_key = API_KEY; + /* Assign the RTDB URL */ + config.database_url = DATABASE_URL; + Firebase.reconnectWiFi(true); Serial.println("------------------------------------"); @@ -123,6 +123,9 @@ void setup() Serial.printf("Failed, %s\n", config.signer.signupError.message.c_str()); } + /* Assign the callback function for the long running token generation task */ + config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h + /** The id token (C++ string) will be available from config.signer.tokens.id_token * if the sig-up was successful. * @@ -136,34 +139,23 @@ void setup() void loop() { - if (millis() - dataMillis > 5000 && signupOK) + if (millis() - dataMillis > 5000 && signupOK && Firebase.ready()) { dataMillis = millis(); - /* Get the token status */ - struct token_info_t info = Firebase.authTokenInfo(); - Serial.println("------------------------------------"); - if (info.status == token_status_error) - { - Serial.printf("Token info: type = %s, status = %s\n", getTokenType(info).c_str(), getTokenStatus(info).c_str()); - Serial.printf("Token error: %s\n\n", getTokenError(info).c_str()); - } - else - { - Serial.printf("Token info: type = %s, status = %s\n\n", getTokenType(info).c_str(), getTokenStatus(info).c_str()); - } - Serial.println("------------------------------------"); Serial.println("Set int test..."); - if (Firebase.set(fbdo, path + "/int", count++)) + String node = path + "/int"; + + if (Firebase.set(fbdo, node.c_str(), count++)) { Serial.println("PASSED"); Serial.println("PATH: " + fbdo.dataPath()); Serial.println("TYPE: " + fbdo.dataType()); Serial.println("ETag: " + fbdo.ETag()); Serial.print("VALUE: "); - printResult(fbdo); + printResult(fbdo); //see addons/RTDBHelper.h Serial.println("------------------------------------"); Serial.println(); } @@ -176,198 +168,3 @@ void loop() } } } - -void printResult(FirebaseData &data) -{ - - if (data.dataType() == "int") - Serial.println(data.intData()); - else if (data.dataType() == "float") - Serial.println(data.floatData(), 5); - else if (data.dataType() == "double") - printf("%.9lf\n", data.doubleData()); - else if (data.dataType() == "boolean") - Serial.println(data.boolData() == 1 ? "true" : "false"); - else if (data.dataType() == "string") - Serial.println(data.stringData()); - else if (data.dataType() == "json") - { - Serial.println(); - FirebaseJson &json = data.jsonObject(); - //Print all object data - Serial.println("Pretty printed JSON data:"); - String jsonStr; - json.toString(jsonStr, true); - Serial.println(jsonStr); - Serial.println(); - Serial.println("Iterate JSON data:"); - Serial.println(); - size_t len = json.iteratorBegin(); - String key, value = ""; - int type = 0; - for (size_t i = 0; i < len; i++) - { - json.iteratorGet(i, type, key, value); - Serial.print(i); - Serial.print(", "); - Serial.print("Type: "); - Serial.print(type == FirebaseJson::JSON_OBJECT ? "object" : "array"); - if (type == FirebaseJson::JSON_OBJECT) - { - Serial.print(", Key: "); - Serial.print(key); - } - Serial.print(", Value: "); - Serial.println(value); - } - json.iteratorEnd(); - } - else if (data.dataType() == "array") - { - Serial.println(); - //get array data from FirebaseData using FirebaseJsonArray object - FirebaseJsonArray &arr = data.jsonArray(); - //Print all array values - Serial.println("Pretty printed Array:"); - String arrStr; - arr.toString(arrStr, true); - Serial.println(arrStr); - Serial.println(); - Serial.println("Iterate array values:"); - Serial.println(); - for (size_t i = 0; i < arr.size(); i++) - { - Serial.print(i); - Serial.print(", Value: "); - - FirebaseJsonData &jsonData = data.jsonData(); - //Get the result data from FirebaseJsonArray object - arr.get(jsonData, i); - if (jsonData.typeNum == FirebaseJson::JSON_BOOL) - Serial.println(jsonData.boolValue ? "true" : "false"); - else if (jsonData.typeNum == FirebaseJson::JSON_INT) - Serial.println(jsonData.intValue); - else if (jsonData.typeNum == FirebaseJson::JSON_FLOAT) - Serial.println(jsonData.floatValue); - else if (jsonData.typeNum == FirebaseJson::JSON_DOUBLE) - printf("%.9lf\n", jsonData.doubleValue); - else if (jsonData.typeNum == FirebaseJson::JSON_STRING || - jsonData.typeNum == FirebaseJson::JSON_NULL || - jsonData.typeNum == FirebaseJson::JSON_OBJECT || - jsonData.typeNum == FirebaseJson::JSON_ARRAY) - Serial.println(jsonData.stringValue); - } - } - else if (data.dataType() == "blob") - { - - Serial.println(); - - for (size_t i = 0; i < data.blobData().size(); i++) - { - if (i > 0 && i % 16 == 0) - Serial.println(); - - if (i < 16) - Serial.print("0"); - - Serial.print(data.blobData()[i], HEX); - Serial.print(" "); - } - Serial.println(); - } - else if (data.dataType() == "file") - { - - Serial.println(); - - File file = data.fileStream(); - int i = 0; - - while (file.available()) - { - if (i > 0 && i % 16 == 0) - Serial.println(); - - int v = file.read(); - - if (v < 16) - Serial.print("0"); - - Serial.print(v, HEX); - Serial.print(" "); - i++; - } - Serial.println(); - file.close(); - } - else - { - Serial.println(data.payload()); - } -} - -/* The helper function to get the token type string */ -String getTokenType(struct token_info_t info) -{ - switch (info.type) - { - case token_type_undefined: - return "undefined"; - - case token_type_legacy_token: - return "legacy token"; - - case token_type_id_token: - return "id token"; - - case token_type_custom_token: - return "custom token"; - - case token_type_oauth2_access_token: - return "OAuth2.0 access token"; - - default: - break; - } - return "undefined"; -} - -/* The helper function to get the token status string */ -String getTokenStatus(struct token_info_t info) -{ - switch (info.status) - { - case token_status_uninitialized: - return "uninitialized"; - - case token_status_on_signing: - return "on signing"; - - case token_status_on_request: - return "on request"; - - case token_status_on_refresh: - return "on refreshing"; - - case token_status_ready: - return "ready"; - - case token_status_error: - return "error"; - - default: - break; - } - return "uninitialized"; -} - -/* The helper function to get the token error string */ -String getTokenError(struct token_info_t info) -{ - String s = "code: "; - s += String(info.error.code); - s += ", message: "; - s += info.error.message.c_str(); - return s; -} diff --git a/examples/Authentications/Custom_Token/Custom_Token.ino b/examples/Authentications/Custom_Token/Custom_Token.ino index 55342343..094ad8c2 100644 --- a/examples/Authentications/Custom_Token/Custom_Token.ino +++ b/examples/Authentications/Custom_Token/Custom_Token.ino @@ -22,17 +22,24 @@ * guard the unauthorized access with the uid and custom claims assigned in the token. */ +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) #include #include +#endif + +//Provide the token generation process info. +#include "addons/TokenHelper.h" +//Provide the RTDB payload printing info and other helper functions. +#include "addons/RTDBHelper.h" /* 1. Define the WiFi credentials */ #define WIFI_SSID "WIFI_AP" #define WIFI_PASSWORD "WIFI_PASSWORD" -/* 2. Define the Firebase project host name (required) */ -#define FIREBASE_HOST "PROJECT_ID.firebaseio.com" - -/** 3. Define the API key +/** 2. Define the API key * * The API key can be obtained since you created the project and set up * the Authentication in Firebase console. @@ -42,7 +49,7 @@ * The API key also available by click at the link APPLICATION SETUP DETAILS. * */ -#define API_KEY "WEB_API_KEY" +#define API_KEY "API_KEY" /** 3. Define the Service Account credentials (required for token generation) * @@ -55,6 +62,9 @@ #define FIREBASE_CLIENT_EMAIL "CLIENT_EMAIL" const char PRIVATE_KEY[] PROGMEM = "-----BEGIN PRIVATE KEY-----XXXXXXXXXXXX-----END PRIVATE KEY-----\n"; +/* 4. If work with RTDB, define the RTDB URL */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app + /* This is Google root CA certificate */ /* const char rootCACert[] PROGMEM = "-----BEGIN CERTIFICATE-----\n" @@ -87,7 +97,7 @@ const char rootCACert[] PROGMEM = "-----BEGIN CERTIFICATE-----\n" * * If you edit the database rules yourself, this is not required. */ -#define FIREBASE_AUTH "DATABASE_SECRET" +#define DATABASE_SECRET "DATABASE_SECRET" /* 5. Define the Firebase Data object */ FirebaseData fbdo; @@ -98,24 +108,6 @@ FirebaseAuth auth; /* 7. Define the FirebaseConfig data for config data */ FirebaseConfig config; -/* The calback function to print the token generation status */ -void tokenStatusCallback(TokenInfo info); - -/* The helper function to modify the database rules (optional) */ -void prepareDatabaseRules(const char *path, const char *var, const char *readVal, const char *writeVal); - -/* The function to print the operating results */ -void printResult(FirebaseData &data); - -/* The helper function to get the token status string */ -String getTokenStatus(struct token_info_t info); - -/* The helper function to get the token type string */ -String getTokenType(struct token_info_t info); - -/* The helper function to get the token error string */ -String getTokenError(struct token_info_t info); - String path = ""; unsigned long dataMillis = 0; int count = 0; @@ -140,8 +132,7 @@ void setup() /* Assign the certificate data (optional) */ //config.cert.data = rootCACert; - /* Assign the project host and api key (required) */ - config.host = FIREBASE_HOST; + /* Assign the api key (required) */ config.api_key = API_KEY; /* Assign the sevice account credentials and private key (required) */ @@ -170,21 +161,40 @@ void setup() auth.token.claims.add("premium_account", true); auth.token.claims.add("admin", true); + /* Assign the RTDB URL */ + config.database_url = DATABASE_URL; + Firebase.reconnectWiFi(true); fbdo.setResponseSize(4096); /* path for user data is now "/UsersData/Node1" */ String base_path = "/UsersData/"; + /* Assign the callback function for the long running token generation task */ + config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h + + /** Assign the maximum retry of token generation */ + config.max_token_generation_retry = 5; + + /* Now we start to signin using custom token */ + + /** Initialize the library with the Firebase authen and config. + * + * The device time will be set by sending request to the NTP server + * befor token generation and exchanging. + * + * The signed RSA256 jwt token will be created and used for id token exchanging. + * + * Theses process may take time to complete. + */ + Firebase.begin(&config, &auth); + /** Now modify the database rules (if not yet modified) * * The user, Node1 in this case will be granted to read and write * at the curtain location i.e. "/UsersData/Node1" and we will also check the * custom claims in the rules which must be matched. * - * To modify the database rules in this exanple, we need the full access rights then - * using the database secret in prepareDatabaseRules function to sign in. - * * If you database rules has been modified, please comment this code out. * * The character $ is to make a wildcard variable (can be any name) represents any node key @@ -198,26 +208,7 @@ void setup() */ String var = "$userId"; String val = "($userId === auth.uid && auth.token.premium_account === true && auth.token.admin === true)"; - prepareDatabaseRules(base_path.c_str(), var.c_str(), val.c_str(), val.c_str()); - - /** Assign the callback function for the long running token generation task */ - config.token_status_callback = tokenStatusCallback; - - /** Assign the maximum retry of token generation */ - config.max_token_generation_retry = 5; - - /* Now we start to signin using custom token */ - - /** Initialize the library with the Firebase authen and config. - * - * The device time will be set by sending request to the NTP server - * befor token generation and exchanging. - * - * The signed RSA256 jwt token will be created and used for id token exchanging. - * - * Theses process may take time to complete. - */ - Firebase.begin(&config, &auth); + Firebase.setReadWriteRules(fbdo, base_path.c_str(), var.c_str(), val.c_str(), val.c_str(), DATABASE_SECRET); /** * The custom token which created internally in this library will use @@ -236,324 +227,32 @@ void setup() void loop() { - if (millis() - dataMillis > 5000) + if (millis() - dataMillis > 5000 && Firebase.ready()) { dataMillis = millis(); - /* Get the token status */ - TokenInfo info = Firebase.authTokenInfo(); - if (info.status == token_status_ready) - { - Serial.println("------------------------------------"); - Serial.println("Set int test..."); - - if (Firebase.set(fbdo, path + "/int", count++)) - { - Serial.println("PASSED"); - Serial.println("PATH: " + fbdo.dataPath()); - Serial.println("TYPE: " + fbdo.dataType()); - Serial.println("ETag: " + fbdo.ETag()); - Serial.print("VALUE: "); - printResult(fbdo); - Serial.println("------------------------------------"); - Serial.println(); - } - else - { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); - Serial.println("------------------------------------"); - Serial.println(); - } - } - - } -} - -void tokenStatusCallback(TokenInfo info) -{ - /** fb_esp_auth_token_status enum - * token_status_uninitialized, - * token_status_on_initialize, - * token_status_on_signing, - * token_status_on_request, - * token_status_on_refresh, - * token_status_ready, - * token_status_error - */ - if (info.status == token_status_error) - { - Serial.printf("Token info: type = %s, status = %s\n", getTokenType(info).c_str(), getTokenStatus(info).c_str()); - Serial.printf("Token error: %s\n", getTokenError(info).c_str()); - } - else - { - Serial.printf("Token info: type = %s, status = %s\n", getTokenType(info).c_str(), getTokenStatus(info).c_str()); - } -} - -/* The helper function to modify the database rules (optional) */ -void prepareDatabaseRules(const char *path, const char *var, const char *readVal, const char *writeVal) -{ - //We will sign in using legacy token (database secret) for full RTDB access - Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH); - - Serial.println("------------------------------------"); - Serial.println("Read database ruless..."); - if (Firebase.getRules(fbdo)) - { - FirebaseJsonData result; - FirebaseJson &json = fbdo.jsonObject(); - bool rd = false, wr = false; - - String _path = "rules"; - if (path[0] != '/') - _path += "/"; - _path += path; - _path += "/"; - _path += var; - - if (strlen(readVal) > 0) - { - rd = true; - json.get(result, _path + "/.read"); - if (result.success) - if (strcmp(result.stringValue.c_str(), readVal) == 0) - rd = false; - } - - if (strlen(writeVal) > 0) - { - wr = true; - json.get(result, _path + "/.write"); - if (result.success) - if (strcmp(result.stringValue.c_str(), writeVal) == 0) - wr = false; - } - - //modify if the rules changed or does not exist. - if (wr || rd) - { - FirebaseJson js; - std::string s; - if (rd) - js.add(".read", readVal); - - if (wr) - js.add(".write", writeVal); - - Serial.println("Set database rules..."); - json.set(_path, js); - String rules = ""; - json.toString(rules, true); - if (!Firebase.setRules(fbdo, rules)) - { - Serial.println("Failed to edit the database rules, " + fbdo.errorReason()); - } - } - - json.clear(); - } - else - { - Serial.println("Failed to read the database rules, " + fbdo.errorReason()); - } -} - -void printResult(FirebaseData &data) -{ - - if (data.dataType() == "int") - Serial.println(data.intData()); - else if (data.dataType() == "float") - Serial.println(data.floatData(), 5); - else if (data.dataType() == "double") - printf("%.9lf\n", data.doubleData()); - else if (data.dataType() == "boolean") - Serial.println(data.boolData() == 1 ? "true" : "false"); - else if (data.dataType() == "string") - Serial.println(data.stringData()); - else if (data.dataType() == "json") - { - Serial.println(); - FirebaseJson &json = data.jsonObject(); - //Print all object data - Serial.println("Pretty printed JSON data:"); - String jsonStr; - json.toString(jsonStr, true); - Serial.println(jsonStr); - Serial.println(); - Serial.println("Iterate JSON data:"); - Serial.println(); - size_t len = json.iteratorBegin(); - String key, value = ""; - int type = 0; - for (size_t i = 0; i < len; i++) - { - json.iteratorGet(i, type, key, value); - Serial.print(i); - Serial.print(", "); - Serial.print("Type: "); - Serial.print(type == FirebaseJson::JSON_OBJECT ? "object" : "array"); - if (type == FirebaseJson::JSON_OBJECT) - { - Serial.print(", Key: "); - Serial.print(key); - } - Serial.print(", Value: "); - Serial.println(value); - } - json.iteratorEnd(); - } - else if (data.dataType() == "array") - { - Serial.println(); - //get array data from FirebaseData using FirebaseJsonArray object - FirebaseJsonArray &arr = data.jsonArray(); - //Print all array values - Serial.println("Pretty printed Array:"); - String arrStr; - arr.toString(arrStr, true); - Serial.println(arrStr); - Serial.println(); - Serial.println("Iterate array values:"); - Serial.println(); - for (size_t i = 0; i < arr.size(); i++) - { - Serial.print(i); - Serial.print(", Value: "); - - FirebaseJsonData &jsonData = data.jsonData(); - //Get the result data from FirebaseJsonArray object - arr.get(jsonData, i); - if (jsonData.typeNum == FirebaseJson::JSON_BOOL) - Serial.println(jsonData.boolValue ? "true" : "false"); - else if (jsonData.typeNum == FirebaseJson::JSON_INT) - Serial.println(jsonData.intValue); - else if (jsonData.typeNum == FirebaseJson::JSON_FLOAT) - Serial.println(jsonData.floatValue); - else if (jsonData.typeNum == FirebaseJson::JSON_DOUBLE) - printf("%.9lf\n", jsonData.doubleValue); - else if (jsonData.typeNum == FirebaseJson::JSON_STRING || - jsonData.typeNum == FirebaseJson::JSON_NULL || - jsonData.typeNum == FirebaseJson::JSON_OBJECT || - jsonData.typeNum == FirebaseJson::JSON_ARRAY) - Serial.println(jsonData.stringValue); - } - } - else if (data.dataType() == "blob") - { + Serial.println("------------------------------------"); + Serial.println("Set int test..."); - Serial.println(); + String node = path + "/int"; - for (size_t i = 0; i < data.blobData().size(); i++) + if (Firebase.set(fbdo, node.c_str(), count++)) { - if (i > 0 && i % 16 == 0) - Serial.println(); - - if (i < 16) - Serial.print("0"); - - Serial.print(data.blobData()[i], HEX); - Serial.print(" "); + Serial.println("PASSED"); + Serial.println("PATH: " + fbdo.dataPath()); + Serial.println("TYPE: " + fbdo.dataType()); + Serial.println("ETag: " + fbdo.ETag()); + Serial.print("VALUE: "); + printResult(fbdo); //see addons/RTDBHelper.h + Serial.println("------------------------------------"); + Serial.println(); } - Serial.println(); - } - else if (data.dataType() == "file") - { - - Serial.println(); - - File file = data.fileStream(); - int i = 0; - - while (file.available()) + else { - if (i > 0 && i % 16 == 0) - Serial.println(); - - int v = file.read(); - - if (v < 16) - Serial.print("0"); - - Serial.print(v, HEX); - Serial.print(" "); - i++; + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + Serial.println("------------------------------------"); + Serial.println(); } - Serial.println(); - file.close(); - } - else - { - Serial.println(data.payload()); - } -} - -/* The helper function to get the token type string */ -String getTokenType(struct token_info_t info) -{ - switch (info.type) - { - case token_type_undefined: - return "undefined"; - - case token_type_legacy_token: - return "legacy token"; - - case token_type_id_token: - return "id token"; - - case token_type_custom_token: - return "custom token"; - - case token_type_oauth2_access_token: - return "OAuth2.0 access token"; - - default: - break; } - return "undefined"; -} - -/* The helper function to get the token status string */ -String getTokenStatus(struct token_info_t info) -{ - switch (info.status) - { - case token_status_uninitialized: - return "uninitialized"; - - case token_status_on_initialize: - return "on initializing"; - - case token_status_on_signing: - return "on signing"; - - case token_status_on_request: - return "on request"; - - case token_status_on_refresh: - return "on refreshing"; - - case token_status_ready: - return "ready"; - - case token_status_error: - return "error"; - - default: - break; - } - return "uninitialized"; -} - -/* The helper function to get the token error string */ -String getTokenError(struct token_info_t info) -{ - String s = "code: "; - s += String(info.error.code); - s += ", message: "; - s += info.error.message.c_str(); - return s; -} +} \ No newline at end of file diff --git a/examples/Authentications/Custom_Token_from_File/Custom_Token_from_File.ino b/examples/Authentications/Custom_Token_from_File/Custom_Token_from_File.ino index cf3098ab..8eba5d16 100644 --- a/examples/Authentications/Custom_Token_from_File/Custom_Token_from_File.ino +++ b/examples/Authentications/Custom_Token_from_File/Custom_Token_from_File.ino @@ -22,17 +22,24 @@ * guard the unauthorized access with the uid and custom claims assigned in the token. */ +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) #include #include +#endif + +//Provide the token generation process info. +#include "addons/TokenHelper.h" +//Provide the RTDB payload printing info and other helper functions. +#include "addons/RTDBHelper.h" /* 1. Define the WiFi credentials */ #define WIFI_SSID "WIFI_AP" #define WIFI_PASSWORD "WIFI_PASSWORD" -/* 2. Define the Firebase project host name (required) */ -#define FIREBASE_HOST "PROJECT_ID.firebaseio.com" - -/** 3. Define the API key +/** 2. Define the API key * * The API key can be obtained since you created the project and set up * the Authentication in Firebase console. @@ -41,14 +48,11 @@ * Select your project, click at ENABLE IDENTITY PLATFORM button. * The API key also available by click at the link APPLICATION SETUP DETAILS. * - * The library will connect to NTP server to get the time (in case your device time was not set) - * and waiting for the time to be ready. - * - * If the waiting is timed out and the system time is not ready, the custom and OAuth2.0 acces tokens generation will fail - * because of invalid expiration time in JWT token that used in the id/access token request. - * */ -#define API_KEY "WEB_API_KEY" +#define API_KEY "API_KEY" + +/* 3. If work with RTDB, define the RTDB URL */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app /** 4. Define the database secret (optional) * @@ -57,7 +61,7 @@ * * If you edit the database rules manually, this legacy database secret is not required. */ -#define FIREBASE_AUTH "DATABASE_SECRET" +#define DATABASE_SECRET "DATABASE_SECRET" /* 5. Define the Firebase Data object */ FirebaseData fbdo; @@ -68,24 +72,6 @@ FirebaseAuth auth; /* 7. Define the FirebaseConfig data for config data */ FirebaseConfig config; -/* The calback function to print the token generation status */ -void tokenStatusCallback(TokenInfo info); - -/* The helper function to modify the database rules (optional) */ -void prepareDatabaseRules(const char *path, const char *var, const char *readVal, const char *writeVal); - -/* The function to print the operating results */ -void printResult(FirebaseData &data); - -/* The helper function to get the token status string */ -String getTokenStatus(struct token_info_t info); - -/* The helper function to get the token type string */ -String getTokenType(struct token_info_t info); - -/* The helper function to get the token error string */ -String getTokenError(struct token_info_t info); - String path = ""; unsigned long dataMillis = 0; int count = 0; @@ -108,16 +94,17 @@ void setup() Serial.println(); /* Assign the certificate file (optional) */ - //config.cert.file = "/gsr2.pem"; - //config.cert.file_storage = StorageType::FLASH;//Don't assign number, use struct instead + //config.cert.file = "/cert.cer"; + //config.cert.file_storage = mem_storage_type_flash; - /* Assign the project host and api key (required) */ - config.host = FIREBASE_HOST; + /* Assign the api key (required) */ config.api_key = API_KEY; + /* The file systems for flash and SD/SDMMC can be changed in FirebaseFS.h. */ + /* Assign the sevice account JSON file and the file storage type (required) */ - config.service_account.json.path = "/service_account_file.json"; //change this for your json file - config.service_account.json.storage_type = StorageType::FLASH; //Don't assign number, use struct instead + config.service_account.json.path = "/service_account_file.json"; //change this for your json file + config.service_account.json.storage_type = StorageType::FLASH; //or StorageType::SD /** Assign the unique user ID (uid) (required) * This uid will be compare to the auth.uid variable in the database rules. @@ -133,6 +120,9 @@ void setup() */ auth.token.uid = "Node1"; + /* Assign the RTDB URL */ + config.database_url = DATABASE_URL; + /** Assign the custom claims (optional) * This uid will be compare to the auth.token.premium_account variable * (for this case) in the database rules. @@ -146,15 +136,40 @@ void setup() /* path for user data is now "/UsersData/Node1" */ String base_path = "/UsersData/"; + /* Assign the callback function for the long running token generation task */ + config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h + + /** Assign the maximum retry of token generation */ + config.max_token_generation_retry = 5; + + /** To set system time with the timestamp from RTC + * The internal NTP server time acquisition + * of token generation process will be skipped, + * if the system time is already set. + * + * sec is the seconds from midnight Jan 1, 1970 + */ + //Firebase.setSystemTime(sec); + + /* Now we start to signin using custom token */ + + /** Initialize the library with the Firebase authen and config. + * + * The device time will be set by sending request to the NTP server + * befor token generation and exchanging. + * + * The signed RSA256 jwt token will be created and used for id token exchanging. + * + * Theses process may take time to complete. + */ + Firebase.begin(&config, &auth); + /** Now modify the database rules (if not yet modified) * * The user, Node1 in this case will be granted to read and write * at the curtain location i.e. "/UsersData/Node1" and we will also check the * custom claims in the rules which must be matched. * - * To modify the database rules in this exanple, we need the full access rights then - * using the database secret in prepareDatabaseRules function to sign in. - * * If you database rules has been modified, please comment this code out. * * The character $ is to make a wildcard variable (can be any name) represents any node key @@ -168,26 +183,7 @@ void setup() */ String var = "$userId"; String val = "($userId === auth.uid && auth.token.premium_account === true && auth.token.admin === true)"; - prepareDatabaseRules(base_path.c_str(), var.c_str(), val.c_str(), val.c_str()); - - /** Assign the callback function for the long running token generation task */ - config.token_status_callback = tokenStatusCallback; - - /** Assign the maximum retry of token generation */ - config.max_token_generation_retry = 5; - - /* Now we start to signin using custom token */ - - /** Initialize the library with the Firebase authen and config. - * - * The device time will be set by sending request to the NTP server - * befor token generation and exchanging. - * - * The signed RSA256 jwt token will be created and used for id token exchanging. - * - * Theses process may take time to complete. - */ - Firebase.begin(&config, &auth); + Firebase.setReadWriteRules(fbdo, base_path.c_str(), var.c_str(), val.c_str(), val.c_str(), DATABASE_SECRET); /** * The custom token which created internally in this library will use @@ -206,323 +202,32 @@ void setup() void loop() { - if (millis() - dataMillis > 5000) + if (millis() - dataMillis > 5000 && Firebase.ready()) { dataMillis = millis(); - /* Get the token status */ - TokenInfo info = Firebase.authTokenInfo(); - if (info.status == token_status_ready) - { - Serial.println("------------------------------------"); - Serial.println("Set int test..."); - - if (Firebase.set(fbdo, path + "/int", count++)) - { - Serial.println("PASSED"); - Serial.println("PATH: " + fbdo.dataPath()); - Serial.println("TYPE: " + fbdo.dataType()); - Serial.println("ETag: " + fbdo.ETag()); - Serial.print("VALUE: "); - printResult(fbdo); - Serial.println("------------------------------------"); - Serial.println(); - } - else - { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); - Serial.println("------------------------------------"); - Serial.println(); - } - } - } -} - -void tokenStatusCallback(TokenInfo info) -{ - /** fb_esp_auth_token_status enum - * token_status_uninitialized, - * token_status_on_initialize, - * token_status_on_signing, - * token_status_on_request, - * token_status_on_refresh, - * token_status_ready, - * token_status_error - */ - if (info.status == token_status_error) - { - Serial.printf("Token info: type = %s, status = %s\n", getTokenType(info).c_str(), getTokenStatus(info).c_str()); - Serial.printf("Token error: %s\n", getTokenError(info).c_str()); - } - else - { - Serial.printf("Token info: type = %s, status = %s\n", getTokenType(info).c_str(), getTokenStatus(info).c_str()); - } -} - -/* The helper function to modify the database rules (optional) */ -void prepareDatabaseRules(const char *path, const char *var, const char *readVal, const char *writeVal) -{ - //We will sign in using legacy token (database secret) for full RTDB access - Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH); - - Serial.println("------------------------------------"); - Serial.println("Read database rules..."); - if (Firebase.getRules(fbdo)) - { - FirebaseJsonData result; - FirebaseJson &json = fbdo.jsonObject(); - bool rd = false, wr = false; - - String _path = "rules"; - if (path[0] != '/') - _path += "/"; - _path += path; - _path += "/"; - _path += var; - - if (strlen(readVal) > 0) - { - rd = true; - json.get(result, _path + "/.read"); - if (result.success) - if (strcmp(result.stringValue.c_str(), readVal) == 0) - rd = false; - } + Serial.println("------------------------------------"); + Serial.println("Set int test..."); - if (strlen(writeVal) > 0) - { - wr = true; - json.get(result, _path + "/.write"); - if (result.success) - if (strcmp(result.stringValue.c_str(), writeVal) == 0) - wr = false; - } - - //modify if the rules changed or does not exist. - if (wr || rd) - { - FirebaseJson js; - std::string s; - if (rd) - js.add(".read", readVal); - - if (wr) - js.add(".write", writeVal); - - Serial.println("Set database rules..."); - json.set(_path, js); - String rules = ""; - json.toString(rules, true); - if (!Firebase.setRules(fbdo, rules)) - { - Serial.println("Failed to edit the database rules, " + fbdo.errorReason()); - } - } + String node = path + "/int"; - json.clear(); - } - else - { - Serial.println("Failed to read the database rules, " + fbdo.errorReason()); - } -} - -void printResult(FirebaseData &data) -{ - - if (data.dataType() == "int") - Serial.println(data.intData()); - else if (data.dataType() == "float") - Serial.println(data.floatData(), 5); - else if (data.dataType() == "double") - printf("%.9lf\n", data.doubleData()); - else if (data.dataType() == "boolean") - Serial.println(data.boolData() == 1 ? "true" : "false"); - else if (data.dataType() == "string") - Serial.println(data.stringData()); - else if (data.dataType() == "json") - { - Serial.println(); - FirebaseJson &json = data.jsonObject(); - //Print all object data - Serial.println("Pretty printed JSON data:"); - String jsonStr; - json.toString(jsonStr, true); - Serial.println(jsonStr); - Serial.println(); - Serial.println("Iterate JSON data:"); - Serial.println(); - size_t len = json.iteratorBegin(); - String key, value = ""; - int type = 0; - for (size_t i = 0; i < len; i++) + if (Firebase.set(fbdo, node.c_str(), count++)) { - json.iteratorGet(i, type, key, value); - Serial.print(i); - Serial.print(", "); - Serial.print("Type: "); - Serial.print(type == FirebaseJson::JSON_OBJECT ? "object" : "array"); - if (type == FirebaseJson::JSON_OBJECT) - { - Serial.print(", Key: "); - Serial.print(key); - } - Serial.print(", Value: "); - Serial.println(value); - } - json.iteratorEnd(); - } - else if (data.dataType() == "array") - { - Serial.println(); - //get array data from FirebaseData using FirebaseJsonArray object - FirebaseJsonArray &arr = data.jsonArray(); - //Print all array values - Serial.println("Pretty printed Array:"); - String arrStr; - arr.toString(arrStr, true); - Serial.println(arrStr); - Serial.println(); - Serial.println("Iterate array values:"); - Serial.println(); - for (size_t i = 0; i < arr.size(); i++) - { - Serial.print(i); - Serial.print(", Value: "); - - FirebaseJsonData &jsonData = data.jsonData(); - //Get the result data from FirebaseJsonArray object - arr.get(jsonData, i); - if (jsonData.typeNum == FirebaseJson::JSON_BOOL) - Serial.println(jsonData.boolValue ? "true" : "false"); - else if (jsonData.typeNum == FirebaseJson::JSON_INT) - Serial.println(jsonData.intValue); - else if (jsonData.typeNum == FirebaseJson::JSON_FLOAT) - Serial.println(jsonData.floatValue); - else if (jsonData.typeNum == FirebaseJson::JSON_DOUBLE) - printf("%.9lf\n", jsonData.doubleValue); - else if (jsonData.typeNum == FirebaseJson::JSON_STRING || - jsonData.typeNum == FirebaseJson::JSON_NULL || - jsonData.typeNum == FirebaseJson::JSON_OBJECT || - jsonData.typeNum == FirebaseJson::JSON_ARRAY) - Serial.println(jsonData.stringValue); - } - } - else if (data.dataType() == "blob") - { - - Serial.println(); - - for (size_t i = 0; i < data.blobData().size(); i++) - { - if (i > 0 && i % 16 == 0) - Serial.println(); - - if (i < 16) - Serial.print("0"); - - Serial.print(data.blobData()[i], HEX); - Serial.print(" "); + Serial.println("PASSED"); + Serial.println("PATH: " + fbdo.dataPath()); + Serial.println("TYPE: " + fbdo.dataType()); + Serial.println("ETag: " + fbdo.ETag()); + Serial.print("VALUE: "); + printResult(fbdo); //see addons/RTDBHelper.h + Serial.println("------------------------------------"); + Serial.println(); } - Serial.println(); - } - else if (data.dataType() == "file") - { - - Serial.println(); - - File file = data.fileStream(); - int i = 0; - - while (file.available()) + else { - if (i > 0 && i % 16 == 0) - Serial.println(); - - int v = file.read(); - - if (v < 16) - Serial.print("0"); - - Serial.print(v, HEX); - Serial.print(" "); - i++; + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + Serial.println("------------------------------------"); + Serial.println(); } - Serial.println(); - file.close(); - } - else - { - Serial.println(data.payload()); } } - -/* The helper function to get the token type string */ -String getTokenType(struct token_info_t info) -{ - switch (info.type) - { - case token_type_undefined: - return "undefined"; - - case token_type_legacy_token: - return "legacy token"; - - case token_type_id_token: - return "id token"; - - case token_type_custom_token: - return "custom token"; - - case token_type_oauth2_access_token: - return "OAuth2.0 access token"; - - default: - break; - } - return "undefined"; -} - -/* The helper function to get the token status string */ -String getTokenStatus(struct token_info_t info) -{ - switch (info.status) - { - case token_status_uninitialized: - return "uninitialized"; - - case token_status_on_initialize: - return "on initializing"; - - case token_status_on_signing: - return "on signing"; - - case token_status_on_request: - return "on request"; - - case token_status_on_refresh: - return "on refreshing"; - - case token_status_ready: - return "ready"; - - case token_status_error: - return "error"; - - default: - break; - } - return "uninitialized"; -} - -/* The helper function to get the token error string */ -String getTokenError(struct token_info_t info) -{ - String s = "code: "; - s += String(info.error.code); - s += ", message: "; - s += info.error.message.c_str(); - return s; -} diff --git a/examples/Authentications/Email_Password/Email_Password.ino b/examples/Authentications/Email_Password/Email_Password.ino index 09962d66..b5b98e70 100644 --- a/examples/Authentications/Email_Password/Email_Password.ino +++ b/examples/Authentications/Email_Password/Email_Password.ino @@ -23,17 +23,24 @@ * guard the unauthorized access with the user Email. */ +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) #include #include +#endif + +//Provide the token generation process info. +#include "addons/TokenHelper.h" +//Provide the RTDB payload printing info and other helper functions. +#include "addons/RTDBHelper.h" /* 1. Define the WiFi credentials */ #define WIFI_SSID "WIFI_AP" #define WIFI_PASSWORD "WIFI_PASSWORD" -/* 2. Define the Firebase project host name (required) */ -#define FIREBASE_HOST "PROJECT_ID.firebaseio.com" - -/** 3. Define the API key +/** 2. Define the API key * * The API key (required) can be obtained since you created the project and set up * the Authentication in Firebase console. Then you will get the API key from @@ -45,19 +52,22 @@ * The API key also available by click at the link APPLICATION SETUP DETAILS. * */ -#define API_KEY "WEB_API_KEY" +#define API_KEY "API_KEY" -/* 4. Define the user Email and password that alreaey registerd or added in your project */ +/* 3. Define the user Email and password that already registerd or added in your project */ #define USER_EMAIL "USER_EMAIL" #define USER_PASSWORD "USER_PASSWORD" +/* 4. If work with RTDB, define the RTDB URL */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app + /** 5. Define the database secret (optional) * * This database secret needed only for this example to modify the database rules * * If you edit the database rules yourself, this is not required. */ -#define FIREBASE_AUTH "DATABASE_SECRET" +#define DATABASE_SECRET "DATABASE_SECRET" /* 6. Define the Firebase Data object */ FirebaseData fbdo; @@ -68,24 +78,6 @@ FirebaseAuth auth; /* 8. Define the FirebaseConfig data for config data */ FirebaseConfig config; -/* The calback function to print the token generation status */ -void tokenStatusCallback(TokenInfo info); - -/* The helper function to modify the database rules (optional) */ -void prepareDatabaseRules(const char *path, const char *var, const char *readVal, const char *writeVal); - -/* The function to print the operating results */ -void printResult(FirebaseData &data); - -/* The helper function to get the token status string */ -String getTokenStatus(struct token_info_t info); - -/* The helper function to get the token type string */ -String getTokenType(struct token_info_t info); - -/* The helper function to get the token error string */ -String getTokenError(struct token_info_t info); - String path = ""; unsigned long dataMillis = 0; int count = 0; @@ -107,47 +99,50 @@ void setup() Serial.println(WiFi.localIP()); Serial.println(); - /* Assign the project host and api key (required) */ - config.host = FIREBASE_HOST; + /* Assign the api key (required) */ config.api_key = API_KEY; /* Assign the user sign in credentials */ auth.user.email = USER_EMAIL; auth.user.password = USER_PASSWORD; + /* Assign the RTDB URL */ + config.database_url = DATABASE_URL; + Firebase.reconnectWiFi(true); fbdo.setResponseSize(4096); String base_path = "/UsersData2/"; - /** Modify the database rules if not yet modified (optional) + /* Assign the callback function for the long running token generation task */ + config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h + + /** Assign the maximum retry of token generation */ + config.max_token_generation_retry = 5; + + /* Initialize the library with the Firebase authen and config */ + Firebase.begin(&config, &auth); + + /** Now modify the database rules (if not yet modified) * - * The user in this case will be granted access to read and write - * at the curtain path i.e. "/UsersData2/xxxx" which xxxx is uid of a user. + * The user, Node1 in this case will be granted to read and write + * at the curtain location i.e. "/UsersData/Node1" and we will also check the + * custom claims in the rules which must be matched. * - * Please check your the database rules to see the changes. - * - * To modify the database rules in this exanple, we need the full access rights then - * using the database secret in prepareDatabaseRules function to sign in. + * If you database rules has been modified, please comment this code out. * * The character $ is to make a wildcard variable (can be any name) represents any node key * which located at some level in the rule structure and use as reference variable * in .read, .write and .validate rules * - * If you database rules has been modified, please comment this code out + * For this case $userId represents any xxxx node that places under UsersData node i.e. + * /UsersData/xxxxx which xxxx is user UID or "Node1" in this case. + * + * Please check your the database rules to see the changes after run the below code. */ - String var = "$user"; - String val = "(auth.uid === $user)"; - prepareDatabaseRules(base_path.c_str(), var.c_str(), val.c_str(), val.c_str()); - - /** Assign the callback function for the long running token generation task */ - config.token_status_callback = tokenStatusCallback; - - /** Assign the maximum retry of token generation */ - config.max_token_generation_retry = 5; - - /* Initialize the library with the Firebase authen and config */ - Firebase.begin(&config, &auth); + String var = "$userId"; + String val = "($userId === auth.uid && auth.token.premium_account === true && auth.token.admin === true)"; + Firebase.setReadWriteRules(fbdo, base_path.c_str(), var.c_str(), val.c_str(), val.c_str(), DATABASE_SECRET); /** path for user data is now "/UsersData2/YOUR_USER_UID" * The user UID can be taken from auth.token.uid @@ -157,323 +152,32 @@ void setup() void loop() { - if (millis() - dataMillis > 5000) + if (millis() - dataMillis > 5000 && Firebase.ready()) { dataMillis = millis(); - /* Get the token status */ - TokenInfo info = Firebase.authTokenInfo(); - if (info.status == token_status_ready) - { - Serial.println("------------------------------------"); - Serial.println("Set int test..."); + Serial.println("------------------------------------"); + Serial.println("Set int test..."); - if (Firebase.set(fbdo, path + "/int", count++)) - { - Serial.println("PASSED"); - Serial.println("PATH: " + fbdo.dataPath()); - Serial.println("TYPE: " + fbdo.dataType()); - Serial.println("ETag: " + fbdo.ETag()); - Serial.print("VALUE: "); - printResult(fbdo); - Serial.println("------------------------------------"); - Serial.println(); - } - else - { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); - Serial.println("------------------------------------"); - Serial.println(); - } - } - } -} - -void tokenStatusCallback(TokenInfo info) -{ - /** fb_esp_auth_token_status enum - * token_status_uninitialized, - * token_status_on_initialize, - * token_status_on_signing, - * token_status_on_request, - * token_status_on_refresh, - * token_status_ready, - * token_status_error - */ - if (info.status == token_status_error) - { - Serial.printf("Token info: type = %s, status = %s\n", getTokenType(info).c_str(), getTokenStatus(info).c_str()); - Serial.printf("Token error: %s\n", getTokenError(info).c_str()); - } - else - { - Serial.printf("Token info: type = %s, status = %s\n", getTokenType(info).c_str(), getTokenStatus(info).c_str()); - } -} - -/* The helper function to modify the database rules (optional) */ -void prepareDatabaseRules(const char *path, const char *var, const char *readVal, const char *writeVal) -{ - //We will sign in using legacy token (database secret) for full RTDB access - Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH); - - Serial.println("------------------------------------"); - Serial.println("Read database rules..."); - if (Firebase.getRules(fbdo)) - { - FirebaseJsonData result; - FirebaseJson &json = fbdo.jsonObject(); - bool rd = false, wr = false; + String node = path + "/int"; - String _path = "rules"; - if (path[0] != '/') - _path += "/"; - _path += path; - _path += "/"; - _path += var; - - if (strlen(readVal) > 0) - { - rd = true; - json.get(result, _path + "/.read"); - if (result.success) - if (strcmp(result.stringValue.c_str(), readVal) == 0) - rd = false; - } - - if (strlen(writeVal) > 0) - { - wr = true; - json.get(result, _path + "/.write"); - if (result.success) - if (strcmp(result.stringValue.c_str(), writeVal) == 0) - wr = false; - } - - //modify if the rules changed or does not exist. - if (wr || rd) + if (Firebase.set(fbdo, node.c_str(), count++)) { - FirebaseJson js; - std::string s; - if (rd) - js.add(".read", readVal); - - if (wr) - js.add(".write", writeVal); - - Serial.println("Set database rules..."); - json.set(_path, js); - String rules = ""; - json.toString(rules, true); - if (!Firebase.setRules(fbdo, rules)) - { - Serial.println("Failed to edit the database rules, " + fbdo.errorReason()); - } - } - - json.clear(); - } - else - { - Serial.println("Failed to read the database rules, " + fbdo.errorReason()); - } -} - -void printResult(FirebaseData &data) -{ - - if (data.dataType() == "int") - Serial.println(data.intData()); - else if (data.dataType() == "float") - Serial.println(data.floatData(), 5); - else if (data.dataType() == "double") - printf("%.9lf\n", data.doubleData()); - else if (data.dataType() == "boolean") - Serial.println(data.boolData() == 1 ? "true" : "false"); - else if (data.dataType() == "string") - Serial.println(data.stringData()); - else if (data.dataType() == "json") - { - Serial.println(); - FirebaseJson &json = data.jsonObject(); - //Print all object data - Serial.println("Pretty printed JSON data:"); - String jsonStr; - json.toString(jsonStr, true); - Serial.println(jsonStr); - Serial.println(); - Serial.println("Iterate JSON data:"); - Serial.println(); - size_t len = json.iteratorBegin(); - String key, value = ""; - int type = 0; - for (size_t i = 0; i < len; i++) - { - json.iteratorGet(i, type, key, value); - Serial.print(i); - Serial.print(", "); - Serial.print("Type: "); - Serial.print(type == FirebaseJson::JSON_OBJECT ? "object" : "array"); - if (type == FirebaseJson::JSON_OBJECT) - { - Serial.print(", Key: "); - Serial.print(key); - } - Serial.print(", Value: "); - Serial.println(value); - } - json.iteratorEnd(); - } - else if (data.dataType() == "array") - { - Serial.println(); - //get array data from FirebaseData using FirebaseJsonArray object - FirebaseJsonArray &arr = data.jsonArray(); - //Print all array values - Serial.println("Pretty printed Array:"); - String arrStr; - arr.toString(arrStr, true); - Serial.println(arrStr); - Serial.println(); - Serial.println("Iterate array values:"); - Serial.println(); - for (size_t i = 0; i < arr.size(); i++) - { - Serial.print(i); - Serial.print(", Value: "); - - FirebaseJsonData &jsonData = data.jsonData(); - //Get the result data from FirebaseJsonArray object - arr.get(jsonData, i); - if (jsonData.typeNum == FirebaseJson::JSON_BOOL) - Serial.println(jsonData.boolValue ? "true" : "false"); - else if (jsonData.typeNum == FirebaseJson::JSON_INT) - Serial.println(jsonData.intValue); - else if (jsonData.typeNum == FirebaseJson::JSON_FLOAT) - Serial.println(jsonData.floatValue); - else if (jsonData.typeNum == FirebaseJson::JSON_DOUBLE) - printf("%.9lf\n", jsonData.doubleValue); - else if (jsonData.typeNum == FirebaseJson::JSON_STRING || - jsonData.typeNum == FirebaseJson::JSON_NULL || - jsonData.typeNum == FirebaseJson::JSON_OBJECT || - jsonData.typeNum == FirebaseJson::JSON_ARRAY) - Serial.println(jsonData.stringValue); - } - } - else if (data.dataType() == "blob") - { - - Serial.println(); - - for (size_t i = 0; i < data.blobData().size(); i++) - { - if (i > 0 && i % 16 == 0) - Serial.println(); - - if (i < 16) - Serial.print("0"); - - Serial.print(data.blobData()[i], HEX); - Serial.print(" "); + Serial.println("PASSED"); + Serial.println("PATH: " + fbdo.dataPath()); + Serial.println("TYPE: " + fbdo.dataType()); + Serial.println("ETag: " + fbdo.ETag()); + Serial.print("VALUE: "); + printResult(fbdo); //see addons/RTDBHelper.h + Serial.println("------------------------------------"); + Serial.println(); } - Serial.println(); - } - else if (data.dataType() == "file") - { - - Serial.println(); - - File file = data.fileStream(); - int i = 0; - - while (file.available()) + else { - if (i > 0 && i % 16 == 0) - Serial.println(); - - int v = file.read(); - - if (v < 16) - Serial.print("0"); - - Serial.print(v, HEX); - Serial.print(" "); - i++; + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + Serial.println("------------------------------------"); + Serial.println(); } - Serial.println(); - file.close(); - } - else - { - Serial.println(data.payload()); - } -} - -/* The helper function to get the token type string */ -String getTokenType(struct token_info_t info) -{ - switch (info.type) - { - case token_type_undefined: - return "undefined"; - - case token_type_legacy_token: - return "legacy token"; - - case token_type_id_token: - return "id token"; - - case token_type_custom_token: - return "custom token"; - - case token_type_oauth2_access_token: - return "OAuth2.0 access token"; - - default: - break; - } - return "undefined"; -} - -/* The helper function to get the token status string */ -String getTokenStatus(struct token_info_t info) -{ - switch (info.status) - { - case token_status_uninitialized: - return "uninitialized"; - - case token_status_on_initialize: - return "on initializing"; - - case token_status_on_signing: - return "on signing"; - - case token_status_on_request: - return "on request"; - - case token_status_on_refresh: - return "on refreshing"; - - case token_status_ready: - return "ready"; - - case token_status_error: - return "error"; - - default: - break; } - return "uninitialized"; -} - -/* The helper function to get the token error string */ -String getTokenError(struct token_info_t info) -{ - String s = "code: "; - s += String(info.error.code); - s += ", message: "; - s += info.error.message.c_str(); - return s; } diff --git a/examples/Authentications/Legacy_Token/Legacy_Token.ino b/examples/Authentications/Legacy_Token/Legacy_Token.ino index 04d49a3a..4c7fe877 100644 --- a/examples/Authentications/Legacy_Token/Legacy_Token.ino +++ b/examples/Authentications/Legacy_Token/Legacy_Token.ino @@ -13,18 +13,24 @@ /** This example will show how to authenticate using * the legacy token or database secret with the new APIs (using config and auth data). */ - +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) #include #include +#endif + +//Provide the RTDB payload printing info and other helper functions. +#include "addons/RTDBHelper.h" /* 1. Define the WiFi credentials */ #define WIFI_SSID "WIFI_AP" #define WIFI_PASSWORD "WIFI_PASSWORD" -/* 2. Define the Firebase project host name (required) */ -#define FIREBASE_HOST "PROJECT_ID.firebaseio.com" -#define FIREBASE_AUTH "DATABASE_SECRET" - +/* 2. If work with RTDB, define the RTDB URL and database secret */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app +#define DATABASE_SECRET "DATABASE_SECRET" /* 3. Define the Firebase Data object */ FirebaseData fbdo; @@ -35,9 +41,6 @@ FirebaseAuth auth; /* Define the FirebaseConfig data for config data */ FirebaseConfig config; -/* The function to print the operating results */ -void printResult(FirebaseData &data); - String path = "/Test"; unsigned long dataMillis = 0; int count = 0; @@ -63,10 +66,9 @@ void setup() //config.cert.file = "/cert.cer"; //config.cert.file_storage = StorageType::FLASH; - /* Assign the project host and database secret(required) */ - config.host = FIREBASE_HOST; - config.signer.tokens.legacy_token = FIREBASE_AUTH; - + /* Assign the database URL and database secret(required) */ + config.database_url = DATABASE_URL; + config.signer.tokens.legacy_token = DATABASE_SECRET; Firebase.reconnectWiFi(true); @@ -83,14 +85,16 @@ void loop() Serial.println("------------------------------------"); Serial.println("Set int test..."); - if (Firebase.set(fbdo, path + "/int", count++)) + String node = path + "/int"; + + if (Firebase.set(fbdo, node.c_str(), count++)) { Serial.println("PASSED"); Serial.println("PATH: " + fbdo.dataPath()); Serial.println("TYPE: " + fbdo.dataType()); Serial.println("ETag: " + fbdo.ETag()); Serial.print("VALUE: "); - printResult(fbdo); + printResult(fbdo); //see addons/RTDBHelper.h Serial.println("------------------------------------"); Serial.println(); } @@ -103,133 +107,3 @@ void loop() } } } - -void printResult(FirebaseData &data) -{ - - if (data.dataType() == "int") - Serial.println(data.intData()); - else if (data.dataType() == "float") - Serial.println(data.floatData(), 5); - else if (data.dataType() == "double") - printf("%.9lf\n", data.doubleData()); - else if (data.dataType() == "boolean") - Serial.println(data.boolData() == 1 ? "true" : "false"); - else if (data.dataType() == "string") - Serial.println(data.stringData()); - else if (data.dataType() == "json") - { - Serial.println(); - FirebaseJson &json = data.jsonObject(); - //Print all object data - Serial.println("Pretty printed JSON data:"); - String jsonStr; - json.toString(jsonStr, true); - Serial.println(jsonStr); - Serial.println(); - Serial.println("Iterate JSON data:"); - Serial.println(); - size_t len = json.iteratorBegin(); - String key, value = ""; - int type = 0; - for (size_t i = 0; i < len; i++) - { - json.iteratorGet(i, type, key, value); - Serial.print(i); - Serial.print(", "); - Serial.print("Type: "); - Serial.print(type == FirebaseJson::JSON_OBJECT ? "object" : "array"); - if (type == FirebaseJson::JSON_OBJECT) - { - Serial.print(", Key: "); - Serial.print(key); - } - Serial.print(", Value: "); - Serial.println(value); - } - json.iteratorEnd(); - } - else if (data.dataType() == "array") - { - Serial.println(); - //get array data from FirebaseData using FirebaseJsonArray object - FirebaseJsonArray &arr = data.jsonArray(); - //Print all array values - Serial.println("Pretty printed Array:"); - String arrStr; - arr.toString(arrStr, true); - Serial.println(arrStr); - Serial.println(); - Serial.println("Iterate array values:"); - Serial.println(); - for (size_t i = 0; i < arr.size(); i++) - { - Serial.print(i); - Serial.print(", Value: "); - - FirebaseJsonData &jsonData = data.jsonData(); - //Get the result data from FirebaseJsonArray object - arr.get(jsonData, i); - if (jsonData.typeNum == FirebaseJson::JSON_BOOL) - Serial.println(jsonData.boolValue ? "true" : "false"); - else if (jsonData.typeNum == FirebaseJson::JSON_INT) - Serial.println(jsonData.intValue); - else if (jsonData.typeNum == FirebaseJson::JSON_FLOAT) - Serial.println(jsonData.floatValue); - else if (jsonData.typeNum == FirebaseJson::JSON_DOUBLE) - printf("%.9lf\n", jsonData.doubleValue); - else if (jsonData.typeNum == FirebaseJson::JSON_STRING || - jsonData.typeNum == FirebaseJson::JSON_NULL || - jsonData.typeNum == FirebaseJson::JSON_OBJECT || - jsonData.typeNum == FirebaseJson::JSON_ARRAY) - Serial.println(jsonData.stringValue); - } - } - else if (data.dataType() == "blob") - { - - Serial.println(); - - for (size_t i = 0; i < data.blobData().size(); i++) - { - if (i > 0 && i % 16 == 0) - Serial.println(); - - if (i < 16) - Serial.print("0"); - - Serial.print(data.blobData()[i], HEX); - Serial.print(" "); - } - Serial.println(); - } - else if (data.dataType() == "file") - { - - Serial.println(); - - File file = data.fileStream(); - int i = 0; - - while (file.available()) - { - if (i > 0 && i % 16 == 0) - Serial.println(); - - int v = file.read(); - - if (v < 16) - Serial.print("0"); - - Serial.print(v, HEX); - Serial.print(" "); - i++; - } - Serial.println(); - file.close(); - } - else - { - Serial.println(data.payload()); - } -} diff --git a/examples/Authentications/Reset_Password/Reset_Password.ino b/examples/Authentications/Reset_Password/Reset_Password.ino index c839364a..cef42d35 100644 --- a/examples/Authentications/Reset_Password/Reset_Password.ino +++ b/examples/Authentications/Reset_Password/Reset_Password.ino @@ -14,17 +14,19 @@ * */ +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) #include #include +#endif /* 1. Define the WiFi credentials */ #define WIFI_SSID "WIFI_AP" #define WIFI_PASSWORD "WIFI_PASSWORD" -/* 2. Define the Firebase project host name (required) */ -#define FIREBASE_HOST "PROJECT_ID.firebaseio.com" - -/** 3. Define the API key +/** 2. Define the API key * * The API key can be obtained since you created the project and set up * the Authentication in Firebase console. @@ -34,16 +36,17 @@ * The API key also available by click at the link APPLICATION SETUP DETAILS. * */ -#define API_KEY "WEB_API_KEY" +#define API_KEY "API_KEY" -/* 4. Define the user Email to reset the password */ +/* 3. Define the user Email to reset the password */ #define USER_EMAIL "USER_EMAIL" +/* 4. If work with RTDB, define the RTDB URL */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app /* 5. Define the FirebaseConfig data for config data */ FirebaseConfig config; - void setup() { @@ -61,10 +64,12 @@ void setup() Serial.println(WiFi.localIP()); Serial.println(); - /* Assign the project host and API key (required) */ - config.host = FIREBASE_HOST; + /* Assign the API key (required) */ config.api_key = API_KEY; + /* Assign the RTDB URL */ + config.database_url = DATABASE_URL; + Firebase.reconnectWiFi(true); Serial.println("------------------------------------"); @@ -83,5 +88,4 @@ void setup() void loop() { - } diff --git a/examples/Authentications/Send_Verification/Send_Verification.ino b/examples/Authentications/Send_Verification/Send_Verification.ino index 8d021955..4e7eab47 100644 --- a/examples/Authentications/Send_Verification/Send_Verification.ino +++ b/examples/Authentications/Send_Verification/Send_Verification.ino @@ -19,17 +19,24 @@ * In the database rules, you can guard the unverified user from access by adding "auth.token.email_verified == true" */ +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) #include #include +#endif + +//Provide the token generation process info. +#include "addons/TokenHelper.h" +//Provide the RTDB payload printing info and other helper functions. +#include "addons/RTDBHelper.h" /* 1. Define the WiFi credentials */ #define WIFI_SSID "WIFI_AP" #define WIFI_PASSWORD "WIFI_PASSWORD" -/* 2. Define the Firebase project host name (required) */ -#define FIREBASE_HOST "PROJECT_ID.firebaseio.com" - -/** 3. Define the API key +/** 2. Define the API key * * The API key can be obtained since you created the project and set up * the Authentication in Firebase console. @@ -39,12 +46,15 @@ * The API key also available by click at the link APPLICATION SETUP DETAILS. * */ -#define API_KEY "WEB_API_KEY" +#define API_KEY "API_KEY" -/* 4. Define the user Email and password that already registerd or added in your project */ +/* 3. Define the user Email and password that already registerd or added in your project */ #define USER_EMAIL "USER_EMAIL" #define USER_PASSWORD "USER_PASSWORD" +/* 4. If work with RTDB, define the RTDB URL */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app + /* 5. Define the Firebase Data object */ FirebaseData fbdo; @@ -54,18 +64,6 @@ FirebaseAuth auth; /* 7. Define the FirebaseConfig data for config data */ FirebaseConfig config; -/* The function to print the operating results */ -void printResult(FirebaseData &data); - -/* The helper function to get the token status string */ -String getTokenStatus(struct token_info_t info); - -/* The helper function to get the token type string */ -String getTokenType(struct token_info_t info); - -/* The helper function to get the token error string */ -String getTokenError(struct token_info_t info); - String path = ""; unsigned long dataMillis = 0; int count = 0; @@ -88,10 +86,12 @@ void setup() Serial.println(WiFi.localIP()); Serial.println(); - /* Assign the project host and API key (required) */ - config.host = FIREBASE_HOST; + /* Assign the API key (required) */ config.api_key = API_KEY; + /* Assign the RTDB URL */ + config.database_url = DATABASE_URL; + Firebase.reconnectWiFi(true); /* Assign the user sign in credentials */ @@ -100,6 +100,9 @@ void setup() Firebase.reconnectWiFi(true); + /* Assign the callback function for the long running token generation task */ + config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h + String base_path = "/UsersData2/"; /* Initialize the library with the Firebase authen and config */ @@ -126,34 +129,23 @@ void setup() void loop() { - if (millis() - dataMillis > 5000 && signupOK) + if (millis() - dataMillis > 5000 && Firebase.ready()) { dataMillis = millis(); - /* Get the token status */ - struct token_info_t info = Firebase.authTokenInfo(); - Serial.println("------------------------------------"); - if (info.status == token_status_error) - { - Serial.printf("Token info: type = %s, status = %s\n", getTokenType(info).c_str(), getTokenStatus(info).c_str()); - Serial.printf("Token error: %s\n\n", getTokenError(info).c_str()); - } - else - { - Serial.printf("Token info: type = %s, status = %s\n\n", getTokenType(info).c_str(), getTokenStatus(info).c_str()); - } - Serial.println("------------------------------------"); Serial.println("Set int test..."); - if (Firebase.set(fbdo, path + "/int", count++)) + String Path = path + "/int"; + + if (Firebase.set(fbdo, Path.c_str(), count++)) { Serial.println("PASSED"); Serial.println("PATH: " + fbdo.dataPath()); Serial.println("TYPE: " + fbdo.dataType()); Serial.println("ETag: " + fbdo.ETag()); Serial.print("VALUE: "); - printResult(fbdo); + printResult(fbdo); //see addons/RTDBHelper.h Serial.println("------------------------------------"); Serial.println(); } @@ -166,198 +158,3 @@ void loop() } } } - -void printResult(FirebaseData &data) -{ - - if (data.dataType() == "int") - Serial.println(data.intData()); - else if (data.dataType() == "float") - Serial.println(data.floatData(), 5); - else if (data.dataType() == "double") - printf("%.9lf\n", data.doubleData()); - else if (data.dataType() == "boolean") - Serial.println(data.boolData() == 1 ? "true" : "false"); - else if (data.dataType() == "string") - Serial.println(data.stringData()); - else if (data.dataType() == "json") - { - Serial.println(); - FirebaseJson &json = data.jsonObject(); - //Print all object data - Serial.println("Pretty printed JSON data:"); - String jsonStr; - json.toString(jsonStr, true); - Serial.println(jsonStr); - Serial.println(); - Serial.println("Iterate JSON data:"); - Serial.println(); - size_t len = json.iteratorBegin(); - String key, value = ""; - int type = 0; - for (size_t i = 0; i < len; i++) - { - json.iteratorGet(i, type, key, value); - Serial.print(i); - Serial.print(", "); - Serial.print("Type: "); - Serial.print(type == FirebaseJson::JSON_OBJECT ? "object" : "array"); - if (type == FirebaseJson::JSON_OBJECT) - { - Serial.print(", Key: "); - Serial.print(key); - } - Serial.print(", Value: "); - Serial.println(value); - } - json.iteratorEnd(); - } - else if (data.dataType() == "array") - { - Serial.println(); - //get array data from FirebaseData using FirebaseJsonArray object - FirebaseJsonArray &arr = data.jsonArray(); - //Print all array values - Serial.println("Pretty printed Array:"); - String arrStr; - arr.toString(arrStr, true); - Serial.println(arrStr); - Serial.println(); - Serial.println("Iterate array values:"); - Serial.println(); - for (size_t i = 0; i < arr.size(); i++) - { - Serial.print(i); - Serial.print(", Value: "); - - FirebaseJsonData &jsonData = data.jsonData(); - //Get the result data from FirebaseJsonArray object - arr.get(jsonData, i); - if (jsonData.typeNum == FirebaseJson::JSON_BOOL) - Serial.println(jsonData.boolValue ? "true" : "false"); - else if (jsonData.typeNum == FirebaseJson::JSON_INT) - Serial.println(jsonData.intValue); - else if (jsonData.typeNum == FirebaseJson::JSON_FLOAT) - Serial.println(jsonData.floatValue); - else if (jsonData.typeNum == FirebaseJson::JSON_DOUBLE) - printf("%.9lf\n", jsonData.doubleValue); - else if (jsonData.typeNum == FirebaseJson::JSON_STRING || - jsonData.typeNum == FirebaseJson::JSON_NULL || - jsonData.typeNum == FirebaseJson::JSON_OBJECT || - jsonData.typeNum == FirebaseJson::JSON_ARRAY) - Serial.println(jsonData.stringValue); - } - } - else if (data.dataType() == "blob") - { - - Serial.println(); - - for (size_t i = 0; i < data.blobData().size(); i++) - { - if (i > 0 && i % 16 == 0) - Serial.println(); - - if (i < 16) - Serial.print("0"); - - Serial.print(data.blobData()[i], HEX); - Serial.print(" "); - } - Serial.println(); - } - else if (data.dataType() == "file") - { - - Serial.println(); - - File file = data.fileStream(); - int i = 0; - - while (file.available()) - { - if (i > 0 && i % 16 == 0) - Serial.println(); - - int v = file.read(); - - if (v < 16) - Serial.print("0"); - - Serial.print(v, HEX); - Serial.print(" "); - i++; - } - Serial.println(); - file.close(); - } - else - { - Serial.println(data.payload()); - } -} - -/* The helper function to get the token type string */ -String getTokenType(struct token_info_t info) -{ - switch (info.type) - { - case token_type_undefined: - return "undefined"; - - case token_type_legacy_token: - return "legacy token"; - - case token_type_id_token: - return "id token"; - - case token_type_custom_token: - return "custom token"; - - case token_type_oauth2_access_token: - return "OAuth2.0 access token"; - - default: - break; - } - return "undefined"; -} - -/* The helper function to get the token status string */ -String getTokenStatus(struct token_info_t info) -{ - switch (info.status) - { - case token_status_uninitialized: - return "uninitialized"; - - case token_status_on_signing: - return "on signing"; - - case token_status_on_request: - return "on request"; - - case token_status_on_refresh: - return "on refreshing"; - - case token_status_ready: - return "ready"; - - case token_status_error: - return "error"; - - default: - break; - } - return "uninitialized"; -} - -/* The helper function to get the token error string */ -String getTokenError(struct token_info_t info) -{ - String s = "code: "; - s += String(info.error.code); - s += ", message: "; - s += info.error.message.c_str(); - return s; -} diff --git a/examples/Authentications/Signup/Signup.ino b/examples/Authentications/Signup/Signup.ino index eddc7d8d..a0c12065 100644 --- a/examples/Authentications/Signup/Signup.ino +++ b/examples/Authentications/Signup/Signup.ino @@ -17,17 +17,24 @@ * under the Sign-in providers list, enable Email/Password provider. */ +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) #include #include +#endif + +//Provide the token generation process info. +#include "addons/TokenHelper.h" +//Provide the RTDB payload printing info and other helper functions. +#include "addons/RTDBHelper.h" /* 1. Define the WiFi credentials */ #define WIFI_SSID "WIFI_AP" #define WIFI_PASSWORD "WIFI_PASSWORD" -/* 2. Define the Firebase project host name (required) */ -#define FIREBASE_HOST "PROJECT_ID.firebaseio.com" - -/** 3. Define the API key +/** 2. Define the API key * * The API key can be obtained since you created the project and set up * the Authentication in Firebase console. @@ -39,6 +46,9 @@ */ #define API_KEY "WEB_API_KEY" +/* 3. If work with RTDB, define the RTDB URL */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app + /* 4. Define the Firebase Data object */ FirebaseData fbdo; @@ -48,18 +58,6 @@ FirebaseAuth auth; /* 6. Define the FirebaseConfig data for config data */ FirebaseConfig config; -/* The function to print the operating results */ -void printResult(FirebaseData &data); - -/* The helper function to get the token status string */ -String getTokenStatus(struct token_info_t info); - -/* The helper function to get the token type string */ -String getTokenType(struct token_info_t info); - -/* The helper function to get the token error string */ -String getTokenError(struct token_info_t info); - String path = ""; unsigned long dataMillis = 0; int count = 0; @@ -82,10 +80,12 @@ void setup() Serial.println(WiFi.localIP()); Serial.println(); - /* Assign the project host and API key (required) */ - config.host = FIREBASE_HOST; + /* Assign the API key (required) */ config.api_key = API_KEY; + /* Assign the RTDB URL */ + config.database_url = DATABASE_URL; + Firebase.reconnectWiFi(true); Serial.println("------------------------------------"); @@ -110,6 +110,9 @@ void setup() Serial.printf("Failed, %s\n", config.signer.signupError.message.c_str()); } + /* Assign the callback function for the long running token generation task */ + config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h + /** The id token (C++ string) will be available from config.signer.tokens.id_token * if the sig-up was successful. * @@ -119,40 +122,27 @@ void setup() * the internal authentication credentials are not created. */ Firebase.begin(&config, &auth); - - } void loop() { - if (millis() - dataMillis > 5000 && signupOK) + if (millis() - dataMillis > 5000 && signupOK && Firebase.ready()) { dataMillis = millis(); - /* Get the token status */ - struct token_info_t info = Firebase.authTokenInfo(); - Serial.println("------------------------------------"); - if (info.status == token_status_error) - { - Serial.printf("Token info: type = %s, status = %s\n", getTokenType(info).c_str(), getTokenStatus(info).c_str()); - Serial.printf("Token error: %s\n\n", getTokenError(info).c_str()); - } - else - { - Serial.printf("Token info: type = %s, status = %s\n\n", getTokenType(info).c_str(), getTokenStatus(info).c_str()); - } - Serial.println("------------------------------------"); Serial.println("Set int test..."); - if (Firebase.set(fbdo, path + "/int", count++)) + String Path = path + "/int"; + + if (Firebase.set(fbdo, Path.c_str(), count++)) { Serial.println("PASSED"); Serial.println("PATH: " + fbdo.dataPath()); Serial.println("TYPE: " + fbdo.dataType()); Serial.println("ETag: " + fbdo.ETag()); Serial.print("VALUE: "); - printResult(fbdo); + printResult(fbdo); //see addons/RTDBHelper.h Serial.println("------------------------------------"); Serial.println(); } @@ -164,199 +154,4 @@ void loop() Serial.println(); } } -} - -void printResult(FirebaseData &data) -{ - - if (data.dataType() == "int") - Serial.println(data.intData()); - else if (data.dataType() == "float") - Serial.println(data.floatData(), 5); - else if (data.dataType() == "double") - printf("%.9lf\n", data.doubleData()); - else if (data.dataType() == "boolean") - Serial.println(data.boolData() == 1 ? "true" : "false"); - else if (data.dataType() == "string") - Serial.println(data.stringData()); - else if (data.dataType() == "json") - { - Serial.println(); - FirebaseJson &json = data.jsonObject(); - //Print all object data - Serial.println("Pretty printed JSON data:"); - String jsonStr; - json.toString(jsonStr, true); - Serial.println(jsonStr); - Serial.println(); - Serial.println("Iterate JSON data:"); - Serial.println(); - size_t len = json.iteratorBegin(); - String key, value = ""; - int type = 0; - for (size_t i = 0; i < len; i++) - { - json.iteratorGet(i, type, key, value); - Serial.print(i); - Serial.print(", "); - Serial.print("Type: "); - Serial.print(type == FirebaseJson::JSON_OBJECT ? "object" : "array"); - if (type == FirebaseJson::JSON_OBJECT) - { - Serial.print(", Key: "); - Serial.print(key); - } - Serial.print(", Value: "); - Serial.println(value); - } - json.iteratorEnd(); - } - else if (data.dataType() == "array") - { - Serial.println(); - //get array data from FirebaseData using FirebaseJsonArray object - FirebaseJsonArray &arr = data.jsonArray(); - //Print all array values - Serial.println("Pretty printed Array:"); - String arrStr; - arr.toString(arrStr, true); - Serial.println(arrStr); - Serial.println(); - Serial.println("Iterate array values:"); - Serial.println(); - for (size_t i = 0; i < arr.size(); i++) - { - Serial.print(i); - Serial.print(", Value: "); - - FirebaseJsonData &jsonData = data.jsonData(); - //Get the result data from FirebaseJsonArray object - arr.get(jsonData, i); - if (jsonData.typeNum == FirebaseJson::JSON_BOOL) - Serial.println(jsonData.boolValue ? "true" : "false"); - else if (jsonData.typeNum == FirebaseJson::JSON_INT) - Serial.println(jsonData.intValue); - else if (jsonData.typeNum == FirebaseJson::JSON_FLOAT) - Serial.println(jsonData.floatValue); - else if (jsonData.typeNum == FirebaseJson::JSON_DOUBLE) - printf("%.9lf\n", jsonData.doubleValue); - else if (jsonData.typeNum == FirebaseJson::JSON_STRING || - jsonData.typeNum == FirebaseJson::JSON_NULL || - jsonData.typeNum == FirebaseJson::JSON_OBJECT || - jsonData.typeNum == FirebaseJson::JSON_ARRAY) - Serial.println(jsonData.stringValue); - } - } - else if (data.dataType() == "blob") - { - - Serial.println(); - - for (size_t i = 0; i < data.blobData().size(); i++) - { - if (i > 0 && i % 16 == 0) - Serial.println(); - - if (i < 16) - Serial.print("0"); - - Serial.print(data.blobData()[i], HEX); - Serial.print(" "); - } - Serial.println(); - } - else if (data.dataType() == "file") - { - - Serial.println(); - - File file = data.fileStream(); - int i = 0; - - while (file.available()) - { - if (i > 0 && i % 16 == 0) - Serial.println(); - - int v = file.read(); - - if (v < 16) - Serial.print("0"); - - Serial.print(v, HEX); - Serial.print(" "); - i++; - } - Serial.println(); - file.close(); - } - else - { - Serial.println(data.payload()); - } -} - -/* The helper function to get the token type string */ -String getTokenType(struct token_info_t info) -{ - switch (info.type) - { - case token_type_undefined: - return "undefined"; - - case token_type_legacy_token: - return "legacy token"; - - case token_type_id_token: - return "id token"; - - case token_type_custom_token: - return "custom token"; - - case token_type_oauth2_access_token: - return "OAuth2.0 access token"; - - default: - break; - } - return "undefined"; -} - -/* The helper function to get the token status string */ -String getTokenStatus(struct token_info_t info) -{ - switch (info.status) - { - case token_status_uninitialized: - return "uninitialized"; - - case token_status_on_signing: - return "on signing"; - - case token_status_on_request: - return "on request"; - - case token_status_on_refresh: - return "on refreshing"; - - case token_status_ready: - return "ready"; - - case token_status_error: - return "error"; - - default: - break; - } - return "uninitialized"; -} - -/* The helper function to get the token error string */ -String getTokenError(struct token_info_t info) -{ - String s = "code: "; - s += String(info.error.code); - s += ", message: "; - s += info.error.message.c_str(); - return s; -} +} \ No newline at end of file diff --git a/examples/AutomaticPlantWatering/AutomaticPlantWatering.ino b/examples/AutomaticPlantWatering/AutomaticPlantWatering.ino deleted file mode 100644 index bf0c2b7c..00000000 --- a/examples/AutomaticPlantWatering/AutomaticPlantWatering.ino +++ /dev/null @@ -1,540 +0,0 @@ - -/** - * Created by K. Suwatchai (Mobizt) - * - * Email: k_suwatchai@hotmail.com - * - * Github: https://github.com/mobizt - * - * Copyright (c) 2021 mobizt - * -*/ - -/** - * This example shows the basic example for automatic plant watering system. - * The sketch will set GPIO16 for Pump1, and GPIO12 for Pump2 - * The status of pumps showed at /PlantWatering/status - * - * Two pumps will be set to turn on in the moring and evening for 120 second everyday - * To manually turn on and off both pumps, change the value under /PlantWatering/control - * - * To control the device, send command at /PlantWatering/control/cmd and the result from process - * showed at /PlantWatering/status/terminal - * - * The command and its description. - * - * idle: nothing to do - * get-time: get time from NTP server - * boot: restart the device - * load-pump: load pump configuration - * load-schedule: load schedule configuration - * pump-count: show the number of pumps at /PlantWatering/status/terminal - * schedule-count: show the number of schedules at /PlantWatering/status/terminal -*/ - -#include -#include -#include - -#define WIFI_SSID "WIFI_AP" -#define WIFI_PASSWORD "WIFI_PASSWORD" - -#define FIREBASE_HOST "PROJECT_ID.firebaseio.com" - -/** The database secret is obsoleted, please use other authentication methods, - * see examples in the Authentications folder. -*/ -#define FIREBASE_AUTH "DATABASE_SECRET" - -struct schedule_info_t -{ - int tm_sec; - int tm_min; - int tm_hour; - int duration; - int state; - String pump_uid; - int active; - int inactive; -}; - -struct pump_info_t -{ - String id; - String name; - String location; - String uid; - int state; - int gpio; -}; - -FirebaseData fbdo1; -FirebaseData fbdo2; - -String path = "/PlantWatering"; -bool timeReady = false; -//Change to match your time zone -float time_zone = 3; -float daylight_offset_in_sec = 0; -char letters[36] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0'}; - -std::vector scheduleInfo; -std::vector pumpInfo; - -void setPumpState(int pumpIndex, int state); -void streamCallback(StreamData data); -void streamTimeoutCallback(bool timeout); -void setClock(float time_zone, float daylight_offset_in_sec); -void addSchedule(String pumpId, int activeState, int inactiveState, int hour, int min, int sec, int duration_in_sec, FirebaseJsonArray *scheduleConfig); -void runSchedule(); -void loadSchedule(FirebaseData &data); -void addPump(String id, String name, String location, int gpio, int state, FirebaseJsonArray *pumpConfig); -void loadPump(FirebaseData &data); -String randomUid(uint8_t length); - -void setup() -{ - - Serial.begin(115200); - - WiFi.begin(WIFI_SSID, WIFI_PASSWORD); - Serial.print("Connecting to Wi-Fi"); - while (WiFi.status() != WL_CONNECTED) - { - Serial.print("."); - delay(300); - } - Serial.println(); - Serial.print("Connected with IP: "); - Serial.println(WiFi.localIP()); - Serial.println(); - - //get time from NTP server and set up - Serial.println("Get time from NTP server..."); - setClock(time_zone, daylight_offset_in_sec); - - Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH); - Firebase.reconnectWiFi(true); - - //Set the size of WiFi rx/tx buffers in the case where we want to work with large data. - fbdo2.setBSSLBufferSize(1024, 1024); - - //Set the size of HTTP response buffers in the case where we want to work with large data. - fbdo2.setResponseSize(1024); - - if (!Firebase.beginStream(fbdo1, path + "/control")) - Serial.println(fbdo1.errorReason()); - - Firebase.setStreamCallback(fbdo1, streamCallback, streamTimeoutCallback); - - Firebase.set(fbdo2, path + "/control/cmd", "idle"); - - if (!Firebase.pathExist(fbdo2, path + "/config/pump")) - { - //Setup initial pump data - - FirebaseJsonArray pumpConfig; - - //pump id, name, location, gpio, state, config - addPump("P01", "Pump 1", "Garden", 16, 0, &pumpConfig); - addPump("P02", "Pump 2", "Garden", 12, 0, &pumpConfig); - - Firebase.set(fbdo2, path + "/config/pump", pumpConfig); - } - else - { - if (Firebase.get(fbdo2, path + "/config/pump")) - loadPump(fbdo2); - } - - //Set up node for pump if not exist. - int pumpNum = sizeof(pumpInfo) / sizeof(pumpInfo[0]); - for (int i = 0; i < pumpNum; i++) - { - if (pumpInfo[i].id != "") - { - if (!Firebase.pathExist(fbdo2, path + "/control/" + pumpInfo[i].id)) - { - Firebase.set(fbdo2, path + "/control/" + pumpInfo[i].id, pumpInfo[i].state); - Firebase.set(fbdo2, path + "/status/" + pumpInfo[i].id, pumpInfo[i].state); - } - } - } - - if (timeReady) - { - - if (!Firebase.pathExist(fbdo2, path + "/config/schedule")) - { - - Serial.println("Setup schedule..."); - - FirebaseJsonArray scheduleConfig; - - //preset index, pump index, activeState, inactiveState, hour, minute, second, duration in second, new setting - - //Set for Pump 1 (P01) to turn on (1) 120 seconds from 7:30:00 then turn off (0) - addSchedule("P01", 1, 0, 7, 30, 00, 120, &scheduleConfig); - //Set for Pump1 (P01) to turn on (1) 120 seconds from 17:30:00 then turn off (0) - addSchedule("P01", 1, 0, 17, 30, 00, 120, &scheduleConfig); - - //Set for Pump2 (P02) to turn on (1) 120 seconds from 7:30:00 then turn off (0) - addSchedule("P02", 1, 0, 7, 30, 00, 120, &scheduleConfig); - //Set for Pump2 (P02) to turn on (1) 120 seconds from 17:30:00 then turn off (0) - addSchedule("P02", 1, 0, 17, 30, 00, 120, &scheduleConfig); - - Firebase.set(fbdo2, path + "/config/schedule", scheduleConfig); - } - else - { - if (Firebase.get(fbdo2, path + "/config/schedule")) - loadSchedule(fbdo2); - } - } - - Serial.println("Ready!"); -} - -void loop() -{ - runSchedule(); -} - -void setPumpState(int pumpIndex, int state) -{ - int pumpNum = sizeof(pumpInfo) / sizeof(pumpInfo[0]); - if (pumpIndex < 0 || pumpIndex >= pumpNum) - return; - - if (pumpInfo[pumpIndex].state == state) - return; - - digitalWrite(pumpInfo[pumpIndex].gpio, state); - pumpInfo[pumpIndex].state = state; - - Firebase.set(fbdo2, path + "/status/" + pumpInfo[pumpIndex].id, state); - if (state == 0) - Serial.println(pumpInfo[pumpIndex].id + " OFF"); - else if (state == 1) - Serial.println(pumpInfo[pumpIndex].id + " ON"); -} - -void streamCallback(StreamData data) -{ - - int pumpNum = sizeof(pumpInfo) / sizeof(pumpInfo[0]); - - if (data.dataType() == "json") - { - FirebaseJson *json = data.jsonObjectPtr(); - FirebaseJsonData jsonData; - - for (int i = 0; i < pumpNum; i++) - { - //Parse for each pump state - json->get(jsonData, pumpInfo[i].id); - setPumpState(i, jsonData.intValue); - } - } - else if (data.dataType() == "int") - { - for (int i = 0; i < pumpNum; i++) - { - if (data.dataPath() == "/" + pumpInfo[i].id) - { - setPumpState(i, data.intData()); - String status = pumpInfo[i].id; - if (data.intData() == 0) - status += " OFF"; - else if (data.intData() == 1) - status += " ON"; - Firebase.set(fbdo2, path + "/status/terminal", status); - } - } - } - else if (data.dataPath() == "/cmd") - { - if (data.stringData() == "get-time") - { - Serial.println("cmd: get time from NTP server"); - Firebase.set(fbdo2, path + "/status/terminal", "get time"); - setClock(time_zone, daylight_offset_in_sec); - } - else if (data.stringData() == "load-pump") - { - Serial.println("cmd: load pump"); - Firebase.set(fbdo2, path + "/status/terminal", "load pump"); - if (Firebase.get(fbdo2, path + "/config/pump")) - loadPump(fbdo2); - } - else if (data.stringData() == "load-schedule") - { - Serial.println("cmd: load schedule"); - Firebase.set(fbdo2, path + "/status/terminal", "load schedule"); - if (Firebase.get(fbdo2, path + "/config/schedule")) - loadSchedule(fbdo2); - } - if (data.stringData() == "schedule-count") - { - Serial.println("cmd: schedule-count"); - Firebase.set(fbdo2, path + "/status/terminal", String(scheduleInfo.size())); - } - if (data.stringData() == "pump-count") - { - Serial.println("cmd: pump-count"); - Firebase.set(fbdo2, path + "/status/terminal", String(pumpInfo.size())); - } - else if (data.stringData() == "boot") - { - Serial.println("cmd: reboot device"); - Firebase.set(fbdo2, path + "/status/terminal", "restart device"); - ESP.restart(); - } - } -} - -void streamTimeoutCallback(bool timeout) -{ - if (timeout) - { - //Timeout occurred - } -} - -void setClock(float time_zone, float daylight_offset_in_sec) -{ - configTime(time_zone * 3600, daylight_offset_in_sec, "pool.ntp.org", "time.nist.gov", NULL); - time_t now = time(nullptr); - int cnt = 0; - - while (now < 8 * 3600 * 2 && cnt < 20) - { - delay(50); - now = time(nullptr); - cnt++; - } - - timeReady = now > 8 * 3600 * 2; - if (timeReady) - Firebase.set(fbdo2, path + "/status/terminal", "idle"); - else - Firebase.set(fbdo2, path + "/status/terminal", "cannot get time"); -} - -void addPump(String id, String name, String location, int gpio, int state, FirebaseJsonArray *pumpConfig) -{ - pump_info_t pinfo; - pinfo.id = id; - pinfo.uid = randomUid(10); - pinfo.name = name; - pinfo.location = location; - pinfo.gpio = gpio; - pinfo.state = state; - pinMode(gpio, OUTPUT); - pumpInfo.push_back(pinfo); - if (pumpConfig) - { - FirebaseJson json; - json.add("id", id); - json.add("name", name); - json.add("location", location); - json.add("uid", pinfo.uid); - json.add("gpio", gpio); - json.add("state", state); - pumpConfig->add(json); - } -} - -void addSchedule(String pumpId, int activeState, int inactiveState, int hour, int min, int sec, int duration_in_sec, FirebaseJsonArray *scheduleConfig) -{ - for (size_t i = 0; i < pumpInfo.size(); i++) - { - if (pumpInfo[i].id == pumpId && pumpId != "") - { - schedule_info_t tinfo; - tinfo.tm_hour = hour; - tinfo.tm_min = min; - tinfo.tm_sec = sec; - tinfo.state = 1; - tinfo.duration = duration_in_sec; - tinfo.pump_uid = pumpInfo[i].uid; - tinfo.active = activeState; - tinfo.inactive = inactiveState; - scheduleInfo.push_back(tinfo); - - if (scheduleConfig) - { - FirebaseJson json; - json.add("hour", hour); - json.add("min", min); - json.add("sec", sec); - json.add("duration", duration_in_sec); - json.add("uid", pumpInfo[i].uid); - json.add("active", activeState); - json.add("inactive", inactiveState); - scheduleConfig->add(json); - } - - break; - } - } -} - -void runSchedule() -{ - struct tm current_timeinfo; - struct tm target_timeinfo; - time_t current_ts = time(nullptr); - time_t target_ts; - gmtime_r(¤t_ts, ¤t_timeinfo); - target_timeinfo.tm_year = current_timeinfo.tm_year; - target_timeinfo.tm_mon = current_timeinfo.tm_mon; - target_timeinfo.tm_mday = current_timeinfo.tm_mday; - - for (size_t i = 0; i < scheduleInfo.size(); i++) - { - if (scheduleInfo[i].state > 0) - { - target_timeinfo.tm_hour = scheduleInfo[i].tm_hour; - target_timeinfo.tm_min = scheduleInfo[i].tm_min; - target_timeinfo.tm_sec = scheduleInfo[i].tm_sec; - - target_ts = mktime(&target_timeinfo); - - if (current_ts >= target_ts && current_ts <= target_ts + scheduleInfo[i].duration && scheduleInfo[i].state == 1) - { - int index = -1; - for (size_t j = 0; j < pumpInfo.size(); j++) - if (scheduleInfo[i].pump_uid == pumpInfo[j].uid) - index = j; - - if (index > -1) - { - if (scheduleInfo[i].active != pumpInfo[index].state) - { - String status = pumpInfo[index].id + " ON - " + String(scheduleInfo[i].duration) + " sec from "; - - if (target_timeinfo.tm_hour < 10) - status += "0"; - status + String(target_timeinfo.tm_hour); - status += ":"; - if (target_timeinfo.tm_min < 10) - status + "0"; - status + String(target_timeinfo.tm_min); - status += ":"; - if (target_timeinfo.tm_sec < 10) - status += "0"; - status + String(target_timeinfo.tm_sec); - - Serial.println(status); - - scheduleInfo[i].state = 2; - Firebase.set(fbdo2, path + "/control/" + pumpInfo[index].id, scheduleInfo[i].active); - setPumpState(index, scheduleInfo[i].active); - Firebase.set(fbdo2, path + "/status/terminal", status); - } - } - } - else if (current_ts > target_ts + scheduleInfo[i].duration && scheduleInfo[i].state == 2) - { - int index = -1; - for (size_t j = 0; j < pumpInfo.size(); j++) - if (scheduleInfo[i].pump_uid == pumpInfo[j].uid) - index = j; - - if (index > -1) - { - if (scheduleInfo[i].inactive != pumpInfo[index].state) - { - scheduleInfo[i].state = 1; - Firebase.set(fbdo2, path + "/control/" + pumpInfo[index].id, scheduleInfo[i].inactive); - setPumpState(index, scheduleInfo[i].inactive); - String status = pumpInfo[index].id + " OFF"; - Firebase.set(fbdo2, path + "/status/terminal", status); - } - } - } - } - } -} - -void loadSchedule(FirebaseData &data) -{ - - scheduleInfo.clear(); - - FirebaseJsonArray *scheduleConfig = data.jsonArrayPtr(); - FirebaseJson json; - - Serial.println("Schedule config:"); - - for (size_t i = 0; i < scheduleConfig->size(); i++) - { - FirebaseJsonData &jsonData = data.jsonData(); - scheduleConfig->get(jsonData, i); - Serial.println(jsonData.stringValue); - json.setJsonData(jsonData.stringValue); - json.get(jsonData, "hour"); - int hour = jsonData.intValue; - json.get(jsonData, "min"); - int min = jsonData.intValue; - json.get(jsonData, "sec"); - int sec = jsonData.intValue; - json.get(jsonData, "duration"); - int duration = jsonData.intValue; - json.get(jsonData, "uid"); - String uid = jsonData.stringValue; - json.get(jsonData, "active"); - int act = jsonData.intValue; - json.get(jsonData, "inactive"); - int ina = jsonData.intValue; - String id; - for (size_t i = 0; i < pumpInfo.size(); i++) - if (uid == pumpInfo[i].uid) - id = pumpInfo[i].id; - - addSchedule(id, act, ina, hour, min, sec, duration, nullptr); - } -} - -void loadPump(FirebaseData &data) -{ - - int pumpNum = sizeof(pumpInfo) / sizeof(pumpInfo[0]); - for (int i = 0; i < pumpNum; i++) - pumpInfo[i].id = ""; - - FirebaseJsonArray *pumpConfig = data.jsonArrayPtr(); - FirebaseJson json; - - Serial.println("Pump config:"); - - for (size_t i = 0; i < pumpConfig->size(); i++) - { - FirebaseJsonData &jsonData = data.jsonData(); - pumpConfig->get(jsonData, i); - Serial.println(jsonData.stringValue); - json.setJsonData(jsonData.stringValue); - json.get(jsonData, "id"); - String id = jsonData.stringValue; - json.get(jsonData, "uid"); - String uid = jsonData.stringValue; - json.get(jsonData, "name"); - String name = jsonData.stringValue; - json.get(jsonData, "location"); - String location = jsonData.stringValue; - json.get(jsonData, "state"); - int state = jsonData.intValue; - json.get(jsonData, "gpio"); - int gpio = jsonData.intValue; - addPump(id, name, location, gpio, state, nullptr); - } -} - -String randomUid(uint8_t length) -{ - String randString = ""; - for (uint8_t i = 0; i < length; i++) - randString = randString + letters[random(0, 36)]; - return randString; -} diff --git a/examples/Backup_and_Restore_flash_memory/Backup_and_restore_flash_memory.ino b/examples/Backup_and_Restore_flash_memory/Backup_and_restore_flash_memory.ino index 0ce39103..1dafb037 100644 --- a/examples/Backup_and_Restore_flash_memory/Backup_and_restore_flash_memory.ino +++ b/examples/Backup_and_Restore_flash_memory/Backup_and_restore_flash_memory.ino @@ -11,21 +11,37 @@ //This example shows how to backup and restore database data +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) #include #include +#endif +//Provide the token generation process info. +#include "addons/TokenHelper.h" +/* 1. Define the WiFi credentials */ #define WIFI_SSID "WIFI_AP" #define WIFI_PASSWORD "WIFI_PASSWORD" -#define FIREBASE_HOST "PROJECT_ID.firebaseio.com" +/* 2. Define the API Key */ +#define API_KEY "API_KEY" -/** The database secret is obsoleted, please use other authentication methods, - * see examples in the Authentications folder. -*/ -#define FIREBASE_AUTH "DATABASE_SECRET" +/* 3. Define the RTDB URL */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app + +/* 4. Define the user Email and password that alreadey registerd or added in your project */ +#define USER_EMAIL "USER_EMAIL" +#define USER_PASSWORD "USER_PASSWORD" //Define Firebase Data object -FirebaseData firebaseData; +FirebaseData fbdo; + +FirebaseAuth auth; +FirebaseConfig config; + +bool taskCompleted; void setup() { @@ -44,61 +60,80 @@ void setup() Serial.println(WiFi.localIP()); Serial.println(); - Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH); - Firebase.reconnectWiFi(true); - - //Set the size of WiFi rx/tx buffers in the case where we want to work with large data. - firebaseData.setBSSLBufferSize(1024, 1024); + /* Assign the api key (required) */ + config.api_key = API_KEY; - //Set the size of HTTP response buffers in the case where we want to work with large data. - firebaseData.setResponseSize(1024); + /* Assign the user sign in credentials */ + auth.user.email = USER_EMAIL; + auth.user.password = USER_PASSWORD; - Serial.println("------------------------------------"); - Serial.println("Backup test..."); + /* Assign the RTDB URL (required) */ + config.database_url = DATABASE_URL; - //Download and save data to Flash memory. - //{TARGET_NODE_PATH} is the full path of database to backup and restore. - //{FILE_NAME} is file name included path to save to Flash meory + /* Assign the callback function for the long running token generation task */ + config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h - if (!Firebase.backup(firebaseData, StorageType::FLASH, "/{TARGET_NODE_PATH}", "/{FILE_NAME}")) - { - Serial.println("FAILED"); - Serial.println("REASON: " + firebaseData.fileTransferError()); - Serial.println("------------------------------------"); - Serial.println(); - } - else - { - Serial.println("PASSED"); - Serial.println("BACKUP FILE: " + firebaseData.getBackupFilename()); - Serial.println("FILE SIZE: " + String(firebaseData.getBackupFileSize())); - Serial.println("------------------------------------"); - Serial.println(); - } + Firebase.begin(&config, &auth); + Firebase.reconnectWiFi(true); - Serial.println("------------------------------------"); - Serial.println("Restore test..."); +#ifdef ESP8266 + //Set the size of WiFi rx/tx buffers in the case where we want to work with large data. + fbdo.setBSSLBufferSize(1024, 1024); +#endif - //Restore data to defined database path using backup file on Flash memory. - //{TARGET_NODE_PATH} is the full path of database to restore - //{FILE_NAME} is file name included path of backed up file. + //Set the size of HTTP response buffers in the case where we want to work with large data. + fbdo.setResponseSize(1024); +} - if (!Firebase.restore(firebaseData, StorageType::FLASH, "/{TARGET_NODE_PATH}", "/{FILE_NAME}")) +void loop() +{ + if (Firebase.ready() && !taskCompleted) { - Serial.println("FAILED"); - Serial.println("REASON: " + firebaseData.fileTransferError()); + taskCompleted = true; + Serial.println("------------------------------------"); - Serial.println(); - } - else - { - Serial.println("PASSED"); - Serial.println("BACKUP FILE: " + firebaseData.getBackupFilename()); + Serial.println("Backup test..."); + + //Download and save data to Flash memory. + // is the full path of database to backup and restore. + // is file name included path to save to Flash meory + //The file systems for flash and SD/SDMMC can be changed in FirebaseFS.h. + if (!Firebase.backup(fbdo, StorageType::FLASH, "/", "/")) + { + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.fileTransferError()); + Serial.println("------------------------------------"); + Serial.println(); + } + else + { + Serial.println("PASSED"); + Serial.println("BACKUP FILE: " + fbdo.getBackupFilename()); + Serial.printf("FILE SIZE: %d\n", fbdo.getBackupFileSize()); + Serial.println("------------------------------------"); + Serial.println(); + } + Serial.println("------------------------------------"); - Serial.println(); + Serial.println("Restore test..."); + + //Restore data to defined database path using backup file on Flash memory. + // is the full path of database to restore + // is file name included path of backed up file. + //The file systems for flash and SD/SDMMC can be changed in FirebaseFS.h. + if (!Firebase.restore(fbdo, StorageType::FLASH, "/", "/")) + { + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.fileTransferError()); + Serial.println("------------------------------------"); + Serial.println(); + } + else + { + Serial.println("PASSED"); + Serial.println("BACKUP FILE: " + fbdo.getBackupFilename()); + Serial.println("------------------------------------"); + Serial.println(); + } } } - -void loop() -{ -} diff --git a/examples/Backup_and_Send_Email/Backup_and_Send_Email.ino b/examples/Backup_and_Send_Email/Backup_and_Send_Email.ino index 1d65f602..de797af4 100644 --- a/examples/Backup_and_Send_Email/Backup_and_Send_Email.ino +++ b/examples/Backup_and_Send_Email/Backup_and_Send_Email.ino @@ -11,8 +11,16 @@ //This example shows how to backup database and send the Email +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) #include #include +#endif + +//Provide the token generation process info. +#include "addons/TokenHelper.h" /* Required ESP Mail Client library for Arduino @@ -21,36 +29,45 @@ #include +/* 1. Define the WiFi credentials */ #define WIFI_SSID "WIFI_AP" #define WIFI_PASSWORD "WIFI_PASSWORD" -#define FIREBASE_HOST "PROJECT_ID.firebaseio.com" +/* 2. Define the API Key */ +#define API_KEY "API_KEY" -/** The database secret is obsoleted, please use other authentication methods, - * see examples in the Authentications folder. -*/ -#define FIREBASE_AUTH "DATABASE_SECRET" +/* 3. Define the RTDB URL */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app -//Define Firebase Data object -FirebaseData fbdo; +/* 4. Define the user Email and password that alreadey registerd or added in your project */ +#define USER_EMAIL "USER_EMAIL" +#define USER_PASSWORD "USER_PASSWORD" -/* The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook */ +/* 5. The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook */ #define SMTP_HOST "################" -/** The smtp port e.g. +/** 6. The smtp port e.g. * 25 or esp_mail_smtp_port_25 * 465 or esp_mail_smtp_port_465 * 587 or esp_mail_smtp_port_587 */ #define SMTP_PORT 25 -/* The sign in credentials */ +/* 7. The sign in credentials */ #define AUTHOR_EMAIL "################" #define AUTHOR_PASSWORD "################" /* The SMTP Session object used for Email sending */ SMTPSession smtp; +//Define Firebase Data object +FirebaseData fbdo; + +FirebaseAuth auth; +FirebaseConfig config; + +bool taskCompleted = false; + /* Callback function to get the Email sending status */ void smtpCallback(SMTP_Status status); @@ -71,109 +88,126 @@ void setup() Serial.println(WiFi.localIP()); Serial.println(); - Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH); - Firebase.reconnectWiFi(true); + /* Assign the api key (required) */ + config.api_key = API_KEY; + /* Assign the user sign in credentials */ + auth.user.email = USER_EMAIL; + auth.user.password = USER_PASSWORD; - Serial.println(); + /* Assign the RTDB URL (required) */ + config.database_url = DATABASE_URL; - Serial.println("------------------------------------"); - Serial.println("Backup test..."); + /* Assign the callback function for the long running token generation task */ + config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h - if (!Firebase.backup(fbdo, StorageType::FLASH, "/PATH_TO_THE_NODE", "/PATH_TO_SAVE_FILE")) - { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.fileTransferError()); - Serial.println("------------------------------------"); - Serial.println(); - } - else + Firebase.begin(&config, &auth); + Firebase.reconnectWiFi(true); + + Serial.println(); +} + +void loop() +{ + if (Firebase.ready() && !taskCompleted) { - Serial.println("PASSED"); - Serial.println("SAVE PATH: " + fbdo.getBackupFilename()); - Serial.println("FILE SIZE: " + String(fbdo.getBackupFileSize())); - Serial.println("------------------------------------"); - Serial.println(); + taskCompleted - true; - String filename = fbdo.getBackupFilename(); + Serial.println("------------------------------------"); + Serial.println("Backup test..."); - if (fbdo.pauseFirebase(true)) + //The file systems for flash and SD/SDMMC can be changed in FirebaseFS.h. + if (!Firebase.backup(fbdo, StorageType::FLASH, "/", "/")) + { + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.fileTransferError()); + Serial.println("------------------------------------"); + Serial.println(); + } + else { + Serial.println("PASSED"); + Serial.println("SAVE PATH: " + fbdo.getBackupFilename()); + Serial.printf("FILE SIZE: %d\n", fbdo.getBackupFileSize()); + Serial.println("------------------------------------"); + Serial.println(); - //Send backup file via Email + String filename = fbdo.getBackupFilename(); - smtp.debug(1); + if (fbdo.pauseFirebase(true)) + { - /* Set the callback function to get the sending results */ - smtp.callback(smtpCallback); + //Send backup file via Email - /* Declare the session config data */ - ESP_Mail_Session session; + smtp.debug(1); - /* Set the session config */ - session.server.host_name = SMTP_HOST; - session.server.port = SMTP_PORT; - session.login.email = AUTHOR_EMAIL; - session.login.password = AUTHOR_PASSWORD; - session.login.user_domain = "mydomain.net"; + /* Set the callback function to get the sending results */ + smtp.callback(smtpCallback); - /* Declare the message class */ - SMTP_Message message; + /* Declare the session config data */ + ESP_Mail_Session session; - /* Set the message headers */ - message.sender.name = "ESP Mail"; - message.sender.email = AUTHOR_EMAIL; - message.subject = "Firebase Database Backup File"; - message.addRecipient("Someone", "k_suwatchai@hotmail.com"); + /* Set the session config */ + session.server.host_name = SMTP_HOST; + session.server.port = SMTP_PORT; + session.login.email = AUTHOR_EMAIL; + session.login.password = AUTHOR_PASSWORD; + session.login.user_domain = "mydomain.net"; - message.text.content = "Firebase Database Backup File\r\nSent from ESP8266"; + /* Declare the message class */ + SMTP_Message message; - /** The Plain text message character set */ - message.text.charSet = "us-ascii"; + /* Set the message headers */ + message.sender.name = "ESP Mail"; + message.sender.email = AUTHOR_EMAIL; + message.subject = "Firebase Database Backup File"; + message.addRecipient("Someone", "yourmail@mail.com"); - /** The content transfer encoding */ - message.text.transfer_encoding = Content_Transfer_Encoding::enc_7bit; + message.text.content = "Firebase Database Backup File\r\nSent from ESP device"; - /** The message priority */ - message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low; + /** The Plain text message character set */ + message.text.charSet = "us-ascii"; - /* The attachment data item */ - SMTP_Attachment att; + /** The content transfer encoding */ + message.text.transfer_encoding = Content_Transfer_Encoding::enc_7bit; - /** Set the attachment info */ - att.descr.filename = filename.c_str(); - att.descr.mime = "application/octet-stream"; - String path = "/" + filename; + /** The message priority */ + message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low; - att.file.path = path.c_str(); - att.file.storage_type = esp_mail_file_storage_type_flash; - att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; + /* The attachment data item */ + SMTP_Attachment att; - /* Add attachment to the message */ - message.addAttachment(att); + /** Set the attachment info */ + att.descr.filename = filename.c_str(); + att.descr.mime = "application/octet-stream"; + String path = "/" + filename; - /* Connect to server with the session config */ - if (!smtp.connect(&session)) - return; + att.file.path = path.c_str(); + att.file.storage_type = esp_mail_file_storage_type_flash; + att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; - /* Start sending Email and close the session */ - if (!MailClient.sendMail(&smtp, &message)) - Serial.println("Error sending Email, " + smtp.errorReason()); + /* Add attachment to the message */ + message.addAttachment(att); - Serial.println(); - } - else - { - Serial.println("Could not pause Firebase"); - } - } + /* Connect to server with the session config */ + if (!smtp.connect(&session)) + return; - //Quit Firebase and release all resources - Firebase.end(fbdo); -} + /* Start sending Email and close the session */ + if (!MailClient.sendMail(&smtp, &message)) + Serial.println("Error sending Email, " + smtp.errorReason()); -void loop() -{ + Serial.println(); + } + else + { + Serial.println("Could not pause Firebase"); + } + } + + //Quit Firebase and release all resources + Firebase.end(fbdo); + } } /* Callback function to get the Email sending status */ diff --git a/examples/Backup_and_restore/Backup_and_restore.ino b/examples/Backup_and_restore/Backup_and_restore.ino index 44a4e5d1..cad04dac 100644 --- a/examples/Backup_and_restore/Backup_and_restore.ino +++ b/examples/Backup_and_restore/Backup_and_restore.ino @@ -11,22 +11,39 @@ //This example shows how to backup and restore database data +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) #include #include +#endif +//Provide the token generation process info. +#include "addons/TokenHelper.h" + +/* 1. Define the WiFi credentials */ #define WIFI_SSID "WIFI_AP" #define WIFI_PASSWORD "WIFI_PASSWORD" -#define FIREBASE_HOST "PROJECT_ID.firebaseio.com" +/* 2. Define the API Key */ +#define API_KEY "API_KEY" -/** The database secret is obsoleted, please use other authentication methods, - * see examples in the Authentications folder. -*/ -#define FIREBASE_AUTH "DATABASE_SECRET" +/* 3. Define the RTDB URL */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app + +/* 4. Define the user Email and password that alreadey registerd or added in your project */ +#define USER_EMAIL "USER_EMAIL" +#define USER_PASSWORD "USER_PASSWORD" //Define Firebase Data object FirebaseData fbdo; +FirebaseAuth auth; +FirebaseConfig config; + +bool taskCompleted = false; + void setup() { @@ -44,61 +61,80 @@ void setup() Serial.println(WiFi.localIP()); Serial.println(); - Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH); + /* Assign the api key (required) */ + config.api_key = API_KEY; + + /* Assign the user sign in credentials */ + auth.user.email = USER_EMAIL; + auth.user.password = USER_PASSWORD; + + /* Assign the RTDB URL (required) */ + config.database_url = DATABASE_URL; + + /* Assign the callback function for the long running token generation task */ + config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h + + Firebase.begin(&config, &auth); Firebase.reconnectWiFi(true); +#ifdef ESP8266 //Set the size of WiFi rx/tx buffers in the case where we want to work with large data. fbdo.setBSSLBufferSize(1024, 1024); +#endif //Set the size of HTTP response buffers in the case where we want to work with large data. fbdo.setResponseSize(1024); - - Serial.println("------------------------------------"); - Serial.println("Backup test..."); - - //Download and save data to SD card. - //{TARGET_NODE_PATH} is the full path of database to backup and restore. - //{FILE_NAME} is file name in 8.3 DOS format (max. 8 bytes file name and 3 bytes file extension) - - if (!Firebase.backup(fbdo, StorageType::SD, "/{TARGET_NODE_PATH}", "/{FILE_NAME}")) - { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.fileTransferError()); - Serial.println("------------------------------------"); - Serial.println(); - } - else - { - Serial.println("PASSED"); - Serial.println("BACKUP FILE: " + fbdo.getBackupFilename()); - Serial.println("FILE SIZE: " + String(fbdo.getBackupFileSize())); - Serial.println("------------------------------------"); - Serial.println(); - } - - Serial.println("------------------------------------"); - Serial.println("Restore test..."); - - //Restore data to defined database path using backup file on SD card. - //{TARGET_NODE_PATH} is the full path of database to restore - //{FILE_NAME} is file name in 8.3 DOS format (max. 8 bytes file name and 3 bytes file extension) - - if (!Firebase.restore(fbdo, StorageType::SD, "/{TARGET_NODE_PATH}", "/{FILE_NAME}")) - { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.fileTransferError()); - Serial.println("------------------------------------"); - Serial.println(); - } - else - { - Serial.println("PASSED"); - Serial.println("BACKUP FILE: " + fbdo.getBackupFilename()); - Serial.println("------------------------------------"); - Serial.println(); - } } void loop() { + if (Firebase.ready() && !taskCompleted) + { + taskCompleted = true; + Serial.println("------------------------------------"); + Serial.println("Backup test..."); + + //Download and save data to SD card. + // is the full path of database to backup and restore. + // is file name in 8.3 DOS format (max. 8 bytes file name and 3 bytes file extension) + + if (!Firebase.backup(fbdo, StorageType::SD, "/", "/")) + { + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.fileTransferError()); + Serial.println("------------------------------------"); + Serial.println(); + } + else + { + Serial.println("PASSED"); + Serial.println("BACKUP FILE: " + fbdo.getBackupFilename()); + Serial.printf("FILE SIZE: %d\n", fbdo.getBackupFileSize()); + Serial.println("------------------------------------"); + Serial.println(); + } + + Serial.println("------------------------------------"); + Serial.println("Restore test..."); + + //Restore data to defined database path using backup file on SD card. + // is the full path of database to restore + // is file name in 8.3 DOS format (max. 8 bytes file name and 3 bytes file extension) + + //The file systems for flash and SD/SDMMC can be changed in FirebaseFS.h. + if (!Firebase.restore(fbdo, StorageType::SD, "/", "/")) + { + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.fileTransferError()); + Serial.println("------------------------------------"); + Serial.println(); + } + else + { + Serial.println("PASSED"); + Serial.println("BACKUP FILE: " + fbdo.getBackupFilename()); + Serial.println("------------------------------------"); + Serial.println(); + } + } } diff --git a/examples/Basic/Basic.ino b/examples/Basic/Basic.ino index 72d43354..0f99bad4 100644 --- a/examples/Basic/Basic.ino +++ b/examples/Basic/Basic.ino @@ -10,25 +10,42 @@ * */ +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) #include #include +#endif +//Provide the token generation process info. +#include "addons/TokenHelper.h" +//Provide the RTDB payload printing info and other helper functions. +#include "addons/RTDBHelper.h" + +/* 1. Define the WiFi credentials */ #define WIFI_SSID "WIFI_AP" #define WIFI_PASSWORD "WIFI_PASSWORD" -#define FIREBASE_HOST "PROJECT_ID.firebaseio.com" +/* 2. Define the API Key */ +#define API_KEY "API_KEY" -/** The database secret is obsoleted, please use other authentication methods, - * see examples in the Authentications folder. -*/ -#define FIREBASE_AUTH "DATABASE_SECRET" +/* 3. Define the RTDB URL */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app + +/* 4. Define the user Email and password that alreadey registerd or added in your project */ +#define USER_EMAIL "USER_EMAIL" +#define USER_PASSWORD "USER_PASSWORD" -//Define FirebaseESP8266 data object +//Define Firebase Data object FirebaseData fbdo; -FirebaseJson json; +FirebaseAuth auth; +FirebaseConfig config; + +bool taskCompleted = false; -void printResult(FirebaseData &data); +FirebaseJson json; void setup() { @@ -47,11 +64,26 @@ void setup() Serial.println(WiFi.localIP()); Serial.println(); - Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH); + /* Assign the api key (required) */ + config.api_key = API_KEY; + + /* Assign the user sign in credentials */ + auth.user.email = USER_EMAIL; + auth.user.password = USER_PASSWORD; + + /* Assign the RTDB URL (required) */ + config.database_url = DATABASE_URL; + + /* Assign the callback function for the long running token generation task */ + config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h + + Firebase.begin(&config, &auth); Firebase.reconnectWiFi(true); +#if defined(ESP8266) //Set the size of WiFi rx/tx buffers in the case where we want to work with large data. fbdo.setBSSLBufferSize(1024, 1024); +#endif //Set the size of HTTP response buffers in the case where we want to work with large data. fbdo.setResponseSize(1024); @@ -66,280 +98,162 @@ void setup() Firebase.setFloatDigits(2); Firebase.setDoubleDigits(6); - /* - This option allows get and delete functions (PUT and DELETE HTTP requests) works for device connected behind the - Firewall that allows only GET and POST requests. - - Firebase.enableClassicRequest(fbdo, true); + /** + * This option allows get and delete functions (PUT and DELETE HTTP requests) works for device connected behind the + * Firewall that allows only GET and POST requests. + * + * Firebase.enableClassicRequest(&fbdo, true); */ +} - String path = "/Test"; - - Serial.println("------------------------------------"); - Serial.println("Set double test..."); - - for (uint8_t i = 0; i < 10; i++) - { - //Also can use Firebase.set instead of Firebase.setDouble - if (Firebase.setDouble(fbdo, path + "/Double/Data" + (i + 1), ((i + 1) * 10) + 0.123456789)) - { - Serial.println("PASSED"); - Serial.println("PATH: " + fbdo.dataPath()); - Serial.println("TYPE: " + fbdo.dataType()); - Serial.println("ETag: " + fbdo.ETag()); - Serial.print("VALUE: "); - printResult(fbdo); - Serial.println("------------------------------------"); - Serial.println(); - } - else - { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); - Serial.println("------------------------------------"); - Serial.println(); - } - } - - Serial.println("------------------------------------"); - Serial.println("Get double test..."); - - for (uint8_t i = 0; i < 10; i++) - { - //Also can use Firebase.get instead of Firebase.setInt - if (Firebase.getInt(fbdo, path + "/Double/Data" + (i + 1))) - { - Serial.println("PASSED"); - Serial.println("PATH: " + fbdo.dataPath()); - Serial.println("TYPE: " + fbdo.dataType()); - Serial.println("ETag: " + fbdo.ETag()); - Serial.print("VALUE: "); - printResult(fbdo); - Serial.println("------------------------------------"); - Serial.println(); - } - else - { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); - Serial.println("------------------------------------"); - Serial.println(); - } - } - - Serial.println("------------------------------------"); - Serial.println("Push integer test..."); - - for (uint8_t i = 0; i < 5; i++) +void loop() +{ + if (Firebase.ready() && !taskCompleted) { - //Also can use Firebase.push instead of Firebase.pushInt - if (Firebase.pushInt(fbdo, path + "/Push/Int", (i + 1))) - { - Serial.println("PASSED"); - Serial.println("PATH: " + fbdo.dataPath()); - Serial.print("PUSH NAME: "); - Serial.println(fbdo.pushName()); - Serial.println("ETag: " + fbdo.ETag()); - Serial.println("------------------------------------"); - Serial.println(); - } - else - { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); - Serial.println("------------------------------------"); - Serial.println(); - } - } + taskCompleted = true; - Serial.println("------------------------------------"); - Serial.println("Push JSON test..."); + String path = "/Test"; + String node; - for (uint8_t i = 5; i < 10; i++) - { - - json.clear().add("Data" + String(i + 1), i + 1); + Serial.println("------------------------------------"); + Serial.println("Set double test..."); - //Also can use Firebase.push instead of Firebase.pushJSON - //Json string is not support in v 2.6.0 and later, only FirebaseJson object is supported. - if (Firebase.pushJSON(fbdo, path + "/Push/Int", json)) - { - Serial.println("PASSED"); - Serial.println("PATH: " + fbdo.dataPath()); - Serial.print("PUSH NAME: "); - Serial.println(fbdo.pushName()); - Serial.println("ETag: " + fbdo.ETag()); - Serial.println("------------------------------------"); - Serial.println(); - } - else + for (uint8_t i = 0; i < 10; i++) { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); - Serial.println("------------------------------------"); - Serial.println(); + node = path + "/Double/Data" + String(i + 1); + //Also can use Firebase.set instead of Firebase.setDouble + if (Firebase.setDouble(fbdo, node.c_str(), ((i + 1) * 10) + 0.123456789)) + { + Serial.println("PASSED"); + Serial.println("PATH: " + fbdo.dataPath()); + Serial.println("TYPE: " + fbdo.dataType()); + Serial.println("ETag: " + fbdo.ETag()); + Serial.print("VALUE: "); + printResult(fbdo); //see addons/RTDBHelper.h + Serial.println("------------------------------------"); + Serial.println(); + } + else + { + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + Serial.println("------------------------------------"); + Serial.println(); + } } - } - - Serial.println("------------------------------------"); - Serial.println("Update test..."); - for (uint8_t i = 0; i < 5; i++) - { - - json.set("Data" + String(i + 1), i + 5.5); + Serial.println("------------------------------------"); + Serial.println("Get double test..."); - if (Firebase.updateNode(fbdo, path + "/float", json)) - { - Serial.println("PASSED"); - Serial.println("PATH: " + fbdo.dataPath()); - Serial.println("TYPE: " + fbdo.dataType()); - //No ETag available - Serial.print("VALUE: "); - printResult(fbdo); - Serial.println("------------------------------------"); - Serial.println(); - } - else + for (uint8_t i = 0; i < 10; i++) { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); - Serial.println("------------------------------------"); - Serial.println(); + node = path + "/Double/Data" + String(i + 1); + //Also can use Firebase.get instead of Firebase.setInt + if (Firebase.getInt(fbdo, node.c_str())) + { + Serial.println("PASSED"); + Serial.println("PATH: " + fbdo.dataPath()); + Serial.println("TYPE: " + fbdo.dataType()); + Serial.println("ETag: " + fbdo.ETag()); + Serial.print("VALUE: "); + printResult(fbdo); //see addons/RTDBHelper.h + Serial.println("------------------------------------"); + Serial.println(); + } + else + { + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + Serial.println("------------------------------------"); + Serial.println(); + } } - } -} -void printResult(FirebaseData &data) -{ + Serial.println("------------------------------------"); + Serial.println("Push integer test..."); - if (data.dataType() == "int") - Serial.println(data.intData()); - else if (data.dataType() == "float") - Serial.println(data.floatData(), 5); - else if (data.dataType() == "double") - printf("%.9lf\n", data.doubleData()); - else if (data.dataType() == "boolean") - Serial.println(data.boolData() == 1 ? "true" : "false"); - else if (data.dataType() == "string") - Serial.println(data.stringData()); - else if (data.dataType() == "json") - { - Serial.println(); - FirebaseJson &json = data.jsonObject(); - //Print all object data - Serial.println("Pretty printed JSON data:"); - String jsonStr; - json.toString(jsonStr, true); - Serial.println(jsonStr); - Serial.println(); - Serial.println("Iterate JSON data:"); - Serial.println(); - size_t len = json.iteratorBegin(); - String key, value = ""; - int type = 0; - for (size_t i = 0; i < len; i++) + for (uint8_t i = 0; i < 5; i++) { - json.iteratorGet(i, type, key, value); - Serial.print(i); - Serial.print(", "); - Serial.print("Type: "); - Serial.print(type == FirebaseJson::JSON_OBJECT ? "object" : "array"); - if (type == FirebaseJson::JSON_OBJECT) + node = path + "/Push/Int"; + //Also can use Firebase.push instead of Firebase.pushInt + if (Firebase.pushInt(fbdo, node.c_str(), (i + 1))) { - Serial.print(", Key: "); - Serial.print(key); + Serial.println("PASSED"); + Serial.println("PATH: " + fbdo.dataPath()); + Serial.print("PUSH NAME: "); + Serial.println(fbdo.pushName()); + Serial.println("ETag: " + fbdo.ETag()); + Serial.println("------------------------------------"); + Serial.println(); + } + else + { + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + Serial.println("------------------------------------"); + Serial.println(); } - Serial.print(", Value: "); - Serial.println(value); - } - json.iteratorEnd(); - } - else if (data.dataType() == "array") - { - Serial.println(); - //get array data from FirebaseData using FirebaseJsonArray object - FirebaseJsonArray &arr = data.jsonArray(); - //Print all array values - Serial.println("Pretty printed Array:"); - String arrStr; - arr.toString(arrStr, true); - Serial.println(arrStr); - Serial.println(); - Serial.println("Iterate array values:"); - Serial.println(); - for (size_t i = 0; i < arr.size(); i++) - { - Serial.print(i); - Serial.print(", Value: "); - - FirebaseJsonData &jsonData = data.jsonData(); - //Get the result data from FirebaseJsonArray object - arr.get(jsonData, i); - if (jsonData.typeNum == FirebaseJson::JSON_BOOL) - Serial.println(jsonData.boolValue ? "true" : "false"); - else if (jsonData.typeNum == FirebaseJson::JSON_INT) - Serial.println(jsonData.intValue); - else if (jsonData.typeNum == FirebaseJson::JSON_FLOAT) - Serial.println(jsonData.floatValue); - else if (jsonData.typeNum == FirebaseJson::JSON_DOUBLE) - printf("%.9lf\n", jsonData.doubleValue); - else if (jsonData.typeNum == FirebaseJson::JSON_STRING || - jsonData.typeNum == FirebaseJson::JSON_NULL || - jsonData.typeNum == FirebaseJson::JSON_OBJECT || - jsonData.typeNum == FirebaseJson::JSON_ARRAY) - Serial.println(jsonData.stringValue); } - } - else if (data.dataType() == "blob") - { - Serial.println(); + Serial.println("------------------------------------"); + Serial.println("Push JSON test..."); - for (int i = 0; i < data.blobData().size(); i++) + for (uint8_t i = 5; i < 10; i++) { - if (i > 0 && i % 16 == 0) - Serial.println(); - if (i < 16) - Serial.print("0"); + json.clear().add("Data" + String(i + 1), i + 1); - Serial.print(data.blobData()[i], HEX); - Serial.print(" "); - } - Serial.println(); - } - else if (data.dataType() == "file") - { + node = path + "/Push/Int"; - Serial.println(); + //Also can use Firebase.push instead of Firebase.pushJSON + //Json string is not support in v 2.6.0 and later, only FirebaseJson object is supported. + if (Firebase.pushJSON(fbdo, node.c_str(), json)) + { + Serial.println("PASSED"); + Serial.println("PATH: " + fbdo.dataPath()); + Serial.print("PUSH NAME: "); + Serial.println(fbdo.pushName()); + Serial.println("ETag: " + fbdo.ETag()); + Serial.println("------------------------------------"); + Serial.println(); + } + else + { + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + Serial.println("------------------------------------"); + Serial.println(); + } + } - File file = data.fileStream(); - int i = 0; + Serial.println("------------------------------------"); + Serial.println("Update test..."); - while (file.available()) + for (uint8_t i = 0; i < 5; i++) { - if (i > 0 && i % 16 == 0) - Serial.println(); - int v = file.read(); + json.set("Data" + String(i + 1), i + 5.5); - if (v < 16) - Serial.print("0"); + node = path + "/float"; - Serial.print(v, HEX); - Serial.print(" "); - i++; + if (Firebase.updateNode(fbdo, node.c_str(), json)) + { + Serial.println("PASSED"); + Serial.println("PATH: " + fbdo.dataPath()); + Serial.println("TYPE: " + fbdo.dataType()); + //No ETag is available + Serial.print("VALUE: "); + printResult(fbdo); //see addons/RTDBHelper.h + Serial.println("------------------------------------"); + Serial.println(); + } + else + { + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + Serial.println("------------------------------------"); + Serial.println(); + } } - Serial.println(); - file.close(); } - else - { - Serial.println(data.payload()); - } -} - -void loop() -{ } diff --git a/examples/Basic_with_cert/Basic_with_cert.ino b/examples/Basic_with_cert/Basic_with_cert.ino index 012eb272..90e7b0b8 100644 --- a/examples/Basic_with_cert/Basic_with_cert.ino +++ b/examples/Basic_with_cert/Basic_with_cert.ino @@ -10,48 +10,66 @@ * */ +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) #include #include +#endif +//Provide the token generation process info. +#include "addons/TokenHelper.h" +//Provide the RTDB payload printing info and other helper functions. +#include "addons/RTDBHelper.h" + +/* 1. Define the WiFi credentials */ #define WIFI_SSID "WIFI_AP" #define WIFI_PASSWORD "WIFI_PASSWORD" -#define FIREBASE_HOST "PROJECT_ID.firebaseio.com" - -/** The database secret is obsoleted, please use other authentication methods, - * see examples in the Authentications folder. -*/ -#define FIREBASE_AUTH "DATABASE_SECRET" - -const char CA_cert[] PROGMEM = "-----BEGIN CERTIFICATE-----\n" - "MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G\n" - "A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp\n" - "Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1\n" - "MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG\n" - "A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI\n" - "hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL\n" - "v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8\n" - "eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq\n" - "tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd\n" - "C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa\n" - "zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB\n" - "mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH\n" - "V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n\n" - "bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG\n" - "3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs\n" - "J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO\n" - "291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS\n" - "ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd\n" - "AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7\n" - "TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==\n" - "-----END CERTIFICATE-----\n"; - -//Define FirebaseESP8266 data object +/* 2. Define the API Key */ +#define API_KEY "API_KEY" + +/* 3. Define the RTDB URL */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app + +/* 4. Define the user Email and password that alreadey registerd or added in your project */ +#define USER_EMAIL "USER_EMAIL" +#define USER_PASSWORD "USER_PASSWORD" + +/* Google Root CA can be downloaded from https://pki.goog/repository/ */ +const char rootCACert[] PROGMEM = "-----BEGIN CERTIFICATE-----\n" + "MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G\n" + "A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp\n" + "Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1\n" + "MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG\n" + "A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI\n" + "hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL\n" + "v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8\n" + "eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq\n" + "tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd\n" + "C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa\n" + "zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB\n" + "mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH\n" + "V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n\n" + "bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG\n" + "3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs\n" + "J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO\n" + "291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS\n" + "ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd\n" + "AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7\n" + "TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==\n" + "-----END CERTIFICATE-----\n"; + +//Define Firebase Data object FirebaseData fbdo; -FirebaseJson json; +FirebaseAuth auth; +FirebaseConfig config; -void printResult(FirebaseData &data); +bool taskCompleted = false; + +FirebaseJson json; void setup() { @@ -70,31 +88,43 @@ void setup() Serial.println(WiFi.localIP()); Serial.println(); - //GMT time offset in hour is required to set time in order to make BearSSL data decryption/encryption to work. - //This parameter is only required in ESP8266 Core SDK v2 .5.x or later. - //Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH, root_ca, 9.3); - Serial.println("------------------------------------"); - Serial.println("Save the Firebase credentials and config the device time from NTP server..."); - Serial.println(); - Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH, CA_cert); + /* Assign the api key (required) */ + config.api_key = API_KEY; + + /* Assign the user sign in credentials */ + auth.user.email = USER_EMAIL; + auth.user.password = USER_PASSWORD; + + /* Assign the RTDB URL (required) */ + config.database_url = DATABASE_URL; + + /** + * In case using flash mem to keep the certificate files + * Upload the certificate files cert.pem and cert.der to flash memory. + * Use the following lines to set the certificate file. + * + * config.cert.file = "/gsr2.der"; or + * config.cert.file = "/gsr2.pem"; + * config.cert.file_storage = mem_storage_type_flash; //or mem_storage_type_sd + * + * ESP32 ssl_client class is alble to parse PEM certificate format. + * + * The file systems for flash and SD/SDMMC can be changed in FirebaseFS.h. + */ - //For Storage Type,don't assign number, use struct instead e.g. StorageType::FLASH or StorageType::SD + /* In case the certificate data was used */ + config.cert.data = rootCACert; - /* - //The following feature is for ESP8266 Arduino Core SDK v2.5.x. - - //To set root CA cert file, DER format (gsr2.pem in data folder) in this example, use this plugin to upload - //https://github.com/esp8266/arduino-esp8266fs-plugin - Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH, "/gsr2.pem",StorageType::FLASH); - - //or add gsr2.pem file to SD card - Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH, "/gsr2.pem",StorageType::SD); - - */ + /* Assign the callback function for the long running token generation task */ + config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h + + Firebase.begin(&config, &auth); Firebase.reconnectWiFi(true); +#if defined(ESP8266) //Set the size of WiFi rx/tx buffers in the case where we want to work with large data. fbdo.setBSSLBufferSize(1024, 1024); +#endif //Set the size of HTTP response buffers in the case where we want to work with large data. fbdo.setResponseSize(1024); @@ -113,276 +143,158 @@ void setup() This option allows get and delete functions (PUT and DELETE HTTP requests) works for device connected behind the Firewall that allows only GET and POST requests. - Firebase.enableClassicRequest(fbdo, true); + Firebase.enableClassicRequest(&fbdo, true); */ +} - String path = "/Test"; - - Serial.println("------------------------------------"); - Serial.println("Set double test..."); - - for (uint8_t i = 0; i < 10; i++) +void loop() +{ + if (Firebase.ready() && !taskCompleted) { - //Also can use Firebase.set instead of Firebase.setDouble - if (Firebase.setDouble(fbdo, path + "/Double/Data" + (i + 1), ((i + 1) * 10) + 0.123456789)) - { - Serial.println("PASSED"); - Serial.println("PATH: " + fbdo.dataPath()); - Serial.println("TYPE: " + fbdo.dataType()); - Serial.println("ETag: " + fbdo.ETag()); - Serial.print("VALUE: "); - printResult(fbdo); - Serial.println("------------------------------------"); - Serial.println(); - } - else - { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); - Serial.println("------------------------------------"); - Serial.println(); - } - } + taskCompleted = true; - Serial.println("------------------------------------"); - Serial.println("Get double test..."); + String path = "/Test"; + String node; - for (uint8_t i = 0; i < 10; i++) - { - //Also can use Firebase.get instead of Firebase.setInt - if (Firebase.getInt(fbdo, path + "/Double/Data" + (i + 1))) - { - Serial.println("PASSED"); - Serial.println("PATH: " + fbdo.dataPath()); - Serial.println("TYPE: " + fbdo.dataType()); - Serial.println("ETag: " + fbdo.ETag()); - Serial.print("VALUE: "); - printResult(fbdo); - Serial.println("------------------------------------"); - Serial.println(); - } - else - { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); - Serial.println("------------------------------------"); - Serial.println(); - } - } + Serial.println("------------------------------------"); + Serial.println("Set double test..."); - Serial.println("------------------------------------"); - Serial.println("Push integer test..."); - - for (uint8_t i = 0; i < 5; i++) - { - //Also can use Firebase.push instead of Firebase.pushInt - if (Firebase.pushInt(fbdo, path + "/Push/Int", (i + 1))) + for (uint8_t i = 0; i < 10; i++) { - Serial.println("PASSED"); - Serial.println("PATH: " + fbdo.dataPath()); - Serial.print("PUSH NAME: "); - Serial.println(fbdo.pushName()); - Serial.println("ETag: " + fbdo.ETag()); - Serial.println("------------------------------------"); - Serial.println(); - } - else - { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); - Serial.println("------------------------------------"); - Serial.println(); + node = path + "/Double/Data" + String(i + 1); + //Also can use Firebase.set instead of Firebase.setDouble + if (Firebase.setDouble(fbdo, node.c_str(), ((i + 1) * 10) + 0.123456789)) + { + Serial.println("PASSED"); + Serial.println("PATH: " + fbdo.dataPath()); + Serial.println("TYPE: " + fbdo.dataType()); + Serial.println("ETag: " + fbdo.ETag()); + Serial.print("VALUE: "); + printResult(fbdo); //see addons/RTDBHelper.h + Serial.println("------------------------------------"); + Serial.println(); + } + else + { + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + Serial.println("------------------------------------"); + Serial.println(); + } } - } - - Serial.println("------------------------------------"); - Serial.println("Push JSON test..."); - for (uint8_t i = 5; i < 10; i++) - { - - json.clear().add("Data" + String(i + 1), i + 1); + Serial.println("------------------------------------"); + Serial.println("Get double test..."); - //Also can use Firebase.push instead of Firebase.pushJSON - //Json string is not support in v 2.6.0 and later, only FirebaseJson object is supported. - if (Firebase.pushJSON(fbdo, path + "/Push/Int", json)) - { - Serial.println("PASSED"); - Serial.println("PATH: " + fbdo.dataPath()); - Serial.print("PUSH NAME: "); - Serial.println(fbdo.pushName()); - Serial.println("ETag: " + fbdo.ETag()); - Serial.println("------------------------------------"); - Serial.println(); - } - else + for (uint8_t i = 0; i < 10; i++) { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); - Serial.println("------------------------------------"); - Serial.println(); - } - } - - Serial.println("------------------------------------"); - Serial.println("Update test..."); - - for (uint8_t i = 0; i < 5; i++) - { - - json.set("Data" + String(i + 1), i + 5.5); - - if (Firebase.updateNode(fbdo, path + "/float", json)) - { - Serial.println("PASSED"); - Serial.println("PATH: " + fbdo.dataPath()); - Serial.println("TYPE: " + fbdo.dataType()); - //No ETag available - Serial.print("VALUE: "); - printResult(fbdo); - Serial.println("------------------------------------"); - Serial.println(); - } - else - { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); - Serial.println("------------------------------------"); - Serial.println(); + node = path + "/Double/Data" + String(i + 1); + //Also can use Firebase.get instead of Firebase.setInt + if (Firebase.getInt(fbdo, node.c_str())) + { + Serial.println("PASSED"); + Serial.println("PATH: " + fbdo.dataPath()); + Serial.println("TYPE: " + fbdo.dataType()); + Serial.println("ETag: " + fbdo.ETag()); + Serial.print("VALUE: "); + printResult(fbdo); //see addons/RTDBHelper.h + Serial.println("------------------------------------"); + Serial.println(); + } + else + { + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + Serial.println("------------------------------------"); + Serial.println(); + } } - } -} -void printResult(FirebaseData &data) -{ + Serial.println("------------------------------------"); + Serial.println("Push integer test..."); - if (data.dataType() == "int") - Serial.println(data.intData()); - else if (data.dataType() == "float") - Serial.println(data.floatData(), 5); - else if (data.dataType() == "double") - printf("%.9lf\n", data.doubleData()); - else if (data.dataType() == "boolean") - Serial.println(data.boolData() == 1 ? "true" : "false"); - else if (data.dataType() == "string") - Serial.println(data.stringData()); - else if (data.dataType() == "json") - { - Serial.println(); - FirebaseJson &json = data.jsonObject(); - //Print all object data - Serial.println("Pretty printed JSON data:"); - String jsonStr; - json.toString(jsonStr, true); - Serial.println(jsonStr); - Serial.println(); - Serial.println("Iterate JSON data:"); - Serial.println(); - size_t len = json.iteratorBegin(); - String key, value = ""; - int type = 0; - for (size_t i = 0; i < len; i++) + for (uint8_t i = 0; i < 5; i++) { - json.iteratorGet(i, type, key, value); - Serial.print(i); - Serial.print(", "); - Serial.print("Type: "); - Serial.print(type == FirebaseJson::JSON_OBJECT ? "object" : "array"); - if (type == FirebaseJson::JSON_OBJECT) + node = path + "/Push/Int"; + //Also can use Firebase.push instead of Firebase.pushInt + if (Firebase.pushInt(fbdo, node.c_str(), (i + 1))) { - Serial.print(", Key: "); - Serial.print(key); + Serial.println("PASSED"); + Serial.println("PATH: " + fbdo.dataPath()); + Serial.print("PUSH NAME: "); + Serial.println(fbdo.pushName()); + Serial.println("ETag: " + fbdo.ETag()); + Serial.println("------------------------------------"); + Serial.println(); + } + else + { + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + Serial.println("------------------------------------"); + Serial.println(); } - Serial.print(", Value: "); - Serial.println(value); - } - json.iteratorEnd(); - } - else if (data.dataType() == "array") - { - Serial.println(); - //get array data from FirebaseData using FirebaseJsonArray object - FirebaseJsonArray &arr = data.jsonArray(); - //Print all array values - Serial.println("Pretty printed Array:"); - String arrStr; - arr.toString(arrStr, true); - Serial.println(arrStr); - Serial.println(); - Serial.println("Iterate array values:"); - Serial.println(); - for (size_t i = 0; i < arr.size(); i++) - { - Serial.print(i); - Serial.print(", Value: "); - - FirebaseJsonData &jsonData = data.jsonData(); - //Get the result data from FirebaseJsonArray object - arr.get(jsonData, i); - if (jsonData.typeNum == FirebaseJson::JSON_BOOL) - Serial.println(jsonData.boolValue ? "true" : "false"); - else if (jsonData.typeNum == FirebaseJson::JSON_INT) - Serial.println(jsonData.intValue); - else if (jsonData.typeNum == FirebaseJson::JSON_FLOAT) - Serial.println(jsonData.floatValue); - else if (jsonData.typeNum == FirebaseJson::JSON_DOUBLE) - printf("%.9lf\n", jsonData.doubleValue); - else if (jsonData.typeNum == FirebaseJson::JSON_STRING || - jsonData.typeNum == FirebaseJson::JSON_NULL || - jsonData.typeNum == FirebaseJson::JSON_OBJECT || - jsonData.typeNum == FirebaseJson::JSON_ARRAY) - Serial.println(jsonData.stringValue); } - } - else if (data.dataType() == "blob") - { - Serial.println(); + Serial.println("------------------------------------"); + Serial.println("Push JSON test..."); - for (int i = 0; i < data.blobData().size(); i++) + for (uint8_t i = 5; i < 10; i++) { - if (i > 0 && i % 16 == 0) - Serial.println(); - if (i < 16) - Serial.print("0"); + json.clear().add("Data" + String(i + 1), i + 1); - Serial.print(data.blobData()[i], HEX); - Serial.print(" "); - } - Serial.println(); - } - else if (data.dataType() == "file") - { + node = path + "/Push/Int"; - Serial.println(); + //Also can use Firebase.push instead of Firebase.pushJSON + //Json string is not support in v 2.6.0 and later, only FirebaseJson object is supported. + if (Firebase.pushJSON(fbdo, node.c_str(), json)) + { + Serial.println("PASSED"); + Serial.println("PATH: " + fbdo.dataPath()); + Serial.print("PUSH NAME: "); + Serial.println(fbdo.pushName()); + Serial.println("ETag: " + fbdo.ETag()); + Serial.println("------------------------------------"); + Serial.println(); + } + else + { + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + Serial.println("------------------------------------"); + Serial.println(); + } + } - File file = data.fileStream(); - int i = 0; + Serial.println("------------------------------------"); + Serial.println("Update test..."); - while (file.available()) + for (uint8_t i = 0; i < 5; i++) { - if (i > 0 && i % 16 == 0) - Serial.println(); - int v = file.read(); + json.set("Data" + String(i + 1), i + 5.5); - if (v < 16) - Serial.print("0"); + node = path + "/float"; - Serial.print(v, HEX); - Serial.print(" "); - i++; + if (Firebase.updateNode(fbdo, node.c_str(), json)) + { + Serial.println("PASSED"); + Serial.println("PATH: " + fbdo.dataPath()); + Serial.println("TYPE: " + fbdo.dataType()); + //No ETag available + Serial.print("VALUE: "); + printResult(fbdo); //see addons/RTDBHelper.h + Serial.println("------------------------------------"); + Serial.println(); + } + else + { + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + Serial.println("------------------------------------"); + Serial.println(); + } } - Serial.println(); - file.close(); - } - else - { - Serial.println(data.payload()); } -} - -void loop() -{ -} +} \ No newline at end of file diff --git a/examples/Beginner_start_here/Beginner_start_here.ino b/examples/Beginner_start_here/Beginner_start_here.ino index 096fe274..3691b175 100644 --- a/examples/Beginner_start_here/Beginner_start_here.ino +++ b/examples/Beginner_start_here/Beginner_start_here.ino @@ -10,22 +10,41 @@ * */ -#include "FirebaseESP8266.h" -#include - - +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) #include #include +#endif -//1. Change the following info +//Provide the token generation process info. +#include "addons/TokenHelper.h" + +/* 1. Define the WiFi credentials */ #define WIFI_SSID "WIFI_AP" #define WIFI_PASSWORD "WIFI_PASSWORD" -#define FIREBASE_HOST "PROJECT_ID.firebaseio.com" -#define FIREBASE_AUTH "DATABASE_SECRET" -//2. Define FirebaseESP8266 data object for data sending and receiving +/* 2. Define the API Key */ +#define API_KEY "API_KEY" + +/* 3. Define the RTDB URL */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app + +/* 4. Define the user Email and password that alreadey registerd or added in your project */ +#define USER_EMAIL "USER_EMAIL" +#define USER_PASSWORD "USER_PASSWORD" + +/* 5. Define FirebaseESP8266 data object for data sending and receiving */ FirebaseData fbdo; +/* 6. Define the FirebaseAuth data for authentication data */ +FirebaseAuth auth; + +/* 7. Define the FirebaseConfig data for config data */ +FirebaseConfig config; + +bool taskCompleted = false; void setup() { @@ -44,47 +63,67 @@ void setup() Serial.println(WiFi.localIP()); Serial.println(); + /* 8. Assign the api key (required) */ + config.api_key = API_KEY; - //3. Set your Firebase info + /* 9. Assign the user sign in credentials */ + auth.user.email = USER_EMAIL; + auth.user.password = USER_PASSWORD; - Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH); + /* 10. Assign the RTDB URL (required) */ + config.database_url = DATABASE_URL; - //4. Enable auto reconnect the WiFi when connection lost - Firebase.reconnectWiFi(true); + /* 11. Assign the callback function for the long running token generation task */ + config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h - //5. Try to set int data to Firebase - //The set function returns bool for the status of operation - //fbdo requires for sending the data - if(Firebase.setInt(fbdo, "/LED_Status", 1)) - { - //Success - Serial.println("Set int data success"); - - }else{ - //Failed?, get the error reason from fbdo - - Serial.print("Error in setInt, "); - Serial.println(fbdo.errorReason()); - } + /* 12. Initialize the library with the autentication data */ + Firebase.begin(&config, &auth); + /* 13. Enable auto reconnect the WiFi when connection lost */ + Firebase.reconnectWiFi(true); +} - //6. Try to get int data from Firebase - //The get function returns bool for the status of operation - //fbdo requires for receiving the data - if(Firebase.getInt(fbdo, "/LED_Status")) +void loop() +{ + /* 14. Check the ready state of Firebase before calling other functions that related to data transfer */ + if (Firebase.ready() && !taskCompleted) { - //Success - Serial.print("Get int data success, int = "); - Serial.println(fbdo.intData()); + taskCompleted = true; + + /* 15. Try to set int data to Firebase */ + //The set function returns bool for the status of operation + //fbdo requires for sending the data and pass as the pointer + if (Firebase.setInt(fbdo, "/LED_Status", 1)) + { + //Success + Serial.println("Set int data success"); + } + else + { + //Failed?, get the error reason from fbdo - }else{ - //Failed?, get the error reason from fbdo + Serial.print("Error in setInt, "); + Serial.println(fbdo.errorReason()); + } - Serial.print("Error in getInt, "); - Serial.println(fbdo.errorReason()); - } + /* 16. Try to get int data from Firebase */ + //The get function returns bool for the status of operation + //fbdo requires for receiving the data + if (Firebase.getInt(fbdo, "/LED_Status")) + { + //Success + Serial.print("Get int data success, int = "); + Serial.println(fbdo.intData()); + } + else + { + //Failed?, get the error reason from fbdo - /* + Serial.print("Error in getInt, "); + Serial.println(fbdo.errorReason()); + } + + /* In case where you want to set other data types i.e. bool, float, double and String, you can use setBool, setFloat, setDouble and setString. If you want to get data which you known its type at specific node, use getInt, getBool, getFloat, getDouble, getString. @@ -94,44 +133,40 @@ void setup() */ - if(Firebase.get(fbdo, "/LED_Status")) - { - //Success - Serial.print("Get variant data success, type = "); - Serial.println(fbdo.dataType()); - - if(fbdo.dataType() == "int"){ - Serial.print("data = "); - Serial.println(fbdo.intData()); - }else if(fbdo.dataType() == "bool"){ - if(fbdo.boolData()) - Serial.println("data = true"); - else - Serial.println("data = false"); + if (Firebase.get(fbdo, "/LED_Status")) + { + //Success + Serial.print("Get variant data success, type = "); + Serial.println(fbdo.dataType()); + + if (fbdo.dataType() == "int") + { + Serial.print("data = "); + Serial.println(fbdo.intData()); + } + else if (fbdo.dataType() == "bool") + { + if (fbdo.boolData()) + Serial.println("data = true"); + else + Serial.println("data = false"); + } } + else + { + //Failed?, get the error reason from fbdo - }else{ - //Failed?, get the error reason from fbdo - - Serial.print("Error in get, "); - Serial.println(fbdo.errorReason()); - } + Serial.print("Error in get, "); + Serial.println(fbdo.errorReason()); + } - /* + /* If you want to get the data in realtime instead of using get, see the stream examples. If you want to work with JSON, see the FirebaseJson, jsonObject and jsonArray examples. - If you have questions or found the bugs, feel free to open the issue here https://github.com/mobizt/Firebase-ESP8266 + If you have questions or found the bugs, feel free to open the issue here https://github.com/mobizt/Firebase-ESP-Client */ - - - - -} - -void loop() -{ + } } - diff --git a/examples/Blob/Blob.ino b/examples/Blob/Blob.ino index 4b394db9..7f85c75f 100644 --- a/examples/Blob/Blob.ino +++ b/examples/Blob/Blob.ino @@ -11,22 +11,41 @@ //This example shows how to store and read binary data from memory to database. +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) #include #include +#endif +//Provide the token generation process info. +#include "addons/TokenHelper.h" +//Provide the RTDB payload printing info and other helper functions. +#include "addons/RTDBHelper.h" + +/* 1. Define the WiFi credentials */ #define WIFI_SSID "WIFI_AP" #define WIFI_PASSWORD "WIFI_PASSWORD" -#define FIREBASE_HOST "PROJECT_ID.firebaseio.com" +/* 2. Define the API Key */ +#define API_KEY "API_KEY" -/** The database secret is obsoleted, please use other authentication methods, - * see examples in the Authentications folder. -*/ -#define FIREBASE_AUTH "DATABASE_SECRET" +/* 3. Define the RTDB URL */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app + +/* 4. Define the user Email and password that alreadey registerd or added in your project */ +#define USER_EMAIL "USER_EMAIL" +#define USER_PASSWORD "USER_PASSWORD" //Define Firebase Data object FirebaseData fbdo; +FirebaseAuth auth; +FirebaseConfig config; + +bool taskCompleted = false; + String path = "/Test"; void setup() @@ -48,125 +67,124 @@ void setup() Serial.println(WiFi.localIP()); Serial.println(); - Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH); - Firebase.reconnectWiFi(true); - //Set the size of WiFi rx/tx buffers in the case where we want to work with large data. - fbdo.setBSSLBufferSize(1024, 1024); + /* Assign the api key (required) */ + config.api_key = API_KEY; - //Set the size of HTTP response buffers in the case where we want to work with large data. - fbdo.setResponseSize(1024); + /* Assign the user sign in credentials */ + auth.user.email = USER_EMAIL; + auth.user.password = USER_PASSWORD; + /* Assign the RTDB URL (required) */ + config.database_url = DATABASE_URL; + /* Assign the callback function for the long running token generation task */ + config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h - Serial.println("------------------------------------"); - Serial.println("Set BLOB data test..."); + Firebase.begin(&config, &auth); + Firebase.reconnectWiFi(true); - //Create demo data - uint8_t data[256]; - for (int i = 0; i < 256; i++) - data[i] = i; +#if defined(ESP8266) + //Set the size of WiFi rx/tx buffers in the case where we want to work with large data. + fbdo.setBSSLBufferSize(1024, 1024); +#endif + //Set the size of HTTP response buffers in the case where we want to work with large data. + fbdo.setResponseSize(1024); +} - //Set binary data to database (also can use Firebase.set) - if (Firebase.setBlob(fbdo, path + "/Binary/Blob/data", data, sizeof(data))) - { - Serial.println("PASSED"); - Serial.println("------------------------------------"); - Serial.println(); - } - else +void loop() +{ + if (Firebase.ready() && !taskCompleted) { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); + taskCompleted = true; + Serial.println("------------------------------------"); - Serial.println(); - } + Serial.println("Set BLOB data test..."); - Serial.println("------------------------------------"); - Serial.println("Get BLOB data test..."); + //Create demo data + uint8_t data[256]; + for (int i = 0; i < 256; i++) + data[i] = i; - //Get binary data from database (also can use Firebase.get) - if (Firebase.getBlob(fbdo, path + "/Binary/Blob/data")) - { - Serial.println("PASSED"); - Serial.println("PATH: " + fbdo.dataPath()); - Serial.println("TYPE: " + fbdo.dataType()); - Serial.print("VALUE: "); - if (fbdo.dataType() == "blob") + String Path = path + "/Binary/Blob/data"; + //Set binary data to database (also can use Firebase.set) + if (Firebase.setBlob(fbdo, Path.c_str(), data, sizeof(data))) { - - std::vector blob = fbdo.blobData(); - + Serial.println("PASSED"); + Serial.println("------------------------------------"); Serial.println(); - - for (size_t i = 0; i < blob.size(); i++) - { - if (i > 0 && i % 16 == 0) - Serial.println(); - - if (blob[i] < 16) - Serial.print("0"); - - Serial.print(blob[i], HEX); - Serial.print(" "); - } + } + else + { + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + Serial.println("------------------------------------"); Serial.println(); } - Serial.println("------------------------------------"); - Serial.println(); - } - else - { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); - Serial.println("------------------------------------"); - Serial.println(); - } - Serial.println("------------------------------------"); - Serial.println("Append BLOB data test..."); + Serial.println("------------------------------------"); + Serial.println("Get BLOB data test..."); - //Create demo data - for (int i = 0; i < 256; i++) - data[i] = 255 - i; + //Get binary data from database (also can use Firebase.get) + if (Firebase.getBlob(fbdo, Path.c_str())) + { + Serial.println("PASSED"); + Serial.println("PATH: " + fbdo.dataPath()); + Serial.println("TYPE: " + fbdo.dataType()); + Serial.print("VALUE: "); + printResult(fbdo); //see addons/RTDBHelper.h + Serial.println("------------------------------------"); + Serial.println(); + } + else + { + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + Serial.println("------------------------------------"); + Serial.println(); + } - //Append binary data to database (also can use Firebase.push) - if (Firebase.pushBlob(fbdo, path + "/Binary/Blob/Logs", data, sizeof(data))) - { - Serial.println("PASSED"); - Serial.println("PATH: " + fbdo.dataPath()); - Serial.println("PUSH NAME: " + fbdo.pushName()); Serial.println("------------------------------------"); - Serial.println(); + Serial.println("Append BLOB data test..."); - Serial.println("------------------------------------"); - Serial.println("Get appended BLOB data test..."); + //Create demo data + for (int i = 0; i < 256; i++) + data[i] = 255 - i; + + Path = path + "/Binary/Blob/Logs"; - //Get appended binary data from database (also can use Firebase.get) - if (Firebase.getBlob(fbdo, path + "/Binary/Blob/Logs/" + fbdo.pushName())) + //Append binary data to database (also can use Firebase.push) + if (Firebase.pushBlob(fbdo, Path.c_str(), data, sizeof(data))) { Serial.println("PASSED"); Serial.println("PATH: " + fbdo.dataPath()); - Serial.println("TYPE: " + fbdo.dataType()); - Serial.print("VALUE: "); - if (fbdo.dataType() == "blob") - { + Serial.println("PUSH NAME: " + fbdo.pushName()); + Serial.println("------------------------------------"); + Serial.println(); - std::vector blob = fbdo.blobData(); + Serial.println("------------------------------------"); + Serial.println("Get appended BLOB data test..."); + + Path = path + "/Binary/Blob/Logs/" + fbdo.pushName(); + + //Get appended binary data from database (also can use Firebase.get) + if (Firebase.getBlob(fbdo, Path.c_str())) + { + Serial.println("PASSED"); + Serial.println("PATH: " + fbdo.dataPath()); + Serial.println("TYPE: " + fbdo.dataType()); + Serial.print("VALUE: "); + printResult(fbdo); //see addons/RTDBHelper.h + Serial.println("------------------------------------"); Serial.println(); - for (size_t i = 0; i < blob.size(); i++) - { - if (i > 0 && i % 16 == 0) - Serial.println(); - if (blob[i] < 16) - Serial.print("0"); - Serial.print(blob[i], HEX); - Serial.print(" "); - } + } + else + { + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + Serial.println("------------------------------------"); Serial.println(); } - Serial.println("------------------------------------"); - Serial.println(); } else { @@ -176,15 +194,4 @@ void setup() Serial.println(); } } - else - { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); - Serial.println("------------------------------------"); - Serial.println(); - } -} - -void loop() -{ } diff --git a/examples/Blynk/Blynk.ino b/examples/Blynk/Blynk.ino index 72e0778e..3f677d67 100644 --- a/examples/Blynk/Blynk.ino +++ b/examples/Blynk/Blynk.ino @@ -11,53 +11,62 @@ //This example shows the basic usage of Blynk platform and Firebase RTDB. +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) #include #include +#endif +//Provide the token generation process info. +#include "addons/TokenHelper.h" +//Provide the RTDB payload printing info and other helper functions. +#include "addons/RTDBHelper.h" + +#include + +/* 1. Define the WiFi credentials */ #define WIFI_SSID "WIFI_AP" #define WIFI_PASSWORD "WIFI_PASSWORD" -#define FIREBASE_HOST "PROJECT_ID.firebaseio.com" +/* 2. Define the API Key */ +#define API_KEY "API_KEY" -/** The database secret is obsoleted, please use other authentication methods, - * see examples in the Authentications folder. -*/ -#define FIREBASE_AUTH "DATABASE_SECRET" +/* 3. Define the RTDB URL */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app -//Debug Blynk to serial port -#define BLYNK_PRINT Serial +/* 4. Define the user Email and password that alreadey registerd or added in your project */ +#define USER_EMAIL "USER_EMAIL" +#define USER_PASSWORD "USER_PASSWORD" -#include -#include - -//Auth token for your Blynk app project -#define BLYNK_AUTH "YOUR_BLYNK_APP_PROJECT_AUTH_TOKEN" - -//Define FirebaseESP8266 data objects +//Define Firebase Data object FirebaseData fbdo1; FirebaseData fbdo2; +FirebaseAuth auth; +FirebaseConfig config; + +//Debug Blynk to serial port +#define BLYNK_PRINT Serial +//Auth token for your Blynk app project +#define BLYNK_AUTH "YOUR_BLYNK_APP_PROJECT_AUTH_TOKEN" String path = "/Blynk_Test/Int"; //D4 or GPIO2 on Wemos D1 mini uint8_t BuiltIn_LED = 2; - -/* - -Blynk app Widget setup -********************** - -1. Button Widget (Switch type), Output -> Virtual pin V1 -2. LED Widget, Input -> Virtual pin V2 - +/** + * Blynk app Widget setup + * ********************** + * + * 1. Button Widget (Switch type), Output -> Virtual pin V1 + * 2. LED Widget, Input -> Virtual pin V2 */ WidgetLED led(V2); - - void setup() { @@ -77,23 +86,39 @@ void setup() Serial.println(WiFi.localIP()); Serial.println(); - Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH); + /* Assign the api key (required) */ + config.api_key = API_KEY; + + /* Assign the user sign in credentials */ + auth.user.email = USER_EMAIL; + auth.user.password = USER_PASSWORD; + + /* Assign the RTDB URL (required) */ + config.database_url = DATABASE_URL; + + /* Assign the callback function for the long running token generation task */ + config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h + + Firebase.begin(&config, &auth); Firebase.reconnectWiFi(true); +#if defined(ESP8266) //Set the size of WiFi rx/tx buffers in the case where we want to work with large data. fbdo1.setBSSLBufferSize(1024, 1024); +#endif //Set the size of HTTP response buffers in the case where we want to work with large data. fbdo1.setResponseSize(1024); +#if defined(ESP8266) //Set the size of WiFi rx/tx buffers in the case where we want to work with large data. fbdo2.setBSSLBufferSize(1024, 1024); +#endif //Set the size of HTTP response buffers in the case where we want to work with large data. fbdo2.setResponseSize(1024); - - if (!Firebase.beginStream(fbdo1, path)) + if (!Firebase.beginStream(fbdo1, path.c_str())) { Serial.println("------------------------------------"); Serial.println("Can't begin stream connection..."); @@ -109,47 +134,50 @@ void loop() { Blynk.run(); - if (!Firebase.readStream(fbdo1)) + if (Firebase.ready()) { - Serial.println("------------------------------------"); - Serial.println("Can't read stream data..."); - Serial.println("REASON: " + fbdo1.errorReason()); - Serial.println("------------------------------------"); - Serial.println(); - } - - if (fbdo1.streamTimeout()) - { - Serial.println("Stream timeout, resume streaming..."); - Serial.println(); - } + if (!Firebase.readStream(fbdo1)) + { + Serial.println("------------------------------------"); + Serial.println("Can't read stream data..."); + Serial.println("REASON: " + fbdo1.errorReason()); + Serial.println("------------------------------------"); + Serial.println(); + } - if (fbdo1.streamAvailable()) - { - Serial.println("------------------------------------"); - Serial.println("Stream Data available..."); - Serial.println("STREAM PATH: " + fbdo1.streamPath()); - Serial.println("EVENT PATH: " + fbdo1.dataPath()); - Serial.println("DATA TYPE: " + fbdo1.dataType()); - Serial.println("EVENT TYPE: " + fbdo1.eventType()); - Serial.print("VALUE: "); - if (fbdo1.dataType() == "int") + if (fbdo1.streamTimeout()) { + Serial.println("Stream timeout, resume streaming..."); + Serial.println(); + } - Serial.println(fbdo1.intData()); - if (fbdo1.intData() == 0) - { - digitalWrite(BuiltIn_LED, LOW); - led.off(); - } - else if (fbdo1.intData() == 1) + if (fbdo1.streamAvailable()) + { + Serial.println("------------------------------------"); + Serial.println("Stream Data available..."); + Serial.println("STREAM PATH: " + fbdo1.streamPath()); + Serial.println("EVENT PATH: " + fbdo1.dataPath()); + Serial.println("DATA TYPE: " + fbdo1.dataType()); + Serial.println("EVENT TYPE: " + fbdo1.eventType()); + Serial.print("VALUE: "); + if (fbdo1.dataType() == "int") { - digitalWrite(BuiltIn_LED, HIGH); - led.on(); + + Serial.println(fbdo1.intData()); + if (fbdo1.intData() == 0) + { + digitalWrite(BuiltIn_LED, LOW); + led.off(); + } + else if (fbdo1.intData() == 1) + { + digitalWrite(BuiltIn_LED, HIGH); + led.on(); + } } + Serial.println("------------------------------------"); + Serial.println(); } - Serial.println("------------------------------------"); - Serial.println(); } } @@ -160,7 +188,7 @@ BLYNK_WRITE(V1) Serial.println("------------------------------------"); Serial.println("Set integer..."); //Also can use Firebase.set instead of Firebase.setInt - if (Firebase.setInt(fbdo2, path, pinValue)) + if (Firebase.setInt(fbdo2, path.c_str(), pinValue)) { Serial.println("PASSED"); Serial.println("PATH: " + fbdo2.dataPath()); @@ -179,4 +207,3 @@ BLYNK_WRITE(V1) Serial.println(); } } - diff --git a/examples/Cloud_Messaging/Cloud_Messaging.ino b/examples/Cloud_Messaging/Cloud_Messaging.ino index af2cfd28..87354e47 100644 --- a/examples/Cloud_Messaging/Cloud_Messaging.ino +++ b/examples/Cloud_Messaging/Cloud_Messaging.ino @@ -11,19 +11,17 @@ //This example shows how to send Firebase Cloud Messaging. +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) #include #include +#endif #define WIFI_SSID "WIFI_AP" #define WIFI_PASSWORD "WIFI_PASSWORD" -#define FIREBASE_HOST "PROJECT_ID.firebaseio.com" - -/** The database secret is obsoleted, please use other authentication methods, - * see examples in the Authentications folder. -*/ -#define FIREBASE_AUTH "DATABASE_SECRET" - #define FIREBASE_FCM_SERVER_KEY "FIREBASE_PROJECT_CLOUD_MESSAGING_SERVER_KEY" #define FIREBASE_FCM_DEVICE_TOKEN_1 "RECIPIENT_DEVICE_TOKEN" #define FIREBASE_FCM_DEVICE_TOKEN_2 "ANOTHER_RECIPIENT_DEVICE_TOKEN" @@ -53,7 +51,6 @@ void setup() Serial.println(WiFi.localIP()); Serial.println(); - Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH); Firebase.reconnectWiFi(true); //Set the size of WiFi rx/tx buffers in the case where we want to work with large data. diff --git a/examples/Data_filter/Data_filter.ino b/examples/Data_filter/Data_filter.ino index b9681a8f..123f0a1c 100644 --- a/examples/Data_filter/Data_filter.ino +++ b/examples/Data_filter/Data_filter.ino @@ -11,26 +11,45 @@ //This example shows how to construct queries to filter data. +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) #include #include +#endif +//Provide the token generation process info. +#include "addons/TokenHelper.h" +//Provide the RTDB payload printing info and other helper functions. +#include "addons/RTDBHelper.h" + +/* 1. Define the WiFi credentials */ #define WIFI_SSID "WIFI_AP" #define WIFI_PASSWORD "WIFI_PASSWORD" -#define FIREBASE_HOST "PROJECT_ID.firebaseio.com" +/* 2. Define the API Key */ +#define API_KEY "API_KEY" -/** The database secret is obsoleted, please use other authentication methods, - * see examples in the Authentications folder. -*/ -#define FIREBASE_AUTH "DATABASE_SECRET" +/* 3. Define the RTDB URL */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app + +/* 4. Define the user Email and password that alreadey registerd or added in your project */ +#define USER_EMAIL "USER_EMAIL" +#define USER_PASSWORD "USER_PASSWORD" -//Define the Firebase Data object +/* This database secret required in this example to get the righs access to database rules */ +#define DATABASE_SECRET "DATABASE_SECRET" + +//Define Firebase Data object FirebaseData fbdo; -FirebaseJson json; +FirebaseAuth auth; +FirebaseConfig config; -void printResult(FirebaseData &data); -void updateDatabaseRules(FirebaseData &dataObj); +bool taskCompleted = false; + +FirebaseJson json; void setup() { @@ -51,209 +70,103 @@ void setup() Serial.println(WiFi.localIP()); Serial.println(); - Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH); - Firebase.reconnectWiFi(true); + /* Assign the api key (required) */ + config.api_key = API_KEY; + + /* Assign the user sign in credentials */ + auth.user.email = USER_EMAIL; + auth.user.password = USER_PASSWORD; + /* Assign the RTDB URL (required) */ + config.database_url = DATABASE_URL; - //Set the size of WiFi rx/tx buffers in the case where we want to work with large data in this example. + /* Assign the callback function for the long running token generation task */ + config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h + + Firebase.begin(&config, &auth); + Firebase.reconnectWiFi(true); + +#if defined(ESP8266) + //Set the size of WiFi rx/tx buffers in the case where we want to work with large data. fbdo.setBSSLBufferSize(1024, 1024); +#endif //Set the size of HTTP response buffers in the case where we want to work with large data in this example. fbdo.setResponseSize(1024); +} - Serial.println("------------------------------------"); - Serial.println("Push JSON test..."); - - for (uint8_t i = 0; i < 30; i++) +void loop() +{ + if (Firebase.ready() && !taskCompleted) { - json.set("Data1",i + 1); - json.set("Data2",i + 100); + taskCompleted = true; - //Also can use Firebase.push instead of Firebase.pushJSON - //JSON string does not support in v 2.6.0 and later, only FirebaseJson object is supported. - if (Firebase.pushJSON(fbdo, "/Test/Int", json)) - { - Serial.println("PASSED"); - Serial.println("PATH: " + fbdo.dataPath()); - Serial.print("PUSH NAME: "); - Serial.println(fbdo.pushName()); - Serial.println("------------------------------------"); - Serial.println(); - } - else + Serial.println("------------------------------------"); + Serial.println("Push JSON test..."); + + for (uint8_t i = 0; i < 30; i++) { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); - Serial.println("------------------------------------"); - Serial.println(); + json.set("Data1", i + 1); + json.set("Data2", i + 100); + + //Also can use Firebase.push instead of Firebase.pushJSON + //JSON string does not support in v 2.6.0 and later, only FirebaseJson object is supported. + if (Firebase.pushJSON(fbdo, "/Test/Int", json)) + { + Serial.println("PASSED"); + Serial.println("PATH: " + fbdo.dataPath()); + Serial.print("PUSH NAME: "); + Serial.println(fbdo.pushName()); + Serial.println("------------------------------------"); + Serial.println(); + } + else + { + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + Serial.println("------------------------------------"); + Serial.println(); + } } - } - //Add an index to the node that being query. - //Update the existing database rules by adding key "Test/Int/.indexOn" and value "Data2" - //Check your database rules changes after running this function. - updateDatabaseRules(fbdo); + //Add an index to the node that being query. + //Update the existing database rules by adding key "Test/Int/.indexOn" and value "Data2" + //Check your database rules changes after running this function. - QueryFilter query; + /** If the authentication type is OAuth2.0 which allows the admin right access, + * the database secret is not necessary by set this parameter with empty string "". + */ + Firebase.setQueryIndex(fbdo, "Test/Int", "Data2", DATABASE_SECRET); - query.orderBy("Data2"); - query.startAt(105); - query.endAt(120); - query.limitToLast(8); + QueryFilter query; - - //Begin the data filtering test - Serial.println("------------------------------------"); - Serial.println("Data Filtering test..."); + query.orderBy("Data2"); + query.startAt(105); + query.endAt(120); + query.limitToLast(8); - if (Firebase.getJSON(fbdo, "/Test/Int", query)) - { - - Serial.println("PASSED"); - Serial.println("JSON DATA: "); - printResult(fbdo); - Serial.println("------------------------------------"); - Serial.println(); - } - else - { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); + //Begin the data filtering test Serial.println("------------------------------------"); - Serial.println(); - } - - //Clear all query parameters - query.clear(); -} - -void printResult(FirebaseData &data) -{ + Serial.println("Data Filtering test..."); - if (data.dataType() == "int") - Serial.println(data.intData()); - else if (data.dataType() == "float") - Serial.println(data.floatData(), 5); - else if (data.dataType() == "double") - printf("%.9lf\n", data.doubleData()); - else if (data.dataType() == "boolean") - Serial.println(data.boolData() == 1 ? "true" : "false"); - else if (data.dataType() == "string") - Serial.println(data.stringData()); - else if (data.dataType() == "json") - { - Serial.println(); - FirebaseJson &json = data.jsonObject(); - //Print all object data - Serial.println("Pretty printed JSON data:"); - String jsonStr; - json.toString(jsonStr,true); - Serial.println(jsonStr); - Serial.println(); - Serial.println("Iterate JSON data:"); - Serial.println(); - size_t len = json.iteratorBegin(); - String key, value = ""; - int type = 0; - for (size_t i = 0; i < len; i++) - { - json.iteratorGet(i, type, key, value); - Serial.print(i); - Serial.print(", "); - Serial.print("Type: "); - Serial.print(type == FirebaseJson::JSON_OBJECT ? "object" : "array"); - if (type == FirebaseJson::JSON_OBJECT) - { - Serial.print(", Key: "); - Serial.print(key); - } - Serial.print(", Value: "); - Serial.println(value); - } - json.iteratorEnd(); - } - else if (data.dataType() == "array") + if (Firebase.getJSON(fbdo, "/Test/Int", query)) { - Serial.println(); - //get the array data from FirebaseData using FirebaseJsonArray object - FirebaseJsonArray &arr = data.jsonArray(); - //Print all array values - Serial.println("Pretty printed Array:"); - String arrStr; - arr.toString(arrStr,true); - Serial.println(arrStr); - Serial.println(); - Serial.println("Iterate array values:"); - Serial.println(); - for (size_t i = 0; i < arr.size(); i++) - { - Serial.print(i); - Serial.print(", Value: "); - - FirebaseJsonData &jsonData = data.jsonData(); - //Get the result data from FirebaseJsonArray object - arr.get(jsonData, i); - if (jsonData.typeNum == FirebaseJson::JSON_BOOL) - Serial.println(jsonData.boolValue ? "true" : "false"); - else if (jsonData.typeNum == FirebaseJson::JSON_INT) - Serial.println(jsonData.intValue); - else if (jsonData.typeNum == FirebaseJson::JSON_FLOAT) - Serial.println(jsonData.floatValue); - else if (jsonData.typeNum == FirebaseJson::JSON_DOUBLE) - printf("%.9lf\n", jsonData.doubleValue); - else if (jsonData.typeNum == FirebaseJson::JSON_STRING || - jsonData.typeNum == FirebaseJson::JSON_NULL || - jsonData.typeNum == FirebaseJson::JSON_OBJECT || - jsonData.typeNum == FirebaseJson::JSON_ARRAY) - Serial.println(jsonData.stringValue); - } - } - else - { - Serial.println(data.payload()); - } -} -void loop() -{ -} - -void updateDatabaseRules(FirebaseData &dataObj) -{ - - String path = "rules/Test/Int/.indexOn"; - //Read all database rules. - if (Firebase.getRules(dataObj)) - { - FirebaseJsonData jdata; - FirebaseJson &json = dataObj.jsonObject(); - bool flag = false; - bool update = false; - - //Check for the existent of the defined path - if (!json.get(jdata, path)) - flag = true; - else if (jdata.stringValue != "Data2") - flag = true; - - //If the defined path does not exist - if (flag) - { - //Add new data to "rules/Test/Int/.indexOn" - json.set(path, "Data2"); - update = true; + Serial.println("PASSED"); + Serial.println("JSON DATA: "); + printResult(fbdo); //see addons/RTDBHelper.h + Serial.println("------------------------------------"); + Serial.println(); } - - if (update) + else { - //Update the database rules - String rules = ""; - json.toString(rules, true); - Firebase.setRules(dataObj, rules); + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + Serial.println("------------------------------------"); + Serial.println(); } - json.clear(); + //Clear all query parameters + query.clear(); } - } - diff --git a/examples/Different_objects_stream/Different_objects_stream.ino b/examples/Different_objects_stream/Different_objects_stream.ino index ec07a866..aad5911e 100644 --- a/examples/Different_objects_stream/Different_objects_stream.ino +++ b/examples/Different_objects_stream/Different_objects_stream.ino @@ -9,32 +9,46 @@ * */ +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) #include #include +#endif +//Provide the token generation process info. +#include "addons/TokenHelper.h" +//Provide the RTDB payload printing info and other helper functions. +#include "addons/RTDBHelper.h" + +/* 1. Define the WiFi credentials */ #define WIFI_SSID "WIFI_AP" #define WIFI_PASSWORD "WIFI_PASSWORD" -#define FIREBASE_HOST "PROJECT_ID.firebaseio.com" +/* 2. Define the API Key */ +#define API_KEY "API_KEY" -/** The database secret is obsoleted, please use other authentication methods, - * see examples in the Authentications folder. -*/ -#define FIREBASE_AUTH "DATABASE_SECRET" +/* 3. Define the RTDB URL */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app + +/* 4. Define the user Email and password that alreadey registerd or added in your project */ +#define USER_EMAIL "USER_EMAIL" +#define USER_PASSWORD "USER_PASSWORD" //Define Firebase Data objects FirebaseData fbdo1; FirebaseData fbdo2; +FirebaseAuth auth; +FirebaseConfig config; + unsigned long sendDataPrevMillis1; uint16_t count1; - String path = ""; -void printResult(FirebaseData &data); - void setup() { @@ -54,24 +68,42 @@ void setup() Serial.println(WiFi.localIP()); Serial.println(); - Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH); + /* Assign the api key (required) */ + config.api_key = API_KEY; + + /* Assign the user sign in credentials */ + auth.user.email = USER_EMAIL; + auth.user.password = USER_PASSWORD; + + /* Assign the RTDB URL (required) */ + config.database_url = DATABASE_URL; + + /* Assign the callback function for the long running token generation task */ + config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h + + Firebase.begin(&config, &auth); Firebase.reconnectWiFi(true); +#if defined(ESP8266) //Set the size of WiFi rx/tx buffers in the case where we want to work with large data. fbdo1.setBSSLBufferSize(1024, 1024); +#endif //Set the size of HTTP response buffers in the case where we want to work with large data. fbdo1.setResponseSize(1024); +#if defined(ESP8266) //Set the size of WiFi rx/tx buffers in the case where we want to work with large data. fbdo2.setBSSLBufferSize(1024, 1024); +#endif //Set the size of HTTP response buffers in the case where we want to work with large data. fbdo2.setResponseSize(1024); Serial.println("------------------------------------"); Serial.println("Begin stream 1..."); - if (!Firebase.beginStream(fbdo2, path + "/Stream/data1")) + String node = path + "/Stream/data1"; + if (!Firebase.beginStream(fbdo2, node.c_str())) { Serial.println("FAILED"); Serial.println("REASON: " + fbdo2.errorReason()); @@ -88,6 +120,9 @@ void setup() void loop() { + if (!Firebase.ready()) + return; + if (!Firebase.readStream(fbdo2)) { Serial.println("Can't read stream data"); @@ -110,27 +145,7 @@ void loop() Serial.println("DATA TYPE: " + fbdo2.dataType()); Serial.println("EVENT TYPE: " + fbdo2.eventType()); Serial.print("VALUE: "); - printResult(fbdo2); - if (fbdo2.dataType() == "blob") - { - std::vector blob = fbdo2.blobData(); - - Serial.println(); - - for (int i = 0; i < blob.size(); i++) - { - if (i > 0 && i % 16 == 0) - Serial.println(); - - if (i < 16) - Serial.print("0"); - - Serial.print(blob[i], HEX); - Serial.print(" "); - } - Serial.println(); - - } + printResult(fbdo2); //see addons/RTDBHelper.h Serial.println("------------------------------------"); Serial.println(); } @@ -147,7 +162,8 @@ void loop() Serial.println("------------------------------------"); Serial.println("Set Blob Data 1..."); - if (Firebase.setBlob(fbdo1, path + "/Stream/data1", data, sizeof(data))) + String Path = path + "/Stream/data1"; + if (Firebase.setBlob(fbdo1, Path.c_str(), data, sizeof(data))) { Serial.println("PASSED"); Serial.println("------------------------------------"); @@ -162,16 +178,17 @@ void loop() } FirebaseJson json; - json.add("data1-1",count1).add("data1-2",count1 + 1).add("data1-3",count1 + 2); + json.add("data1-1", count1).add("data1-2", count1 + 1).add("data1-3", count1 + 2); Serial.println("------------------------------------"); Serial.println("Update Data 1..."); - if (Firebase.updateNode(fbdo1, path + "/Stream/data1", json)) + Path = path + "/Stream/data1"; + if (Firebase.updateNode(fbdo1, Path.c_str(), json)) { Serial.println("PASSED"); Serial.println("PATH: " + fbdo1.dataPath()); Serial.println("TYPE: " + fbdo1.dataType()); Serial.print("VALUE: "); - printResult(fbdo1); + printResult(fbdo1); //see addons/RTDBHelper.h Serial.println("------------------------------------"); Serial.println(); } @@ -187,96 +204,6 @@ void loop() Serial.println(ESP.getFreeHeap()); Serial.println(); - count1+=3; + count1 += 3; } - - -} - -void printResult(FirebaseData &data) -{ - - if (data.dataType() == "int") - Serial.println(data.intData()); - else if (data.dataType() == "float") - Serial.println(data.floatData(), 5); - else if (data.dataType() == "double") - printf("%.9lf\n", data.doubleData()); - else if (data.dataType() == "boolean") - Serial.println(data.boolData() == 1 ? "true" : "false"); - else if (data.dataType() == "string") - Serial.println(data.stringData()); - else if (data.dataType() == "json") - { - Serial.println(); - FirebaseJson &json = data.jsonObject(); - //Print all object data - Serial.println("Pretty printed JSON data:"); - String jsonStr; - json.toString(jsonStr,true); - Serial.println(jsonStr); - Serial.println(); - Serial.println("Iterate JSON data:"); - Serial.println(); - size_t len = json.iteratorBegin(); - String key, value = ""; - int type = 0; - for (size_t i = 0; i < len; i++) - { - json.iteratorGet(i, type, key, value); - Serial.print(i); - Serial.print(", "); - Serial.print("Type: "); - Serial.print(type == FirebaseJson::JSON_OBJECT ? "object" : "array"); - if (type == FirebaseJson::JSON_OBJECT) - { - Serial.print(", Key: "); - Serial.print(key); - } - Serial.print(", Value: "); - Serial.println(value); - } - json.iteratorEnd(); - } - else if (data.dataType() == "array") - { - Serial.println(); - //get array data from FirebaseData using FirebaseJsonArray object - FirebaseJsonArray &arr = data.jsonArray(); - //Print all array values - Serial.println("Pretty printed Array:"); - String arrStr; - arr.toString(arrStr,true); - Serial.println(arrStr); - Serial.println(); - Serial.println("Iterate array values:"); - Serial.println(); - for (size_t i = 0; i < arr.size(); i++) - { - Serial.print(i); - Serial.print(", Value: "); - - FirebaseJsonData &jsonData = data.jsonData(); - //Get the result data from FirebaseJsonArray object - arr.get(jsonData, i); - if (jsonData.typeNum == FirebaseJson::JSON_BOOL) - Serial.println(jsonData.boolValue ? "true" : "false"); - else if (jsonData.typeNum == FirebaseJson::JSON_INT) - Serial.println(jsonData.intValue); - else if (jsonData.typeNum == FirebaseJson::JSON_FLOAT) - Serial.println(jsonData.floatValue); - else if (jsonData.typeNum == FirebaseJson::JSON_DOUBLE) - printf("%.9lf\n", jsonData.doubleValue); - else if (jsonData.typeNum == FirebaseJson::JSON_STRING || - jsonData.typeNum == FirebaseJson::JSON_NULL || - jsonData.typeNum == FirebaseJson::JSON_OBJECT || - jsonData.typeNum == FirebaseJson::JSON_ARRAY) - Serial.println(jsonData.stringValue); - } - } - else - { - Serial.println(data.payload()); - } } - diff --git a/examples/Dynamic_FirebaseData/Dynamic_FirebasseData.ino b/examples/Dynamic_FirebaseData/Dynamic_FirebasseData.ino index b1f51a06..a591ed75 100644 --- a/examples/Dynamic_FirebaseData/Dynamic_FirebasseData.ino +++ b/examples/Dynamic_FirebaseData/Dynamic_FirebasseData.ino @@ -12,18 +12,35 @@ //This example shows how to dynamic allocated the Firebase Data object and deallocated it for release the memory when no further use. +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) #include #include +#endif +//Provide the token generation process info. +#include "addons/TokenHelper.h" +//Provide the RTDB payload printing info and other helper functions. +#include "addons/RTDBHelper.h" + +/* 1. Define the WiFi credentials */ #define WIFI_SSID "WIFI_AP" #define WIFI_PASSWORD "WIFI_PASSWORD" -#define FIREBASE_HOST "PROJECT_ID.firebaseio.com" +/* 2. Define the API Key */ +#define API_KEY "API_KEY" -/** The database secret is obsoleted, please use other authentication methods, - * see examples in the Authentications folder. -*/ -#define FIREBASE_AUTH "DATABASE_SECRET" +/* 3. Define the RTDB URL */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app + +/* 4. Define the user Email and password that alreadey registerd or added in your project */ +#define USER_EMAIL "USER_EMAIL" +#define USER_PASSWORD "USER_PASSWORD" + +FirebaseAuth auth; +FirebaseConfig config; //Define FirebaseESP8266 data object FirebaseData *fbdo1 = new FirebaseData(); @@ -37,9 +54,6 @@ int count = 0; bool deallocated = false; -void printResult(FirebaseData &data); -void printResult(StreamData &data); - void streamCallback(StreamData data) { @@ -49,7 +63,7 @@ void streamCallback(StreamData data) Serial.println("DATA TYPE: " + data.dataType()); Serial.println("EVENT TYPE: " + data.eventType()); Serial.print("VALUE: "); - printResult(data); + printResult(data); //see addons/RTDBHelper.h Serial.println(); } @@ -80,22 +94,39 @@ void setup() Serial.println(WiFi.localIP()); Serial.println(); - Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH); + /* Assign the api key (required) */ + config.api_key = API_KEY; + + /* Assign the user sign in credentials */ + auth.user.email = USER_EMAIL; + auth.user.password = USER_PASSWORD; + + /* Assign the RTDB URL (required) */ + config.database_url = DATABASE_URL; + + /* Assign the callback function for the long running token generation task */ + config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h + + Firebase.begin(&config, &auth); Firebase.reconnectWiFi(true); +#if defined(ESP8266) //Set the size of WiFi rx/tx buffers in the case where we want to work with large data. fbdo1->setBSSLBufferSize(1024, 1024); +#endif //Set the size of HTTP response buffers in the case where we want to work with large data. fbdo1->setResponseSize(1024); +#if defined(ESP8266) //Set the size of WiFi rx/tx buffers in the case where we want to work with large data. fbdo2->setBSSLBufferSize(1024, 1024); +#endif //Set the size of HTTP response buffers in the case where we want to work with large data. fbdo2->setResponseSize(1024); - if (!Firebase.beginStream(*fbdo1, path)) + if (!Firebase.beginStream(*fbdo1, path.c_str())) { Serial.println("------------------------------------"); Serial.println("Can't begin stream connection..."); @@ -109,8 +140,7 @@ void setup() void loop() { - - if (millis() - sendDataPrevMillis > 5000) + if (Firebase.ready() && (millis() - sendDataPrevMillis > 5000 || sendDataPrevMillis == 0)) { count++; sendDataPrevMillis = millis(); @@ -124,19 +154,23 @@ void loop() fbdo1 = new FirebaseData(); fbdo2 = new FirebaseData(); +#if defined(ESP8266) //Set the size of WiFi rx/tx buffers in the case where we want to work with large data. fbdo1->setBSSLBufferSize(1024, 1024); +#endif //Set the size of HTTP response buffers in the case where we want to work with large data. fbdo1->setResponseSize(1024); +#if defined(ESP8266) //Set the size of WiFi rx/tx buffers in the case where we want to work with large data. fbdo2->setBSSLBufferSize(1024, 1024); +#endif //Set the size of HTTP response buffers in the case where we want to work with large data. fbdo2->setResponseSize(1024); - if (!Firebase.beginStream(*fbdo1, path)) + if (!Firebase.beginStream(*fbdo1, path.c_str())) { Serial.println("------------------------------------"); Serial.println("Can't begin stream connection..."); @@ -164,14 +198,15 @@ void loop() Serial.println("------------------------------------"); Serial.println("Set Int..."); + String Path = path + "/Int"; - if (Firebase.set(*fbdo2, path + "/Int", count)) + if (Firebase.set(*fbdo2, Path.c_str(), count)) { Serial.println("PASSED"); Serial.println("PATH: " + fbdo2->dataPath()); Serial.println("TYPE: " + fbdo2->dataType()); Serial.print("VALUE: "); - printResult(*fbdo2); + printResult(*fbdo2); //see addons/RTDBHelper.h Serial.println("------------------------------------"); Serial.println(); } @@ -201,177 +236,4 @@ void loop() fbdo2 = nullptr; } } -} - -//Helper function for printing the response/received data -void printResult(FirebaseData &data) -{ - - if (data.dataType() == "int") - Serial.println(data.intData()); - else if (data.dataType() == "float") - Serial.println(data.floatData(), 5); - else if (data.dataType() == "double") - printf("%.9lf\n", data.doubleData()); - else if (data.dataType() == "boolean") - Serial.println(data.boolData() == 1 ? "true" : "false"); - else if (data.dataType() == "string") - Serial.println(data.stringData()); - else if (data.dataType() == "json") - { - Serial.println(); - FirebaseJson &json = data.jsonObject(); - //Print all object data - Serial.println("Pretty printed JSON data:"); - String jsonStr; - json.toString(jsonStr, true); - Serial.println(jsonStr); - Serial.println(); - Serial.println("Iterate JSON data:"); - Serial.println(); - size_t len = json.iteratorBegin(); - String key, value = ""; - int type = 0; - for (size_t i = 0; i < len; i++) - { - json.iteratorGet(i, type, key, value); - Serial.print(i); - Serial.print(", "); - Serial.print("Type: "); - Serial.print(type == FirebaseJson::JSON_OBJECT ? "object" : "array"); - if (type == FirebaseJson::JSON_OBJECT) - { - Serial.print(", Key: "); - Serial.print(key); - } - Serial.print(", Value: "); - Serial.println(value); - } - json.iteratorEnd(); - } - else if (data.dataType() == "array") - { - Serial.println(); - //get array data from FirebaseData using FirebaseJsonArray object - FirebaseJsonArray &arr = data.jsonArray(); - //Print all array values - Serial.println("Pretty printed Array:"); - String arrStr; - arr.toString(arrStr, true); - Serial.println(arrStr); - Serial.println(); - Serial.println("Iterate array values:"); - Serial.println(); - for (size_t i = 0; i < arr.size(); i++) - { - Serial.print(i); - Serial.print(", Value: "); - - FirebaseJsonData &jsonData = data.jsonData(); - //Get the result data from FirebaseJsonArray object - arr.get(jsonData, i); - if (jsonData.typeNum == FirebaseJson::JSON_BOOL) - Serial.println(jsonData.boolValue ? "true" : "false"); - else if (jsonData.typeNum == FirebaseJson::JSON_INT) - Serial.println(jsonData.intValue); - else if (jsonData.typeNum == FirebaseJson::JSON_FLOAT) - Serial.println(jsonData.floatValue); - else if (jsonData.typeNum == FirebaseJson::JSON_DOUBLE) - printf("%.9lf\n", jsonData.doubleValue); - else if (jsonData.typeNum == FirebaseJson::JSON_STRING || - jsonData.typeNum == FirebaseJson::JSON_NULL || - jsonData.typeNum == FirebaseJson::JSON_OBJECT || - jsonData.typeNum == FirebaseJson::JSON_ARRAY) - Serial.println(jsonData.stringValue); - } - } - else - { - Serial.println(data.payload()); - } -} - -//Helper function for printing the response/received stream data -void printResult(StreamData &data) -{ - - if (data.dataType() == "int") - Serial.println(data.intData()); - else if (data.dataType() == "float") - Serial.println(data.floatData(), 5); - else if (data.dataType() == "double") - printf("%.9lf\n", data.doubleData()); - else if (data.dataType() == "boolean") - Serial.println(data.boolData() == 1 ? "true" : "false"); - else if (data.dataType() == "string" || data.dataType() == "null") - Serial.println(data.stringData()); - else if (data.dataType() == "json") - { - Serial.println(); - FirebaseJson *json = data.jsonObjectPtr(); - //Print all object data - Serial.println("Pretty printed JSON data:"); - String jsonStr; - json->toString(jsonStr, true); - Serial.println(jsonStr); - Serial.println(); - Serial.println("Iterate JSON data:"); - Serial.println(); - size_t len = json->iteratorBegin(); - String key, value = ""; - int type = 0; - for (size_t i = 0; i < len; i++) - { - json->iteratorGet(i, type, key, value); - Serial.print(i); - Serial.print(", "); - Serial.print("Type: "); - Serial.print(type == FirebaseJson::JSON_OBJECT ? "object" : "array"); - if (type == FirebaseJson::JSON_OBJECT) - { - Serial.print(", Key: "); - Serial.print(key); - } - Serial.print(", Value: "); - Serial.println(value); - } - json->iteratorEnd(); - } - else if (data.dataType() == "array") - { - Serial.println(); - //get array data from FirebaseData using FirebaseJsonArray object - FirebaseJsonArray *arr = data.jsonArrayPtr(); - //Print all array values - Serial.println("Pretty printed Array:"); - String arrStr; - arr->toString(arrStr, true); - Serial.println(arrStr); - Serial.println(); - Serial.println("Iterate array values:"); - Serial.println(); - - for (size_t i = 0; i < arr->size(); i++) - { - Serial.print(i); - Serial.print(", Value: "); - - FirebaseJsonData *jsonData = data.jsonDataPtr(); - //Get the result data from FirebaseJsonArray object - arr->get(*jsonData, i); - if (jsonData->typeNum == FirebaseJson::JSON_BOOL) - Serial.println(jsonData->boolValue ? "true" : "false"); - else if (jsonData->typeNum == FirebaseJson::JSON_INT) - Serial.println(jsonData->intValue); - else if (jsonData->typeNum == FirebaseJson::JSON_FLOAT) - Serial.println(jsonData->floatValue); - else if (jsonData->typeNum == FirebaseJson::JSON_DOUBLE) - printf("%.9lf\n", jsonData->doubleValue); - else if (jsonData->typeNum == FirebaseJson::JSON_STRING || - jsonData->typeNum == FirebaseJson::JSON_NULL || - jsonData->typeNum == FirebaseJson::JSON_OBJECT || - jsonData->typeNum == FirebaseJson::JSON_ARRAY) - Serial.println(jsonData->stringValue); - } - } } \ No newline at end of file diff --git a/examples/ETag/ETag.ino b/examples/ETag/ETag.ino index 1d7dd1b6..17585662 100644 --- a/examples/ETag/ETag.ino +++ b/examples/ETag/ETag.ino @@ -12,24 +12,39 @@ //This example shows how to set and delete data with checking the matching between node path ETag (unique identifier string) //and provided Etag +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) #include #include +#endif +//Provide the token generation process info. +#include "addons/TokenHelper.h" +//Provide the RTDB payload printing info and other helper functions. +#include "addons/RTDBHelper.h" +/* 1. Define the WiFi credentials */ #define WIFI_SSID "WIFI_AP" #define WIFI_PASSWORD "WIFI_PASSWORD" -#define FIREBASE_HOST "PROJECT_ID.firebaseio.com" +/* 2. Define the API Key */ +#define API_KEY "API_KEY" -/** The database secret is obsoleted, please use other authentication methods, - * see examples in the Authentications folder. -*/ -#define FIREBASE_AUTH "DATABASE_SECRET" +/* 3. Define the RTDB URL */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app + +/* 4. Define the user Email and password that alreadey registerd or added in your project */ +#define USER_EMAIL "USER_EMAIL" +#define USER_PASSWORD "USER_PASSWORD" //Define Firebase Data object FirebaseData fbdo; -void printResult(FirebaseData &data); +FirebaseAuth auth; +FirebaseConfig config; +bool taskCompleted = false; void setup() { @@ -50,210 +65,142 @@ void setup() Serial.println(WiFi.localIP()); Serial.println(); - Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH); + /* Assign the api key (required) */ + config.api_key = API_KEY; + + /* Assign the user sign in credentials */ + auth.user.email = USER_EMAIL; + auth.user.password = USER_PASSWORD; + + /* Assign the RTDB URL (required) */ + config.database_url = DATABASE_URL; + + /* Assign the callback function for the long running token generation task */ + config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h + + Firebase.begin(&config, &auth); Firebase.reconnectWiFi(true); +#if defined(ESP8266) //Set the size of WiFi rx/tx buffers in the case where we want to work with large data. fbdo.setBSSLBufferSize(1024, 1024); +#endif //Set the size of HTTP response buffers in the case where we want to work with large data. fbdo.setResponseSize(1024); +} - String path = "/Test"; - - String ETag = ""; - String wrong_ETag = "ANY_WRONG_ETag"; - - Serial.println("------------------------------------"); - Serial.println("Set integer without ETag test..."); - - if (Firebase.setInt(fbdo, path + "/Int/Data", 100)) - { - Serial.println("PASSED"); - Serial.println("PATH: " + fbdo.dataPath()); - Serial.println("TYPE: " + fbdo.dataType()); - Serial.println("CURRENT ETag: " + fbdo.ETag()); - ETag = fbdo.ETag(); - Serial.print("VALUE: "); - printResult(fbdo); - Serial.println("------------------------------------"); - Serial.println(); - } - else +void loop() +{ + if (Firebase.ready() && !taskCompleted) { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); - Serial.println("------------------------------------"); - Serial.println(); - } - - Serial.println("------------------------------------"); - Serial.println("Set integer with valid ETag test..."); + taskCompleted = true; - if (Firebase.setInt(fbdo, path + "/Int/Data", 200)) - { - Serial.println("PASSED"); - Serial.println("PATH: " + fbdo.dataPath()); - Serial.println("TYPE: " + fbdo.dataType()); - Serial.println("CURRENT ETag: " + fbdo.ETag()); - ETag = fbdo.ETag(); - Serial.print("VALUE: "); - printResult(fbdo); - Serial.println("------------------------------------"); - Serial.println(); - } - else - { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); - Serial.println("------------------------------------"); - Serial.println(); - } + String path = "/Test"; - Serial.println("------------------------------------"); - Serial.println("Set integer with wrong ETag test..."); + String ETag = ""; + String wrong_ETag = "ANY_WRONG_ETag"; - if (Firebase.setInt(fbdo, path + "/Int/Data", 300, wrong_ETag)) - { - Serial.println("PASSED"); - Serial.println("PATH: " + fbdo.dataPath()); - Serial.println("TYPE: " + fbdo.dataType()); - Serial.println("ETag: " + fbdo.ETag()); - ETag = fbdo.ETag(); - Serial.print("VALUE: "); - printResult(fbdo); Serial.println("------------------------------------"); - Serial.println(); - } - else - { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); + Serial.println("Set integer without ETag test..."); + String Path = path + "/Int/Data"; - //If provided ETag is not match to current ETag (httpCode 412) - if (fbdo.httpCode() == 412) + if (Firebase.setInt(fbdo, Path.c_str(), 100)) { + Serial.println("PASSED"); Serial.println("PATH: " + fbdo.dataPath()); Serial.println("TYPE: " + fbdo.dataType()); - Serial.println("PROVIDED ETag: " + wrong_ETag); Serial.println("CURRENT ETag: " + fbdo.ETag()); ETag = fbdo.ETag(); - Serial.print("CURRENT VALUE: "); - printResult(fbdo); + Serial.print("VALUE: "); + printResult(fbdo); //see addons/RTDBHelper.h + Serial.println("------------------------------------"); + Serial.println(); + } + else + { + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + Serial.println("------------------------------------"); + Serial.println(); } Serial.println("------------------------------------"); - Serial.println(); - } - - Serial.println("------------------------------------"); - Serial.println("Delete node with wrong ETag test..."); - if (Firebase.deleteNode(fbdo, path + "/Int/Data", wrong_ETag)) - { + Serial.println("Set integer with valid ETag test..."); - Serial.println("PASSED"); - Serial.println("CURRENT ETag: " + fbdo.ETag()); - Serial.println("------------------------------------"); - Serial.println(); - } - else - { + if (Firebase.setInt(fbdo, Path.c_str(), 200)) + { + Serial.println("PASSED"); + Serial.println("PATH: " + fbdo.dataPath()); + Serial.println("TYPE: " + fbdo.dataType()); + Serial.println("CURRENT ETag: " + fbdo.ETag()); + ETag = fbdo.ETag(); + Serial.print("VALUE: "); + printResult(fbdo); //see addons/RTDBHelper.h + Serial.println("------------------------------------"); + Serial.println(); + } + else + { + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + Serial.println("------------------------------------"); + Serial.println(); + } - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); Serial.println("------------------------------------"); - Serial.println(); - } -} + Serial.println("Set integer with wrong ETag test..."); -void printResult(FirebaseData &data) -{ - if (data.dataType() == "int") - Serial.println(data.intData()); - else if (data.dataType() == "float") - Serial.println(data.floatData(), 5); - else if (data.dataType() == "double") - printf("%.9lf\n", data.doubleData()); - else if (data.dataType() == "boolean") - Serial.println(data.boolData() == 1 ? "true" : "false"); - else if (data.dataType() == "string") - Serial.println(data.stringData()); - else if (data.dataType() == "json") - { - Serial.println(); - FirebaseJson &json = data.jsonObject(); - //Print all object data - Serial.println("Pretty printed JSON data:"); - String jsonStr; - json.toString(jsonStr,true); - Serial.println(jsonStr); - Serial.println(); - Serial.println("Iterate JSON data:"); - Serial.println(); - size_t len = json.iteratorBegin(); - String key, value = ""; - int type = 0; - for (size_t i = 0; i < len; i++) + if (Firebase.setInt(fbdo, Path.c_str(), 300, wrong_ETag.c_str())) { - json.iteratorGet(i, type, key, value); - Serial.print(i); - Serial.print(", "); - Serial.print("Type: "); - Serial.print(type == FirebaseJson::JSON_OBJECT ? "object" : "array"); - if (type == FirebaseJson::JSON_OBJECT) + Serial.println("PASSED"); + Serial.println("PATH: " + fbdo.dataPath()); + Serial.println("TYPE: " + fbdo.dataType()); + Serial.println("ETag: " + fbdo.ETag()); + ETag = fbdo.ETag(); + Serial.print("VALUE: "); + printResult(fbdo); //see addons/RTDBHelper.h + Serial.println("------------------------------------"); + Serial.println(); + } + else + { + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + + //If provided ETag is not match to current ETag (httpCode 412) + if (fbdo.httpCode() == 412) { - Serial.print(", Key: "); - Serial.print(key); + Serial.println("PATH: " + fbdo.dataPath()); + Serial.println("TYPE: " + fbdo.dataType()); + Serial.println("PROVIDED ETag: " + wrong_ETag); + Serial.println("CURRENT ETag: " + fbdo.ETag()); + ETag = fbdo.ETag(); + Serial.print("CURRENT VALUE: "); + printResult(fbdo); //see addons/RTDBHelper.h } - Serial.print(", Value: "); - Serial.println(value); + + Serial.println("------------------------------------"); + Serial.println(); } - json.iteratorEnd(); - } - else if (data.dataType() == "array") - { - Serial.println(); - //get array data from FirebaseData using FirebaseJsonArray object - FirebaseJsonArray &arr = data.jsonArray(); - //Print all array values - Serial.println("Pretty printed Array:"); - String arrStr; - arr.toString(arrStr,true); - Serial.println(arrStr); - Serial.println(); - Serial.println("Iterate array values:"); - Serial.println(); - for (size_t i = 0; i < arr.size(); i++) + + Serial.println("------------------------------------"); + Serial.println("Delete node with wrong ETag test..."); + if (Firebase.deleteNode(fbdo, Path.c_str(), wrong_ETag.c_str())) { - Serial.print(i); - Serial.print(", Value: "); - - FirebaseJsonData &jsonData = data.jsonData(); - //Get the result data from FirebaseJsonArray object - arr.get(jsonData, i); - if (jsonData.typeNum == FirebaseJson::JSON_BOOL) - Serial.println(jsonData.boolValue ? "true" : "false"); - else if (jsonData.typeNum == FirebaseJson::JSON_INT) - Serial.println(jsonData.intValue); - else if (jsonData.typeNum == FirebaseJson::JSON_FLOAT) - Serial.println(jsonData.floatValue); - else if (jsonData.typeNum == FirebaseJson::JSON_DOUBLE) - printf("%.9lf\n", jsonData.doubleValue); - else if (jsonData.typeNum == FirebaseJson::JSON_STRING || - jsonData.typeNum == FirebaseJson::JSON_NULL || - jsonData.typeNum == FirebaseJson::JSON_OBJECT || - jsonData.typeNum == FirebaseJson::JSON_ARRAY) - Serial.println(jsonData.stringValue); + + Serial.println("PASSED"); + Serial.println("CURRENT ETag: " + fbdo.ETag()); + Serial.println("------------------------------------"); + Serial.println(); } - } - else - { - Serial.println(data.payload()); - } -} + else + { -void loop() -{ + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + Serial.println("------------------------------------"); + Serial.println(); + } + } } - - diff --git a/examples/File/File.ino b/examples/File/File.ino index e5034b59..a59c3a30 100644 --- a/examples/File/File.ino +++ b/examples/File/File.ino @@ -11,22 +11,41 @@ //This example shows how to store and read binary data from file on SD card to database. +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) #include #include +#endif +//Provide the token generation process info. +#include "addons/TokenHelper.h" +//Provide the RTDB payload printing info and other helper functions. +#include "addons/RTDBHelper.h" + +/* 1. Define the WiFi credentials */ #define WIFI_SSID "WIFI_AP" #define WIFI_PASSWORD "WIFI_PASSWORD" -#define FIREBASE_HOST "PROJECT_ID.firebaseio.com" +/* 2. Define the API Key */ +#define API_KEY "API_KEY" -/** The database secret is obsoleted, please use other authentication methods, - * see examples in the Authentications folder. -*/ -#define FIREBASE_AUTH "DATABASE_SECRET" +/* 3. Define the RTDB URL */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app + +/* 4. Define the user Email and password that alreadey registerd or added in your project */ +#define USER_EMAIL "USER_EMAIL" +#define USER_PASSWORD "USER_PASSWORD" //Define Firebase Data object FirebaseData fbdo; +FirebaseAuth auth; +FirebaseConfig config; + +bool taskCompleted = false; + String path = "/Test"; File file; @@ -50,11 +69,26 @@ void setup() Serial.println(WiFi.localIP()); Serial.println(); - Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH); + /* Assign the api key (required) */ + config.api_key = API_KEY; + + /* Assign the user sign in credentials */ + auth.user.email = USER_EMAIL; + auth.user.password = USER_PASSWORD; + + /* Assign the RTDB URL (required) */ + config.database_url = DATABASE_URL; + + /* Assign the callback function for the long running token generation task */ + config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h + + Firebase.begin(&config, &auth); Firebase.reconnectWiFi(true); +#if defined(ESP8266) //Set the size of WiFi rx/tx buffers in the case where we want to work with large data. fbdo.setBSSLBufferSize(1024, 1024); +#endif //Set the size of HTTP response buffers in the case where we want to work with large data. fbdo.setResponseSize(1024); @@ -89,121 +123,63 @@ void setup() } file.close(); +} - //In case of Root CA was set, set this option to false to disable low memory for secured mode BearSSL to support large file data - //Firebase.lowMemBSSL(false); - - //Set file (read file from SD card and set to database) - //File name must be in 8.3 DOS format (max. 8 bytes file name and 3 bytes file extension) - if (Firebase.setFile(fbdo, StorageType::SD, path + "/Binary/File/data", "/file1.txt")) - { - Serial.println("PASSED"); - Serial.println("------------------------------------"); - Serial.println(); - } - else - { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.fileTransferError()); - Serial.println("------------------------------------"); - Serial.println(); - } - - Serial.println("------------------------------------"); - Serial.println("Get file data test..."); - - //Get file (download file to SD card) - //File name must be in 8.3 DOS format (max. 8 bytes file name and 3 bytes file extension) - if (Firebase.getFile(fbdo, StorageType::SD, path + "/Binary/File/data", "/file2.txt")) +void loop() +{ + if (Firebase.ready() && !taskCompleted) { + taskCompleted = true; - Serial.println("PASSED"); - Serial.println("DATA"); + //In case of Root CA was set, set this option to false to disable low memory for secured mode BearSSL to support large file data + //Firebase.lowMemBSSL(false); - //Readout the downloaded file - file = SD.open("/file2.txt", FILE_READ); - int i = 0; + String Path = path + "/Binary/File/data"; - while (file.available()) + //Set file (read file from SD card and set to database) + //File name must be in 8.3 DOS format (max. 8 bytes file name and 3 bytes file extension) + if (Firebase.setFile(fbdo, StorageType::SD, Path.c_str(), "/file1.txt")) { - if (i > 0 && i % 16 == 0) - Serial.println(); - - v = file.read(); - - if (v < 16) - Serial.print("0"); - - Serial.print(v, HEX); - Serial.print(" "); - i++; + Serial.println("PASSED"); + Serial.println("------------------------------------"); + Serial.println(); + } + else + { + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.fileTransferError()); + Serial.println("------------------------------------"); + Serial.println(); } - Serial.println(); - Serial.println("------------------------------------"); - Serial.println(); - file.close(); - } - else - { - - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.fileTransferError()); - Serial.println("------------------------------------"); - Serial.println(); - } - - Serial.println("------------------------------------"); - Serial.println("Append file data test..."); - - if (SD.exists("/file1.txt")) - SD.remove("/file1.txt"); - - //Write demo data to file - file = SD.open("/file1.txt", FILE_WRITE); - for (int i = 255; i >= 0; i--) - file.write((uint8_t)i); - - file.close(); - - //Append file data to database - //File name must be in 8.3 DOS format (max. 8 bytes file name and 3 bytes file extension) - if (Firebase.pushFile(fbdo, StorageType::SD, path + "/Binary/File/Logs", "/file1.txt")) - { - Serial.println("PASSED"); - Serial.println("PATH: " + fbdo.dataPath()); - Serial.println("PUSH NAME: " + fbdo.pushName()); - Serial.println("------------------------------------"); - - Serial.println(); Serial.println("------------------------------------"); - Serial.println("Get appended file data test..."); + Serial.println("Get file data test..."); - //Get the recently appended file (download file to SD card) + //Get file (download file to SD card) //File name must be in 8.3 DOS format (max. 8 bytes file name and 3 bytes file extension) - if (Firebase.getFile(fbdo, StorageType::SD, path + "/Binary/File/Logs/" + fbdo.pushName(), "/file3.txt")) + if (Firebase.getFile(fbdo, StorageType::SD, Path.c_str(), "/file2.txt")) { Serial.println("PASSED"); Serial.println("DATA"); //Readout the downloaded file - file = SD.open("/file3.txt", FILE_READ); + file = SD.open("/file2.txt", FILE_READ); int i = 0; - int idx = 0; while (file.available()) { - i = file.read(); - if (i < 16) + if (i > 0 && i % 16 == 0) + Serial.println(); + + uint8_t v = file.read(); + + if (v < 16) Serial.print("0"); - Serial.print(i, HEX); + Serial.print(v, HEX); Serial.print(" "); - - if (idx > 0 && (idx + 1) % 16 == 0) - Serial.println(); - idx++; + i++; } Serial.println(); Serial.println("------------------------------------"); @@ -218,16 +194,84 @@ void setup() Serial.println("------------------------------------"); Serial.println(); } - } - else - { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.fileTransferError()); + Serial.println("------------------------------------"); - Serial.println(); - } -} + Serial.println("Append file data test..."); -void loop() -{ + if (SD.exists("/file1.txt")) + SD.remove("/file1.txt"); + + //Write demo data to file + file = SD.open("/file1.txt", FILE_WRITE); + for (int i = 255; i >= 0; i--) + file.write((uint8_t)i); + + file.close(); + + Path = path + "/Binary/File/Logs"; + + //Append file data to database + //File name must be in 8.3 DOS format (max. 8 bytes file name and 3 bytes file extension) + if (Firebase.pushFile(fbdo, StorageType::SD, Path.c_str(), "/file1.txt")) + { + Serial.println("PASSED"); + Serial.println("PATH: " + fbdo.dataPath()); + Serial.println("PUSH NAME: " + fbdo.pushName()); + Serial.println("------------------------------------"); + + Serial.println(); + + Serial.println("------------------------------------"); + Serial.println("Get appended file data test..."); + + Path = path + "/Binary/File/Logs/" + fbdo.pushName(); + + //Get the recently appended file (download file to SD card) + //File name must be in 8.3 DOS format (max. 8 bytes file name and 3 bytes file extension) + if (Firebase.getFile(fbdo, StorageType::SD, Path.c_str(), "/file3.txt")) + { + + Serial.println("PASSED"); + Serial.println("DATA"); + + //Readout the downloaded file + file = SD.open("/file3.txt", FILE_READ); + int i = 0; + int idx = 0; + + while (file.available()) + { + i = file.read(); + if (i < 16) + Serial.print("0"); + + Serial.print(i, HEX); + Serial.print(" "); + + if (idx > 0 && (idx + 1) % 16 == 0) + Serial.println(); + idx++; + } + Serial.println(); + Serial.println("------------------------------------"); + Serial.println(); + file.close(); + } + else + { + + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.fileTransferError()); + Serial.println("------------------------------------"); + Serial.println(); + } + } + else + { + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.fileTransferError()); + Serial.println("------------------------------------"); + Serial.println(); + } + } } diff --git a/examples/File_flash_memory/File_flash_memory.ino b/examples/File_flash_memory/File_flash_memory.ino index 3b8e6140..284107f9 100644 --- a/examples/File_flash_memory/File_flash_memory.ino +++ b/examples/File_flash_memory/File_flash_memory.ino @@ -11,23 +11,42 @@ //This example shows how to store and read binary data from file on Flash memory to database. +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) #include #include +#endif +//Provide the token generation process info. +#include "addons/TokenHelper.h" +//Provide the RTDB payload printing info and other helper functions. +#include "addons/RTDBHelper.h" + +/* 1. Define the WiFi credentials */ #define WIFI_SSID "WIFI_AP" #define WIFI_PASSWORD "WIFI_PASSWORD" -#define FIREBASE_HOST "PROJECT_ID.firebaseio.com" +/* 2. Define the API Key */ +#define API_KEY "API_KEY" -/** The database secret is obsoleted, please use other authentication methods, - * see examples in the Authentications folder. -*/ -#define FIREBASE_AUTH "DATABASE_SECRET" +/* 3. Define the RTDB URL */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app + +/* 4. Define the user Email and password that alreadey registerd or added in your project */ +#define USER_EMAIL "USER_EMAIL" +#define USER_PASSWORD "USER_PASSWORD" //Define Firebase Data object FirebaseData fbdo; -String path = "/ESP8266_Test"; +FirebaseAuth auth; +FirebaseConfig config; + +bool taskCompleted = false; + +String path = "/Test"; fs::File file; @@ -57,11 +76,26 @@ void setup() Serial.println(WiFi.localIP()); Serial.println(); - Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH); + /* Assign the api key (required) */ + config.api_key = API_KEY; + + /* Assign the user sign in credentials */ + auth.user.email = USER_EMAIL; + auth.user.password = USER_PASSWORD; + + /* Assign the RTDB URL (required) */ + config.database_url = DATABASE_URL; + + /* Assign the callback function for the long running token generation task */ + config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h + + Firebase.begin(&config, &auth); Firebase.reconnectWiFi(true); +#if defined(ESP8266) //Set the size of WiFi rx/tx buffers in the case where we want to work with large data. fbdo.setBSSLBufferSize(1024, 1024); +#endif //Set the size of HTTP response buffers in the case where we want to work with large data. fbdo.setResponseSize(1024); @@ -72,7 +106,6 @@ void setup() Serial.println("For Arduino IDE, please select flash size from menu Tools > Flash size"); return; } - //Delete demo files if (SPIFFS.exists("/file1.txt")) @@ -87,7 +120,7 @@ void setup() Serial.println("------------------------------------"); Serial.println("Set file data test..."); - //Write demo data to file + //Write demo data to file file = SPIFFS.open("/file1.txt", "w"); uint8_t v = 0; for (int i = 0; i < 512; i++) @@ -97,117 +130,60 @@ void setup() } file.close(); - - //In case of Root CA was set, set this option to false to disable low memory for secured mode BearSSL to support large file data - //Firebase.lowMemBSSL(false); - - //Set file (read file from Flash memory and set to database) - if (Firebase.setFile(fbdo, StorageType::FLASH, path + "/Binary/File/data", "/file1.txt")) - { - Serial.println("PASSED"); - Serial.println("------------------------------------"); - Serial.println(); - } - else - { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.fileTransferError()); - Serial.println("------------------------------------"); - Serial.println(); - } - - Serial.println("------------------------------------"); - Serial.println("Get file data test..."); +} - //Get file (download file to Flash memory) - if (Firebase.getFile(fbdo, StorageType::FLASH, path + "/Binary/File/data", "/file2.txt")) +void loop() +{ + if (Firebase.ready() && !taskCompleted) { + taskCompleted = true; - Serial.println("PASSED"); - Serial.println("DATA"); - - //Readout the downloaded file - file = SPIFFS.open("/file2.txt", "r"); - int i = 0; + //In case of Root CA was set, set this option to false to disable low memory for secured mode BearSSL to support large file data + //Firebase.lowMemBSSL(false); + String Path = path + "/Binary/File/data"; - while (file.available()) + //Set file (read file from Flash memory and set to database) + if (Firebase.setFile(fbdo, StorageType::FLASH, Path.c_str(), "/file1.txt")) { - if (i > 0 && i % 16 == 0) - Serial.println(); - - v = file.read(); - - if (v < 16) - Serial.print("0"); - - Serial.print(v, HEX); - Serial.print(" "); - i++; + Serial.println("PASSED"); + Serial.println("------------------------------------"); + Serial.println(); + } + else + { + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.fileTransferError()); + Serial.println("------------------------------------"); + Serial.println(); } - Serial.println(); - Serial.println("------------------------------------"); - Serial.println(); - file.close(); - } - else - { - - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.fileTransferError()); - Serial.println("------------------------------------"); - Serial.println(); - } - - Serial.println("------------------------------------"); - Serial.println("Append file data test..."); - - if (SPIFFS.exists("/file1.txt")) - SPIFFS.remove("/file1.txt"); - - //Write demo data to file - file = SPIFFS.open("/file1.txt", "w"); - for (int i = 255; i >= 0; i--) - file.write((uint8_t)i); - - file.close(); - - //Append file data to database - if (Firebase.pushFile(fbdo, StorageType::FLASH, path + "/Binary/File/Logs", "/file1.txt")) - { - Serial.println("PASSED"); - Serial.println("PATH: " + fbdo.dataPath()); - Serial.println("PUSH NAME: " + fbdo.pushName()); - Serial.println("------------------------------------"); - - Serial.println(); Serial.println("------------------------------------"); - Serial.println("Get appended file data test..."); + Serial.println("Get file data test..."); - //Get the recently appended file (download file to Flash memory) - if (Firebase.getFile(fbdo, StorageType::FLASH, path + "/Binary/File/Logs/" + fbdo.pushName(), "/file3.txt")) + //Get file (download file to Flash memory) + if (Firebase.getFile(fbdo, StorageType::FLASH, Path.c_str(), "/file2.txt")) { Serial.println("PASSED"); Serial.println("DATA"); //Readout the downloaded file - file = SPIFFS.open("/file3.txt", "r"); + file = SPIFFS.open("/file2.txt", "r"); int i = 0; - int idx = 0; while (file.available()) { - i = file.read(); - if (i < 16) + if (i > 0 && i % 16 == 0) + Serial.println(); + + uint8_t v = file.read(); + + if (v < 16) Serial.print("0"); - Serial.print(i, HEX); + Serial.print(v, HEX); Serial.print(" "); - - if (idx > 0 && (idx + 1) % 16 == 0) - Serial.println(); - idx++; + i++; } Serial.println(); Serial.println("------------------------------------"); @@ -222,16 +198,82 @@ void setup() Serial.println("------------------------------------"); Serial.println(); } - } - else - { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.fileTransferError()); + Serial.println("------------------------------------"); - Serial.println(); - } -} + Serial.println("Append file data test..."); -void loop() -{ + if (SPIFFS.exists("/file1.txt")) + SPIFFS.remove("/file1.txt"); + + //Write demo data to file + file = SPIFFS.open("/file1.txt", "w"); + for (int i = 255; i >= 0; i--) + file.write((uint8_t)i); + + file.close(); + + Path = path + "/Binary/File/Logs"; + + //Append file data to database + if (Firebase.pushFile(fbdo, StorageType::FLASH, Path.c_str(), "/file1.txt")) + { + Serial.println("PASSED"); + Serial.println("PATH: " + fbdo.dataPath()); + Serial.println("PUSH NAME: " + fbdo.pushName()); + Serial.println("------------------------------------"); + + Serial.println(); + + Serial.println("------------------------------------"); + Serial.println("Get appended file data test..."); + + Path = path + "/Binary/File/Logs/" + fbdo.pushName(); + + //Get the recently appended file (download file to Flash memory) + if (Firebase.getFile(fbdo, StorageType::FLASH, Path.c_str(), "/file3.txt")) + { + + Serial.println("PASSED"); + Serial.println("DATA"); + + //Readout the downloaded file + file = SPIFFS.open("/file3.txt", "r"); + int i = 0; + int idx = 0; + + while (file.available()) + { + i = file.read(); + if (i < 16) + Serial.print("0"); + + Serial.print(i, HEX); + Serial.print(" "); + + if (idx > 0 && (idx + 1) % 16 == 0) + Serial.println(); + idx++; + } + Serial.println(); + Serial.println("------------------------------------"); + Serial.println(); + file.close(); + } + else + { + + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.fileTransferError()); + Serial.println("------------------------------------"); + Serial.println(); + } + } + else + { + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.fileTransferError()); + Serial.println("------------------------------------"); + Serial.println(); + } + } } diff --git a/examples/FireSense/Analog_Read/Analog_Read.ino b/examples/FireSense/Analog_Read/Analog_Read.ino new file mode 100644 index 00000000..67009615 --- /dev/null +++ b/examples/FireSense/Analog_Read/Analog_Read.ino @@ -0,0 +1,249 @@ + +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: k_suwatchai@hotmail.com + * + * Github: https://github.com/mobizt + * + * Copyright (c) 2021 mobizt + * +*/ + +/** + * This example shows how to read the and process IO channels programatically. + * + * The code will read the analog value and calculate the measured voltage and average voltage periodically. + * + * This example used the FireSense, The Programmable Data Logging and IO Control library to + * control the IOs. + * + * The status of IO showed at /{DATA_PATH}/status/Node-ESP-{DEVICE_ID} + * + * Where the {DATA_PATH} is the base path (rooth) for all data will be stored. + * + * The {DEVICE_ID} is the uniqued id of the device which can get from FireSense.getDeviceId(). + * + * + * + * To manually set the IO or Value channel value, change the value at /{DATA_PATH}/control/Node-ESP-{DEVICE_ID} + * + * To control the device, send the test command at /{DATA_PATH}/control/Node-ESP-{DEVICE_ID}/cmd. + * + * The supported commands and the descriptions are following, + * the result of processing is at /{DATA_PATH}/status/Node-ESP-{DEVICE_ID}/terminal + * + * time To get the device timestamp + * + * time {TIMESTAMP} To set the device timestamp {TIMESTAMP} + * + * config To load the config from database. If no config existed in database, + * the default config may load within the user default config callback function. + * + * condition To load the conditions, the IF THEN ELSE statments's conditions and statements. + * + * run To run the conditions checking tasks, the condition checking tasks will run automatically by default. + * To disable conditions checking to run at the device startup, call FireSense.enableController(false) + * after FireSense.begin. + * + * stop to stop the conditions checking tasks. + * + * store To store the channels's status (value) to the database under /{DATA_PATH}/status/Node-ESP-{DEVICE_ID} + * This depends on the the channal's status parameter value. + * The device will store the channels's current values to database when its value changed and the channal's status parameter value is 'true'. + * + * restore To restore (read) the status at /{DATA_PATH}/status/Node-ESP-{DEVICE_ID} and set to the channels's values. + * + * clear To clear all log data at /{DATA_PATH}/logs/Node-ESP-{DEVICE_ID}. + * The device will store the channnels's value to this logs path at the preconfigured interval and the channels's log parameter value is 'true'. + * + * ping To test the device is running or stream is still connected. + * + * restart To restart the device. + * +*/ + +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) +#include +#include +#endif + +//Provide the token generation process info. +#include "addons/TokenHelper.h" + +//The FireSense class used in this example. +#include "addons/FireSense/FireSense.h" + +/* 1. Define the WiFi credentials */ +#define WIFI_SSID "WIFI_AP" +#define WIFI_PASSWORD "WIFI_PASSWORD" + +/* 2. Define the API Key */ +#define API_KEY "API_KEY" + +/* 3. Define the RTDB URL */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app + +/* 4. Define the user Email and password that alreadey registerd or added in your project */ +#define USER_EMAIL "USER_EMAIL" +#define USER_PASSWORD "USER_PASSWORD" + +/* 5. Define the database secret in case we need to access database rules*/ +#define DATABASE_SECRET "DATABASE_SECRET" + +FirebaseData fbdo1; +FirebaseData fbdo2; + +FirebaseAuth auth; +FirebaseConfig config; + +//The config data for FireSense class +Firesense_Config fsConfig; + +int count = 0; +float sum = 0, avg = 0; + +void testFunc1(const char *msg) +{ + if (strlen(msg) > 0) + Serial.println(msg); +} + +void testFunc2(const char *msg) +{ + if (strlen(msg) > 0) + Serial.println(msg); +} + +void loadDefaultConfig() +{ + //The config can be set manually from below or read from the stored config file. + + //To store the current config file (read from database and store to device storage), + //FireSense.backupConfig("/filename.txt" /* path of file to save */, mem_storage_type_flash /* or mem_storage_type_sd */); + + //To restore the current config (read from device storage and add to database), + //FireSense.restoreConfig("/filename.txt" /* path of back up file to read */, mem_storage_type_flash /* or mem_storage_type_sd */); + + FireSense_Channel channel[5]; + + channel[0].id = "ANALOG1"; + channel[0].name = "Analog channel"; +#if defined(ESP32) + channel[0].gpio = 34; +#elif defined(ESP8266) + channel[0].gpio = 0; +#endif + channel[0].type = Firesense_Channel_Type::Analog_input; + FireSense.addChannel(channel[0]); + + channel[1].id = "FLAG1"; + channel[1].name = "FLAG"; + channel[1].type = Firesense_Channel_Type::Value; + channel[1].unbinded_type = FireSense_Data_Type::Boolean; //this channel does not bind to any variable, the unbined type should be assigned + FireSense.addChannel(channel[1]); + + channel[2].id = "COUNT"; + channel[2].name = "counter of measurement"; + channel[2].type = Firesense_Channel_Type::Value; + channel[2].value_index = 0; //this the index of binded user variable which added with FireSense.addUserValue + FireSense.addChannel(channel[2]); + + channel[3].id = "SUM"; + channel[3].name = "sum of measured value"; + channel[3].type = Firesense_Channel_Type::Value; + channel[3].value_index = 1; //this the index of binded user variable which added with FireSense.addUserValue + FireSense.addChannel(channel[3]); + + channel[4].id = "AVG"; + channel[4].name = "average of measured value"; + channel[4].status = true; //store the changed to the database status + channel[4].type = Firesense_Channel_Type::Value; + channel[4].value_index = 2; //this the index of binded user variable which added with FireSense.addUserValue + FireSense.addChannel(channel[4]); + + FireSense_Condition cond[2]; + + cond[0].IF = "FLAG1 == true"; + cond[0].THEN = "func(0,1,'\\n[FUNC0] The measured voltage is {AVG} V.\\n'),delay(2000), FLAG1 = false"; + cond[0].ELSE = "func(0,1,'\\n[FUNC1] The total measures is {COUNT}.\\n'),delay(2000), FLAG1 = true"; + FireSense.addCondition(cond[0]); + + cond[1].IF = "change(FLAG1) && FLAG1 == true"; +#if defined(ESP32) + cond[1].THEN = "COUNT += 1, SUM += ANALOG1*3.3/4095, AVG = SUM/COUNT"; +#elif defined(ESP8266) + cond[1].THEN = "COUNT += 1, SUM += ANALOG1*3.3/1023, AVG = SUM/COUNT"; +#endif + FireSense.addCondition(cond[1]); +} + +void setup() +{ + + Serial.begin(115200); + + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + Serial.print("Connecting to Wi-Fi"); + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Assign the api key (required) */ + config.api_key = API_KEY; + + /* Assign the user sign in credentials */ + auth.user.email = USER_EMAIL; + auth.user.password = USER_PASSWORD; + + /* Assign the RTDB URL (required) */ + config.database_url = DATABASE_URL; + + /* Assign the callback function for the long running token generation task */ + config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h + + Firebase.begin(&config, &auth); + + Firebase.reconnectWiFi(true); + + //Set up the config + fsConfig.basePath = "/AnalogValue"; + fsConfig.deviceId = "Node1"; + fsConfig.time_zone = 3; //change for your local time zone + fsConfig.daylight_offset_in_sec = 0; + fsConfig.last_seen_interval = 60 * 1000; //for store timestamp and time string in database + fsConfig.log_interval = 60 * 1000; //store data to database log every 60 seconds + fsConfig.condition_process_interval = 20; // check the conditions every 20 mSec + fsConfig.dataRetainingPeriod = 24 * 60 * 60; //keep the log data within 1 day + fsConfig.shared_fbdo = &fbdo1; //for store/restore database values + fsConfig.stream_fbdo = &fbdo2; //for stream connection object, set this stream_fbdo to nullptr for less memory usage, the stream will connected through shared Firebase Data object. + fsConfig.debug = true; + + //Add the user variable that will bind to the channels + FireSense.addUserValue(&count); + FireSense.addUserValue(&sum); + FireSense.addUserValue(&avg); + + //Add the callback function that will bind to the func syntax + FireSense.addCallbackFunction(testFunc1); + FireSense.addCallbackFunction(testFunc2); + + //Initiate the FireSense class + FireSense.begin(&fsConfig, DATABASE_SECRET); //The database secret can be empty string when using the OAuthen2.0 sign-in method + //Load the config from database or create the default config + FireSense.loadConfig(loadDefaultConfig); //The loadDefaultConfig is the function to configure the channels and condition information. +} + +void loop() +{ + //do not use delay or blocking operating code heare +} \ No newline at end of file diff --git a/examples/FireSense/Automatic_Plant_Watering/Automatic_Plant_Watering.ino b/examples/FireSense/Automatic_Plant_Watering/Automatic_Plant_Watering.ino new file mode 100644 index 00000000..6b114dab --- /dev/null +++ b/examples/FireSense/Automatic_Plant_Watering/Automatic_Plant_Watering.ino @@ -0,0 +1,216 @@ + +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: k_suwatchai@hotmail.com + * + * Github: https://github.com/mobizt + * + * Copyright (c) 2021 mobizt + * +*/ + +/** + * This is the basic example for automatic plant watering system. + * + * The code will set GPIO16 for the Water Pump1, and GPIO12 for the Water Pump2 + * + * The two water pumps will operate automatically at the preset time. + * + * This example used the FireSense, The Programmable Data Logging and IO Control library to + * control the IOs. + * + * The status of pumps showed at /{DATA_PATH}/status/Node-ESP-{DEVICE_ID} + * + * Where the {DATA_PATH} is the base path (rooth) for all data will be stored. + * + * The {DEVICE_ID} is the uniqued id of the device which can get from FireSense.getDeviceId(). + * + * + * + * The pump number 1 and number 2 will be set to run on Monday to Friday at 8.00 - 8.05 and 17.00 - 17.05 and + * on the Saturday to Sunday at 6.00 - 6.05 and 15.00 - 15.05 + * + * To manually run and stop the both pumps, change the value at /{DATA_PATH}/control/Node-ESP-{DEVICE_ID} + * + * To control the device, send the test command at /{DATA_PATH}/control/Node-ESP-{DEVICE_ID}/cmd. + * + * The supported commands and the descriptions are following, + * the result of processing is at /{DATA_PATH}/status/Node-ESP-{DEVICE_ID}/terminal + * + * time To get the device timestamp + * + * time {TIMESTAMP} To set the device timestamp {TIMESTAMP} + * + * config To load the config from database. If no config existed in database, + * the default config may load within the user default config callback function. + * + * condition To load the conditions, the IF THEN ELSE statments's conditions and statements. + * + * run To run the conditions checking tasks, the condition checking tasks will run automatically by default. + * To disable conditions checking to run at the device startup, call FireSense.enableController(false) + * after FireSense.begin. + * + * stop to stop the conditions checking tasks. + * + * store To store the channels's status (value) to the database under /{DATA_PATH}/status/Node-ESP-{DEVICE_ID} + * This depends on the the channal's status parameter value. + * The device will store the channels's current values to database when its value changed and the channal's status parameter value is 'true'. + * + * restore To restore (read) the status at /{DATA_PATH}/status/Node-ESP-{DEVICE_ID} and set to the channels's values. + * + * clear To clear all log data at /{DATA_PATH}/logs/Node-ESP-{DEVICE_ID}. + * The device will store the channnels's value to this logs path at the preconfigured interval and the channels's log parameter value is 'true'. + * + * ping To test the device is running or stream is still connected. + * + * restart To restart the device. + * +*/ + +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) +#include +#include +#endif + +//Provide the token generation process info. +#include "addons/TokenHelper.h" + +//The FireSense class used in this example. +#include "addons/FireSense/FireSense.h" + +/* 1. Define the WiFi credentials */ +#define WIFI_SSID "WIFI_AP" +#define WIFI_PASSWORD "WIFI_PASSWORD" + +/* 2. Define the API Key */ +#define API_KEY "API_KEY" + +/* 3. Define the RTDB URL */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app + +/* 4. Define the user Email and password that alreadey registerd or added in your project */ +#define USER_EMAIL "USER_EMAIL" +#define USER_PASSWORD "USER_PASSWORD" + +/* 5. Define the database secret in case we need to access database rules*/ +#define DATABASE_SECRET "DATABASE_SECRET" + +FirebaseData fbdo1; +FirebaseData fbdo2; + +FirebaseAuth auth; +FirebaseConfig config; + +//The config data for FireSense class +Firesense_Config fsConfig; + +void loadDefaultConfig() +{ + //The config can be set manually from below or read from the stored config file. + + //To store the current config file (read from database and store to device storage), + //FireSense.backupConfig("/filename.txt" /* path of file to save */, mem_storage_type_flash /* or mem_storage_type_sd */); + + //To restore the current config (read from device storage and add to database), + //FireSense.restoreConfig("/filename.txt" /* path of back up file to read */, mem_storage_type_flash /* or mem_storage_type_sd */); + + FireSense_Channel channel[2]; + + channel[0].id = "PUMP1"; + channel[0].name = "Water Pump No.1"; + channel[0].location = "Garden 1"; + + channel[0].gpio = 16; + channel[0].type = Firesense_Channel_Type::Output; + channel[0].status = true; //to store value to the database status + channel[0].log = true; //to store value to the database log + FireSense.addChannel(channel[0]); + + channel[1].id = "PUMP2"; + channel[1].name = "Water Pump No.2"; + channel[1].location = "Garden 2"; + + channel[1].gpio = 12; + channel[1].type = Firesense_Channel_Type::Output; + channel[1].status = true; //to store value to the database status + channel[1].log = true; //to store value to the database log + FireSense.addChannel(channel[1]); + + FireSense_Condition cond[2]; + + //Multi- and multi-level conditions used more memory and may cause the low memory condition and device can be crashed. + + //Pumps will run on Monday to Friday at 8.00 - 8.05 and 17.00 to 17.05 + cond[0].IF = "weekday < 6 && ((time >= 8:00:00 && time < 8:05:00) || (time >= 17:00:00 && time < 17:05:00))"; + cond[0].THEN = "PUMP1 = true, PUMP2 = true"; + cond[0].ELSE = "PUMP1 = false, PUMP2 = false"; + FireSense.addCondition(cond[0]); + + //Pumps will run on Saturday to Sunday at 6.00 - 6.05 and 15.00 to 15.05 + cond[1].IF = "weekday > 6 && ((time >= 6:00:00 && time < 6:05:00) || (time >= 15:00:00 && time < 15:05:00))"; + cond[1].THEN = "PUMP1 = true, PUMP2 = true"; + cond[1].ELSE = "PUMP1 = false, PUMP2 = false"; + FireSense.addCondition(cond[1]); +} + +void setup() +{ + + Serial.begin(115200); + + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + Serial.print("Connecting to Wi-Fi"); + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Assign the api key (required) */ + config.api_key = API_KEY; + + /* Assign the user sign in credentials */ + auth.user.email = USER_EMAIL; + auth.user.password = USER_PASSWORD; + + /* Assign the RTDB URL (required) */ + config.database_url = DATABASE_URL; + + /* Assign the callback function for the long running token generation task */ + config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h + + Firebase.begin(&config, &auth); + + Firebase.reconnectWiFi(true); + + //Set up the config + fsConfig.basePath = "/PlantWatering"; + fsConfig.deviceId = "Node1"; + fsConfig.time_zone = 3; //change for your local time zone + fsConfig.daylight_offset_in_sec = 0; + fsConfig.last_seen_interval = 60 * 1000; //for store timestamp and time string in database + fsConfig.log_interval = 60 * 1000; //store data to database log every 60 seconds + fsConfig.condition_process_interval = 20; // check the conditions every 20 mSec + fsConfig.dataRetainingPeriod = 24 * 60 * 60; //keep the log data within 1 day + fsConfig.shared_fbdo = &fbdo1; //for store/restore database values + fsConfig.stream_fbdo = &fbdo2; //for stream connection object, set this stream_fbdo to nullptr for less memory usage, the stream will connected through shared Firebase Data object. + fsConfig.debug = true; + + //Initiate the FireSense class + FireSense.begin(&fsConfig, DATABASE_SECRET); //The database secret can be empty string when using the OAuthen2.0 sign-in method + //Load the config from database or create the default config + FireSense.loadConfig(loadDefaultConfig); //The loadDefaultConfig is the function to configure the channels and condition information. +} + +void loop() +{ + //do not use delay or blocking operating code heare +} \ No newline at end of file diff --git a/examples/FireSense/Blink/Blink.ino b/examples/FireSense/Blink/Blink.ino new file mode 100644 index 00000000..a264415e --- /dev/null +++ b/examples/FireSense/Blink/Blink.ino @@ -0,0 +1,203 @@ + +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: k_suwatchai@hotmail.com + * + * Github: https://github.com/mobizt + * + * Copyright (c) 2021 mobizt + * +*/ + +/** + * This example shows how to blink the LED programatically. + * + * This example used the FireSense, The Programmable Data Logging and IO Control library to + * control the IOs. + * + * The status of IO showed at /{DATA_PATH}/status/Node-ESP-{DEVICE_ID} + * + * Where the {DATA_PATH} is the base path (rooth) for all data will be stored. + * + * The {DEVICE_ID} is the uniqued id of the device which can get from FireSense.getDeviceId(). + * + * + * + * To manually set the IO or Value channel value, change the value at /{DATA_PATH}/control/Node-ESP-{DEVICE_ID} + * + * To control the device, send the test command at /{DATA_PATH}/control/Node-ESP-{DEVICE_ID}/cmd. + * + * The supported commands and the descriptions are following, + * the result of processing is at /{DATA_PATH}/status/Node-ESP-{DEVICE_ID}/terminal + * + * time To get the device timestamp + * + * time {TIMESTAMP} To set the device timestamp {TIMESTAMP} + * + * config To load the config from database. If no config existed in database, + * the default config may load within the user default config callback function. + * + * condition To load the conditions, the IF THEN ELSE statments's conditions and statements. + * + * run To run the conditions checking tasks, the condition checking tasks will run automatically by default. + * To disable conditions checking to run at the device startup, call FireSense.enableController(false) + * after FireSense.begin. + * + * stop to stop the conditions checking tasks. + * + * store To store the channels's status (value) to the database under /{DATA_PATH}/status/Node-ESP-{DEVICE_ID} + * This depends on the the channal's status parameter value. + * The device will store the channels's current values to database when its value changed and the channal's status parameter value is 'true'. + * + * restore To restore (read) the status at /{DATA_PATH}/status/Node-ESP-{DEVICE_ID} and set to the channels's values. + * + * clear To clear all log data at /{DATA_PATH}/logs/Node-ESP-{DEVICE_ID}. + * The device will store the channnels's value to this logs path at the preconfigured interval and the channels's log parameter value is 'true'. + * + * ping To test the device is running or stream is still connected. + * + * restart To restart the device. + * +*/ + +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) +#include +#include +#endif + +//Provide the token generation process info. +#include "addons/TokenHelper.h" + +//The FireSense class used in this example. +#include "addons/FireSense/FireSense.h" + +/* 1. Define the WiFi credentials */ +#define WIFI_SSID "WIFI_AP" +#define WIFI_PASSWORD "WIFI_PASSWORD" + +/* 2. Define the API Key */ +#define API_KEY "API_KEY" + +/* 3. Define the RTDB URL */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app + +/* 4. Define the user Email and password that alreadey registerd or added in your project */ +#define USER_EMAIL "USER_EMAIL" +#define USER_PASSWORD "USER_PASSWORD" + +/* 5. Define the database secret in case we need to access database rules*/ +#define DATABASE_SECRET "DATABASE_SECRET" + +FirebaseData fbdo1; + +FirebaseAuth auth; +FirebaseConfig config; + +//The config data for FireSense class +Firesense_Config fsConfig; + +int count = 0; +float sum = 0, avg = 0; + +void testFunc1(const char *msg) +{ + if (strlen(msg) > 0) + Serial.println(msg); +} + +void testFunc2(const char *msg) +{ + if (strlen(msg) > 0) + Serial.println(msg); +} + +void loadDefaultConfig() +{ + //The config can be set manually from below or read from the stored config file. + + //To store the current config file (read from database and store to device storage), + //FireSense.backupConfig("/filename.txt" /* path of file to save */, mem_storage_type_flash /* or mem_storage_type_sd */); + + //To restore the current config (read from device storage and add to database), + //FireSense.restoreConfig("/filename.txt" /* path of back up file to read */, mem_storage_type_flash /* or mem_storage_type_sd */); + + FireSense_Channel channel[1]; + + channel[0].id = "LED1"; +#if defined(ESP32) + channel[0].gpio = 5; +#elif defined(ESP8266) + channel[0].gpio = 2; +#endif + channel[0].type = Firesense_Channel_Type::Output; + FireSense.addChannel(channel[0]); + + FireSense_Condition cond[1]; + + cond[0].IF = "LED1 == true && millis < 120000"; //blink until 2 minutes reached since boot + cond[0].THEN = "delay(20), LED1 = false"; + cond[0].ELSE = "delay(980), LED1 = true"; + FireSense.addCondition(cond[0]); +} + +void setup() +{ + + Serial.begin(115200); + + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + Serial.print("Connecting to Wi-Fi"); + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Assign the api key (required) */ + config.api_key = API_KEY; + + /* Assign the user sign in credentials */ + auth.user.email = USER_EMAIL; + auth.user.password = USER_PASSWORD; + + /* Assign the RTDB URL (required) */ + config.database_url = DATABASE_URL; + + /* Assign the callback function for the long running token generation task */ + config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h + + Firebase.begin(&config, &auth); + + Firebase.reconnectWiFi(true); + + //Set up the config + fsConfig.basePath = "/Blink"; + fsConfig.deviceId = "Node1"; + fsConfig.time_zone = 3; //change for your local time zone + fsConfig.daylight_offset_in_sec = 0; + fsConfig.last_seen_interval = 60 * 1000; //for store timestamp and time string in database + fsConfig.log_interval = 60 * 1000; //store data to database log every 60 seconds + fsConfig.condition_process_interval = 0; // check the conditions continuously without delay + fsConfig.dataRetainingPeriod = 24 * 60 * 60; //keep the log data within 1 day + fsConfig.shared_fbdo = &fbdo1; //for store/restore database values + //fsConfig.stream_fbdo = nullptr; + fsConfig.debug = true; + + //Initiate the FireSense class + FireSense.begin(&fsConfig, DATABASE_SECRET); //The database secret can be empty string when using the OAuthen2.0 sign-in method + //Load the config from database or create the default config + FireSense.loadConfig(loadDefaultConfig); //The loadDefaultConfig is the function to configure the channels and condition information. +} + +void loop() +{ + //do not use delay or blocking operating code heare +} \ No newline at end of file diff --git a/examples/FireSense/Sensors/Sensors.ino b/examples/FireSense/Sensors/Sensors.ino new file mode 100644 index 00000000..dc817c35 --- /dev/null +++ b/examples/FireSense/Sensors/Sensors.ino @@ -0,0 +1,227 @@ + +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: k_suwatchai@hotmail.com + * + * Github: https://github.com/mobizt + * + * Copyright (c) 2021 mobizt + * +*/ + +/** + * This is the basic example to simulate the sensor data updates. + * + * This example used the FireSense, The Programmable Data Logging and IO Control library to + * control the IOs. + * + * The status of sensors showed at /{DATA_PATH}/status/Node-ESP-{DEVICE_ID} + * + * Where the {DATA_PATH} is the base path (rooth) for all data will be stored. + * + * The {DEVICE_ID} is the uniqued id of the device which can get from FireSense.getDeviceId(). + * + * + * To control the device, send the test command at /{DATA_PATH}/control/Node-ESP-{DEVICE_ID}/cmd. + * + * The supported commands and the descriptions are following, + * the result of processing is at /{DATA_PATH}/status/Node-ESP-{DEVICE_ID}/terminal + * + * time To get the device timestamp + * + * time {TIMESTAMP} To set the device timestamp {TIMESTAMP} + * + * config To load the config from database. If no config existed in database, + * the default config may load within the user default config callback function. + * + * condition To load the conditions, the IF THEN ELSE statments's conditions and statements. + * + * run To run the conditions checking tasks, the condition checking tasks will run automatically by default. + * To disable conditions checking to run at the device startup, call FireSense.enableController(false) + * after FireSense.begin. + * + * stop to stop the conditions checking tasks. + * + * store To store the channels's status (value) to the database under /{DATA_PATH}/status/Node-ESP-{DEVICE_ID} + * This depends on the the channal's status parameter value. + * The device will store the channels's current values to database when its value changed and the channal's status parameter value is 'true'. + * + * restore To restore (read) the status at /{DATA_PATH}/status/Node-ESP-{DEVICE_ID} and set to the channels's values. + * + * clear To clear all log data at /{DATA_PATH}/logs/Node-ESP-{DEVICE_ID}. + * The device will store the channnels's value to this logs path at the preconfigured interval and the channels's log parameter value is 'true'. + * + * ping To test the device is running or stream is still connected. + * + * restart To restart the device. + * +*/ + +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) +#include +#include +#endif + +//Provide the token generation process info. +#include "addons/TokenHelper.h" + +//The FireSense class used in this example. +#include "addons/FireSense/FireSense.h" + +/* 1. Define the WiFi credentials */ +#define WIFI_SSID "WIFI_AP" +#define WIFI_PASSWORD "WIFI_PASSWORD" + +/* 2. Define the API Key */ +#define API_KEY "API_KEY" + +/* 3. Define the RTDB URL */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app + +/* 4. Define the user Email and password that alreadey registerd or added in your project */ +#define USER_EMAIL "USER_EMAIL" +#define USER_PASSWORD "USER_PASSWORD" + +/* 5. Define the database secret in case we need to access database rules*/ +#define DATABASE_SECRET "DATABASE_SECRET" + +FirebaseData fbdo1; +FirebaseData fbdo2; + +FirebaseAuth auth; +FirebaseConfig config; + +//The config data for FireSense class +Firesense_Config fsConfig; + +unsigned long randomMillis = 0; + +float humidity = 0; +float temperature = 0; + +void printSerial(const char *msg) +{ + if (strlen(msg) > 0) + Serial.println(msg); +} + +void randomDemoSensorData() +{ + if (millis() - randomMillis > 5000) + { + randomMillis = millis(); + humidity = (float)random(100, 1000) / 10.1; + temperature = (float)random(100, 500) / 10.1; + } +} + +void loadDefaultConfig() +{ + //The config can be set manually from below or read from the stored config file. + + //To store the current config file (read from database and store to device storage), + //FireSense.backupConfig("/filename.txt" /* path of file to save */, mem_storage_type_flash /* or mem_storage_type_sd */); + + //To restore the current config (read from device storage and add to database), + //FireSense.restoreConfig("/filename.txt" /* path of back up file to read */, mem_storage_type_flash /* or mem_storage_type_sd */); + + FireSense_Channel channel[2]; + + channel[0].id = "HUMID1"; + channel[0].name = "Humidity sensor data"; + channel[0].location = "Room1 1"; + channel[0].type = Firesense_Channel_Type::Value; + channel[0].status = true; //to store value to the database status + channel[0].log = true; //to store value to the database log + channel[0].value_index = 0; //this the index of binded user variable which added with FireSense.addUserValue + FireSense.addChannel(channel[0]); + + channel[1].id = "TEMP1"; + channel[1].name = "Temperature sensor data"; + channel[1].location = "Room1 1"; + channel[1].type = Firesense_Channel_Type::Value; + channel[1].status = true; //to store value to the database status + channel[1].log = true; //to store value to the database log + channel[1].value_index = 1; //this the index of binded user variable which added with FireSense.addUserValue + FireSense.addChannel(channel[1]); + + FireSense_Condition cond[2]; + + cond[0].IF = "HUMID1 < 30 || HUMID1 > 70"; + cond[0].THEN = "func(0,1,'\\n[FUNC0] The humidity ({HUMID1} %) is out of range.\\n')"; + FireSense.addCondition(cond[0]); + + cond[1].IF = "TEMP1 < 15 || TEMP1 > 40"; + cond[1].THEN = "func(0,1,'\\n[FUNC0] The temperature ({TEMP1} °C) is out of range.\\n')"; + FireSense.addCondition(cond[1]); +} + +void setup() +{ + + Serial.begin(115200); + + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + Serial.print("Connecting to Wi-Fi"); + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Assign the api key (required) */ + config.api_key = API_KEY; + + /* Assign the user sign in credentials */ + auth.user.email = USER_EMAIL; + auth.user.password = USER_PASSWORD; + + /* Assign the RTDB URL (required) */ + config.database_url = DATABASE_URL; + + /* Assign the callback function for the long running token generation task */ + config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h + + Firebase.begin(&config, &auth); + + Firebase.reconnectWiFi(true); + + //Set up the config + fsConfig.basePath = "/Sensors"; + fsConfig.deviceId = "Node1"; + fsConfig.time_zone = 3; //change for your local time zone + fsConfig.daylight_offset_in_sec = 0; + fsConfig.last_seen_interval = 60 * 1000; //for store timestamp and time string in database + fsConfig.log_interval = 60 * 1000; //store data to database log every 60 seconds + fsConfig.condition_process_interval = 20; // check the conditions every 20 mSec + fsConfig.dataRetainingPeriod = 24 * 60 * 60; //keep the log data within 1 day + fsConfig.shared_fbdo = &fbdo1; //for store/restore database values + fsConfig.stream_fbdo = &fbdo2; //for stream connection object, set this stream_fbdo to nullptr for less memory usage, the stream will connected through shared Firebase Data object. + fsConfig.debug = true; + + //Add the user variable that will bind to the channels + FireSense.addUserValue(&humidity); + FireSense.addUserValue(&temperature); + + //Add the callback function that will bind to the func syntax + FireSense.addCallbackFunction(printSerial); + + //Initiate the FireSense class + FireSense.begin(&fsConfig, DATABASE_SECRET); //The database secret can be empty string when using the OAuthen2.0 sign-in method + //Load the config from database or create the default config + FireSense.loadConfig(loadDefaultConfig); //The loadDefaultConfig is the function to configure the channels and condition information. +} + +void loop() +{ + //do not use delay or blocking operating code heare + randomDemoSensorData(); +} \ No newline at end of file diff --git a/examples/Get_set_database_rules/Get_set_database_rules.ino b/examples/Get_set_database_rules/Get_set_database_rules.ino index 596f21dd..6bd67bc5 100644 --- a/examples/Get_set_database_rules/Get_set_database_rules.ino +++ b/examples/Get_set_database_rules/Get_set_database_rules.ino @@ -11,26 +11,47 @@ //This example shows how to read and write database rules +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) #include #include +#endif +//Provide the token generation process info. +#include "addons/TokenHelper.h" +//Provide the RTDB payload printing info and other helper functions. +#include "addons/RTDBHelper.h" +/* 1. Define the WiFi credentials */ #define WIFI_SSID "WIFI_AP" #define WIFI_PASSWORD "WIFI_PASSWORD" -#define FIREBASE_HOST "PROJECT_ID.firebaseio.com" +/* 2. Define the API Key */ +#define API_KEY "API_KEY" -/** The database secret is obsoleted, please use other authentication methods, - * see examples in the Authentications folder. +/* 3. Define the RTDB URL */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app + +/** 4. Define the Service Account credentials (required for token generation) + * + * This information can be taken from the service account JSON file. * - * To access the database rules, this requires the sign in as admin (sign in with OAuth2.0 access token) - * or legacy token (database secret) - * + * To download service account file, from the Firebase console, goto project settings, + * select "Service accounts" tab and click at "Generate new private key" button */ -#define FIREBASE_AUTH "DATABASE_SECRET" +#define FIREBASE_PROJECT_ID "PROJECT_ID" +#define FIREBASE_CLIENT_EMAIL "CLIENT_EMAIL" +const char PRIVATE_KEY[] PROGMEM = "-----BEGIN PRIVATE KEY-----XXXXXXXXXXXX-----END PRIVATE KEY-----\n"; //Define Firebase Data object FirebaseData fbdo; +FirebaseAuth auth; +FirebaseConfig config; + +bool taskCompleted = false; + void setup() { @@ -50,82 +71,101 @@ void setup() Serial.println(WiFi.localIP()); Serial.println(); - Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH); + /* Assign the api key (required) */ + config.api_key = API_KEY; + + /* Assign the RTDB URL (required) */ + config.database_url = DATABASE_URL; + + /* Assign the sevice account credentials and private key (required) */ + config.service_account.data.client_email = FIREBASE_CLIENT_EMAIL; + config.service_account.data.project_id = FIREBASE_PROJECT_ID; + config.service_account.data.private_key = PRIVATE_KEY; + + /* Assign the callback function for the long running token generation task */ + config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h + + Firebase.begin(&config, &auth); Firebase.reconnectWiFi(true); +#if defined(ESP8266) //Set the size of WiFi rx/tx buffers in the case where we want to work with large data. fbdo.setBSSLBufferSize(1024, 1024); +#endif //Set the size of HTTP response buffers in the case where we want to work with large data. fbdo.setResponseSize(1024); +} - String rules = ""; - - Serial.println("------------------------------------"); - Serial.println("Read Database Rules test..."); - - if (Firebase.getRules(fbdo)) +void loop() +{ + if (Firebase.ready() && !taskCompleted) { - Serial.println("PASSED"); - Serial.println("DATABASE RULES: "); + taskCompleted = true; - FirebaseJson &json = fbdo.jsonObject(); - json.toString(rules, true); - Serial.println(rules); + String rules = ""; - Serial.println(); Serial.println("------------------------------------"); - Serial.println("PARSE: "); + Serial.println("Read Database Rules test..."); - size_t len = json.iteratorBegin(); - String key, value = ""; - int type = 0; - for (size_t i = 0; i < len; i++) + if (Firebase.getRules(fbdo)) { - json.iteratorGet(i, type, key, value); - Serial.print(i); - Serial.print(", "); - Serial.print("Type: "); - Serial.print(type == FirebaseJson::JSON_OBJECT ? "object" : "array"); - if (type == FirebaseJson::JSON_OBJECT) + Serial.println("PASSED"); + Serial.println("DATABASE RULES: "); + + FirebaseJson &json = fbdo.jsonObject(); + json.toString(rules, true); + Serial.println(rules); + + Serial.println(); + Serial.println("------------------------------------"); + Serial.println("PARSE: "); + + size_t len = json.iteratorBegin(); + String key, value = ""; + int type = 0; + for (size_t i = 0; i < len; i++) { - Serial.print(", Key: "); - Serial.print(key); + json.iteratorGet(i, type, key, value); + Serial.print(i); + Serial.print(", "); + Serial.print("Type: "); + Serial.print(type == FirebaseJson::JSON_OBJECT ? "object" : "array"); + if (type == FirebaseJson::JSON_OBJECT) + { + Serial.print(", Key: "); + Serial.print(key); + } + Serial.print(", Value: "); + Serial.println(value); } - Serial.print(", Value: "); - Serial.println(value); + + json.iteratorEnd(); + Serial.println(); + } + else + { + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + Serial.println("------------------------------------"); + Serial.println(); } - json.iteratorEnd(); - Serial.println(); - } - else - { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); Serial.println("------------------------------------"); - Serial.println(); - } - - - Serial.println("------------------------------------"); - Serial.println("Write Database Rules test..."); + Serial.println("Write Database Rules test..."); - if (Firebase.setRules(fbdo, rules)) - { - Serial.println("PASSED"); - Serial.println("------------------------------------"); - Serial.println(); - } - else - { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); - Serial.println("------------------------------------"); - Serial.println(); + if (Firebase.setRules(fbdo, rules.c_str())) + { + Serial.println("PASSED"); + Serial.println("------------------------------------"); + Serial.println(); + } + else + { + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + Serial.println("------------------------------------"); + Serial.println(); + } } } - -void loop() -{ -} diff --git a/examples/Line_notify/Line_notify.ino b/examples/Line_notify/Line_notify.ino index 4a279c0e..2a871330 100644 --- a/examples/Line_notify/Line_notify.ino +++ b/examples/Line_notify/Line_notify.ino @@ -17,22 +17,41 @@ * More about Line Notify service https://notify-bot.line.me/en/ */ +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) #include #include +#endif + +//Provide the token generation process info. +#include "addons/TokenHelper.h" +//Provide the RTDB payload printing info and other helper functions. +#include "addons/RTDBHelper.h" + #include +/* 1. Define the WiFi credentials */ #define WIFI_SSID "WIFI_AP" #define WIFI_PASSWORD "WIFI_PASSWORD" -#define FIREBASE_HOST "PROJECT_ID.firebaseio.com" +/* 2. Define the API Key */ +#define API_KEY "API_KEY" -/** The database secret is obsoleted, please use other authentication methods, - * see examples in the Authentications folder. -*/ -#define FIREBASE_AUTH "DATABASE_SECRET" +/* 3. Define the RTDB URL */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app + +/* 4. Define the user Email and password that alreadey registerd or added in your project */ +#define USER_EMAIL "USER_EMAIL" +#define USER_PASSWORD "USER_PASSWORD" +//Define Firebase Data object FirebaseData fbdo; +FirebaseAuth auth; +FirebaseConfig config; + String path = "/Test"; unsigned long sendDataPrevMillis = 0; @@ -50,8 +69,6 @@ void LineNotifyResult(LineNotifySendingResult result); /* The sending callback function (optional) */ void LineNotifyCallback(LineNotifySendingResult result); -void printResult(FirebaseData &data); - void setup() { @@ -71,12 +88,35 @@ void setup() Serial.println(WiFi.localIP()); Serial.println(); - Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH); + /* Assign the api key (required) */ + config.api_key = API_KEY; + + /* Assign the user sign in credentials */ + auth.user.email = USER_EMAIL; + auth.user.password = USER_PASSWORD; + + /* Assign the RTDB URL (required) */ + config.database_url = DATABASE_URL; + + /* Assign the callback function for the long running token generation task */ + config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h + + Firebase.begin(&config, &auth); Firebase.reconnectWiFi(true); +#if defined(ESP8266) + //Set the size of WiFi rx/tx buffers in the case where we want to work with large data. + fbdo.setBSSLBufferSize(1024, 1024); +#endif + + //Set the size of HTTP response buffers in the case where we want to work with large data. + fbdo.setResponseSize(1024); + + String Path = path + "/Stream/String"; + Serial.println("------------------------------------"); Serial.println("Begin stream..."); - if (!Firebase.beginStream(fbdo, path + "/Stream/String")) + if (!Firebase.beginStream(fbdo, Path.c_str())) { Serial.println("FAILED"); Serial.println("REASON: " + fbdo.errorReason()); @@ -94,28 +134,30 @@ void setup() void loop() { - if (millis() - sendDataPrevMillis > 30000) + if (Firebase.ready() && (millis() - sendDataPrevMillis > 30000 || sendDataPrevMillis == 0)) { sendDataPrevMillis = millis(); count++; Serial.println("------------------------------------"); Serial.println("Set Data..."); - if (Firebase.setString(fbdo, path + "/Stream/String", "Hello World! " + String(count))) + String Path = path + "/Stream/String"; + String value = "Hello World! " + String(count); + if (Firebase.set(fbdo, Path.c_str(), value.c_str())) { Serial.println("PASSED"); Serial.println("PATH: " + fbdo.dataPath()); Serial.println("TYPE: " + fbdo.dataType()); Serial.print("VALUE: "); printResult(fbdo); - Serial.println("--------------------------------"); + Serial.println("------------------------------------"); Serial.println(); } else { Serial.println("FAILED"); Serial.println("REASON: " + fbdo.errorReason()); - Serial.println("--------------------------------"); + Serial.println("------------------------------------"); Serial.println(); } @@ -146,116 +188,37 @@ void loop() fbdo.pauseFirebase(false); } - if (!Firebase.readStream(fbdo)) - { - Serial.println("------------------------------------"); - Serial.println("Read stream..."); - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); - Serial.println("------------------------------------"); - Serial.println(); - } - - if (fbdo.streamTimeout()) - { - Serial.println("Stream timeout, resume streaming..."); - Serial.println(); - } - - if (fbdo.streamAvailable()) + if (Firebase.ready()) { - Serial.println("------------------------------------"); - Serial.println("Stream Data available..."); - Serial.println("STREAM PATH: " + fbdo.streamPath()); - Serial.println("EVENT PATH: " + fbdo.dataPath()); - Serial.println("DATA TYPE: " + fbdo.dataType()); - Serial.println("EVENT TYPE: " + fbdo.eventType()); - Serial.print("VALUE: "); - printResult(fbdo); - Serial.println("------------------------------------"); - Serial.println(); - } -} -void printResult(FirebaseData &data) -{ + if (!Firebase.readStream(fbdo)) + { + Serial.println("------------------------------------"); + Serial.println("Read stream..."); + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + Serial.println("------------------------------------"); + Serial.println(); + } - if (data.dataType() == "int") - Serial.println(data.intData()); - else if (data.dataType() == "float") - Serial.println(data.floatData(), 5); - else if (data.dataType() == "double") - printf("%.9lf\n", data.doubleData()); - else if (data.dataType() == "boolean") - Serial.println(data.boolData() == 1 ? "true" : "false"); - else if (data.dataType() == "string") - Serial.println(data.stringData()); - else if (data.dataType() == "json") - { - Serial.println(); - FirebaseJson &json = data.jsonObject(); - //Print all object data - Serial.println("Pretty printed JSON data:"); - String jsonStr; - json.toString(jsonStr, true); - Serial.println(jsonStr); - Serial.println(); - Serial.println("Iterate JSON data:"); - Serial.println(); - size_t len = json.iteratorBegin(); - String key, value = ""; - int type = 0; - for (size_t i = 0; i < len; i++) + if (fbdo.streamTimeout()) { - json.iteratorGet(i, type, key, value); - Serial.print(i); - Serial.print(", "); - Serial.print("Type: "); - Serial.print(type == FirebaseJson::JSON_OBJECT ? "object" : "array"); - if (type == FirebaseJson::JSON_OBJECT) - { - Serial.print(", Key: "); - Serial.print(key); - } - Serial.print(", Value: "); - Serial.println(value); + Serial.println("Stream timeout, resume streaming..."); + Serial.println(); } - json.iteratorEnd(); - } - else if (data.dataType() == "array") - { - Serial.println(); - //get array data from FirebaseData using FirebaseJsonArray object - FirebaseJsonArray &arr = data.jsonArray(); - //Print all array values - Serial.println("Pretty printed Array:"); - String arrStr; - arr.toString(arrStr, true); - Serial.println(arrStr); - Serial.println(); - Serial.println("Iterate array values:"); - Serial.println(); - for (size_t i = 0; i < arr.size(); i++) + + if (fbdo.streamAvailable()) { - Serial.print(i); - Serial.print(", Value: "); - - FirebaseJsonData &jsonData = data.jsonData(); - //Get the result data from FirebaseJsonArray object - arr.get(jsonData, i); - if (jsonData.typeNum == FirebaseJson::JSON_BOOL) - Serial.println(jsonData.boolValue ? "true" : "false"); - else if (jsonData.typeNum == FirebaseJson::JSON_INT) - Serial.println(jsonData.intValue); - else if (jsonData.typeNum == FirebaseJson::JSON_FLOAT) - Serial.println(jsonData.floatValue); - else if (jsonData.typeNum == FirebaseJson::JSON_DOUBLE) - printf("%.9lf\n", jsonData.doubleValue); - else if (jsonData.typeNum == FirebaseJson::JSON_STRING || - jsonData.typeNum == FirebaseJson::JSON_NULL || - jsonData.typeNum == FirebaseJson::JSON_OBJECT || - jsonData.typeNum == FirebaseJson::JSON_ARRAY) - Serial.println(jsonData.stringValue); + Serial.println("------------------------------------"); + Serial.println("Stream Data available..."); + Serial.println("STREAM PATH: " + fbdo.streamPath()); + Serial.println("EVENT PATH: " + fbdo.dataPath()); + Serial.println("DATA TYPE: " + fbdo.dataType()); + Serial.println("EVENT TYPE: " + fbdo.eventType()); + Serial.print("VALUE: "); + printResult(fbdo); + Serial.println("------------------------------------"); + Serial.println(); } } } diff --git a/examples/MultiPath_stream/MultiPath_stream.ino b/examples/MultiPath_stream/MultiPath_stream.ino index 5e9e2f8f..37ca63dc 100644 --- a/examples/MultiPath_stream/MultiPath_stream.ino +++ b/examples/MultiPath_stream/MultiPath_stream.ino @@ -9,41 +9,56 @@ * */ +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) #include #include +#endif +//Provide the token generation process info. +#include "addons/TokenHelper.h" +//Provide the RTDB payload printing info and other helper functions. +#include "addons/RTDBHelper.h" + +/* 1. Define the WiFi credentials */ #define WIFI_SSID "WIFI_AP" #define WIFI_PASSWORD "WIFI_PASSWORD" -#define FIREBASE_HOST "PROJECT_ID.firebaseio.com" +/* 2. Define the API Key */ +#define API_KEY "API_KEY" -/** The database secret is obsoleted, please use other authentication methods, - * see examples in the Authentications folder. -*/ -#define FIREBASE_AUTH "DATABASE_SECRET" +/* 3. Define the RTDB URL */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app + +/* 4. Define the user Email and password that alreadey registerd or added in your project */ +#define USER_EMAIL "USER_EMAIL" +#define USER_PASSWORD "USER_PASSWORD" //Define FirebaseESP8266 data object FirebaseData fbdo1; FirebaseData fbdo2; +FirebaseAuth auth; +FirebaseConfig config; + unsigned long sendDataPrevMillis = 0; String parentPath = "/Test/Stream"; -String childPath[2] = {"/node1","/node2"}; +String childPath[2] = {"/node1", "/node2"}; size_t childPathSize = 2; uint16_t count = 0; -void printResult(FirebaseData &data); - void streamCallback(MultiPathStreamData stream) { Serial.println(); Serial.println("Stream Data1 available..."); - size_t numChild = sizeof(childPath)/sizeof(childPath[0]); + size_t numChild = sizeof(childPath) / sizeof(childPath[0]); - for(size_t i = 0;i< numChild;i++) + for (size_t i = 0; i < numChild; i++) { if (stream.get(childPath[i])) { @@ -52,7 +67,6 @@ void streamCallback(MultiPathStreamData stream) } Serial.println(); - } void streamTimeoutCallback(bool timeout) @@ -82,23 +96,47 @@ void setup() Serial.println(WiFi.localIP()); Serial.println(); - Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH); + /* Assign the api key (required) */ + config.api_key = API_KEY; + + /* Assign the user sign in credentials */ + auth.user.email = USER_EMAIL; + auth.user.password = USER_PASSWORD; + + /* Assign the RTDB URL (required) */ + config.database_url = DATABASE_URL; + + /* Assign the callback function for the long running token generation task */ + config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h + + Firebase.begin(&config, &auth); Firebase.reconnectWiFi(true); +#if defined(ESP8266) //Set the size of WiFi rx/tx buffers in the case where we want to work with large data. fbdo1.setBSSLBufferSize(1024, 1024); +#endif //Set the size of HTTP response buffers in the case where we want to work with large data. fbdo1.setResponseSize(1024); - +#if defined(ESP8266) //Set the size of WiFi rx/tx buffers in the case where we want to work with large data. fbdo2.setBSSLBufferSize(1024, 1024); +#endif //Set the size of HTTP response buffers in the case where we want to work with large data. fbdo2.setResponseSize(1024); - if (!Firebase.beginMultiPathStream(fbdo1, parentPath, childPath, childPathSize)) + //The data under the node being stream (parent path) should keep small + //Large stream payload leads to the parsing error due to memory allocation. + + //The operations is the same as normal stream unless the JSON stream payload will be parsed + //with the predefined node path (child paths). + + //The changes occurred in any child node that is not in the child paths array will sent to the + //client as usual. + if (!Firebase.beginMultiPathStream(fbdo1, parentPath.c_str(), childPath, childPathSize)) { Serial.println("------------------------------------"); Serial.println("Can't begin stream connection..."); @@ -113,7 +151,7 @@ void setup() void loop() { - if (millis() - sendDataPrevMillis > 15000) + if (Firebase.ready() && (millis() - sendDataPrevMillis > 15000 || sendDataPrevMillis == 0)) { sendDataPrevMillis = millis(); count++; @@ -126,7 +164,7 @@ void loop() json.set("node1/num", count); json.set("node2/data", "hi"); json.set("node2/num", count); - if (Firebase.setJSON(fbdo2, parentPath, json)) + if (Firebase.setJSON(fbdo2, parentPath.c_str(), json)) { Serial.println("PASSED"); Serial.println(); @@ -144,7 +182,9 @@ void loop() Serial.println("------------------------------------"); Serial.println("Set string..."); - if (Firebase.setString(fbdo2, parentPath + "/node2/new/data", "test")) + String Path = parentPath + "/node2/new/data"; + + if (Firebase.setString(fbdo2, Path.c_str(), "test")) { Serial.println("PASSED"); Serial.println(); @@ -157,12 +197,14 @@ void loop() Serial.println(); } - //This will trig the another stream event. + //This will trig the another stream event. Serial.println("------------------------------------"); Serial.println("Set int..."); - if (Firebase.setInt(fbdo2, parentPath + "/node1/new/data", count)) + Path = parentPath + "/node1/new/data"; + + if (Firebase.setInt(fbdo2, Path.c_str(), count)) { Serial.println("PASSED"); Serial.println(); diff --git a/examples/Priority/Priority.ino b/examples/Priority/Priority.ino index 38d0897d..eac2e5f4 100644 --- a/examples/Priority/Priority.ino +++ b/examples/Priority/Priority.ino @@ -14,25 +14,42 @@ //Since data ordering is not supported in Firebase's REST APIs, then the query result will not sorted. +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) #include #include +#endif +//Provide the token generation process info. +#include "addons/TokenHelper.h" +//Provide the RTDB payload printing info and other helper functions. +#include "addons/RTDBHelper.h" + +/* 1. Define the WiFi credentials */ #define WIFI_SSID "WIFI_AP" #define WIFI_PASSWORD "WIFI_PASSWORD" -#define FIREBASE_HOST "PROJECT_ID.firebaseio.com" +/* 2. Define the API Key */ +#define API_KEY "API_KEY" -/** The database secret is obsoleted, please use other authentication methods, - * see examples in the Authentications folder. -*/ -#define FIREBASE_AUTH "DATABASE_SECRET" +/* 3. Define the RTDB URL */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app + +/* 4. Define the user Email and password that alreadey registerd or added in your project */ +#define USER_EMAIL "USER_EMAIL" +#define USER_PASSWORD "USER_PASSWORD" -//Define Firebase Data object +//Define FirebaseESP8266 data object FirebaseData fbdo; -FirebaseJson json; +FirebaseAuth auth; +FirebaseConfig config; + +bool taskCompleted = false; -void printResult(FirebaseData &data); +FirebaseJson json; void setup() { @@ -53,206 +70,97 @@ void setup() Serial.println(WiFi.localIP()); Serial.println(); - Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH); + /* Assign the api key (required) */ + config.api_key = API_KEY; + + /* Assign the user sign in credentials */ + auth.user.email = USER_EMAIL; + auth.user.password = USER_PASSWORD; + + /* Assign the RTDB URL (required) */ + config.database_url = DATABASE_URL; + + /* Assign the callback function for the long running token generation task */ + config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h + + Firebase.begin(&config, &auth); Firebase.reconnectWiFi(true); +#if defined(ESP8266) //Set the size of WiFi rx/tx buffers in the case where we want to work with large data. fbdo.setBSSLBufferSize(1024, 1024); +#endif //Set the size of HTTP response buffers in the case where we want to work with large data. fbdo.setResponseSize(1024); +} - String path = "/Test"; - - Serial.println("------------------------------------"); - Serial.println("Set priority test..."); - - for (int i = 0; i < 15; i++) +void loop() +{ + if (Firebase.ready() && !taskCompleted) { + taskCompleted = true; - float priority = 15 - i; - String key = "item_" + String(i + 1); - String val = "value_" + String(i + 1); - json.clear(); - json.set(key, val); - String Path = path + "/Items/priority_" + String(15 - i); + String path = "/Test"; - if (Firebase.setJSON(fbdo, Path, json, priority)) - { - Serial.println("PASSED"); - Serial.println("PATH: " + fbdo.dataPath()); - Serial.println("TYPE: " + fbdo.dataType()); - Serial.println("CURRENT ETag: " + fbdo.ETag()); - Serial.print("VALUE: "); - printResult(fbdo); - Serial.println("------------------------------------"); - Serial.println(); - } - else - { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); - Serial.println("------------------------------------"); - Serial.println(); - } - } - - //Qury child nodes under "/Test/Item" with priority between 3.0 and 8.0 - //Since data ordering is not supported in Firebase's REST APIs, then the query result will not sorted. - QueryFilter query; - query.orderBy("$priority").startAt(3.0).endAt(8.0); - - Serial.println("------------------------------------"); - Serial.println("Filtering based on priority test..."); - - if (Firebase.getJSON(fbdo, path + "/Items", query)) - { - - Serial.println("PASSED"); - Serial.println("JSON DATA: "); - printResult(fbdo); - Serial.println("------------------------------------"); - Serial.println(); - } - else - { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); Serial.println("------------------------------------"); - Serial.println(); - } -} + Serial.println("Set priority test..."); -void printResult(FirebaseData &data) -{ - - if (data.dataType() == "int") - Serial.println(data.intData()); - else if (data.dataType() == "float") - Serial.println(data.floatData(), 5); - else if (data.dataType() == "double") - printf("%.9lf\n", data.doubleData()); - else if (data.dataType() == "boolean") - Serial.println(data.boolData() == 1 ? "true" : "false"); - else if (data.dataType() == "string") - Serial.println(data.stringData()); - else if (data.dataType() == "json") - { - Serial.println(); - FirebaseJson &json = data.jsonObject(); - //Print all object data - Serial.println("Pretty printed JSON data:"); - String jsonStr; - json.toString(jsonStr, true); - Serial.println(jsonStr); - Serial.println(); - Serial.println("Iterate JSON data:"); - Serial.println(); - size_t len = json.iteratorBegin(); - String key, value = ""; - int type = 0; - for (size_t i = 0; i < len; i++) + for (int i = 0; i < 15; i++) { - json.iteratorGet(i, type, key, value); - Serial.print(i); - Serial.print(", "); - Serial.print("Type: "); - Serial.print(type == FirebaseJson::JSON_OBJECT ? "object" : "array"); - if (type == FirebaseJson::JSON_OBJECT) - { - Serial.print(", Key: "); - Serial.print(key); - } - Serial.print(", Value: "); - Serial.println(value); - } - json.iteratorEnd(); - } - else if (data.dataType() == "array") - { - Serial.println(); - //get array data from FirebaseData using FirebaseJsonArray object - FirebaseJsonArray &arr = data.jsonArray(); - //Print all array values - Serial.println("Pretty printed Array:"); - String arrStr; - arr.toString(arrStr, true); - Serial.println(arrStr); - Serial.println(); - Serial.println("Iterate array values:"); - Serial.println(); - for (size_t i = 0; i < arr.size(); i++) - { - Serial.print(i); - Serial.print(", Value: "); - - FirebaseJsonData &jsonData = data.jsonData(); - //Get the result data from FirebaseJsonArray object - arr.get(jsonData, i); - if (jsonData.typeNum == FirebaseJson::JSON_BOOL) - Serial.println(jsonData.boolValue ? "true" : "false"); - else if (jsonData.typeNum == FirebaseJson::JSON_INT) - Serial.println(jsonData.intValue); - else if (jsonData.typeNum == FirebaseJson::JSON_FLOAT) - Serial.println(jsonData.floatValue); - else if (jsonData.typeNum == FirebaseJson::JSON_DOUBLE) - printf("%.9lf\n", jsonData.doubleValue); - else if (jsonData.typeNum == FirebaseJson::JSON_STRING || - jsonData.typeNum == FirebaseJson::JSON_NULL || - jsonData.typeNum == FirebaseJson::JSON_OBJECT || - jsonData.typeNum == FirebaseJson::JSON_ARRAY) - Serial.println(jsonData.stringValue); - } - } - else if (data.dataType() == "blob") - { - Serial.println(); + float priority = 15 - i; + String key = "item_" + String(i + 1); + String val = "value_" + String(i + 1); + json.clear(); + json.set(key, val); + String Path = path + "/Items/priority_" + String(15 - i); - for (int i = 0; i < data.blobData().size(); i++) - { - if (i > 0 && i % 16 == 0) + if (Firebase.setJSON(fbdo, Path.c_str(), json, priority)) + { + Serial.println("PASSED"); + Serial.println("PATH: " + fbdo.dataPath()); + Serial.println("TYPE: " + fbdo.dataType()); + Serial.println("CURRENT ETag: " + fbdo.ETag()); + Serial.print("VALUE: "); + printResult(fbdo); //see addons/RTDBHelper.h + Serial.println("------------------------------------"); Serial.println(); - - if (i < 16) - Serial.print("0"); - - Serial.print(data.blobData()[i], HEX); - Serial.print(" "); + } + else + { + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + Serial.println("------------------------------------"); + Serial.println(); + } } - Serial.println(); - } - else if (data.dataType() == "file") - { - - Serial.println(); - File file = data.fileStream(); - int i = 0; + //Qury child nodes under "/Test/Item" with priority between 3.0 and 8.0 + //Since data ordering is not supported in Firebase's REST APIs, then the query result will not sorted. + QueryFilter query; + query.orderBy("$priority").startAt(3.0).endAt(8.0); - while (file.available()) - { - if (i > 0 && i % 16 == 0) - Serial.println(); + Serial.println("------------------------------------"); + Serial.println("Filtering based on priority test..."); - int v = file.read(); + String Path = path + "/Items"; - if (v < 16) - Serial.print("0"); + if (Firebase.getJSON(fbdo, Path.c_str(), query)) + { - Serial.print(v, HEX); - Serial.print(" "); - i++; + Serial.println("PASSED"); + Serial.println("JSON DATA: "); + printResult(fbdo); //see addons/RTDBHelper.h + Serial.println("------------------------------------"); + Serial.println(); + } + else + { + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + Serial.println("------------------------------------"); + Serial.println(); } - Serial.println(); - file.close(); - } - else - { - Serial.println(data.payload()); } } - -void loop() -{ -} diff --git a/examples/Retry_and_queue/Retry_and_queue.ino b/examples/Retry_and_queue/Retry_and_queue.ino index 378231e1..3f3112b0 100644 --- a/examples/Retry_and_queue/Retry_and_queue.ino +++ b/examples/Retry_and_queue/Retry_and_queue.ino @@ -11,21 +11,40 @@ //This example shows how error retry and queues work. +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) #include #include +#endif +//Provide the token generation process info. +#include "addons/TokenHelper.h" +//Provide the RTDB payload printing info and other helper functions. +#include "addons/RTDBHelper.h" + +/* 1. Define the WiFi credentials */ #define WIFI_SSID "WIFI_AP" #define WIFI_PASSWORD "WIFI_PASSWORD" -#define FIREBASE_HOST "PROJECT_ID.firebaseio.com" +/* 2. Define the API Key */ +#define API_KEY "API_KEY" -/** The database secret is obsoleted, please use other authentication methods, - * see examples in the Authentications folder. -*/ -#define FIREBASE_AUTH "DATABASE_SECRET" -//Define Firebase Data object +/* 3. Define the RTDB URL */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app + +/* 4. Define the user Email and password that alreadey registerd or added in your project */ +#define USER_EMAIL "USER_EMAIL" +#define USER_PASSWORD "USER_PASSWORD" + +//Define FirebaseESP8266 data object FirebaseData fbdo; +FirebaseAuth auth; +FirebaseConfig config; + +bool taskCompleted = false; String path = "/Test"; @@ -35,8 +54,6 @@ double mydouble = 0; uint32_t queueID[20]; uint8_t qIdx = 0; -void printResult(FirebaseData &data); - void callback(QueueInfo queueinfo) { @@ -49,10 +66,10 @@ void callback(QueueInfo queueinfo) Serial.println(queueinfo.totalQueues()); Serial.print("Being processed queue ID: "); - Serial.println(queueinfo.currentQueueID()); + Serial.println(queueinfo.currentQueueID()); Serial.print("Data type:"); - Serial.println(queueinfo.dataType()); + Serial.println(queueinfo.dataType()); Serial.print("Method: "); Serial.println(queueinfo.firebaseMethod()); @@ -82,18 +99,32 @@ void setup() Serial.println(WiFi.localIP()); Serial.println(); - Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH); + /* Assign the api key (required) */ + config.api_key = API_KEY; + + /* Assign the user sign in credentials */ + auth.user.email = USER_EMAIL; + auth.user.password = USER_PASSWORD; + + /* Assign the RTDB URL (required) */ + config.database_url = DATABASE_URL; + + /* Assign the callback function for the long running token generation task */ + config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h + + Firebase.begin(&config, &auth); Firebase.reconnectWiFi(true); +#if defined(ESP8266) //Set the size of WiFi rx/tx buffers in the case where we want to work with large data. fbdo.setBSSLBufferSize(1024, 1024); +#endif //Set the size of HTTP response buffers in the case where we want to work with large data. fbdo.setResponseSize(1024); - - //Open and retore Firebase Error Queues from file. + //The file systems for flash and SD/SDMMC can be changed in FirebaseFS.h. if (Firebase.errorQueueCount(fbdo, "/test.txt", StorageType::FLASH) > 0) { Firebase.restoreErrorQueue(fbdo, "/test.txt", StorageType::FLASH); @@ -107,175 +138,188 @@ void setup() //Firebase read/store operation causes by network problems and buffer overflow will be added to Firebase Error Queues collection. Firebase.setMaxErrorQueue(fbdo, 10); - Firebase.beginAutoRunErrorQueue(fbdo, callback); //Firebase.beginAutoRunErrorQueue(fbdo); +} +void loop() +{ + if (Firebase.ready() && !taskCompleted) + { + taskCompleted = true; - Serial.println("------------------------------------"); - Serial.println("Set BLOB data test..."); + Serial.println("------------------------------------"); + Serial.println("Set BLOB data test..."); - //Create demo data - uint8_t data[256]; - for (int i = 0; i < 256; i++) - data[i] = i; + //Create demo data + uint8_t data[256]; + for (int i = 0; i < 256; i++) + data[i] = i; - //Set binary data to database - if (Firebase.setBlob(fbdo, path + "/Binary/Blob/data", data, sizeof(data))) - { - Serial.println("PASSED"); - Serial.println("------------------------------------"); - Serial.println(); - } - else - { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); - if (Firebase.getErrorQueueID(fbdo) > 0) + String Path = path + "/Binary/Blob/data"; + + //Set binary data to database + if (Firebase.setBlob(fbdo, Path.c_str(), data, sizeof(data))) { - Serial.println("Error Queue ID: " + String(Firebase.getErrorQueueID(fbdo))); - queueID[qIdx] = Firebase.getErrorQueueID(fbdo); - qIdx++; + Serial.println("PASSED"); + Serial.println("------------------------------------"); + Serial.println(); + } + else + { + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + if (Firebase.getErrorQueueID(fbdo) > 0) + { + Serial.println("Error Queue ID: " + String(Firebase.getErrorQueueID(fbdo))); + queueID[qIdx] = Firebase.getErrorQueueID(fbdo); + qIdx++; + } + Serial.println("------------------------------------"); + Serial.println(); } - Serial.println("------------------------------------"); - Serial.println(); - } - if (WiFi.status() == WL_CONNECTED) - { - Serial.println("--------------------------------------------------------------------------"); - Serial.println("To test error queue, turn off WiFi AP to make error in the next operation"); - Serial.println("--------------------------------------------------------------------------"); - Serial.println(); + if (WiFi.status() == WL_CONNECTED) + { + Serial.println("--------------------------------------------------------------------------"); + Serial.println("To test error queue, turn off WiFi AP to make error in the next operation"); + Serial.println("--------------------------------------------------------------------------"); + Serial.println(); - delay(10000); - } + delay(10000); + } - Serial.println("------------------------------------"); - Serial.println("Get BLOB data test..."); + Serial.println("------------------------------------"); + Serial.println("Get BLOB data test..."); - //Get binary data from database - //Assign myblob as the target variable - if (Firebase.getBlob(fbdo, path + "/Binary/Blob/data", myblob)) - { - Serial.println("PASSED"); - Serial.println("PATH: " + fbdo.dataPath()); - Serial.println("TYPE: " + fbdo.dataType()); - Serial.print("VALUE: "); - if (fbdo.dataType() == "blob") + Path = path + "/Binary/Blob/data"; + + //Get binary data from database + //Assign myblob as the target variable + if (Firebase.getBlob(fbdo, Path.c_str(), myblob)) { + Serial.println("PASSED"); + Serial.println("PATH: " + fbdo.dataPath()); + Serial.println("TYPE: " + fbdo.dataType()); + Serial.print("VALUE: "); + if (fbdo.dataType() == "blob") + { - Serial.println(); + Serial.println(); - for (size_t i = 0; i < myblob.size(); i++) - { - if (i > 0 && i % 16 == 0) - Serial.println(); + for (size_t i = 0; i < myblob.size(); i++) + { + if (i > 0 && i % 16 == 0) + Serial.println(); - if (i < 16) - Serial.print("0"); + if (i < 16) + Serial.print("0"); - Serial.print(myblob[i], HEX); - Serial.print(" "); + Serial.print(myblob[i], HEX); + Serial.print(" "); + } + myblob.clear(); + Serial.println(); } - myblob.clear(); + Serial.println("------------------------------------"); Serial.println(); } - Serial.println("------------------------------------"); - Serial.println(); - } - else - { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); - if (Firebase.getErrorQueueID(fbdo) > 0) + else { - Serial.println("Error Queue ID: " + String(Firebase.getErrorQueueID(fbdo))); - queueID[qIdx] = Firebase.getErrorQueueID(fbdo); - qIdx++; + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + if (Firebase.getErrorQueueID(fbdo) > 0) + { + Serial.println("Error Queue ID: " + String(Firebase.getErrorQueueID(fbdo))); + queueID[qIdx] = Firebase.getErrorQueueID(fbdo); + qIdx++; + } + Serial.println("------------------------------------"); + Serial.println(); } + Serial.println("------------------------------------"); - Serial.println(); - } + Serial.println("Set double test..."); - Serial.println("------------------------------------"); - Serial.println("Set double test..."); + Path = path + "/Double/Data"; - if (Firebase.setDouble(fbdo, path + "/Double/Data", 340.123456789)) - { - Serial.println("PASSED"); - Serial.println("PATH: " + fbdo.dataPath()); - Serial.println("TYPE: " + fbdo.dataType()); - Serial.print("VALUE: "); - printResult(fbdo); - Serial.println("------------------------------------"); - Serial.println(); - } - else - { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); - if (Firebase.getErrorQueueID(fbdo) > 0) + if (Firebase.setDouble(fbdo, Path.c_str(), 340.123456789)) { - Serial.println("Error Queue ID: " + String(Firebase.getErrorQueueID(fbdo))); - queueID[qIdx] = Firebase.getErrorQueueID(fbdo); - qIdx++; + Serial.println("PASSED"); + Serial.println("PATH: " + fbdo.dataPath()); + Serial.println("TYPE: " + fbdo.dataType()); + Serial.print("VALUE: "); + printResult(fbdo); //see addons/RTDBHelper.h + Serial.println("------------------------------------"); + Serial.println(); } + else + { + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + if (Firebase.getErrorQueueID(fbdo) > 0) + { + Serial.println("Error Queue ID: " + String(Firebase.getErrorQueueID(fbdo))); + queueID[qIdx] = Firebase.getErrorQueueID(fbdo); + qIdx++; + } + Serial.println("------------------------------------"); + Serial.println(); + } + Serial.println("------------------------------------"); - Serial.println(); - } + Serial.println("Get double test..."); - Serial.println("------------------------------------"); - Serial.println("Get double test..."); + Path = path + "/Double/Data"; - if (Firebase.getDouble(fbdo, path + "/Double/Data", mydouble)) - { - Serial.println("PASSED"); - Serial.println("PATH: " + fbdo.dataPath()); - Serial.println("TYPE: " + fbdo.dataType()); - Serial.print("VALUE: "); - printResult(fbdo); - Serial.println("------------------------------------"); - Serial.println(); - mydouble = 0; - } - else - { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); - if (Firebase.getErrorQueueID(fbdo) > 0) + if (Firebase.getDouble(fbdo, Path.c_str(), mydouble)) { - Serial.println("Error Queue ID: " + String(Firebase.getErrorQueueID(fbdo))); - queueID[qIdx] = Firebase.getErrorQueueID(fbdo); - qIdx++; + Serial.println("PASSED"); + Serial.println("PATH: " + fbdo.dataPath()); + Serial.println("TYPE: " + fbdo.dataType()); + Serial.print("VALUE: "); + printResult(fbdo); //see addons/RTDBHelper.h + Serial.println("------------------------------------"); + Serial.println(); + mydouble = 0; + } + else + { + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + if (Firebase.getErrorQueueID(fbdo) > 0) + { + Serial.println("Error Queue ID: " + String(Firebase.getErrorQueueID(fbdo))); + queueID[qIdx] = Firebase.getErrorQueueID(fbdo); + qIdx++; + } + Serial.println("------------------------------------"); + Serial.println(); } - Serial.println("------------------------------------"); - Serial.println(); - } - if (Firebase.errorQueueCount(fbdo) > 0) - { - Serial.println("-----------------------------------------------------------------------------"); - Serial.println("Now turn on WiFi hotspot or router to process these queues"); - Serial.println("-----------------------------------------------------------------------------"); - Serial.println(); + if (Firebase.errorQueueCount(fbdo) > 0) + { + Serial.println("-----------------------------------------------------------------------------"); + Serial.println("Now turn on WiFi hotspot or router to process these queues"); + Serial.println("-----------------------------------------------------------------------------"); + Serial.println(); - //Save Error Queues to file - Firebase.saveErrorQueue(fbdo, "/test.txt", StorageType::FLASH); + //Save Error Queues to file + //The file systems for flash and SD/SDMMC can be changed in FirebaseFS.h. + Firebase.saveErrorQueue(fbdo, "/test.txt", StorageType::FLASH); + } + + //Stop error queue auto run process + //Firebase.endAutoRunErrorQueue(fbdo); } - //Stop error queue auto run process - //Firebase.endAutoRunErrorQueue(fbdo); -} + if (!Firebase.ready()) + return; -void loop() -{ if (Firebase.errorQueueCount(fbdo) > 0) { - - /* if Firebase.beginAutoRunErrorQueue was not call, @@ -336,90 +380,3 @@ void loop() } } } - -void printResult(FirebaseData &data) -{ - - if (data.dataType() == "int") - Serial.println(data.intData()); - else if (data.dataType() == "float") - Serial.println(data.floatData(), 5); - else if (data.dataType() == "double") - printf("%.9lf\n", data.doubleData()); - else if (data.dataType() == "boolean") - Serial.println(data.boolData() == 1 ? "true" : "false"); - else if (data.dataType() == "string") - Serial.println(data.stringData()); - else if (data.dataType() == "json") - { - Serial.println(); - FirebaseJson &json = data.jsonObject(); - //Print all object data - Serial.println("Pretty printed JSON data:"); - String jsonStr; - json.toString(jsonStr, true); - Serial.println(jsonStr); - Serial.println(); - Serial.println("Iterate JSON data:"); - Serial.println(); - size_t len = json.iteratorBegin(); - String key, value = ""; - int type = 0; - for (size_t i = 0; i < len; i++) - { - json.iteratorGet(i, type, key, value); - Serial.print(i); - Serial.print(", "); - Serial.print("Type: "); - Serial.print(type == FirebaseJson::JSON_OBJECT ? "object" : "array"); - if (type == FirebaseJson::JSON_OBJECT) - { - Serial.print(", Key: "); - Serial.print(key); - } - Serial.print(", Value: "); - Serial.println(value); - } - json.iteratorEnd(); - } - else if (data.dataType() == "array") - { - Serial.println(); - //get array data from FirebaseData using FirebaseJsonArray object - FirebaseJsonArray &arr = data.jsonArray(); - //Print all array values - Serial.println("Pretty printed Array:"); - String arrStr; - arr.toString(arrStr, true); - Serial.println(arrStr); - Serial.println(); - Serial.println("Iterate array values:"); - Serial.println(); - for (size_t i = 0; i < arr.size(); i++) - { - Serial.print(i); - Serial.print(", Value: "); - - FirebaseJsonData &jsonData = data.jsonData(); - //Get the result data from FirebaseJsonArray object - arr.get(jsonData, i); - if (jsonData.typeNum == FirebaseJson::JSON_BOOL) - Serial.println(jsonData.boolValue ? "true" : "false"); - else if (jsonData.typeNum == FirebaseJson::JSON_INT) - Serial.println(jsonData.intValue); - else if (jsonData.typeNum == FirebaseJson::JSON_FLOAT) - Serial.println(jsonData.floatValue); - else if (jsonData.typeNum == FirebaseJson::JSON_DOUBLE) - printf("%.9lf\n", jsonData.doubleValue); - else if (jsonData.typeNum == FirebaseJson::JSON_STRING || - jsonData.typeNum == FirebaseJson::JSON_NULL || - jsonData.typeNum == FirebaseJson::JSON_OBJECT || - jsonData.typeNum == FirebaseJson::JSON_ARRAY) - Serial.println(jsonData.stringValue); - } - } - else - { - Serial.println(data.payload()); - } -} diff --git a/examples/Shallowed_data/Shallowed_data.ino b/examples/Shallowed_data/Shallowed_data.ino index 49312e38..86f9ee9f 100644 --- a/examples/Shallowed_data/Shallowed_data.ino +++ b/examples/Shallowed_data/Shallowed_data.ino @@ -11,25 +11,42 @@ //This example shows how to retrieve all database data using shallowed data. +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) #include #include +#endif +//Provide the token generation process info. +#include "addons/TokenHelper.h" +//Provide the RTDB payload printing info and other helper functions. +#include "addons/RTDBHelper.h" + +/* 1. Define the WiFi credentials */ #define WIFI_SSID "WIFI_AP" #define WIFI_PASSWORD "WIFI_PASSWORD" -#define FIREBASE_HOST "PROJECT_ID.firebaseio.com" +/* 2. Define the API Key */ +#define API_KEY "API_KEY" -/** The database secret is obsoleted, please use other authentication methods, - * see examples in the Authentications folder. -*/ -#define FIREBASE_AUTH "DATABASE_SECRET" +/* 3. Define the RTDB URL */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app -//Define Firebase Data object +/* 4. Define the user Email and password that alreadey registerd or added in your project */ +#define USER_EMAIL "USER_EMAIL" +#define USER_PASSWORD "USER_PASSWORD" + +//Define FirebaseESP8266 data object FirebaseData fbdo; -String path = "/"; +FirebaseAuth auth; +FirebaseConfig config; -void printResult(FirebaseData &data); +bool taskCompleted = false; + +String path = "/"; void setup() { @@ -50,7 +67,20 @@ void setup() Serial.println(WiFi.localIP()); Serial.println(); - Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH); + /* Assign the api key (required) */ + config.api_key = API_KEY; + + /* Assign the user sign in credentials */ + auth.user.email = USER_EMAIL; + auth.user.password = USER_PASSWORD; + + /* Assign the RTDB URL (required) */ + config.database_url = DATABASE_URL; + + /* Assign the callback function for the long running token generation task */ + config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h + + Firebase.begin(&config, &auth); Firebase.reconnectWiFi(true); //Set database read timeout to 1 minute (max 15 minutes) @@ -58,162 +88,36 @@ void setup() //tiny, small, medium, large and unlimited. //Size and its write timeout e.g. tiny (1s), small (10s), medium (30s) and large (60s). Firebase.setwriteSizeLimit(fbdo, "tiny"); - - //The following test will print all parent nodes and their shallowed data - - Serial.println("------------------------------------"); - Serial.println("Shallowed Data test..."); - Serial.println(); - - if (Firebase.getShallowData(fbdo, path)) - { - Serial.println("PASSED"); - Serial.println("PATH: " + fbdo.dataPath()); - Serial.println("TYPE: " + fbdo.dataType()); - Serial.print("VALUE: "); - printResult(fbdo); - Serial.println("------------------------------------"); - Serial.println(); - } - else - { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); - Serial.println("------------------------------------"); - Serial.println(); - } } -void printResult(FirebaseData &data) +void loop() { - - if (data.dataType() == "int") - Serial.println(data.intData()); - else if (data.dataType() == "float") - Serial.println(data.floatData(), 5); - else if (data.dataType() == "double") - printf("%.9lf\n", data.doubleData()); - else if (data.dataType() == "boolean") - Serial.println(data.boolData() == 1 ? "true" : "false"); - else if (data.dataType() == "string") - Serial.println(data.stringData()); - else if (data.dataType() == "json") - { - Serial.println(); - FirebaseJson &json = data.jsonObject(); - //Print all object data - Serial.println("Pretty printed JSON data:"); - String jsonStr; - json.toString(jsonStr, true); - Serial.println(jsonStr); - Serial.println(); - Serial.println("Iterate JSON data:"); - Serial.println(); - size_t len = json.iteratorBegin(); - String key, value = ""; - int type = 0; - for (size_t i = 0; i < len; i++) - { - json.iteratorGet(i, type, key, value); - Serial.print(i); - Serial.print(", "); - Serial.print("Type: "); - Serial.print(type == FirebaseJson::JSON_OBJECT ? "object" : "array"); - if (type == FirebaseJson::JSON_OBJECT) - { - Serial.print(", Key: "); - Serial.print(key); - } - Serial.print(", Value: "); - Serial.println(value); - } - json.iteratorEnd(); - } - else if (data.dataType() == "array") - { - Serial.println(); - //get array data from FirebaseData using FirebaseJsonArray object - FirebaseJsonArray &arr = data.jsonArray(); - //Print all array values - Serial.println("Pretty printed Array:"); - String arrStr; - arr.toString(arrStr, true); - Serial.println(arrStr); - Serial.println(); - Serial.println("Iterate array values:"); - Serial.println(); - for (size_t i = 0; i < arr.size(); i++) - { - Serial.print(i); - Serial.print(", Value: "); - - FirebaseJsonData &jsonData = data.jsonData(); - //Get the result data from FirebaseJsonArray object - arr.get(jsonData, i); - if (jsonData.typeNum == FirebaseJson::JSON_BOOL) - Serial.println(jsonData.boolValue ? "true" : "false"); - else if (jsonData.typeNum == FirebaseJson::JSON_INT) - Serial.println(jsonData.intValue); - else if (jsonData.typeNum == FirebaseJson::JSON_FLOAT) - Serial.println(jsonData.floatValue); - else if (jsonData.typeNum == FirebaseJson::JSON_DOUBLE) - printf("%.9lf\n", jsonData.doubleValue); - else if (jsonData.typeNum == FirebaseJson::JSON_STRING || - jsonData.typeNum == FirebaseJson::JSON_NULL || - jsonData.typeNum == FirebaseJson::JSON_OBJECT || - jsonData.typeNum == FirebaseJson::JSON_ARRAY) - Serial.println(jsonData.stringValue); - } - } - else if (data.dataType() == "blob") + if (Firebase.ready() && !taskCompleted) { + taskCompleted = true; + //The following test will print all parent nodes and their shallowed data + + Serial.println("------------------------------------"); + Serial.println("Shallowed Data test..."); Serial.println(); - for (int i = 0; i < data.blobData().size(); i++) + if (Firebase.getShallowData(fbdo, path.c_str())) { - if (i > 0 && i % 16 == 0) - Serial.println(); - - if (i < 16) - Serial.print("0"); - - Serial.print(data.blobData()[i], HEX); - Serial.print(" "); + Serial.println("PASSED"); + Serial.println("PATH: " + fbdo.dataPath()); + Serial.println("TYPE: " + fbdo.dataType()); + Serial.print("VALUE: "); + printResult(fbdo); //see addons/RTDBHelper.h + Serial.println("------------------------------------"); + Serial.println(); } - Serial.println(); - } - else if (data.dataType() == "file") - { - - Serial.println(); - - File file = data.fileStream(); - int i = 0; - - while (file.available()) + else { - if (i > 0 && i % 16 == 0) - Serial.println(); - - int v = file.read(); - - if (v < 16) - Serial.print("0"); - - Serial.print(v, HEX); - Serial.print(" "); - i++; + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + Serial.println("------------------------------------"); + Serial.println(); } - Serial.println(); - file.close(); - } - else - { - Serial.println(data.payload()); } } - -void loop() -{ -} diff --git a/examples/Stream/Stream.ino b/examples/Stream/Stream.ino index 1d686d48..7ae003d8 100644 --- a/examples/Stream/Stream.ino +++ b/examples/Stream/Stream.ino @@ -9,22 +9,38 @@ * */ +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) #include #include +#endif +//Provide the token generation process info. +#include "addons/TokenHelper.h" +//Provide the RTDB payload printing info and other helper functions. +#include "addons/RTDBHelper.h" + +/* 1. Define the WiFi credentials */ #define WIFI_SSID "WIFI_AP" #define WIFI_PASSWORD "WIFI_PASSWORD" -#define FIREBASE_HOST "PROJECT_ID.firebaseio.com" +/* 2. Define the API Key */ +#define API_KEY "API_KEY" -/** The database secret is obsoleted, please use other authentication methods, - * see examples in the Authentications folder. -*/ -#define FIREBASE_AUTH "DATABASE_SECRET" +/* 3. Define the RTDB URL */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app + +/* 4. Define the user Email and password that alreadey registerd or added in your project */ +#define USER_EMAIL "USER_EMAIL" +#define USER_PASSWORD "USER_PASSWORD" //Define FirebaseESP8266 data object FirebaseData fbdo; +FirebaseAuth auth; +FirebaseConfig config; unsigned long sendDataPrevMillis = 0; @@ -32,8 +48,6 @@ String path = "/Test/Stream"; uint16_t count = 0; -void printResult(FirebaseData &data); - void setup() { @@ -51,16 +65,33 @@ void setup() Serial.println(WiFi.localIP()); Serial.println(); - Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH); + /* Assign the api key (required) */ + config.api_key = API_KEY; + + /* Assign the user sign in credentials */ + auth.user.email = USER_EMAIL; + auth.user.password = USER_PASSWORD; + + /* Assign the RTDB URL (required) */ + config.database_url = DATABASE_URL; + + /* Assign the callback function for the long running token generation task */ + config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h + + Firebase.begin(&config, &auth); Firebase.reconnectWiFi(true); +#if defined(ESP8266) //Set the size of WiFi rx/tx buffers in the case where we want to work with large data. fbdo.setBSSLBufferSize(1024, 1024); +#endif //Set the size of HTTP response buffers in the case where we want to work with large data. fbdo.setResponseSize(1024); - if (!Firebase.beginStream(fbdo, path)) + //The data under the node being stream (parent path) should keep small + //Large stream payload leads to the parsing error due to memory allocation. + if (!Firebase.beginStream(fbdo, path.c_str())) { Serial.println("------------------------------------"); Serial.println("Can't begin stream connection..."); @@ -72,21 +103,23 @@ void setup() void loop() { - - if (millis() - sendDataPrevMillis > 15000) + + if (Firebase.ready() && (millis() - sendDataPrevMillis > 15000 || sendDataPrevMillis == 0)) { sendDataPrevMillis = millis(); count++; + String Path = path + "/String"; + String Value = "Hello World! " + String(count); Serial.println("------------------------------------"); Serial.println("Set string..."); - if (Firebase.setString(fbdo, path + "/String", "Hello World! " + String(count))) + if (Firebase.setString(fbdo, Path.c_str(), Value.c_str())) { Serial.println("PASSED"); Serial.println("PATH: " + fbdo.dataPath()); Serial.println("TYPE: " + fbdo.dataType()); Serial.print("VALUE: "); - printResult(fbdo); + printResult(fbdo); //see addons/RTDBHelper.h Serial.println("------------------------------------"); Serial.println(); } @@ -97,165 +130,37 @@ void loop() Serial.println("------------------------------------"); Serial.println(); } - - } - - if (!Firebase.readStream(fbdo)) - { - Serial.println("------------------------------------"); - Serial.println("Can't read stream data..."); - Serial.println("REASON: " + fbdo.errorReason()); - Serial.println("------------------------------------"); - Serial.println(); } - - if (fbdo.streamTimeout()) + if (Firebase.authTokenInfo().status == token_status_ready) { - Serial.println("Stream timeout, resume streaming..."); - Serial.println(); - } - if (fbdo.streamAvailable()) - { - Serial.println("------------------------------------"); - Serial.println("Stream Data available..."); - Serial.println("STREAM PATH: " + fbdo.streamPath()); - Serial.println("EVENT PATH: " + fbdo.dataPath()); - Serial.println("DATA TYPE: " + fbdo.dataType()); - Serial.println("EVENT TYPE: " + fbdo.eventType()); - Serial.print("VALUE: "); - printResult(fbdo); - Serial.println("------------------------------------"); - Serial.println(); - } -} - -void printResult(FirebaseData &data) -{ - - if (data.dataType() == "int") - Serial.println(data.intData()); - else if (data.dataType() == "float") - Serial.println(data.floatData(), 5); - else if (data.dataType() == "double") - printf("%.9lf\n", data.doubleData()); - else if (data.dataType() == "boolean") - Serial.println(data.boolData() == 1 ? "true" : "false"); - else if (data.dataType() == "string") - Serial.println(data.stringData()); - else if (data.dataType() == "json") - { - Serial.println(); - FirebaseJson &json = data.jsonObject(); - //Print all object data - Serial.println("Pretty printed JSON data:"); - String jsonStr; - json.toString(jsonStr, true); - Serial.println(jsonStr); - Serial.println(); - Serial.println("Iterate JSON data:"); - Serial.println(); - size_t len = json.iteratorBegin(); - String key, value = ""; - int type = 0; - for (size_t i = 0; i < len; i++) - { - json.iteratorGet(i, type, key, value); - Serial.print(i); - Serial.print(", "); - Serial.print("Type: "); - Serial.print(type == FirebaseJson::JSON_OBJECT ? "object" : "array"); - if (type == FirebaseJson::JSON_OBJECT) - { - Serial.print(", Key: "); - Serial.print(key); - } - Serial.print(", Value: "); - Serial.println(value); - } - json.iteratorEnd(); - } - else if (data.dataType() == "array") - { - Serial.println(); - //get array data from FirebaseData using FirebaseJsonArray object - FirebaseJsonArray &arr = data.jsonArray(); - //Print all array values - Serial.println("Pretty printed Array:"); - String arrStr; - arr.toString(arrStr, true); - Serial.println(arrStr); - Serial.println(); - Serial.println("Iterate array values:"); - Serial.println(); - for (size_t i = 0; i < arr.size(); i++) + if (!Firebase.readStream(fbdo)) { - Serial.print(i); - Serial.print(", Value: "); - - FirebaseJsonData &jsonData = data.jsonData(); - //Get the result data from FirebaseJsonArray object - arr.get(jsonData, i); - if (jsonData.typeNum == FirebaseJson::JSON_BOOL) - Serial.println(jsonData.boolValue ? "true" : "false"); - else if (jsonData.typeNum == FirebaseJson::JSON_INT) - Serial.println(jsonData.intValue); - else if (jsonData.typeNum == FirebaseJson::JSON_FLOAT) - Serial.println(jsonData.floatValue); - else if (jsonData.typeNum == FirebaseJson::JSON_DOUBLE) - printf("%.9lf\n", jsonData.doubleValue); - else if (jsonData.typeNum == FirebaseJson::JSON_STRING || - jsonData.typeNum == FirebaseJson::JSON_NULL || - jsonData.typeNum == FirebaseJson::JSON_OBJECT || - jsonData.typeNum == FirebaseJson::JSON_ARRAY) - Serial.println(jsonData.stringValue); + Serial.println("------------------------------------"); + Serial.println("Can't read stream data..."); + Serial.println("REASON: " + fbdo.errorReason()); + Serial.println("------------------------------------"); + Serial.println(); } - } - else if (data.dataType() == "blob") - { - Serial.println(); - - for (int i = 0; i < data.blobData().size(); i++) + if (fbdo.streamTimeout()) { - if (i > 0 && i % 16 == 0) - Serial.println(); - - if (i < 16) - Serial.print("0"); - - Serial.print(data.blobData()[i], HEX); - Serial.print(" "); + Serial.println("Stream timeout, resume streaming..."); + Serial.println(); } - Serial.println(); - } - else if (data.dataType() == "file") - { - Serial.println(); - - File file = data.fileStream(); - int i = 0; - - while (file.available()) + if (fbdo.streamAvailable()) { - if (i > 0 && i % 16 == 0) - Serial.println(); - - int v = file.read(); - - if (v < 16) - Serial.print("0"); - - Serial.print(v, HEX); - Serial.print(" "); - i++; + Serial.println("------------------------------------"); + Serial.println("Stream Data available..."); + Serial.println("STREAM PATH: " + fbdo.streamPath()); + Serial.println("EVENT PATH: " + fbdo.dataPath()); + Serial.println("DATA TYPE: " + fbdo.dataType()); + Serial.println("EVENT TYPE: " + fbdo.eventType()); + Serial.print("VALUE: "); + printResult(fbdo); //see addons/RTDBHelper.h + Serial.println("------------------------------------"); + Serial.println(); } - Serial.println(); - file.close(); - } - else - { - Serial.println(data.payload()); } } diff --git a/examples/Stream_callback/Stream_callback.ino b/examples/Stream_callback/Stream_callback.ino index 2235cc00..48bdbc97 100644 --- a/examples/Stream_callback/Stream_callback.ino +++ b/examples/Stream_callback/Stream_callback.ino @@ -9,32 +9,46 @@ * */ +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) #include #include +#endif +//Provide the token generation process info. +#include "addons/TokenHelper.h" +//Provide the RTDB payload printing info and other helper functions. +#include "addons/RTDBHelper.h" + +/* 1. Define the WiFi credentials */ #define WIFI_SSID "WIFI_AP" #define WIFI_PASSWORD "WIFI_PASSWORD" -#define FIREBASE_HOST "PROJECT_ID.firebaseio.com" +/* 2. Define the API Key */ +#define API_KEY "API_KEY" -/** The database secret is obsoleted, please use other authentication methods, - * see examples in the Authentications folder. -*/ -#define FIREBASE_AUTH "DATABASE_SECRET" +/* 3. Define the RTDB URL */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app + +/* 4. Define the user Email and password that alreadey registerd or added in your project */ +#define USER_EMAIL "USER_EMAIL" +#define USER_PASSWORD "USER_PASSWORD" //Define FirebaseESP8266 data object FirebaseData fbdo1; FirebaseData fbdo2; +FirebaseAuth auth; +FirebaseConfig config; + unsigned long sendDataPrevMillis = 0; String path = "/Test/Stream"; uint16_t count = 0; -void printResult(FirebaseData &data); -void printResult(StreamData &data); - void streamCallback(StreamData data) { @@ -44,7 +58,7 @@ void streamCallback(StreamData data) Serial.println("DATA TYPE: " + data.dataType()); Serial.println("EVENT TYPE: " + data.eventType()); Serial.print("VALUE: "); - printResult(data); + printResult(data); //see addons/RTDBHelper.h Serial.println(); } @@ -75,22 +89,41 @@ void setup() Serial.println(WiFi.localIP()); Serial.println(); - Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH); + /* Assign the api key (required) */ + config.api_key = API_KEY; + + /* Assign the user sign in credentials */ + auth.user.email = USER_EMAIL; + auth.user.password = USER_PASSWORD; + + /* Assign the RTDB URL (required) */ + config.database_url = DATABASE_URL; + + /* Assign the callback function for the long running token generation task */ + config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h + + Firebase.begin(&config, &auth); Firebase.reconnectWiFi(true); +#if defined(ESP8266) //Set the size of WiFi rx/tx buffers in the case where we want to work with large data. fbdo1.setBSSLBufferSize(1024, 1024); +#endif //Set the size of HTTP response buffers in the case where we want to work with large data. fbdo1.setResponseSize(1024); +#if defined(ESP8266) //Set the size of WiFi rx/tx buffers in the case where we want to work with large data. fbdo2.setBSSLBufferSize(1024, 1024); +#endif //Set the size of HTTP response buffers in the case where we want to work with large data. fbdo2.setResponseSize(1024); - if (!Firebase.beginStream(fbdo1, path)) + //The data under the node being stream (parent path) should keep small + //Large stream payload leads to the parsing error due to memory allocation. + if (!Firebase.beginStream(fbdo1, path.c_str())) { Serial.println("------------------------------------"); Serial.println("Can't begin stream connection..."); @@ -105,7 +138,7 @@ void setup() void loop() { - if (millis() - sendDataPrevMillis > 15000) + if (Firebase.ready() && (millis() - sendDataPrevMillis > 15000 || sendDataPrevMillis == 0)) { sendDataPrevMillis = millis(); count++; @@ -115,13 +148,14 @@ void loop() FirebaseJson json; json.add("data", "hello").add("num", count); - if (Firebase.setJSON(fbdo2, path + "/Json", json)) + String Path = path + "/Json"; + if (Firebase.setJSON(fbdo2, Path.c_str(), json)) { Serial.println("PASSED"); Serial.println("PATH: " + fbdo2.dataPath()); Serial.println("TYPE: " + fbdo2.dataType()); Serial.print("VALUE: "); - printResult(fbdo2); + printResult(fbdo2); //see addons/RTDBHelper.h Serial.println("------------------------------------"); Serial.println(); } @@ -134,260 +168,3 @@ void loop() } } } - -void printResult(FirebaseData &data) -{ - - if (data.dataType() == "int") - Serial.println(data.intData()); - else if (data.dataType() == "float") - Serial.println(data.floatData(), 5); - else if (data.dataType() == "double") - printf("%.9lf\n", data.doubleData()); - else if (data.dataType() == "boolean") - Serial.println(data.boolData() == 1 ? "true" : "false"); - else if (data.dataType() == "string") - Serial.println(data.stringData()); - else if (data.dataType() == "json") - { - Serial.println(); - FirebaseJson &json = data.jsonObject(); - //Print all object data - Serial.println("Pretty printed JSON data:"); - String jsonStr; - json.toString(jsonStr, true); - Serial.println(jsonStr); - Serial.println(); - Serial.println("Iterate JSON data:"); - Serial.println(); - size_t len = json.iteratorBegin(); - String key, value = ""; - int type = 0; - for (size_t i = 0; i < len; i++) - { - json.iteratorGet(i, type, key, value); - Serial.print(i); - Serial.print(", "); - Serial.print("Type: "); - Serial.print(type == FirebaseJson::JSON_OBJECT ? "object" : "array"); - if (type == FirebaseJson::JSON_OBJECT) - { - Serial.print(", Key: "); - Serial.print(key); - } - Serial.print(", Value: "); - Serial.println(value); - } - json.iteratorEnd(); - } - else if (data.dataType() == "array") - { - Serial.println(); - //get array data from FirebaseData using FirebaseJsonArray object - FirebaseJsonArray &arr = data.jsonArray(); - //Print all array values - Serial.println("Pretty printed Array:"); - String arrStr; - arr.toString(arrStr, true); - Serial.println(arrStr); - Serial.println(); - Serial.println("Iterate array values:"); - Serial.println(); - for (size_t i = 0; i < arr.size(); i++) - { - Serial.print(i); - Serial.print(", Value: "); - - FirebaseJsonData &jsonData = data.jsonData(); - //Get the result data from FirebaseJsonArray object - arr.get(jsonData, i); - if (jsonData.typeNum == FirebaseJson::JSON_BOOL) - Serial.println(jsonData.boolValue ? "true" : "false"); - else if (jsonData.typeNum == FirebaseJson::JSON_INT) - Serial.println(jsonData.intValue); - else if (jsonData.typeNum == FirebaseJson::JSON_FLOAT) - Serial.println(jsonData.floatValue); - else if (jsonData.typeNum == FirebaseJson::JSON_DOUBLE) - printf("%.9lf\n", jsonData.doubleValue); - else if (jsonData.typeNum == FirebaseJson::JSON_STRING || - jsonData.typeNum == FirebaseJson::JSON_NULL || - jsonData.typeNum == FirebaseJson::JSON_OBJECT || - jsonData.typeNum == FirebaseJson::JSON_ARRAY) - Serial.println(jsonData.stringValue); - } - } - else if (data.dataType() == "blob") - { - - Serial.println(); - - for (int i = 0; i < data.blobData().size(); i++) - { - if (i > 0 && i % 16 == 0) - Serial.println(); - - if (i < 16) - Serial.print("0"); - - Serial.print(data.blobData()[i], HEX); - Serial.print(" "); - } - Serial.println(); - } - else if (data.dataType() == "file") - { - - Serial.println(); - - File file = data.fileStream(); - int i = 0; - - while (file.available()) - { - if (i > 0 && i % 16 == 0) - Serial.println(); - - int v = file.read(); - - if (v < 16) - Serial.print("0"); - - Serial.print(v, HEX); - Serial.print(" "); - i++; - } - Serial.println(); - file.close(); - } - else - { - Serial.println(data.payload()); - } -} - -void printResult(StreamData &data) -{ - - if (data.dataType() == "int") - Serial.println(data.intData()); - else if (data.dataType() == "float") - Serial.println(data.floatData(), 5); - else if (data.dataType() == "double") - printf("%.9lf\n", data.doubleData()); - else if (data.dataType() == "boolean") - Serial.println(data.boolData() == 1 ? "true" : "false"); - else if (data.dataType() == "string" || data.dataType() == "null") - Serial.println(data.stringData()); - else if (data.dataType() == "json") - { - Serial.println(); - FirebaseJson *json = data.jsonObjectPtr(); - //Print all object data - Serial.println("Pretty printed JSON data:"); - String jsonStr; - json->toString(jsonStr, true); - Serial.println(jsonStr); - Serial.println(); - Serial.println("Iterate JSON data:"); - Serial.println(); - size_t len = json->iteratorBegin(); - String key, value = ""; - int type = 0; - for (size_t i = 0; i < len; i++) - { - json->iteratorGet(i, type, key, value); - Serial.print(i); - Serial.print(", "); - Serial.print("Type: "); - Serial.print(type == FirebaseJson::JSON_OBJECT ? "object" : "array"); - if (type == FirebaseJson::JSON_OBJECT) - { - Serial.print(", Key: "); - Serial.print(key); - } - Serial.print(", Value: "); - Serial.println(value); - } - json->iteratorEnd(); - } - else if (data.dataType() == "array") - { - Serial.println(); - //get array data from FirebaseData using FirebaseJsonArray object - FirebaseJsonArray *arr = data.jsonArrayPtr(); - //Print all array values - Serial.println("Pretty printed Array:"); - String arrStr; - arr->toString(arrStr, true); - Serial.println(arrStr); - Serial.println(); - Serial.println("Iterate array values:"); - Serial.println(); - - for (size_t i = 0; i < arr->size(); i++) - { - Serial.print(i); - Serial.print(", Value: "); - - FirebaseJsonData *jsonData = data.jsonDataPtr(); - //Get the result data from FirebaseJsonArray object - arr->get(*jsonData, i); - if (jsonData->typeNum == FirebaseJson::JSON_BOOL) - Serial.println(jsonData->boolValue ? "true" : "false"); - else if (jsonData->typeNum == FirebaseJson::JSON_INT) - Serial.println(jsonData->intValue); - else if (jsonData->typeNum == FirebaseJson::JSON_FLOAT) - Serial.println(jsonData->floatValue); - else if (jsonData->typeNum == FirebaseJson::JSON_DOUBLE) - printf("%.9lf\n", jsonData->doubleValue); - else if (jsonData->typeNum == FirebaseJson::JSON_STRING || - jsonData->typeNum == FirebaseJson::JSON_NULL || - jsonData->typeNum == FirebaseJson::JSON_OBJECT || - jsonData->typeNum == FirebaseJson::JSON_ARRAY) - Serial.println(jsonData->stringValue); - } - } - else if (data.dataType() == "blob") - { - - Serial.println(); - - for (int i = 0; i < data.blobData().size(); i++) - { - if (i > 0 && i % 16 == 0) - Serial.println(); - - if (i < 16) - Serial.print("0"); - - Serial.print(data.blobData()[i], HEX); - Serial.print(" "); - } - Serial.println(); - } - else if (data.dataType() == "file") - { - - Serial.println(); - - File file = data.fileStream(); - int i = 0; - - while (file.available()) - { - if (i > 0 && i % 16 == 0) - Serial.println(); - - int v = file.read(); - - if (v < 16) - Serial.print("0"); - - Serial.print(v, HEX); - Serial.print(" "); - i++; - } - Serial.println(); - file.close(); - } -} diff --git a/examples/Test/index.html b/examples/Test/index.html index 4348b302..1aeb3907 100644 --- a/examples/Test/index.html +++ b/examples/Test/index.html @@ -1,14 +1,44 @@ - Set Data Example + Continuous Stream Event Trigger Test -
Press the Set button to set the random data to Firebase RTDB.
- Press the Delete button to delete the previous set data from Firebase RTDB.
- Don't forget to change projectID and Web API Key in the source of this html file.
+
This html test page will store the continuous 10,000 values to the path + /Test_Stream/Stream
+ In your Arduino code, set the stream path in Firebase.beginStream to /Test_Stream/Stream

+ And the stream callback function test code.

+ + void streamCallback(StreamData data)
+ {
+
if (data.dataType() == "int")
+ {
+
Serial.print(count);
+ Serial.print(" ");
+ Serial.println(data.intData());
+ count++;
+ } +
+ }

+ + Tempolary set the database rules in the Firebase project console to allow full read and write.
+ + { +
"rules": { +
".read": true,
+ ".write": true
+ } +
+ }
+ + Press the Set button to store the 10,000 values to the Firebase RTDB.
+ Press the Delete button to delete the previous set data from the Firebase RTDB.
+ Don't forget to change projectID and Web API Key in the source of this html file. +

Check the values received in the stream callback function that will get all of these 10,000 values + changes. +
@@ -20,8 +50,8 @@ diff --git a/examples/Timestamp/Timestamp.ino b/examples/Timestamp/Timestamp.ino index c088341e..504d4aef 100644 --- a/examples/Timestamp/Timestamp.ino +++ b/examples/Timestamp/Timestamp.ino @@ -12,22 +12,41 @@ //This example shows how to set and push timestamp (server time) which is the server variable that suopported by Firebase +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) #include #include +#endif +//Provide the token generation process info. +#include "addons/TokenHelper.h" +//Provide the RTDB payload printing info and other helper functions. +#include "addons/RTDBHelper.h" + +/* 1. Define the WiFi credentials */ #define WIFI_SSID "WIFI_AP" #define WIFI_PASSWORD "WIFI_PASSWORD" -#define FIREBASE_HOST "PROJECT_ID.firebaseio.com" +/* 2. Define the API Key */ +#define API_KEY "API_KEY" -/** The database secret is obsoleted, please use other authentication methods, - * see examples in the Authentications folder. -*/ -#define FIREBASE_AUTH "DATABASE_SECRET" +/* 3. Define the RTDB URL */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app + +/* 4. Define the user Email and password that alreadey registerd or added in your project */ +#define USER_EMAIL "USER_EMAIL" +#define USER_PASSWORD "USER_PASSWORD" -//Define Firebase Data object +//Define FirebaseESP8266 data object FirebaseData fbdo; +FirebaseAuth auth; +FirebaseConfig config; + +bool taskCompleted = false; + void setup() { @@ -47,11 +66,26 @@ void setup() Serial.println(WiFi.localIP()); Serial.println(); - Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH); + /* Assign the api key (required) */ + config.api_key = API_KEY; + + /* Assign the user sign in credentials */ + auth.user.email = USER_EMAIL; + auth.user.password = USER_PASSWORD; + + /* Assign the RTDB URL (required) */ + config.database_url = DATABASE_URL; + + /* Assign the callback function for the long running token generation task */ + config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h + + Firebase.begin(&config, &auth); Firebase.reconnectWiFi(true); +#if defined(ESP8266) //Set the size of WiFi rx/tx buffers in the case where we want to work with large data. fbdo.setBSSLBufferSize(1024, 1024); +#endif //Set the size of HTTP response buffers in the case where we want to work with large data. fbdo.setResponseSize(1024); @@ -62,90 +96,103 @@ void setup() Firebase.enableClassicRequest(fbdo, true); */ +} - String path = "/Test"; - - Serial.println("------------------------------------"); - Serial.println("Set Timestamp test..."); - - if (Firebase.setTimestamp(fbdo, path + "/Set/Timestamp")) +void loop() +{ + if (Firebase.ready() && !taskCompleted) { - Serial.println("PASSED"); - Serial.println("PATH: " + fbdo.dataPath()); - Serial.println("TYPE: " + fbdo.dataType()); + taskCompleted = true; - //Timestamp saved in millisecond, get its seconds from intData() - Serial.print("TIMESTAMP (Seconds): "); - Serial.println(fbdo.intData()); + String path = "/Test"; + String Path = path + "/Set/Timestamp"; - //Or print the total milliseconds from doubleData() - //Due to bugs in Serial.print in Arduino library, use printf to print double instead. - printf("TIMESTAMP (milliSeconds): %.0lf\n", fbdo.doubleData()); - - //Or print it from payload directly - Serial.print("TIMESTAMP (milliSeconds): "); - Serial.println(fbdo.payload()); - - //Due to some internal server error, ETag cannot get from setTimestamp - //Try to get ETag manually - Serial.println("ETag: " + Firebase.getETag(fbdo, path + "/Set/Timestamp")); - Serial.println("------------------------------------"); - Serial.println(); - } - else - { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); Serial.println("------------------------------------"); - Serial.println(); - } - - Serial.println("------------------------------------"); - Serial.println("Get Timestamp (double of milliseconds) test..."); - - if (Firebase.getDouble(fbdo, path + "/Set/Timestamp")) - { - Serial.println("PASSED"); - Serial.println("PATH: " + fbdo.dataPath()); - Serial.println("TYPE: " + fbdo.dataType()); + Serial.println("Set Timestamp test..."); + + if (Firebase.setTimestamp(fbdo, Path.c_str())) + { + Serial.println("PASSED"); + Serial.println("PATH: " + fbdo.dataPath()); + Serial.println("TYPE: " + fbdo.dataType()); + + //Timestamp saved in millisecond, get its seconds from intData() + Serial.print("TIMESTAMP (Seconds): "); + Serial.println(fbdo.intData()); + + //Or print the total milliseconds from doubleData() + //Due to bugs in Serial.print in Arduino library, use printf to print double instead. + printf("TIMESTAMP (milliSeconds): %.0lf\n", fbdo.doubleData()); + + //Or print it from payload directly + Serial.print("TIMESTAMP (milliSeconds): "); + Serial.println(fbdo.payload()); + + Path = path + "/Set/Timestamp"; + + //Due to some internal server error, ETag cannot get from setTimestamp + //Try to get ETag manually + Serial.println("ETag: " + Firebase.getETag(fbdo, Path.c_str())); + Serial.println("------------------------------------"); + Serial.println(); + } + else + { + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + Serial.println("------------------------------------"); + Serial.println(); + } - printf("TIMESTAMP: %.0lf\n", fbdo.doubleData()); Serial.println("------------------------------------"); - Serial.println(); - } - else - { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); - Serial.println("------------------------------------"); - Serial.println(); - } + Serial.println("Get Timestamp (double of milliseconds) test..."); + + Path = path + "/Set/Timestamp"; + + if (Firebase.getDouble(fbdo, Path.c_str())) + { + Serial.println("PASSED"); + Serial.println("PATH: " + fbdo.dataPath()); + Serial.println("TYPE: " + fbdo.dataType()); + + printf("TIMESTAMP: %.0lf\n", fbdo.doubleData()); + Serial.println("------------------------------------"); + Serial.println(); + } + else + { + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + Serial.println("------------------------------------"); + Serial.println(); + } - Serial.println("------------------------------------"); - Serial.println("Push Timestamp test..."); - - if (Firebase.pushTimestamp(fbdo, path + "/Push/Timestamp")) - { - Serial.println("PASSED"); - Serial.println("PATH: " + fbdo.dataPath()); - Serial.print("PUSH NAME: "); - Serial.println(fbdo.pushName()); - - //Due to some internal server error, ETag cannot get from pushTimestamp - //Try to get ETag manually - Serial.println("ETag: " + Firebase.getETag(fbdo, path + "/Push/Timestamp/" + fbdo.pushName())); - Serial.println("------------------------------------"); - Serial.println(); - } - else - { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); Serial.println("------------------------------------"); - Serial.println(); + Serial.println("Push Timestamp test..."); + + Path = path + "/Push/Timestamp"; + + if (Firebase.pushTimestamp(fbdo, Path.c_str())) + { + Serial.println("PASSED"); + Serial.println("PATH: " + fbdo.dataPath()); + Serial.print("PUSH NAME: "); + Serial.println(fbdo.pushName()); + + Path = path + "/Push/Timestamp/" + fbdo.pushName(); + + //Due to some internal server error, ETag cannot get from pushTimestamp + //Try to get ETag manually + Serial.println("ETag: " + Firebase.getETag(fbdo, Path.c_str())); + Serial.println("------------------------------------"); + Serial.println(); + } + else + { + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + Serial.println("------------------------------------"); + Serial.println(); + } } -} - -void loop() -{ } \ No newline at end of file diff --git a/examples/jsonArray/jsonArray.ino b/examples/jsonArray/jsonArray.ino index 948e6afd..20358f87 100644 --- a/examples/jsonArray/jsonArray.ino +++ b/examples/jsonArray/jsonArray.ino @@ -12,25 +12,40 @@ //This example shows how to set array data through FirebaseJsonArray object then read the data back and parse them. +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) #include #include +#endif +//Provide the token generation process info. +#include "addons/TokenHelper.h" +//Provide the RTDB payload printing info and other helper functions. +#include "addons/RTDBHelper.h" + +/* 1. Define the WiFi credentials */ #define WIFI_SSID "WIFI_AP" #define WIFI_PASSWORD "WIFI_PASSWORD" -#define FIREBASE_HOST "PROJECT_ID.firebaseio.com" +/* 2. Define the API Key */ +#define API_KEY "API_KEY" -/** The database secret is obsoleted, please use other authentication methods, - * see examples in the Authentications folder. -*/ -#define FIREBASE_AUTH "DATABASE_SECRET" +/* 3. Define the RTDB URL */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app + +/* 4. Define the user Email and password that alreadey registerd or added in your project */ +#define USER_EMAIL "USER_EMAIL" +#define USER_PASSWORD "USER_PASSWORD" -//Define Firebase Data Object +//Define Firebase Data object FirebaseData fbdo; -FirebaseJsonArray arr; +FirebaseAuth auth; +FirebaseConfig config; -void printResult(FirebaseData &data); +FirebaseJsonArray arr; unsigned long sendDataPrevMillis = 0; @@ -55,16 +70,31 @@ void setup() Serial.println(WiFi.localIP()); Serial.println(); - Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH); + /* Assign the api key (required) */ + config.api_key = API_KEY; + + /* Assign the user sign in credentials */ + auth.user.email = USER_EMAIL; + auth.user.password = USER_PASSWORD; + + /* Assign the RTDB URL (required) */ + config.database_url = DATABASE_URL; + + /* Assign the callback function for the long running token generation task */ + config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h + + Firebase.begin(&config, &auth); Firebase.reconnectWiFi(true); +#if defined(ESP8266) //Set the size of WiFi rx/tx buffers in the case where we want to work with large data. fbdo.setBSSLBufferSize(1024, 1024); +#endif //Set the size of HTTP response buffers in the case where we want to work with large data. fbdo.setResponseSize(1024); - if (!Firebase.beginStream(fbdo, path)) + if (!Firebase.beginStream(fbdo, path.c_str())) { Serial.println("------------------------------------"); Serial.println("Can't begin stream connection..."); @@ -77,7 +107,7 @@ void setup() void loop() { - if (millis() - sendDataPrevMillis > 15000) + if (Firebase.ready() && (millis() - sendDataPrevMillis > 15000 || sendDataPrevMillis == 0)) { sendDataPrevMillis = millis(); count++; @@ -89,13 +119,14 @@ void loop() arr.set("/[0]", count); arr.set("/[1]", "hello"); arr.set("/[4]", 76.54); - if (Firebase.set(fbdo, path + "/Data", arr)) + String Path = path + "/Data"; + if (Firebase.set(fbdo, Path.c_str(), &arr)) { Serial.println("PASSED"); Serial.println("PATH: " + fbdo.dataPath()); Serial.println("TYPE: " + fbdo.dataType()); Serial.print("VALUE: "); - printResult(fbdo); + printResult(fbdo); //see addons/RTDBHelper.h Serial.println("------------------------------------"); Serial.println(); } @@ -109,13 +140,13 @@ void loop() Serial.println("------------------------------------"); Serial.println("Get Array..."); - if (Firebase.get(fbdo, path + "/Data")) + if (Firebase.get(fbdo, Path.c_str())) { Serial.println("PASSED"); Serial.println("PATH: " + fbdo.dataPath()); Serial.println("TYPE: " + fbdo.dataType()); Serial.print("VALUE: "); - printResult(fbdo); + printResult(fbdo); //see addons/RTDBHelper.h Serial.println("------------------------------------"); Serial.println(); } @@ -128,162 +159,35 @@ void loop() } } - if (!Firebase.readStream(fbdo)) - { - Serial.println("------------------------------------"); - Serial.println("Can't read stream data..."); - Serial.println("REASON: " + fbdo.errorReason()); - Serial.println("------------------------------------"); - Serial.println(); - } - - if (fbdo.streamTimeout()) - { - Serial.println("Stream timeout, resume streaming..."); - Serial.println(); - } - - if (fbdo.streamAvailable()) - { - Serial.println("------------------------------------"); - Serial.println("Stream Data available..."); - Serial.println("STREAM PATH: " + fbdo.streamPath()); - Serial.println("EVENT PATH: " + fbdo.dataPath()); - Serial.println("DATA TYPE: " + fbdo.dataType()); - Serial.println("EVENT TYPE: " + fbdo.eventType()); - Serial.print("VALUE: "); - printResult(fbdo); - Serial.println("------------------------------------"); - Serial.println(); - } -} - -void printResult(FirebaseData &data) -{ - - if (data.dataType() == "int") - Serial.println(data.intData()); - else if (data.dataType() == "float") - Serial.println(data.floatData(), 5); - else if (data.dataType() == "double") - printf("%.9lf\n", data.doubleData()); - else if (data.dataType() == "boolean") - Serial.println(data.boolData() == 1 ? "true" : "false"); - else if (data.dataType() == "string") - Serial.println(data.stringData()); - else if (data.dataType() == "json") - { - Serial.println(); - FirebaseJson &json = data.jsonObject(); - //Print all object data - Serial.println("Pretty printed JSON data:"); - String jsonStr; - json.toString(jsonStr, true); - Serial.println(jsonStr); - Serial.println(); - Serial.println("Iterate JSON data:"); - Serial.println(); - size_t len = json.iteratorBegin(); - String key, value = ""; - int type = 0; - for (size_t i = 0; i < len; i++) - { - json.iteratorGet(i, type, key, value); - Serial.print(i); - Serial.print(", "); - Serial.print("Type: "); - Serial.print(type == FirebaseJson::JSON_OBJECT ? "object" : "array"); - if (type == FirebaseJson::JSON_OBJECT) - { - Serial.print(", Key: "); - Serial.print(key); - } - Serial.print(", Value: "); - Serial.println(value); - } - json.iteratorEnd(); - } - else if (data.dataType() == "array") + if (Firebase.ready()) { - Serial.println(); - //get array data from FirebaseData using FirebaseJsonArray object - FirebaseJsonArray &arr = data.jsonArray(); - //Print all array values - Serial.println("Pretty printed Array:"); - String arrStr; - arr.toString(arrStr, true); - Serial.println(arrStr); - Serial.println(); - Serial.println("Iterate array values:"); - Serial.println(); - for (size_t i = 0; i < arr.size(); i++) + if (!Firebase.readStream(fbdo)) { - Serial.print(i); - Serial.print(", Value: "); - - FirebaseJsonData &jsonData = data.jsonData(); - //Get the result data from FirebaseJsonArray object - arr.get(jsonData, i); - if (jsonData.typeNum == FirebaseJson::JSON_BOOL) - Serial.println(jsonData.boolValue ? "true" : "false"); - else if (jsonData.typeNum == FirebaseJson::JSON_INT) - Serial.println(jsonData.intValue); - else if (jsonData.typeNum == FirebaseJson::JSON_FLOAT) - Serial.println(jsonData.floatValue); - else if (jsonData.typeNum == FirebaseJson::JSON_DOUBLE) - printf("%.9lf\n", jsonData.doubleValue); - else if (jsonData.typeNum == FirebaseJson::JSON_STRING || - jsonData.typeNum == FirebaseJson::JSON_NULL || - jsonData.typeNum == FirebaseJson::JSON_OBJECT || - jsonData.typeNum == FirebaseJson::JSON_ARRAY) - Serial.println(jsonData.stringValue); + Serial.println("------------------------------------"); + Serial.println("Can't read stream data..."); + Serial.println("REASON: " + fbdo.errorReason()); + Serial.println("------------------------------------"); + Serial.println(); } - } - else if (data.dataType() == "blob") - { - - Serial.println(); - for (int i = 0; i < data.blobData().size(); i++) + if (fbdo.streamTimeout()) { - if (i > 0 && i % 16 == 0) - Serial.println(); - - if (i < 16) - Serial.print("0"); - - Serial.print(data.blobData()[i], HEX); - Serial.print(" "); + Serial.println("Stream timeout, resume streaming..."); + Serial.println(); } - Serial.println(); - } - else if (data.dataType() == "file") - { - - Serial.println(); - - File file = data.fileStream(); - int i = 0; - while (file.available()) + if (fbdo.streamAvailable()) { - if (i > 0 && i % 16 == 0) - Serial.println(); - - int v = file.read(); - - if (v < 16) - Serial.print("0"); - - Serial.print(v, HEX); - Serial.print(" "); - i++; + Serial.println("------------------------------------"); + Serial.println("Stream Data available..."); + Serial.println("STREAM PATH: " + fbdo.streamPath()); + Serial.println("EVENT PATH: " + fbdo.dataPath()); + Serial.println("DATA TYPE: " + fbdo.dataType()); + Serial.println("EVENT TYPE: " + fbdo.eventType()); + Serial.print("VALUE: "); + printResult(fbdo); //see addons/RTDBHelper.h + Serial.println("------------------------------------"); + Serial.println(); } - Serial.println(); - file.close(); - } - else - { - Serial.println(data.payload()); } } \ No newline at end of file diff --git a/examples/jsonObject/jsonObject.ino b/examples/jsonObject/jsonObject.ino index 4e02dfa8..f3cc6cde 100644 --- a/examples/jsonObject/jsonObject.ino +++ b/examples/jsonObject/jsonObject.ino @@ -12,23 +12,40 @@ //This example shows how to set complex json data through FirebaseJson object then read the data back and parse them. +#if defined(ESP32) +#include +#include +#elif defined(ESP8266) #include #include +#endif +//Provide the token generation process info. +#include "addons/TokenHelper.h" +//Provide the RTDB payload printing info and other helper functions. +#include "addons/RTDBHelper.h" + +/* 1. Define the WiFi credentials */ #define WIFI_SSID "WIFI_AP" #define WIFI_PASSWORD "WIFI_PASSWORD" -#define FIREBASE_HOST "PROJECT_ID.firebaseio.com" +/* 2. Define the API Key */ +#define API_KEY "API_KEY" -/** The database secret is obsoleted, please use other authentication methods, - * see examples in the Authentications folder. -*/ -#define FIREBASE_AUTH "DATABASE_SECRET" +/* 3. Define the RTDB URL */ +#define DATABASE_URL "URL" //.firebaseio.com or ..firebasedatabase.app + +/* 4. Define the user Email and password that alreadey registerd or added in your project */ +#define USER_EMAIL "USER_EMAIL" +#define USER_PASSWORD "USER_PASSWORD" //Define Firebase Data object FirebaseData fbdo; -void printResult(FirebaseData &data); +FirebaseAuth auth; +FirebaseConfig config; + +bool taskCompleted = false; void setup() { @@ -49,233 +66,122 @@ void setup() Serial.println(WiFi.localIP()); Serial.println(); - Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH); + /* Assign the api key (required) */ + config.api_key = API_KEY; + + /* Assign the user sign in credentials */ + auth.user.email = USER_EMAIL; + auth.user.password = USER_PASSWORD; + + /* Assign the RTDB URL (required) */ + config.database_url = DATABASE_URL; + + /* Assign the callback function for the long running token generation task */ + config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h + + Firebase.begin(&config, &auth); Firebase.reconnectWiFi(true); +#if defined(ESP8266) //Set the size of WiFi rx/tx buffers in the case where we want to work with large data. fbdo.setBSSLBufferSize(1024, 1024); +#endif //Set the size of HTTP response buffers in the case where we want to work with large data. fbdo.setResponseSize(1024); +} - String path = "/Test/Json"; - - String jsonStr = ""; +void loop() +{ + if (Firebase.ready() && !taskCompleted) + { + taskCompleted = true; - FirebaseJson json1; + String path = "/Test/Json"; - FirebaseJsonData jsonObj; + String jsonStr = ""; - json1.set("Hi/myInt", 200); - json1.set("Hi/myDouble", 0.0023); - json1.set("Who/are/[0]", "you"); - json1.set("Who/are/[1]", "they"); - json1.set("Who/is/[0]", "she"); - json1.set("Who/is/[1]", "he"); - json1.set("This/is/[0]", false); - json1.set("This/is/[1]", true); - json1.set("This/is/[2]", "my house"); - json1.set("This/is/[3]/my", "world"); + FirebaseJson json1; - Serial.println("------------------------------------"); - Serial.println("JSON Data"); - json1.toString(jsonStr, true); - Serial.println(jsonStr); - Serial.println("------------------------------------"); + FirebaseJsonData jsonObj; - Serial.println("------------------------------------"); - Serial.println("Set JSON test..."); + json1.set("Hi/myInt", 200); + json1.set("Hi/myDouble", 0.0023); + json1.set("Who/are/[0]", "you"); + json1.set("Who/are/[1]", "they"); + json1.set("Who/is/[0]", "she"); + json1.set("Who/is/[1]", "he"); + json1.set("This/is/[0]", false); + json1.set("This/is/[1]", true); + json1.set("This/is/[2]", "my house"); + json1.set("This/is/[3]/my", "world"); - if (Firebase.set(fbdo, path, json1)) - { - Serial.println("PASSED"); - Serial.println("PATH: " + fbdo.dataPath()); - Serial.println("TYPE: " + fbdo.dataType()); - Serial.print("VALUE: "); - printResult(fbdo); Serial.println("------------------------------------"); - Serial.println(); - } - else - { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); + Serial.println("JSON Data"); + json1.toString(jsonStr, true); + Serial.println(jsonStr); Serial.println("------------------------------------"); - Serial.println(); - } - Serial.println("------------------------------------"); - Serial.println("Get JSON test..."); + Serial.println("------------------------------------"); + Serial.println("Set JSON test..."); - if (Firebase.get(fbdo, path)) - { - Serial.println("PASSED"); - Serial.println("PATH: " + fbdo.dataPath()); - Serial.println("TYPE: " + fbdo.dataType()); - Serial.print("VALUE: "); - if (fbdo.dataType() == "json") + if (Firebase.set(fbdo, path.c_str(), json1)) + { + Serial.println("PASSED"); + Serial.println("PATH: " + fbdo.dataPath()); + Serial.println("TYPE: " + fbdo.dataType()); + Serial.print("VALUE: "); + printResult(fbdo); //see addons/RTDBHelper.h + Serial.println("------------------------------------"); + Serial.println(); + } + else { - printResult(fbdo); + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + Serial.println("------------------------------------"); + Serial.println(); } Serial.println("------------------------------------"); - Serial.println(); - } - else - { - Serial.println("FAILED"); - Serial.println("REASON: " + fbdo.errorReason()); - Serial.println("------------------------------------"); - Serial.println(); - } - - Serial.println("------------------------------------"); - Serial.println("Try to parse return data and get value.."); - - json1 = fbdo.jsonObject(); - - json1.get(jsonObj, "This/is/[3]/my"); - - Serial.println("This/is/[3]/my: " + jsonObj.stringValue); - - json1.get(jsonObj, "Hi/myDouble"); - Serial.print("Hi/myDouble: "); - Serial.println(jsonObj.doubleValue, 4); - - Serial.println("------------------------------------"); - Serial.println(); -} - -void printResult(FirebaseData &data) -{ + Serial.println("Get JSON test..."); - if (data.dataType() == "int") - Serial.println(data.intData()); - else if (data.dataType() == "float") - Serial.println(data.floatData(), 5); - else if (data.dataType() == "double") - printf("%.9lf\n", data.doubleData()); - else if (data.dataType() == "boolean") - Serial.println(data.boolData() == 1 ? "true" : "false"); - else if (data.dataType() == "string") - Serial.println(data.stringData()); - else if (data.dataType() == "json") - { - Serial.println(); - FirebaseJson &json = data.jsonObject(); - //Print all object data - Serial.println("Pretty printed JSON data:"); - String jsonStr; - json.toString(jsonStr, true); - Serial.println(jsonStr); - Serial.println(); - Serial.println("Iterate JSON data:"); - Serial.println(); - size_t len = json.iteratorBegin(); - String key, value = ""; - int type = 0; - for (size_t i = 0; i < len; i++) + if (Firebase.get(fbdo, path.c_str())) { - json.iteratorGet(i, type, key, value); - Serial.print(i); - Serial.print(", "); - Serial.print("Type: "); - Serial.print(type == FirebaseJson::JSON_OBJECT ? "object" : "array"); - if (type == FirebaseJson::JSON_OBJECT) + Serial.println("PASSED"); + Serial.println("PATH: " + fbdo.dataPath()); + Serial.println("TYPE: " + fbdo.dataType()); + Serial.print("VALUE: "); + if (fbdo.dataType() == "json") { - Serial.print(", Key: "); - Serial.print(key); + printResult(fbdo); //see addons/RTDBHelper.h } - Serial.print(", Value: "); - Serial.println(value); - } - json.iteratorEnd(); - } - else if (data.dataType() == "array") - { - Serial.println(); - //get array data from FirebaseData using FirebaseJsonArray object - FirebaseJsonArray &arr = data.jsonArray(); - //Print all array values - Serial.println("Pretty printed Array:"); - String arrStr; - arr.toString(arrStr, true); - Serial.println(arrStr); - Serial.println(); - Serial.println("Iterate array values:"); - Serial.println(); - for (size_t i = 0; i < arr.size(); i++) - { - Serial.print(i); - Serial.print(", Value: "); - - FirebaseJsonData &jsonData = data.jsonData(); - //Get the result data from FirebaseJsonArray object - arr.get(jsonData, i); - if (jsonData.typeNum == FirebaseJson::JSON_BOOL) - Serial.println(jsonData.boolValue ? "true" : "false"); - else if (jsonData.typeNum == FirebaseJson::JSON_INT) - Serial.println(jsonData.intValue); - else if (jsonData.typeNum == FirebaseJson::JSON_FLOAT) - Serial.println(jsonData.floatValue); - else if (jsonData.typeNum == FirebaseJson::JSON_DOUBLE) - printf("%.9lf\n", jsonData.doubleValue); - else if (jsonData.typeNum == FirebaseJson::JSON_STRING || - jsonData.typeNum == FirebaseJson::JSON_NULL || - jsonData.typeNum == FirebaseJson::JSON_OBJECT || - jsonData.typeNum == FirebaseJson::JSON_ARRAY) - Serial.println(jsonData.stringValue); - } - } - else if (data.dataType() == "blob") - { - Serial.println(); - - for (int i = 0; i < data.blobData().size(); i++) + Serial.println("------------------------------------"); + Serial.println(); + } + else { - if (i > 0 && i % 16 == 0) - Serial.println(); - - if (i < 16) - Serial.print("0"); - - Serial.print(data.blobData()[i], HEX); - Serial.print(" "); + Serial.println("FAILED"); + Serial.println("REASON: " + fbdo.errorReason()); + Serial.println("------------------------------------"); + Serial.println(); } - Serial.println(); - } - else if (data.dataType() == "file") - { - Serial.println(); + Serial.println("------------------------------------"); + Serial.println("Try to parse return data and get value.."); - File file = data.fileStream(); - int i = 0; + json1 = fbdo.jsonObject(); - while (file.available()) - { - if (i > 0 && i % 16 == 0) - Serial.println(); + json1.get(jsonObj, "This/is/[3]/my"); - int v = file.read(); + Serial.println("This/is/[3]/my: " + jsonObj.stringValue); - if (v < 16) - Serial.print("0"); + json1.get(jsonObj, "Hi/myDouble"); + Serial.print("Hi/myDouble: "); + Serial.println(jsonObj.doubleValue, 4); - Serial.print(v, HEX); - Serial.print(" "); - i++; - } + Serial.println("------------------------------------"); Serial.println(); - file.close(); - } - else - { - Serial.println(data.payload()); } } - -void loop() -{ -} diff --git a/keywords.txt b/keywords.txt index f81cf398..c5496753 100644 --- a/keywords.txt +++ b/keywords.txt @@ -38,6 +38,7 @@ setPriority KEYWORD2 getPriority KEYWORD2 getRules KEYWORD2 setRules KEYWORD2 +setReadWriteRules KEYWORD2 pathExist KEYWORD2 getETag KEYWORD2 enableClassicRequest KEYWORD2 @@ -70,6 +71,7 @@ getJSON KEYWORD2 getBlob KEYWORD2 getFile KEYWORD2 deleteNode KEYWORD2 +deleteNodesByTimestamp KEYWORD2 beginStream KEYWORD2 beginMultiPathStream KEYWORD2 readStream KEYWORD2 @@ -98,10 +100,18 @@ sendMessage KEYWORD2 broadcastMessage KEYWORD2 sendTopic KEYWORD2 authTokenInfo KEYWORD2 +tokenReady KEYWORD2 signUp KEYWORD2 sendEmailVerification KEYWORD2 sendResetPassword KEYWORD2 sdBegin KEYWORD2 +setDeviceTime KEYWORD2 +setQueryIndex KEYWORD2 +removeQueryIndex KEYWORD2 +authenticated KEYWORD2 +ready KEYWORD2 +setSystemTime KEYWORD2 + ############################################# # Methods for Firebase Data object (KEYWORD2) @@ -109,6 +119,7 @@ sdBegin KEYWORD2 getWiFiClient KEYWORD2 pauseFirebase KEYWORD2 +isPause KEYWORD2 dataType KEYWORD2 eventType KEYWORD2 ETag KEYWORD2 @@ -199,6 +210,11 @@ QueueItem KEYWORD3 token_info_t KEYWORD3 TokenInfo KEYWORD3 fb_json_last_error_t KEYWORD3 +Firesense_Config KEYWORD3 +FireSense_Channel KEYWORD3 +Firesense_Channel_Type KEYWORD3 +FireSense_Condition KEYWORD3 +FireSense_Data_Type KEYWORD3 ########################################################### # Methods for FirebaseJSON and FirebaseJsonArray (KEYWORD2) @@ -230,6 +246,22 @@ setBufferLimit KEYWORD2 getLastError KEYWORD2 +######################################### +# Methods for FireSense addons (KEYWORD2) +######################################### + +loadConfig KEYWORD2 +backupConfig KEYWORD2 +restoreConfig KEYWORD2 +enableController KEYWORD2 +addChannel KEYWORD2 +addCondition KEYWORD2 +addCallbackFunction KEYWORD2 +clearAllCallbackFunctions KEYWORD2 +addUserValue KEYWORD2 +clearAllUserValues KEYWORD2 +getDeviceId KEYWORD2 + ###################################### # Constants (LITERAL1) ####################################### @@ -241,4 +273,11 @@ JSON_INT LITERAL1 JSON_FLOAT LITERAL1 JSON_DOUBLE LITERAL1 JSON_BOOL LITERAL1 -JSON_NULL LITERAL1 \ No newline at end of file +JSON_NULL LITERAL1 +Output LITERAL1 +Input LITERAL1 +Value LITERAL1 +Byte LITERAL1 +Boolean LITERAL1 +Integer LITERAL1 +Float LITERAL1 \ No newline at end of file diff --git a/library.properties b/library.properties index 9748a762..ea2e07a5 100644 --- a/library.properties +++ b/library.properties @@ -1,6 +1,6 @@ name=Firebase ESP8266 Client -version=3.1.9 +version=3.1.12 author=Mobizt diff --git a/src/FirebaseESP8266.cpp b/src/FirebaseESP8266.cpp index 8903d1ff..950c09e7 100644 --- a/src/FirebaseESP8266.cpp +++ b/src/FirebaseESP8266.cpp @@ -1,11 +1,21 @@ /** - * Google's Firebase Realtime Database Arduino Library for ESP8266, version 3.1.9 - * - * April 4, 2021 + * Google's Firebase Realtime Database Arduino Library for ESP8266, version 3.1.12 * + * May 1, 2021 + * * Updates: - * - Fix the memory leaks in internal JSON parser. - * - Fix the token pre-refreshment issue. + * + * - Add Firebase.ready() function for token generation ready checking. + * - Add Firebase.setSystemTime function for setting the system timestamp manually. + * - Add Firebase.RTDB.setQueryIndex and removeQueryIndex functions for database query indexing. + * - Add Firebase.RTDB.setReadWriteRules function for adding or removing the read and write rules in the RTDB rules. + * - Add FireSense addon, the Programmable Data Logging and IO Control library. + * - Improve the token handling in the examples. + * - Change the ambiguous defined macro FIREBASE_HOST and FIREBASE_AUTH to FIREBASE_URL and DATABASE_SECRET. + * - Remove Firebase.begin requirement from FCM. + * - Fix compilation errors of conflicts between different FirebaseJson class. + * - Fix the RTDB streamAvailable issue. + * * * This library provides ESP8266 to perform REST API by GET PUT, POST, PATCH, DELETE data from/to with Google's Firebase database using get, set, update * and delete calls. @@ -53,25 +63,7 @@ FirebaseESP8266::~FirebaseESP8266() void FirebaseESP8266::begin(FirebaseConfig *config, FirebaseAuth *auth) { - _auth = auth; - _cfg = config; - - if (_cfg == nullptr) - _cfg = &_cfg_; - - if (_auth == nullptr) - _auth = &_auth_; - - ut = new UtilsClass(_cfg); - - RTDB.begin(ut); - - _cfg->_int.fb_reconnect_wifi = WiFi.getAutoReconnect(); - - _cfg->signer.signup = false; - _cfg_.signer.signup = false; - Signer.begin(ut, _cfg, _auth); - std::string().swap(_cfg_.signer.tokens.error.message); + init(config, auth); if (_cfg->service_account.json.path.length() > 0) { @@ -95,11 +87,13 @@ void FirebaseESP8266::begin(FirebaseConfig *config, FirebaseAuth *auth) _cfg->_int.fb_auth_uri = _cfg->signer.tokens.token_type == token_type_legacy_token || _cfg->signer.tokens.token_type == token_type_id_token; if (_cfg->host.length() > 0) + _cfg->database_url = _cfg->host; + + if (_cfg->database_url.length() > 0) { - ut->getUrlInfo(_cfg->host.c_str(), uinfo); - _cfg->host = uinfo.host; + ut->getUrlInfo(_cfg->database_url.c_str(), uinfo); + _cfg->database_url = uinfo.host; } - if (strlen_P(_cfg->cert.data)) _cfg->_int.fb_caCert = _cfg->cert.data; @@ -114,17 +108,17 @@ void FirebaseESP8266::begin(FirebaseConfig *config, FirebaseAuth *auth) Signer.handleToken(); } -void FirebaseESP8266::begin(const String &host, const String &auth) +void FirebaseESP8266::begin(const String &databaseURL, const String &databaseSecret) { - _cfg_.host = host.c_str(); - _cfg_.signer.tokens.legacy_token = auth.c_str(); + _cfg_.database_url = databaseURL.c_str(); + _cfg_.signer.tokens.legacy_token = databaseSecret.c_str(); begin(&_cfg_, &_auth_); } -void FirebaseESP8266::begin(const String &host, const String &auth, const char *caCert, float GMTOffset) +void FirebaseESP8266::begin(const String &databaseURL, const String &databaseSecret, const char *caCert, float GMTOffset) { - _cfg_.host = host.c_str(); - _cfg_.signer.tokens.legacy_token = auth.c_str(); + _cfg_.database_url = databaseURL.c_str(); + _cfg_.signer.tokens.legacy_token = databaseSecret.c_str(); if (strlen_P(caCert)) { float _gmtOffset = GMTOffset; @@ -136,10 +130,10 @@ void FirebaseESP8266::begin(const String &host, const String &auth, const char * begin(&_cfg_, &_auth_); } -void FirebaseESP8266::begin(const String &host, const String &auth, const String &caCertFile, uint8_t storageType, float GMTOffset) +void FirebaseESP8266::begin(const String &databaseURL, const String &databaseSecret, const String &caCertFile, uint8_t storageType, float GMTOffset) { - _cfg_.host = host.c_str(); - _cfg_.signer.tokens.legacy_token = auth.c_str(); + _cfg_.database_url = databaseURL.c_str(); + _cfg_.signer.tokens.legacy_token = databaseSecret.c_str(); if (caCertFile.length() > 0) { float _gmtOffset = GMTOffset; @@ -154,30 +148,19 @@ void FirebaseESP8266::begin(const String &host, const String &auth, const String bool FirebaseESP8266::signUp(FirebaseConfig *config, FirebaseAuth *auth, const char *email, const char *password) { - _auth = auth; - _cfg = config; - - if (_auth == nullptr) - _auth = &_auth_; - if (_cfg == nullptr) - _cfg = &_cfg_; - + init(config, auth); return Signer.getIdToken(true, email, password); } bool FirebaseESP8266::sendEmailVerification(FirebaseConfig *config, const char *idToken) { - _cfg = config; - if (_cfg == nullptr) - _cfg = &_cfg_; + init(config, nullptr); return Signer.handleEmailSending(idToken, fb_esp_user_email_sending_type_verify); } bool FirebaseESP8266::sendResetPassword(FirebaseConfig *config, const char *email) { - _cfg = config; - if (_cfg == nullptr) - _cfg = &_cfg_; + init(config, nullptr); return Signer.handleEmailSending(email, fb_esp_user_email_sending_type_reset_psw); } @@ -193,6 +176,42 @@ struct token_info_t FirebaseESP8266::authTokenInfo() return Signer.tokenInfo; } +bool FirebaseESP8266::ready() +{ + return Signer.tokenReady(); +} + +bool FirebaseESP8266::authenticated() +{ + return Signer.authenticated; +} + +void FirebaseESP8266::init(FirebaseConfig *config, FirebaseAuth *auth) +{ + _auth = auth; + _cfg = config; + + if (_cfg == nullptr) + _cfg = &_cfg_; + + if (_auth == nullptr) + _auth = &_auth_; + + if (ut) + delete ut; + + ut = new UtilsClass(config); + + RTDB.begin(ut); + + _cfg->_int.fb_reconnect_wifi = WiFi.getAutoReconnect(); + + _cfg->signer.signup = false; + _cfg_.signer.signup = false; + Signer.begin(ut, _cfg, _auth); + std::string().swap(_cfg_.signer.tokens.error.message); +} + void FirebaseESP8266::reconnectWiFi(bool reconnect) { WiFi.setAutoReconnect(reconnect); @@ -230,17 +249,29 @@ bool FirebaseESP8266::setRules(FirebaseData &fbdo, const String &rules) return RTDB.setRules(&fbdo, rules.c_str()); } +bool FirebaseESP8266::setQueryIndex(FirebaseData &fbdo, const String &path, const String &node, const String &databaseSecret) +{ + return RTDB.setQueryIndex(&fbdo, path.c_str(), node.c_str(), databaseSecret.c_str()); +} + +bool FirebaseESP8266::removeQueryIndex(FirebaseData &fbdo, const String &path, const String &databaseSecret) +{ + return RTDB.removeQueryIndex(&fbdo, path.c_str(), databaseSecret.c_str()); +} + +bool FirebaseESP8266::setReadWriteRules(FirebaseData &fbdo, const String &path, const String &var, const String &readVal, const String &writeVal, const String &databaseSecret) +{ + return RTDB.setReadWriteRules(&fbdo, path.c_str(), var.c_str(), readVal.c_str(), writeVal.c_str(), databaseSecret.c_str()); +} + bool FirebaseESP8266::pathExist(FirebaseData &fbdo, const String &path) { - fbdo.queryFilter.clear(); - struct fb_esp_rtdb_request_info_t req; - req.path = path.c_str(); - req.method = m_get_nocontent; - req.dataType = d_string; - if (RTDB.handleRequest(&fbdo, &req)) - return !fbdo._ss.rtdb.path_not_found; - else - return false; + return RTDB.pathExisted(&fbdo, path.c_str()); +} + +bool FirebaseESP8266::pathExisted(FirebaseData &fbdo, const String &path) +{ + return RTDB.pathExisted(&fbdo, path.c_str()); } String FirebaseESP8266::getETag(FirebaseData &fbdo, const String &path) @@ -1354,6 +1385,11 @@ fb_esp_mem_storage_type FirebaseESP8266::getMemStorageType(uint8_t old_type) return (fb_esp_mem_storage_type)(old_type); } +bool FirebaseESP8266::setSystemTime(time_t ts) +{ + return ut->setTimestamp(ts) == 0; +} + FirebaseESP8266 Firebase = FirebaseESP8266(); #endif /* ESP8266 */ diff --git a/src/FirebaseESP8266.h b/src/FirebaseESP8266.h index 383f6995..b5b921b1 100644 --- a/src/FirebaseESP8266.h +++ b/src/FirebaseESP8266.h @@ -1,11 +1,21 @@ /** - * Google's Firebase Realtime Database Arduino Library for ESP8266, version 3.1.9 - * - * April 4, 2021 + * Google's Firebase Realtime Database Arduino Library for ESP8266, version 3.1.12 * + * May 1, 2021 + * * Updates: - * - Fix the memory leaks in internal JSON parser. - * - Fix the token pre-refreshment issue. + * + * - Add Firebase.ready() function for token generation ready checking. + * - Add Firebase.setSystemTime function for setting the system timestamp manually. + * - Add Firebase.RTDB.setQueryIndex and removeQueryIndex functions for database query indexing. + * - Add Firebase.RTDB.setReadWriteRules function for adding or removing the read and write rules in the RTDB rules. + * - Add FireSense addon, the Programmable Data Logging and IO Control library. + * - Improve the token handling in the examples. + * - Change the ambiguous defined macro FIREBASE_HOST and FIREBASE_AUTH to FIREBASE_URL and DATABASE_SECRET. + * - Remove Firebase.begin requirement from FCM. + * - Fix compilation errors of conflicts between different FirebaseJson class. + * - Fix the RTDB streamAvailable issue. + * * * This library provides ESP8266 to perform REST API by GET PUT, POST, PATCH, DELETE data from/to with Google's Firebase database using get, set, update * and delete calls. @@ -98,10 +108,22 @@ class FirebaseESP8266 */ struct token_info_t authTokenInfo(); - /** Store Firebase's authentication credentials using database secret (obsoleted).. + /** Provide the ready state of token generation. * - * @param host Your Firebase database project host e.g. Your_ProjectID.firebaseio.com. - * @param auth Your database secret. + * @return Boolean type status indicates the token generation is completed. + */ + bool ready(); + + /** Provide the grant access status for Firebase Services. + * + * @return Boolean type status indicates the device can access to the services + */ + bool authenticated(); + + /** Store Firebase's legacy authentication credentials. + * + * @param databaseURL Your RTDB URL e.g. .firebaseio.com or ..firebasedatabase.app + * @param databaseSecret Your database secret. * @param caCert Root CA certificate base64 string (PEM file). * @param caCertFile Root CA certificate DER file (binary). * @param StorageType Type of storage, StorageType::SD and StorageType::FLASH. @@ -113,11 +135,11 @@ class FirebaseESP8266 * * The file systems for flash and sd memory can be changed in FirebaseFS.h. */ - void begin(const String &host, const String &auth); + void begin(const String &databaseURL, const String &databaseSecret); - void begin(const String &host, const String &auth, const char *caCert, float GMTOffset = 0.0); + void begin(const String &databaseURL, const String &databaseSecret, const char *caCert, float GMTOffset = 0.0); - void begin(const String &host, const String &auth, const String &caCertFile, uint8_t storageType, float GMTOffset = 0.0); + void begin(const String &databaseURL, const String &databaseSecret, const String &caCertFile, uint8_t storageType, float GMTOffset = 0.0); /** Stop Firebase and release all resources. * @@ -227,6 +249,46 @@ class FirebaseESP8266 */ bool setRules(FirebaseData &fbdo, const String &rules); + /** Set the .read and .write database rules. + * + * @param fbdo The pointer to Firebase Data Object. + * @param path The parent path of child's node that the .read and .write rules are being set. + * @param var The child node key that the .read and .write rules are being set. + * @param readVal The child node key .read value. + * @param writeVal The child node key .write value. + * @param databaseSecret The database secret. + * @return Boolean value, indicates the success of the operation. + * + * @note The databaseSecret can be empty if the auth type is OAuth2.0 or legacy and required if auth type + * is Email/Password sign-in. + */ + bool setReadWriteRules(FirebaseData &fbdo, const String &path, const String &var, const String &readVal, const String &writeVal, const String &databaseSecret); + + /** Set the query index to the database rules. + * + * @param fbdo The pointer to Firebase Data Object. + * @param path The parent path of child's node that being query. + * @param node The child node key that being query. + * @param databaseSecret The database secret. + * @return Boolean value, indicates the success of the operation. + * + * @note The databaseSecret can be empty if the auth type is OAuth2.0 or legacy and required if auth type + * is Email/Password sign-in. + */ + bool setQueryIndex(FirebaseData &fbdo, const String &path, const String &node, const String &databaseSecret); + + /** Remove the query index from the database rules. + * + * @param fbdo The pointer to Firebase Data Object. + * @param path The parent path of child's node that the index is being removed. + * @param databaseSecret The database secret. + * @return Boolean value, indicates the success of the operation. + * + * @note The databaseSecret can be empty if the auth type is OAuth2.0 or legacy and required if auth type + * is Email/Password sign-in. + */ + bool removeQueryIndex(FirebaseData &fbdo, const String &path, const String &databaseSecret); + /** Determine whether the defined database path exists or not. * * @param fbdo Firebase Data Object to hold data and instance. @@ -234,6 +296,7 @@ class FirebaseESP8266 * @return Boolean type result indicates whether the defined path existed or not. */ bool pathExist(FirebaseData &fbdo, const String &path); + bool pathExisted(FirebaseData &fbdo, const String &path); /** Determine the unique identifier (ETag) of current data at the defined database path. * @@ -1624,11 +1687,18 @@ class FirebaseESP8266 /** SD card config with GPIO pins. * - * @param ss - SPI Chip/Slave Select pin. + * @param ss SPI Chip/Slave Select pin. * @return Boolean type status indicates the success of the operation. */ bool sdBegin(int8_t ss); + /** Set system time with timestamp. + * + * @param ts timestamp in seconds from midnight Jan 1, 1970. + * @return Boolean type status indicates the success of the operation. + */ + bool setSystemTime(time_t ts); + void errorToString(int httpCode, std::string &buff); template @@ -1677,6 +1747,7 @@ class FirebaseESP8266 //internal or used by legacy data FirebaseAuth _auth_; FirebaseConfig _cfg_; + void init(FirebaseConfig *config, FirebaseAuth *auth); }; diff --git a/src/README.md b/src/README.md index 45fa30fa..41f084be 100644 --- a/src/README.md +++ b/src/README.md @@ -1,7 +1,7 @@ # Firebase Realtime Database Arduino Library for ESP8266 -Google's Firebase Realtime Database Arduino Library for ESP8266 v 3.1.9 +Google's Firebase Realtime Database Arduino Library for ESP8266 v 3.1.12 ## Global functions @@ -24,6 +24,24 @@ void begin(FirebaseConfig *config, FirebaseAuth *auth); + +#### Set system time with timestamp. + +param **`ts`** timestamp in seconds from midnight Jan 1, 1970. + +return **`Boolean`** type status indicates the success of the operation. + +This function allows the internal time setting by timestamp i.e. timestamp from external RTC. + +```cpp +bool setSystemTime(time_t ts); +``` + + + + + + #### Provide the details of token generation. param **`return`** token_info_t The token_info_t structured data that indicates the status. @@ -64,35 +82,26 @@ struct token_info_t authTokenInfo(); -#### Store Firebase's authentication credentials using the authentication data provider. -param **`host`** Your Firebase database project host e.g. Your_ProjectID.firebaseio.com. -param **`auth`** The Auth_Provider data. +#### Provide the ready status of token generation. -param **`rootCA`** Root CA certificate base64 string (PEM file). +return **`Boolean`** type status indicates the token generation is completed. -param **`rootCAFile`** Root CA certificate DER file (binary). +```C++ +bool ready(); +``` -param **`storageType`** Type of storage, StorageType::SD and StorageType::FLASH. -param **`GMTOffset`** GMT time offset in hour is required to set time in order to make BearSSL - data decryption/encryption to work. - This parameter is only required for ESP8266 Core SDK v2.5.x or later. -Root CA certificate DER file is only supported in Core SDK v2.5.x -The file systems for flash and sd memory can be changed in FirebaseFS.h. +#### Provide the grant access status for Firebase Services. -For Auth_Provider data usage, see the examples. +return **`Boolean`** type status indicates the device can access to the services. ```C++ -void begin(const String &host, Auth_Provider &auth); - -void begin(const String &host, Auth_Provider &auth, const char *rootCA, float GMTOffset = 0.0); - -void begin(const String &host, Auth_Provider &auth, const String &rootCAFile, uint8_t storageType, float GMTOffset = 0.0); +bool authenticated(); ``` @@ -100,11 +109,11 @@ void begin(const String &host, Auth_Provider &auth, const String &rootCAFile, ui -#### Store Firebase's authentication credentials using database secret (obsoleted). +#### Store Firebase's legacy authentication credentials. -param **`host`** Your Firebase database project host e.g. Your_ProjectID.firebaseio.com. +param **`databaseURL`** Your RTDB URL e.g. .firebaseio.com or ..firebasedatabase.app -param **`auth`** Your database secret. +param **`databaseSecret`** Your database secret. param **`rootCA`** Root CA certificate base64 string (PEM file). @@ -122,17 +131,18 @@ Root CA certificate DER file is only supported in Core SDK v2.5.x The file systems for flash and sd memory can be changed in FirebaseFS.h. ```C++ -void begin(const String &host, const String &auth); +void begin(const String &databaseURL, const String &databaseSecret); -void begin(const String &host, const String &auth, const char *rootCA, float GMTOffset = 0.0); +void begin(const String &databaseURL, const String &databaseSecret, const char *rootCA, float GMTOffset = 0.0); -void begin(const String &host, const String &auth, const String &rootCAFile, uint8_t storageType, float GMTOffset = 0.0); +void begin(const String &databaseURL, const String &databaseSecret, const String &rootCAFile, uint8_t storageType, float GMTOffset = 0.0); ``` + #### Sign up for a new user. param **`config`** The pointer to FirebaseConfig data. @@ -300,6 +310,77 @@ bool setRules(FirebaseData &dataObj, const String &rules); +#### Set the .read and .write database rules. + +param **`fbdo`** The pointer to Firebase Data Object. + +param **`path`** The parent path of child's node that the .read and .write rules are being set. + +param **`var`** The child node key that the .read and .write rules are being set. + +param **`readVal`** The child node key .read value. + +param **`writeVal`** The child node key .write value. + +param **`databaseSecret`** The database secret. + +return - **`Boolean`** value, indicates the success of the operation. + +note: The databaseSecret can be empty if the auth type is OAuth2.0 or legacy and required if auth type is Email/Password sign-in. + +```cpp +bool setReadWriteRules(FirebaseData &fbdo, const String &path, const String &var, const String &readVal, const String &writeVal, const String &databaseSecret); +``` + + + + + +#### Set the query index to the database rules. + +param **`fbdo`** The pointer to Firebase Data Object. + +param **`path`** The parent path of child's node that being query. + +param **`node`** The child node key that being query. + +param **`databaseSecret`** The database secret. + +return - **`Boolean`** value, indicates the success of the operation. + +note: The databaseSecret can be empty if the auth type is OAuth2.0 or legacy and required if auth type is Email/Password sign-in. + +```cpp +bool setQueryIndex(FirebaseData &fbdo, const String &path, const String &node, const String &databaseSecret); +``` + + + + + + + + +#### Remove the query index from the database rules. + +param **`fbdo`** The pointer to Firebase Data Object. + +param **`path`** The parent path of child's node that the index is being removed. + +param **`databaseSecret`** The database secret. + +return - **`Boolean`** value, indicates the success of the operation. + +note: The databaseSecret can be empty if the auth type is OAuth2.0 or legacy and required if auth type is Email/Password sign-in. + +```cpp +bool removeQueryIndex(FirebaseData &fbdo, const String &path, const String &databaseSecret); +``` + + + + + #### Determine whether the defined database path has existed or not. @@ -312,6 +393,8 @@ path was existed or not. ```C++ bool pathExist(FirebaseData &dataObj, const String &path); + +bool pathExisted(FirebaseData &dataObj, const String &path); ``` diff --git a/src/Utils.h b/src/Utils.h index 7663edd0..18ec4248 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -1,9 +1,9 @@ /** - * Google's Firebase Util class, Utils.h version 1.0.10 + * Google's Firebase Util class, Utils.h version 1.0.12 * * This library supports Espressif ESP8266 and ESP32 * - * Created April 4, 2021 + * Created May 1, 2021 * * This work is a part of Firebase ESP Client library * Copyright (c) 2021 K. Suwatchai (Mobizt) @@ -339,7 +339,7 @@ class UtilsClass tmp = strP(fb_esp_pgm_str_445); p2 = strpos(uri, tmp, 0); delS(tmp); - + if (p2 > -1) { tmp = strP(fb_esp_pgm_str_446); @@ -379,7 +379,7 @@ class UtilsClass return o - dec; } - std::string url_encode(std::string s) + std::string url_encode(const std::string &s) { const char *str = s.c_str(); std::vector v(s.size()); @@ -554,8 +554,12 @@ class UtilsClass int res = -1; char c = 0; int idx = 0; + if (!stream) + return idx; while (stream->available() && idx <= bufLen) { + if (!stream) + break; res = stream->read(); if (res > -1) { @@ -574,8 +578,12 @@ class UtilsClass int res = -1; char c = 0; int idx = 0; + if (!stream) + return idx; while (stream->available()) { + if (!stream) + break; res = stream->read(); if (res > -1) { @@ -1714,6 +1722,12 @@ class UtilsClass return status; } + int setTimestamp(time_t ts) + { + struct timeval tm = {ts, 0}; // sec, us + return settimeofday((const timeval *)&tm, 0); + } + private: }; diff --git a/src/addons/FireSense/FireSense.h b/src/addons/FireSense/FireSense.h new file mode 100644 index 00000000..47922308 --- /dev/null +++ b/src/addons/FireSense/FireSense.h @@ -0,0 +1,4509 @@ +/** + * FireSense v1.0.0 + * + * The Programmable Data Logging and IO Control library. + * + * This library required FirebaseESP8266 to be installed. + * + * This library supports Espressif ESP8266 and ESP32 + * + * Created April 30, 2021 + * + * This work is a part of Firebase ESP Client library + * Copyright (c) 2021 K. Suwatchai (Mobizt) + * + * The MIT License (MIT) + * Copyright (c) 2021 K. Suwatchai (Mobizt) + * + * + * Permission is hereby granted, free of charge, to any 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 do + * so, + * subject to the following conditions: + * + * The above copyright notice 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 BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 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 USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef FireSenseClass_H +#define FireSenseClass_H +#include +#if defined(ESP32) +#include +#elif defined(ESP8266) +#include +#endif + +class MillisTimer +{ +public: + MillisTimer(){}; + + void setTo(uint32_t timeout) + { + tmo = timeout; + } + + void reset() + { + running = false; + startMillis = 0; + } + + void start() + { + running = true; + startMillis = millis(); + } + + bool isTo() + { + if (startMillis > 0) + { + if (millis() - startMillis > tmo) + return true; + } + + return false; + } + + bool isStarted() + { + return startMillis > 0; + } + +private: + bool running = false; + unsigned long startMillis = 0; + uint32_t tmo = 0; +}; + +typedef struct std::function FireSense_Function; +typedef std::function callback_function_t; + +class FireSenseClass +{ + +public: + enum data_type_t + { + data_type_undefined = -1, + data_type_byte, + data_type_bool, + data_type_int, + data_type_float, + data_type_expression + }; + + enum firesense_data_type_t + { + Byte, + Boolean, + Integer, + Float + }; + + enum channel_type_t + { + Undefined = -1, + Input = 0, + Output = 1, + Analog_input, + Value + }; + + struct data_value_info_t + { + int int_data = 0; + float float_data = 0; + data_type_t type = data_type_undefined; + }; + + struct data_value_pointer_info_t + { + bool *boolPtr = nullptr; + uint8_t *bytePtr = nullptr; + int *intPtr = nullptr; + float *floatPtr = nullptr; + data_type_t type = data_type_undefined; + }; + + struct firesense_config_t + { + String basePath = "/demo"; + String deviceId = ""; + float time_zone = 0; + float daylight_offset_in_sec = 0; + unsigned long last_seen_interval = 60 * 1000; + unsigned long log_interval = 60 * 1000; + unsigned long condition_process_interval = 500; + unsigned long dataRetainingPeriod = 5 * 60; + uint32_t max_node_to_delete = 10; + FirebaseData *shared_fbdo = nullptr; + FirebaseData *stream_fbdo = nullptr; + bool debug = false; + bool close_session = false; + }; + + struct channel_info_t + { + String id; + String name; + String location; + String uid; + int type = -1; + int gpio = -1; + struct data_value_info_t current_value; + struct data_value_info_t last_value; + int value_index = -1; + bool status = false; + bool log = false; + firesense_data_type_t unbinded_type = Integer; + unsigned long lastPolling = 0; + uint32_t pollingInterval = 100; + bool ready = false; + }; + + struct firesense_condition_t + { + String IF; + String THEN; + String ELSE; + }; + + FireSenseClass(); + ~FireSenseClass(); + + /** Initiate the FireSense Class. + * + * @param config The pointer to Firesense_Config data. + * @param databaseSecret The database secret. + * + * @return Boolean value, indicates the success of the operation. + * + * @note Due to query index need to be assign to the database rules, the admin rights access is needed + * The database secret can be empty string if the sign-in sign-in method is OAuth2.0. + */ + bool begin(struct firesense_config_t *config, const char *databaseSecret); + + /** Load the device configurations. + * + * @param defaultDataLoadCallback The callback function that called when no config found in the database. + * + * @note The callback function should add the channals or conditions manually or load from the device storage. + */ + void loadConfig(callback_function_t defaultDataLoadCallback); + + /** Save the current config to the device storage. + * + * @param filename The file path includes its name of file that will be saved. + * @param storageType The enum of memory storage type e.g. mem_storage_type_flash and mem_storage_type_sd. The file systems can be changed in FirebaseFS.h. + * + * @return Boolean value, indicates the success of the operation. + * + */ + bool backupConfig(const String &filename, fb_esp_mem_storage_type storageType); + + /** Read the config from the device storage. + * + * @param filename The file path includes its name of file that will be read. + * @param storageType The enum of memory storage type e.g. mem_storage_type_flash and mem_storage_type_sd. The file systems can be changed in FirebaseFS.h. + * + * @return Boolean value, indicates the success of the operation. + * + */ + bool restoreConfig(const String &filename, fb_esp_mem_storage_type storageType); + + /** Enable (run) or disable (stop) the conditions checking tasks. + * + * @param enable The boolean value to enable/disable. + * + */ + void enableController(bool enable); + + /** Add a channel to device config. + * + * @param channel The FireSense_Channel data to add. + * @param addToDatabase The boolean option, set to true to add the data to database. + * + */ + void addChannel(struct channel_info_t &channel, bool addToDatabase = true); + + /** Add a condition to device config. + * + * @param cond The FireSense_Condition data to add. + * @param addToDatabase The boolean option, set to true to add the data to database. + * + * The format of conditions (IF) and its expression. + * + * CONDITION1 + && or || LOGICAL OPERATOR + CONDITION2 + LOGICAL OPERATOR + CONDITION3 +... + * + * The condition checking and expression evaluation are from left to right + * + * + * The valid left, right operands and syntaxes are + * + * Oerand and Syntaxes Usages + * + * LED1 == false && STATUS == LED1 + * values e.g. boolean, integer and float HUMID1 > 70 || LAMP1 == false + * millis millis > 200000 + VALUE1 + * micros VALUE1 < micros - 1000000 + * time e.g. hour:min:sec time > 12:00:00 && time < 15:30:00 + * date e.g. month/day/year where month start with 0 date == 5/28/2021 + * weekday e.g. 1 for monday and 7 for sunday weekday == 5 + * day e.g. 1 to 31 day > 24 + * month e.g. 0 to 11 month < 11 + * year e.g. 2021 year == 2021 + * hour e.g. 0 to 23 hour == 18 + * min e.g. 0 to 59 min == 30 + * sec e.g. 0 to 59 sec == 20 + * change e.g the value of channel changed change(VALUE1) + * ! e.g. the opposite of expresion result !LED1 || !(time > 15:20:06) + * + * + * The format of statements (THEN and ELSE) and its expression. + * + * STATEMENT1 + COMMA + STATEMENT2 +... + * + * The statement processing and expression evaluation are from left to right. + * + * The valid left, right operands and syntaxes are + * + * Oerand and Syntaxes Usages + * + * LED1 = false, STATUS = 5 * 10 + * values e.g. boolean, integer and float HUMID1 = 70 + * millis VALUE1 += millis + * micros VALUE1 *= micros + * delay delay(1000), LED1 = true + * ;do non-blocking delay until timed out and set LED1 to true + * + * func e.g. func(x,y,z) func(0,10,'hello world') + * where x is the index of callback function added ;send the hello world text 10 times to function with index 0 + * with FireSense.addCallbackFunction + * y is the number of iteration that function will be + * called as long as the conditions is true + * z is the message payload sent to the callback. + * The content of payload other than alphabet (A-Z, a-z + * and 1-9) should be in ''. + * + * Use {CHANNEL_ID} to insert the channel value into + * the text payload. + * + * The supported assignment operators are + * +=, -=, *=, /=, &=, |= + * + * + * The supported comparision operators are + * ==, !=, >, <, >=, <= + * + */ + void addCondition(struct firesense_condition_t cond, bool addToDatabase = true); + + /** Add a callback function used with func syntax in the conditions. + * + * @param func The FireSense_Function callback. + * + */ + void addCallbackFunction(FireSense_Function func); + + /** Clear all callback functions used with func syntax in the conditions. + * + */ + void clearAllCallbackFunctions(); + + /** Add a pointer of uint8_t (byte) variable that bind to the channels. + * + * @param value The uint8_t variable. + * + */ + void addUserValue(uint8_t *value); + + /** Add a pointer of bool variable that bind to the channel. + * + * @param value The bool variable. + * + */ + void addUserValue(bool *value); + + /** Add a pointer of int variable that bind to the channel. + * + * @param value The int variable. + * + */ + void addUserValue(int *value); + + /** Add a pointer of float variable that bind to the channel. + * + * @param value The float variable. + * + */ + void addUserValue(float *value); + + /** Clear all user variable pointers that binded to the channels. + * + */ + void clearAllUserValues(); + + /** Get the devivce id string. + * + * @return The unique id String of device. + * + */ + String getDeviceId(); + + void readStream(StreamData *data); + void readStream(FirebaseData *fbdo); + bool configExisted(); + +private: + //condition's group comparison operator type + enum next_comp_opr_t + { + next_comp_opr_none = -1, + next_comp_opr_or, + next_comp_opr_and + }; + + enum statement_type_t + { + statement_type_then, + statement_type_else + + }; + + enum assignment_operator_type_t + { + assignment_operator_type_undefined = -1, + assignment_operator_type_assignment, + assignment_operator_type_add, + assignment_operator_type_subtract, + assignment_operator_type_multiply, + assignment_operator_type_division, + assignment_operator_type_remainder, + assignment_operator_type_left_shift, + assignment_operator_type_right_shift, + assignment_operator_type_and, + assignment_operator_type_or, + assignment_operator_type_logic_and, + assignment_operator_type_logic_or + }; + + //condition's operand type + enum cond_operand_type_t + { + cond_operand_type_undefined = -1, + cond_operand_type_date = 0, + cond_operand_type_time, + cond_operand_type_day, + cond_operand_type_month, + cond_operand_type_year, + cond_operand_type_weekday, + cond_operand_type_hour, + cond_operand_type_min, + cond_operand_type_sec, + cond_operand_type_changed, + cond_operand_type_millis, + cond_operand_type_micros, + cond_operand_type_channel, + cond_operand_type_expression, + }; + + //expression's operand type + enum expr_operand_type_t + { + expr_operand_type_undefined = -1, + expr_operand_type_channel, + expr_operand_type_value, + expr_operand_type_millis, + expr_operand_type_micros + }; + + //conddition's comparision operator type + enum cond_comp_opr_type_t + { + cond_comp_opr_type_undefined, + cond_comp_opr_type_lt, + cond_comp_opr_type_gt, + cond_comp_opr_type_lteq, + cond_comp_opr_type_gteq, + cond_comp_opr_type_eq, + cond_comp_opr_type_neq + }; + + //statement's operand type + enum stm_operand_type_t + { + stm_operand_type_undefined = -1, + stm_operand_type_function, + stm_operand_type_delay, + stm_operand_type_channel, + stm_operand_type_expression + }; + + //expression item data + struct expr_item_data_t + { + expr_operand_type_t type = expr_operand_type_undefined; + struct channel_info_t *channel = nullptr; + struct data_value_info_t value; + bool not_op = false; + }; + + struct expression_item_info_t + { + struct expr_item_data_t data; + bool is_nested = false; + int depth = 0; + struct data_value_info_t result; + bool not_op = false; + assignment_operator_type_t next_ass_opr = assignment_operator_type_undefined; + std::vector list = std::vector(); + }; + + struct expressions_info_t + { + std::vector expressions = std::vector(); + struct data_value_info_t result; + }; + + //condition's left operand + struct cond_left_oprand_item_t + { + struct expressions_info_t exprs; + cond_operand_type_t type = cond_operand_type_undefined; + struct channel_info_t *channel = nullptr; + bool not_op = false; + struct tm time; + }; + + //condition's right operand + struct cond_right_oprand_item_t + { + struct expressions_info_t exprs; + cond_operand_type_t type = cond_operand_type_undefined; + struct channel_info_t *channel = nullptr; + bool not_op = false; + }; + + //condition item data + struct cond_item_data_t + { + struct cond_left_oprand_item_t left; + struct cond_right_oprand_item_t right; + cond_comp_opr_type_t comp = cond_comp_opr_type_undefined; + }; + + struct function_info_t + { + FireSense_Function *ptr = nullptr; + int numArg = 0; + std::string payload; + int iteration_max = 1; + int iteration_count = 0; + }; + + struct stm_left_operand_item_t + { + stm_operand_type_t type = stm_operand_type_undefined; + struct channel_info_t *channel = nullptr; + struct function_info_t function; + int tmo = -1; + MillisTimer timer; + }; + + struct stm_right_operand_item_t + { + struct expressions_info_t exprs; + stm_operand_type_t type = stm_operand_type_undefined; + struct channel_info_t *channel = nullptr; + }; + + struct stm_item_t + { + struct stm_left_operand_item_t left; + struct stm_right_operand_item_t right; + assignment_operator_type_t ass = assignment_operator_type_undefined; + }; + + struct condition_item_info_t + { + //std::string raw; + struct cond_item_data_t data; + bool is_nested = false; + int depth = 0; + bool result = false; + bool not_op = false; + next_comp_opr_t next_comp_opr = next_comp_opr_none; + std::vector list = std::vector(); + }; + + struct expression_group_item_t + { + struct data_value_info_t result; + assignment_operator_type_t next_ass_opr = assignment_operator_type_undefined; + }; + + struct statement_item_info_t + { + struct stm_item_t data; + bool done = false; + }; + + struct conditions_info_t + { + std::vector conditions = std::vector(); + std::vector thenStatements = std::vector(); + std::vector elseStatements = std::vector(); + bool result = false; + }; + + std::vector channelsList = std::vector(); + std::vector userValueList = std::vector(); + std::vector functionList = std::vector(); + std::vector conditionsList = std::vector(); + + const char *months[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + const char *sdow[7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; + const char letters[36] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0'}; + + struct firesense_config_t *config; + callback_function_t _callback_function = nullptr; + FirebaseJson _json; + FirebaseJsonData _jdat; + + bool timeReady = false; + bool initializing = false; + bool loadingConfig = false; + bool loadingCondition = false; + bool conditionsLoaded = false; + bool loadingStatus = false; + bool sendingLog = false; + bool config_existed = false; + bool initReady = false; + bool configLoadReady = false; + bool streamPause = false; + bool controllerEnable = true; + const char *databaseSecret = ""; + + callback_function_t defaultDataLoadCallback = NULL; + + std::string streamCmd; + unsigned long lastSeenMillis = 0; + unsigned long logMillis = 0; + unsigned long conditionMillis = 0; + unsigned long authen_check_millis = 0; + time_t minTs = ESP_DEFAULT_TS; + uint64_t maxTs = 32503654800; + std::string deviceId; + + std::string controlPath(); + std::string channelControlPath(); + std::string configPath(); + std::string conditionPath(); + std::string channelConfigPath(); + std::string streamCmdPath(); + std::string statusPath(); + std::string terminalPath(); + std::string channelStatusPath(); + std::string lastSeenPath(); + std::string logPath(); + bool int_begin(); + void int_loadConfig(); + void setLogQueryIndex(); + void addDBChannel(struct channel_info_t &channel); + void updateDBStatus(struct channel_info_t &channel); + void storeDBStatus(); + void parseCondition(const char *src, std::vector &conditions, int depth = 0); + void parseExpression(const char *src, std::vector &expressions, int depth = 0); + void parseStatement(const char *src, std::vector &stm); + int getCompareConditionType(const char c); + int getAssignOprType(const char c); + void loadConditionsList(); + void loadStatus(); + void setChannalValueType(); + void setChannelValue(struct channel_info_t &channel, struct data_value_info_t value); + void setUserValue(struct channel_info_t *channel, bool fromUserValue, struct data_value_info_t val); + bool configReady(); + void setClock(float time_zone, float daylight_offset_in_sec); + void clearLog(); + struct data_value_info_t getChannelValue(struct channel_info_t *channel); + void resetStatement(struct conditions_info_t *conditionsListItem, statement_type_t type); + void executeStatement(struct conditions_info_t *conditionsListItem, statement_type_t type); + void assignDataValue(struct data_value_info_t *lvalue, struct data_value_info_t *rvalue, assignment_operator_type_t ass, bool setType, bool rvalTypeCheck); + void assignNotValue(struct data_value_info_t *rvalue); + void evalExpressionsList(struct expressions_info_t *exprList); + void evalExpressionsItem(struct expression_item_info_t *cond); + int isDigit(const char *str); + void testConditionsList(); + void testConditionItem(struct condition_item_info_t *cond); + void restart(); + void checkCommand(); + void checkInput(); + void sendLog(); + void sendLastSeen(); + void sendReadyStatus(); + void getCondition(const char *s, struct cond_item_data_t &data); + void getExpression(const char *s, struct expr_item_data_t &data); + void getStatement(const char *src, struct stm_item_t &data); + void parseDateTime(const char *str, int type, struct tm &out); + void getConditionItem(struct cond_item_data_t &data, std::string &left, std::string &right); + void replaceAll(std::string &str, const char *find, const char *replace); + void replaceChannelsValues(std::string &str); + void trim(const char *s, std::string &d, bool isExpression, const char beginTrim = '(', const char endTrim = ')'); + void split(std::vector &out, const char *str, const char delim, const char beginEsc = 0, const char endEsc = 0); + std::string getChipId(); + std::string randomUid(uint8_t length); + std::string getDateTimeString(); + void setupStream(); + void run(); + void int_run(); + void printError(FirebaseData *fbdo); + void printUpdate(const char *msg, int type, float value = 0); + void pauseStream(); + void unpauseStream(); + +#if defined(ESP8266) + void set_scheduled_callback(callback_function_t callback); +#endif +}; + +FireSenseClass FireSense = FireSenseClass(); +#if defined(ESP32) +TaskHandle_t firesense_run_task_handle = NULL; +#endif +typedef struct FireSenseClass::channel_info_t FireSense_Channel; +typedef enum FireSenseClass::channel_type_t Firesense_Channel_Type; +typedef struct FireSenseClass::firesense_condition_t FireSense_Condition; +typedef struct FireSenseClass::firesense_config_t Firesense_Config; +typedef enum FireSenseClass::firesense_data_type_t FireSense_Data_Type; + +struct firesense_token_t +{ + static constexpr const char *esp = "ESP-"; + static constexpr const char *ping = "ping"; + static constexpr const char *reply = "Reply "; + static constexpr const char *millis = "millis"; + static constexpr const char *micros = "micros"; + static constexpr const char *date = "date"; + static constexpr const char *time = "time"; + static constexpr const char *day = "day"; + static constexpr const char *weekday = "weekday"; + static constexpr const char *month = "month"; + static constexpr const char *year = "year"; + static constexpr const char *hour = "hour"; + static constexpr const char *min = "min"; + static constexpr const char *sec = "sec"; + static constexpr const char *id = "id"; + static constexpr const char *uid = "uid"; + static constexpr const char *name = "name"; + static constexpr const char *location = "location"; + static constexpr const char *utype = "utype"; + static constexpr const char *gpio = "gpio"; + static constexpr const char *type = "type"; + static constexpr const char *vIndex = "vIndex"; + static constexpr const char *status = "status"; + static constexpr const char *log = "log"; + static constexpr const char *Idle = "Idle"; + static constexpr const char *Ready = "Ready"; + static constexpr const char *config = "config"; + static constexpr const char *condition = "condition"; + static constexpr const char *run = "run"; + static constexpr const char *stop = "stop"; + static constexpr const char *store = "store"; + static constexpr const char *restore = "restore"; + static constexpr const char *clear = "clear"; + static constexpr const char *restart = "restart"; + static constexpr const char *n1 = "\\n"; + static constexpr const char *n2 = "\n"; + static constexpr const char *slash = "/"; + static constexpr const char *ntp1 = "pool.ntp.org"; + static constexpr const char *ntp2 = "time.nist.gov"; + static constexpr const char *d_integer = "int"; + static constexpr const char *d_float = "float"; + static constexpr const char *s_if = "if"; + static constexpr const char *s_then = "then"; + static constexpr const char *s_else = "else"; + static constexpr const char *left_pr = "("; + static constexpr const char *right_pr = ")"; + static constexpr const char *left_bk = "{"; + static constexpr const char *right_bk = "}"; + static constexpr const char *left_sb = "["; + static constexpr const char *right_sb = "]"; + static constexpr const char *right_sb_bk = "]}"; + static constexpr const char *dot = "."; + static constexpr const char *d_true = "true"; + static constexpr const char *d_false = "false"; + static constexpr const char *change = "change"; + static constexpr const char *delay = "delay"; + static constexpr const char *func = "func"; + static constexpr const char *demo = "/demo"; + static constexpr const char *dash = "-"; + static constexpr const char *d_boolean = "boolean"; + static constexpr const char *d_double = "double"; +}; + +FireSenseClass::FireSenseClass() +{ +} + +FireSenseClass::~FireSenseClass() +{ +} + +void FireSenseClass::sendReadyStatus() +{ + if (!configReady()) + return; + + Firebase.RTDB.set(config->shared_fbdo, streamCmdPath().c_str(), firesense_token_t::Idle); + Firebase.RTDB.set(config->shared_fbdo, terminalPath().c_str(), firesense_token_t::Ready); + + if (config->close_session) + config->shared_fbdo->clear(); +} + +bool FireSenseClass::configExisted() +{ + if (!configReady()) + return false; + config_existed = Firebase.RTDB.pathExisted(config->shared_fbdo, configPath().c_str()); + + if (config->close_session) + config->shared_fbdo->clear(); + + return config_existed; +} + +static void FiresenseStreamCB(StreamData data) +{ + FireSense.readStream(&data); +} + +static void FiresenseStreamToCB(bool timeout) +{ + if (timeout) + { + } +} + +bool FireSenseClass::begin(struct firesense_config_t *config, const char *databaseSecret) +{ + initReady = false; + + this->config = config; + this->databaseSecret = databaseSecret; + + if (!configReady()) + { + Serial.println(F("No FireSense config assigned.")); + return false; + } + + printUpdate("", 3); + + if (this->config->basePath == "") + this->config->basePath = firesense_token_t::demo; + + if (this->config->deviceId == "") + deviceId = getChipId(); + else + { + deviceId = this->config->deviceId.c_str(); + deviceId += firesense_token_t::dash; + deviceId += getChipId(); + } + + if (!config->shared_fbdo) + { + printUpdate("", 5); + return false; + } + +#ifdef ESP8266 + if (this->config->shared_fbdo) + this->config->shared_fbdo->setBSSLBufferSize(1024, 512); + if (this->config->stream_fbdo) + this->config->stream_fbdo->setBSSLBufferSize(1024, 512); +#endif + + this->config->shared_fbdo->setResponseSize(1024); + if (this->config->stream_fbdo) + this->config->stream_fbdo->setResponseSize(1024); + + return int_begin(); +} + +bool FireSenseClass::int_begin() +{ + if (initializing) + return false; + + initializing = true; + initReady = false; +#if defined(ESP32) + Firebase.RTDB.allowMultipleRequests(true); +#endif + + if (!Firebase.ready()) + { + printUpdate("", 7); + initializing = false; + return false; + } + + if (time(nullptr) < minTs) + { + printUpdate("", 14); + setClock(config->time_zone, config->daylight_offset_in_sec); + } + + printUpdate("", 15); + + configExisted(); + + if (!Firebase.authenticated()) + { + printUpdate("", 16); + initializing = false; + return false; + } + + if (config_existed) + printUpdate("", 17); + + setupStream(); + + setLogQueryIndex(); + + printUpdate("", 18); + + initReady = true; + + initializing = false; + + return true; +} + +void FireSenseClass::enableController(bool enable) +{ + controllerEnable = enable; +} + +void FireSenseClass::setupStream() +{ + + delay(0); + + //No need to run stream check at this time + pauseStream(); + + printUpdate("", 19); + if (config->stream_fbdo) + { + if (!Firebase.RTDB.beginStream(config->stream_fbdo, controlPath().c_str())) + printError(config->stream_fbdo); + else + printUpdate("", 21); + } + else + { + + if (!Firebase.RTDB.beginStream(config->shared_fbdo, controlPath().c_str())) + printError(config->stream_fbdo); + else + printUpdate("", 21); + } + + if (config->stream_fbdo) + Firebase.RTDB.setStreamCallback(config->stream_fbdo, FiresenseStreamCB, FiresenseStreamToCB); +} + +void FireSenseClass::addCallbackFunction(FireSense_Function func) +{ + functionList.push_back(func); +} + +void FireSenseClass::clearAllCallbackFunctions() +{ + functionList.clear(); +} + +void FireSenseClass::addUserValue(uint8_t *value) +{ + struct data_value_pointer_info_t ptr; + ptr.bytePtr = value; + ptr.type = data_type_byte; + userValueList.push_back(ptr); +} + +void FireSenseClass::addUserValue(bool *value) +{ + struct data_value_pointer_info_t ptr; + ptr.boolPtr = value; + ptr.type = data_type_bool; + userValueList.push_back(ptr); +} + +void FireSenseClass::addUserValue(int *value) +{ + struct data_value_pointer_info_t ptr; + ptr.intPtr = value; + ptr.type = data_type_int; + userValueList.push_back(ptr); +} + +void FireSenseClass::addUserValue(float *value) +{ + struct data_value_pointer_info_t ptr; + ptr.floatPtr = value; + ptr.type = data_type_float; + userValueList.push_back(ptr); +} + +void FireSenseClass::clearAllUserValues() +{ + userValueList.clear(); +} + +void FireSenseClass::clearLog() +{ + if (!configReady()) + return; + + printUpdate("", 22); + if (!Firebase.RTDB.deleteNode(config->shared_fbdo, logPath().c_str())) + printError(config->shared_fbdo); + + if (config->close_session) + config->shared_fbdo->clear(); + + sendReadyStatus(); +} + +void FireSenseClass::setChannalValueType() +{ + for (size_t i = 0; i < channelsList.size(); i++) + { + struct channel_info_t *channel = &channelsList[i]; + + if (channel->value_index > -1) + { + for (size_t j = 0; j < userValueList.size(); j++) + { + if (channel->value_index == (int)j) + { + struct data_value_pointer_info_t *valPtr = &userValueList[j]; + if (valPtr->type == data_type_float) + { + channel->current_value.type = data_type_float; + channel->last_value.type = data_type_float; + } + else + { + channel->current_value.type = data_type_int; + channel->last_value.type = data_type_int; + } + + break; + } + } + } + else + { + //The type of unbinded variable channel + channel->current_value.type = (data_type_t)channel->unbinded_type; + channel->last_value.type = (data_type_t)data_type_float; + } + } +} + +void FireSenseClass::resetStatement(struct conditions_info_t *conditionsListItem, statement_type_t type) +{ + std::vector *stms = nullptr; + if (type == statement_type_then) + stms = &conditionsListItem->thenStatements; + else if (type == statement_type_else) + stms = &conditionsListItem->elseStatements; + + for (size_t i = 0; i < stms->size(); i++) + { + statement_item_info_t *statement = &(*(stms->begin() + i)); + + if (statement->data.left.type == stm_operand_type_delay) + { + statement->done = false; + statement->data.left.timer.reset(); + } + else if (statement->data.left.type == stm_operand_type_function) + { + statement->data.left.function.iteration_count = 0; + statement->done = false; + } + } +} + +struct FireSenseClass::data_value_info_t FireSenseClass::getChannelValue(struct channel_info_t *channel) +{ + struct data_value_info_t v; + if (!channel->ready) + { + if (channel->type == channel_type_t::Input || channel->type == channel_type_t::Output) + { + if (channel->type == channel_type_t::Output) + pinMode(channel->gpio, OUTPUT); + else + pinMode(channel->gpio, INPUT); + channel->ready = true; + } + } + + if (channel->type == channel_type_t::Input) + { + v.type = channel->current_value.type; + v.int_data = digitalRead(channel->gpio); + v.float_data = (float)v.int_data; + } + else if (channel->type == channel_type_t::Analog_input) + { + v.type = channel->current_value.type; + v.int_data = analogRead(channel->gpio); + v.float_data = (float)v.int_data; + } + else + v = channel->current_value; + + return v; +} + +void FireSenseClass::executeStatement(struct conditions_info_t *conditionsListItem, statement_type_t type) +{ + if (!timeReady) + return; + + if (!Firebase.ready()) + return; + + bool timerDone = false; + std::vector *stms = nullptr; + if (type == statement_type_then) + stms = &conditionsListItem->thenStatements; + else if (type == statement_type_else) + stms = &conditionsListItem->elseStatements; + + for (size_t i = 0; i < stms->size(); i++) + { + if (!timeReady) + return; + + delay(0); + statement_item_info_t *statement = &(*(stms->begin() + i)); + if (statement->data.left.type == stm_operand_type_delay) + { + + if (!statement->data.left.timer.isStarted()) + { + statement->data.left.timer.setTo(statement->data.left.tmo); + statement->data.left.timer.start(); + } + + if (!statement->data.left.timer.isTo()) + break; + + if (!statement->done) + timerDone = true; + + statement->done = true; + } + else if (statement->data.left.type == stm_operand_type_function) + { + if (timerDone) + { + statement->data.left.function.iteration_count = 0; + statement->done = false; + } + + if (statement->done && statement->data.left.function.iteration_max > 0 && statement->data.left.function.iteration_count >= statement->data.left.function.iteration_max) + continue; + + statement->data.left.function.iteration_count++; + + //call user function + if (statement->data.left.function.ptr || statement->data.left.function.numArg > 0) + { + statement->done = true; + std::string s = statement->data.left.function.payload; + replaceChannelsValues(s); + replaceAll(s, firesense_token_t::n1, firesense_token_t::n2); + + if (statement->data.left.function.ptr) + (*statement->data.left.function.ptr)(s.c_str()); + } + } + else if (statement->data.left.type == stm_operand_type_channel) + { + //update channel value + struct data_value_info_t rvalue; + + if (statement->data.right.type == stm_operand_type_channel) + rvalue = getChannelValue(statement->data.right.channel); + else if (statement->data.right.type == stm_operand_type_expression) + { + evalExpressionsList(&statement->data.right.exprs); + rvalue = statement->data.right.exprs.result; + } + + if (statement->data.left.type == stm_operand_type_channel) + { + if (statement->data.left.channel->type == channel_type_t::Value) + { + if (statement->data.ass == assignment_operator_type_assignment && statement->data.left.channel->current_value.type == rvalue.type) + { + if (statement->data.left.channel->current_value.type == data_type_float) + { + if (statement->data.left.channel->current_value.float_data == rvalue.float_data) + continue; + } + else if (statement->data.left.channel->current_value.int_data == rvalue.int_data) + continue; + } + + assignDataValue(&statement->data.left.channel->current_value, &rvalue, statement->data.ass, false, false); + + if (statement->data.left.channel) + setUserValue(statement->data.left.channel, false, statement->data.left.channel->current_value); + + if (statement->data.left.channel->status) + { + std::string path = channelStatusPath(); + path += firesense_token_t::slash; + path += statement->data.left.channel->id.c_str(); + + printUpdate(statement->data.left.channel->id.c_str(), 0); + if (statement->data.left.channel->current_value.type == data_type_float) + { + if (!Firebase.RTDB.set(config->shared_fbdo, path.c_str(), statement->data.left.channel->current_value.float_data)) + printError(config->shared_fbdo); + } + else + { + if (!Firebase.RTDB.set(config->shared_fbdo, path.c_str(), statement->data.left.channel->current_value.int_data)) + printError(config->shared_fbdo); + } + + if (config->close_session) + config->shared_fbdo->clear(); + } + } + else if (statement->data.left.channel->type == channel_type_t::Output) + setChannelValue(*statement->data.left.channel, rvalue); + } + } + } +} + +void FireSenseClass::assignNotValue(struct data_value_info_t *rvalue) +{ + rvalue->int_data = rvalue->int_data > 0 ? 0 : 1; + rvalue->float_data = (float)rvalue->int_data; +} + +void FireSenseClass::assignDataValue(struct data_value_info_t *lvalue, struct data_value_info_t *rvalue, assignment_operator_type_t ass, bool setType, bool rvalTypeCheck) +{ + data_type_t vtype = rvalTypeCheck ? rvalue->type : lvalue->type; + + switch (ass) + { + case assignment_operator_type_assignment: + + if (vtype == data_type_float) + { + lvalue->float_data = rvalue->float_data; + lvalue->int_data = (int)lvalue->float_data; + } + else + { + lvalue->int_data = rvalue->int_data; + lvalue->float_data = (float)lvalue->int_data; + } + if (setType) + lvalue->type = rvalue->type; + break; + case assignment_operator_type_add: + if (vtype == data_type_float) + { + lvalue->float_data += rvalue->float_data; + lvalue->int_data = (int)lvalue->float_data; + } + else + { + lvalue->int_data += rvalue->int_data; + lvalue->float_data = (float)lvalue->int_data; + } + if (setType) + lvalue->type = rvalue->type; + break; + case assignment_operator_type_subtract: + if (vtype == data_type_float) + { + lvalue->float_data -= rvalue->float_data; + lvalue->int_data = (int)lvalue->float_data; + } + else + { + lvalue->int_data -= rvalue->int_data; + lvalue->float_data = (float)lvalue->int_data; + } + if (setType) + lvalue->type = rvalue->type; + break; + case assignment_operator_type_multiply: + lvalue->float_data *= rvalue->float_data; + lvalue->int_data = (int)lvalue->float_data; + if (setType) + lvalue->type = data_type_float; + break; + case assignment_operator_type_division: + lvalue->float_data /= rvalue->float_data; + lvalue->int_data = (int)lvalue->float_data; + if (setType) + lvalue->type = data_type_float; + break; + case assignment_operator_type_remainder: + lvalue->int_data = lvalue->int_data % rvalue->int_data; + lvalue->float_data = (float)lvalue->int_data; + if (setType) + lvalue->type = data_type_int; + break; + case assignment_operator_type_left_shift: + lvalue->int_data = lvalue->int_data << rvalue->int_data; + lvalue->float_data = (float)lvalue->int_data; + if (setType) + lvalue->type = data_type_int; + break; + case assignment_operator_type_right_shift: + lvalue->int_data = lvalue->int_data >> rvalue->int_data; + lvalue->float_data = (float)lvalue->int_data; + if (setType) + lvalue->type = data_type_int; + break; + case assignment_operator_type_and: + if (vtype == data_type_float) + { + lvalue->float_data = lvalue->float_data && rvalue->float_data; + lvalue->int_data = (int)lvalue->float_data; + } + else + { + lvalue->int_data = lvalue->int_data && rvalue->int_data; + lvalue->float_data = (float)lvalue->int_data; + } + break; + case assignment_operator_type_or: + if (vtype == data_type_float) + { + lvalue->float_data = lvalue->float_data || rvalue->float_data; + lvalue->int_data = (int)lvalue->float_data; + } + else + { + lvalue->int_data = lvalue->int_data || rvalue->int_data; + lvalue->float_data = (float)lvalue->int_data; + } + break; + case assignment_operator_type_logic_and: + lvalue->int_data = lvalue->int_data & rvalue->int_data; + lvalue->float_data = (float)lvalue->int_data; + if (setType) + lvalue->type = data_type_int; + break; + case assignment_operator_type_logic_or: + lvalue->int_data = lvalue->int_data | rvalue->int_data; + lvalue->float_data = (float)lvalue->int_data; + if (setType) + lvalue->type = data_type_int; + break; + default: + break; + } +} + +void FireSenseClass::testConditionItem(struct condition_item_info_t *cond) +{ + if (!timeReady) + return; + + if (!Firebase.ready()) + return; + + bool result = false; + cond->result = false; + delay(0); + + if (cond->data.left.type == cond_operand_type_date || cond->data.left.type == cond_operand_type_time || cond->data.left.type == cond_operand_type_day || cond->data.left.type == cond_operand_type_weekday || cond->data.left.type == cond_operand_type_year || cond->data.left.type == cond_operand_type_month || cond->data.left.type == cond_operand_type_hour || cond->data.left.type == cond_operand_type_min || cond->data.left.type == cond_operand_type_sec) + { + time_t current_ts = time(nullptr); + time_t target_ts = 0; + struct tm current_timeinfo; + localtime_r(¤t_ts, ¤t_timeinfo); + + if (cond->data.left.type == cond_operand_type_day || cond->data.left.type == cond_operand_type_weekday || cond->data.left.type == cond_operand_type_year || cond->data.left.type == cond_operand_type_month || cond->data.left.type == cond_operand_type_hour || cond->data.left.type == cond_operand_type_min || cond->data.left.type == cond_operand_type_sec) + { + if (cond->data.left.type == cond_operand_type_day) + { + target_ts = cond->data.left.time.tm_mday; + current_ts = current_timeinfo.tm_mday; + } + else if (cond->data.left.type == cond_operand_type_weekday) + { + target_ts = cond->data.left.time.tm_wday; + current_ts = current_timeinfo.tm_wday; + } + else if (cond->data.left.type == cond_operand_type_year) + { + target_ts = cond->data.left.time.tm_year; + current_ts = current_timeinfo.tm_year; + } + else if (cond->data.left.type == cond_operand_type_month) + { + target_ts = cond->data.left.time.tm_mon; + current_ts = current_timeinfo.tm_mon; + } + else if (cond->data.left.type == cond_operand_type_hour) + { + target_ts = cond->data.left.time.tm_hour; + current_ts = current_timeinfo.tm_hour; + } + else if (cond->data.left.type == cond_operand_type_min) + { + target_ts = cond->data.left.time.tm_min; + current_ts = current_timeinfo.tm_min; + } + else if (cond->data.left.type == cond_operand_type_sec) + { + target_ts = cond->data.left.time.tm_sec; + current_ts = current_timeinfo.tm_sec; + } + } + else + { + struct tm target_timeinfo = cond->data.left.time; + + if (cond->data.left.time.tm_year == -1) + target_timeinfo.tm_year = current_timeinfo.tm_year; + if (cond->data.left.time.tm_mon == -1) + target_timeinfo.tm_mon = current_timeinfo.tm_mon; + if (cond->data.left.time.tm_mday == -1) + target_timeinfo.tm_mday = current_timeinfo.tm_mday; + + if (cond->data.left.time.tm_hour == -1) + target_timeinfo.tm_hour = current_timeinfo.tm_hour; + if (cond->data.left.time.tm_min == -1) + target_timeinfo.tm_min = current_timeinfo.tm_min; + if (cond->data.left.time.tm_sec == -1) + target_timeinfo.tm_sec = current_timeinfo.tm_sec; + + target_ts = mktime(&target_timeinfo); + } + + if (cond->data.left.not_op) + target_ts = target_ts > 0 ? 0 : 1; + + if (cond->data.comp == cond_comp_opr_type_lt) + result = current_ts < target_ts; + else if (cond->data.comp == cond_comp_opr_type_gt) + result = current_ts > target_ts; + else if (cond->data.comp == cond_comp_opr_type_lteq) + result = current_ts <= target_ts; + else if (cond->data.comp == cond_comp_opr_type_gteq) + result = current_ts >= target_ts; + else if (cond->data.comp == cond_comp_opr_type_eq) + result = current_ts == target_ts; + else if (cond->data.comp == cond_comp_opr_type_neq) + result = current_ts != target_ts; + + if (cond->not_op) + result = !result; + } + else + { + if (cond->data.left.type == cond_operand_type_millis || cond->data.left.type == cond_operand_type_micros || cond->data.left.type == cond_operand_type_expression || cond->data.left.type == cond_operand_type_channel || cond->data.left.type == cond_operand_type_changed) + { + struct data_value_info_t lvalue; + struct data_value_info_t rvalue; + if (cond->data.left.type == cond_operand_type_changed && cond->data.left.channel) + { + lvalue = cond->data.left.channel->current_value; + rvalue = cond->data.left.channel->last_value; + + if (cond->data.left.not_op) + assignNotValue(&lvalue); + + result = (lvalue.int_data != rvalue.int_data || lvalue.float_data != rvalue.float_data); + } + else + { + if (cond->data.left.type == cond_operand_type_channel && cond->data.left.channel) + lvalue = cond->data.left.channel->current_value; + else if (cond->data.left.type == cond_operand_type_millis) + { + lvalue.int_data = millis(); + lvalue.float_data = (float)lvalue.int_data; + lvalue.type = data_type_int; + } + else if (cond->data.left.type == cond_operand_type_micros) + { + lvalue.int_data = micros(); + lvalue.float_data = (float)lvalue.int_data; + lvalue.type = data_type_int; + } + else if (cond->data.left.type == cond_operand_type_expression) + { + evalExpressionsList(&cond->data.left.exprs); + lvalue = cond->data.left.exprs.result; + } + + if (cond->data.left.not_op) + assignNotValue(&lvalue); + + if (cond->data.right.type == cond_operand_type_channel && cond->data.right.channel) + rvalue = cond->data.right.channel->current_value; + else if (cond->data.right.type == cond_operand_type_millis) + { + rvalue.int_data = millis(); + rvalue.float_data = (float)rvalue.int_data; + } + else if (cond->data.right.type == cond_operand_type_micros) + { + rvalue.int_data = micros(); + rvalue.float_data = (float)rvalue.int_data; + } + else if (cond->data.right.type == cond_operand_type_expression) + { + evalExpressionsList(&cond->data.right.exprs); + rvalue = cond->data.right.exprs.result; + } + else if (cond->data.right.type == cond_operand_type_undefined) + result = lvalue.int_data > 0; + + if (cond->data.right.not_op) + assignNotValue(&rvalue); + + if (cond->data.comp == cond_comp_opr_type_lt) + { + if (lvalue.type == data_type_float) + result = (lvalue.float_data < rvalue.float_data); + else + result = (lvalue.int_data < rvalue.int_data); + } + else if (cond->data.comp == cond_comp_opr_type_gt) + { + if (lvalue.type == data_type_float) + result = (lvalue.float_data > rvalue.float_data); + else + result = (lvalue.int_data > rvalue.int_data); + } + else if (cond->data.comp == cond_comp_opr_type_lteq) + { + if (lvalue.type == data_type_float) + result = (lvalue.float_data <= rvalue.float_data); + else + result = (lvalue.int_data <= rvalue.int_data); + } + else if (cond->data.comp == cond_comp_opr_type_gteq) + { + if (lvalue.type == data_type_float) + result = (lvalue.float_data >= rvalue.float_data); + else + result = (lvalue.int_data >= rvalue.int_data); + } + else if (cond->data.comp == cond_comp_opr_type_eq) + { + if (lvalue.type == data_type_float) + result = (lvalue.float_data == rvalue.float_data); + else + result = (lvalue.int_data == rvalue.int_data); + } + else if (cond->data.comp == cond_comp_opr_type_neq) + { + if (lvalue.type == data_type_float) + result = (lvalue.float_data != rvalue.float_data); + else + result = (lvalue.int_data != rvalue.int_data); + } + } + + if (cond->not_op) + result = !result; + } + } + + if (cond->list.size() > 0) + { + bool res = false; + + next_comp_opr_t next_comp_opr = next_comp_opr_none; + + for (size_t i = 0; i < cond->list.size(); i++) + { + delay(0); + struct condition_item_info_t *_cond = &cond->list[i]; + + testConditionItem(_cond); + + if (i == 0) + res = _cond->result; + + if (next_comp_opr == next_comp_opr_or) + { + res |= _cond->result; + if (res) + break; + } + else if (next_comp_opr == next_comp_opr_and) + res &= _cond->result; + + next_comp_opr = _cond->next_comp_opr; + if (next_comp_opr == next_comp_opr_or && res) + break; + } + + if (cond->next_comp_opr == next_comp_opr_or) + result |= res; + else if (cond->next_comp_opr == next_comp_opr_and) + result &= res; + else + result = res; + } + + cond->result = result; +} + +int FireSenseClass::isDigit(const char *str) +{ + int dot = 0; + for (size_t i = 0; i < strlen(str); i++) + { + if (i == 0 && str[i] == '-') + continue; + + if (str[i] == '.') + dot++; + + if (dot > 1 || (!isdigit(str[i] && str[i] != '-'))) + return -1; + } + + return dot; +} + +void FireSenseClass::evalExpressionsList(struct expressions_info_t *exprList) +{ + if (!timeReady) + return; + + if (!Firebase.ready()) + return; + + std::vector resList = std::vector(); + + struct expression_group_item_t r; + + for (size_t i = 0; i < exprList->expressions.size(); i++) + { + if (!timeReady) + break; + + delay(0); + struct expression_item_info_t *expr = &exprList->expressions[i]; + + evalExpressionsItem(expr); + + if (expr->not_op) + assignNotValue(&expr->result); + + if (i == 0) + assignDataValue(&r.result, &expr->result, assignment_operator_type_assignment, true, true); + else + { + if (r.next_ass_opr == assignment_operator_type_add || r.next_ass_opr == assignment_operator_type_subtract) + { + resList.push_back(r); + assignDataValue(&r.result, &expr->result, assignment_operator_type_assignment, true, true); + } + else + assignDataValue(&r.result, &expr->result, r.next_ass_opr, true, true); + } + + r.next_ass_opr = expr->next_ass_opr; + } + + if (resList.size() > 0) + { + assignment_operator_type_t next_ass_opr = assignment_operator_type_undefined; + + for (size_t i = 0; i < resList.size(); i++) + { + if (i == 0) + assignDataValue(&exprList->result, &resList[i].result, assignment_operator_type_assignment, true, true); + else + { + if (next_ass_opr == assignment_operator_type_add || next_ass_opr == assignment_operator_type_subtract) + assignDataValue(&exprList->result, &resList[i].result, next_ass_opr, true, true); + } + next_ass_opr = resList[i].next_ass_opr; + } + + if (next_ass_opr == assignment_operator_type_add || next_ass_opr == assignment_operator_type_subtract) + assignDataValue(&exprList->result, &r.result, next_ass_opr, true, true); + } + else + assignDataValue(&exprList->result, &r.result, assignment_operator_type_assignment, true, true); +} + +void FireSenseClass::evalExpressionsItem(struct expression_item_info_t *expr) +{ + if (!timeReady) + return; + + if (!Firebase.ready()) + return; + + delay(0); + + if (expr->list.size() == 0) + { + if (expr->data.type == expr_operand_type_channel && expr->data.channel) + assignDataValue(&expr->result, &expr->data.channel->current_value, assignment_operator_type_assignment, true, true); + else if (expr->data.type == expr_operand_type_millis) + { + expr->result.int_data = millis(); + expr->result.type = data_type_int; + expr->result.float_data = (float)expr->result.int_data; + } + else if (expr->data.type == expr_operand_type_micros) + { + expr->result.int_data = micros(); + expr->result.type = data_type_int; + expr->result.float_data = (float)expr->result.int_data; + } + else if (expr->data.type == expr_operand_type_value) + assignDataValue(&expr->result, &expr->data.value, assignment_operator_type_assignment, true, true); + + if (expr->data.not_op) + { + expr->result.int_data = expr->result.int_data > 0 ? 0 : 1; + expr->result.float_data = (float)expr->result.int_data; + } + } + else + { + std::vector resList = std::vector(); + + struct expression_group_item_t r; + + for (size_t i = 0; i < expr->list.size(); i++) + { + delay(0); + struct expression_item_info_t *_expr = &expr->list[i]; + evalExpressionsItem(_expr); + if (i == 0) + assignDataValue(&r.result, &_expr->result, assignment_operator_type_assignment, true, true); + else + { + if (r.next_ass_opr == assignment_operator_type_add || r.next_ass_opr == assignment_operator_type_subtract) + { + resList.push_back(r); + assignDataValue(&r.result, &_expr->result, assignment_operator_type_assignment, true, true); + } + else + assignDataValue(&r.result, &_expr->result, r.next_ass_opr, true, true); + } + r.next_ass_opr = _expr->next_ass_opr; + } + + if (resList.size() > 0) + { + assignment_operator_type_t next_ass_opr = assignment_operator_type_undefined; + + for (size_t i = 0; i < resList.size(); i++) + { + if (i == 0) + assignDataValue(&expr->result, &resList[i].result, assignment_operator_type_assignment, true, true); + else if (next_ass_opr == assignment_operator_type_add || next_ass_opr == assignment_operator_type_subtract) + assignDataValue(&expr->result, &resList[i].result, next_ass_opr, true, true); + + next_ass_opr = resList[i].next_ass_opr; + } + + if (next_ass_opr == assignment_operator_type_add || next_ass_opr == assignment_operator_type_subtract) + assignDataValue(&expr->result, &r.result, next_ass_opr, true, true); + } + else + assignDataValue(&expr->result, &r.result, assignment_operator_type_assignment, true, true); + } +} + +void FireSenseClass::testConditionsList() +{ + if (!configReady()) + return; + + if (!Firebase.ready()) + return; + + if (!timeReady || conditionsList.size() == 0 || loadingCondition) + return; + + if (millis() - conditionMillis > config->condition_process_interval || conditionMillis == 0) + { + conditionMillis = millis(); + + for (size_t i = 0; i < conditionsList.size(); i++) + { + if (!timeReady) + break; + delay(0); + struct conditions_info_t *listItem = &conditionsList[i]; + listItem->result = false; + + next_comp_opr_t next_comp_opr = next_comp_opr_none; + + for (size_t j = 0; j < listItem->conditions.size(); j++) + { + if (!timeReady) + break; + + delay(0); + struct condition_item_info_t *condition = &listItem->conditions[j]; + + testConditionItem(condition); + + if (j == 0) + listItem->result = condition->result; + + if (next_comp_opr == next_comp_opr_or) + listItem->result |= condition->result; + else if (next_comp_opr == next_comp_opr_and) + listItem->result &= condition->result; + else + listItem->result = condition->result; + + next_comp_opr = condition->next_comp_opr; + if (next_comp_opr == next_comp_opr_or && listItem->result) + break; + } + + if (listItem->result) + { + resetStatement(listItem, statement_type_else); + executeStatement(listItem, statement_type_then); + } + else + { + resetStatement(listItem, statement_type_then); + executeStatement(listItem, statement_type_else); + } + } + + for (size_t i = 0; i < channelsList.size(); i++) + channelsList[i].last_value = channelsList[i].current_value; + } +} +void FireSenseClass::pauseStream() +{ + if (!configReady() || !config->stream_fbdo) + return; + + if (!config->stream_fbdo->isPause()) + { + streamPause = true; + config->stream_fbdo->pauseFirebase(true); + } +} + +void FireSenseClass::unpauseStream() +{ + if (!configReady() || !config->stream_fbdo) + return; + + if (config->stream_fbdo->isPause()) + { + streamPause = false; + config->stream_fbdo->pauseFirebase(false); + } +} + +void FireSenseClass::int_run() +{ + if (configReady()) + { + time_t now = time(nullptr); + timeReady = now > minTs && Firebase.ready(); + + if (Firebase.ready()) + { + if (!initReady) + int_begin(); + else if (!configLoadReady) + int_loadConfig(); + + if (!config_existed && timeReady && initReady && configLoadReady && millis() - authen_check_millis > 10000) + { + authen_check_millis = millis(); + configExisted(); + } + + if (Firebase.authenticated() && timeReady && initReady && configLoadReady) + { + if (streamPause) + unpauseStream(); + +#if defined(ESP8266) + checkCommand(); +#endif + checkInput(); + + if (controllerEnable) + { + if (!conditionsLoaded) + loadConditionsList(); + testConditionsList(); + } + + if (!config->stream_fbdo) + readStream(config->shared_fbdo); + + sendLog(); + sendLastSeen(); + } + } + } +} + +void FireSenseClass::run() +{ + +#if defined(ESP32) + + if (firesense_run_task_handle) + return; + + int_run(); + + static FireSenseClass *_this = this; + + TaskFunction_t taskCode = [](void *param) { + for (;;) + { + _this->int_run(); + yield(); + vTaskDelay(5 / portTICK_PERIOD_MS); + } + + firesense_run_task_handle = NULL; + vTaskDelete(NULL); + }; + + xTaskCreatePinnedToCore(taskCode, "firesense_run_task", 8192, NULL, 10, &firesense_run_task_handle, 1); + +#elif defined(ESP8266) + int_run(); + set_scheduled_callback(std::bind(&FireSenseClass::run, this)); +#endif +} + +void FireSenseClass::restart() +{ + if (!configReady()) + return; + if (config->debug) + Firebase.RTDB.set(config->shared_fbdo, terminalPath().c_str(), "restarting device..."); + ESP.restart(); +} + +void FireSenseClass::checkCommand() +{ + if (!configReady()) + return; + + if (streamCmd.length() == 0 || streamCmd == firesense_token_t::Idle) + return; + + //get NTP time + if (streamCmd == firesense_token_t::time) + setClock(config->time_zone, config->daylight_offset_in_sec); + else if (streamCmd.find("time ") != std::string::npos) + { + //set system time with timestamp + int t = atoi(streamCmd.substr(9).c_str()); + if (t > (int)minTs && t < (int)maxTs) + { + timeReady = false; + Firebase.setSystemTime(t); + if (time(nullptr) > minTs && Firebase.ready()) + timeReady = true; + } + } + else if (streamCmd == firesense_token_t::config) + //load config + configLoadReady = false; + else if (streamCmd == firesense_token_t::condition) + //load conditions + conditionsLoaded = false; + else if (streamCmd == firesense_token_t::run) + //run conditions test + controllerEnable = true; + else if (streamCmd == firesense_token_t::stop) + //stop conditions test + controllerEnable = false; + + else if (streamCmd == firesense_token_t::store) + //store the channels status + storeDBStatus(); + else if (streamCmd == firesense_token_t::restore) + //restore the channels status + loadStatus(); + else if (streamCmd == firesense_token_t::clear) + //clear log + clearLog(); + else if (streamCmd == firesense_token_t::ping) + { + //ping back + std::string s = firesense_token_t::reply; + s += String(time(nullptr)).c_str(); + Firebase.RTDB.set(config->shared_fbdo, terminalPath().c_str(), s.c_str()); + if (config->close_session) + config->shared_fbdo->clear(); + } + else if (streamCmd == firesense_token_t::restart) + //restart device + restart(); + + else if (config->debug) + { + Firebase.RTDB.set(config->shared_fbdo, terminalPath().c_str(), "Unknown command!"); + + if (config->close_session) + config->shared_fbdo->clear(); + } + + Firebase.RTDB.set(config->shared_fbdo, streamCmdPath().c_str(), firesense_token_t::Idle); + if (config->close_session) + config->shared_fbdo->clear(); + streamCmd.clear(); +} + +void FireSenseClass::checkInput() +{ + if (loadingConfig || loadingCondition || loadingStatus || sendingLog) + return; + + for (size_t i = 0; i < channelsList.size(); i++) + { + if (channelsList[i].type == channel_type_t::Input || channelsList[i].type == channel_type_t::Analog_input || channelsList[i].type == channel_type_t::Value) + setChannelValue(channelsList[i], channelsList[i].current_value); + } +} + +void FireSenseClass::sendLog() +{ + + if (!configReady()) + return; + + if (loadingConfig || loadingCondition || loadingStatus || sendingLog) + return; + + if (millis() - logMillis > config->log_interval || logMillis == 0) + { + sendingLog = true; + + logMillis = millis(); + bool logEnable = false; + for (size_t i = 0; i < channelsList.size(); i++) + { + if (channelsList[i].log) + { + logEnable = true; + break; + } + } + + if (logEnable) + { + printUpdate("", 20); + if (!Firebase.RTDB.deleteNodesByTimestamp(config->shared_fbdo, logPath().c_str(), firesense_token_t::time, config->max_node_to_delete, config->dataRetainingPeriod)) + printError(config->shared_fbdo); + + if (config->close_session) + config->shared_fbdo->clear(); + + _json.clear(); + time_t ts = time(nullptr); + String t = String(ts); + size_t count = 0; + for (size_t i = 0; i < channelsList.size(); i++) + { + if (channelsList[i].log) + { + count++; + struct data_value_info_t val = getChannelValue(&channelsList[i]); + if (val.type == data_type_float) + _json.add(channelsList[i].id, val.float_data); + else + _json.add(channelsList[i].id, val.int_data); + } + } + + if (count > 0) + { + _json.add(firesense_token_t::time, (int)ts); + std::string path = logPath(); + path += firesense_token_t::slash; + path += t.c_str(); + + printUpdate("", 1); + if (!Firebase.RTDB.updateNodeSilent(config->shared_fbdo, path.c_str(), &_json)) + printError(config->shared_fbdo); + + if (config->close_session) + config->shared_fbdo->clear(); + } + + _json.clear(); + } + sendingLog = false; + } +} + +void FireSenseClass::sendLastSeen() +{ + if (millis() - lastSeenMillis > config->last_seen_interval || lastSeenMillis == 0) + { + + lastSeenMillis = millis(); + + if (timeReady) + { + _json.clear(); + _json.add(firesense_token_t::date, getDateTimeString().c_str()); + _json.add("ts", (int)time(nullptr)); + printUpdate("", 2); + if (!Firebase.RTDB.updateNodeSilent(config->shared_fbdo, lastSeenPath().c_str(), &_json)) + printError(config->shared_fbdo); + + if (config->close_session) + config->shared_fbdo->clear(); + sendReadyStatus(); + } + } +} + +bool FireSenseClass::configReady() +{ + if (!config) + return false; + + if (!config->shared_fbdo) + return false; + + return true; +} + +void FireSenseClass::int_loadConfig() +{ + loadConfig(defaultDataLoadCallback); +} + +void FireSenseClass::loadConfig(callback_function_t defaultDataLoadCallback) +{ + this->defaultDataLoadCallback = defaultDataLoadCallback; + + if (!configReady() || !Firebase.ready() || !Firebase.authenticated()) + { + run(); + return; + } + + if (loadingConfig) + return; + + loadingConfig = true; + + if (!configExisted() && defaultDataLoadCallback) + { + + printUpdate("", 23); + defaultDataLoadCallback(); + setChannalValueType(); + loadStatus(); + conditionsLoaded = true; + loadingConfig = false; + printUpdate("", 24); + + configLoadReady = true; + run(); + return; + } + + if (!Firebase.authenticated()) + { + loadingConfig = false; + return; + } + + printUpdate("", 25); + + if (config->debug) + Firebase.RTDB.set(config->shared_fbdo, terminalPath().c_str(), "Loading database config..."); + + if (!Firebase.RTDB.getShallowData(config->shared_fbdo, channelConfigPath().c_str())) + { + loadingConfig = false; + printUpdate("", 26); + + if (config->close_session) + config->shared_fbdo->clear(); + return; + } + + FirebaseJson *js = config->shared_fbdo->jsonObjectPtr(); + std::vector channelIdxs = std::vector(); + + if (js) + { + size_t len = js->iteratorBegin(); + String key, value = ""; + int type = 0; + for (size_t i = 0; i < len; i++) + { + js->iteratorGet(i, type, key, value); + channelIdxs.push_back(key); + } + js->iteratorEnd(); + } + + channelsList.clear(); + + for (size_t i = 0; i < channelIdxs.size(); i++) + { + std::string path = channelConfigPath(); + path += firesense_token_t::slash; + path += channelIdxs[i].c_str(); + printUpdate("", 27); + if (!Firebase.RTDB.get(config->shared_fbdo, path.c_str())) + { + printError(config->shared_fbdo); + loadingConfig = false; + + if (config->close_session) + config->shared_fbdo->clear(); + return; + } + + struct channel_info_t channel; + + FirebaseJson *json = config->shared_fbdo->jsonObjectPtr(); + json->get(_jdat, firesense_token_t::id); + channel.id = _jdat.stringValue; + json->get(_jdat, firesense_token_t::uid); + channel.uid = _jdat.stringValue; + json->get(_jdat, firesense_token_t::name); + channel.name = _jdat.stringValue; + json->get(_jdat, firesense_token_t::location); + channel.location = _jdat.stringValue; + json->get(_jdat, firesense_token_t::gpio); + channel.gpio = _jdat.intValue; + json->get(_jdat, firesense_token_t::type); + channel.type = _jdat.intValue; + json->get(_jdat, firesense_token_t::utype); + channel.unbinded_type = (firesense_data_type_t)_jdat.intValue; + json->get(_jdat, firesense_token_t::vIndex); + channel.value_index = _jdat.intValue; + json->get(_jdat, firesense_token_t::status); + channel.status = _jdat.boolValue; + json->get(_jdat, firesense_token_t::log); + channel.log = _jdat.boolValue; + delay(0); + + if (config->close_session) + config->shared_fbdo->clear(); + addChannel(channel, false); + } + + setChannalValueType(); + loadStatus(); + + if (controllerEnable) + loadConditionsList(); + + printUpdate("", 24); + + loadingConfig = false; + configLoadReady = true; + run(); +} + +bool FireSenseClass::backupConfig(const String &filename, fb_esp_mem_storage_type storageType) +{ + if (!configReady()) + return false; + + if (loadingConfig || loadingCondition || loadingStatus || sendingLog) + return false; + + printUpdate("", 40); + delay(0); + if (!Firebase.RTDB.backup(config->shared_fbdo, storageType, configPath().c_str(), filename.c_str())) + { + printError(config->shared_fbdo); + + if (config->close_session) + config->shared_fbdo->clear(); + return false; + } + return true; +} +bool FireSenseClass::restoreConfig(const String &filename, fb_esp_mem_storage_type storageType) +{ + if (!configReady()) + return false; + + if (loadingConfig || loadingCondition || loadingStatus || sendingLog) + return false; + + delay(0); + printUpdate("", 41); + if (!Firebase.RTDB.restore(config->shared_fbdo, storageType, configPath().c_str(), filename.c_str())) + { + printError(config->shared_fbdo); + + if (config->close_session) + config->shared_fbdo->clear(); + return false; + } + return true; +} + +void FireSenseClass::setClock(float time_zone, float daylight_offset_in_sec) +{ + if (!configReady()) + return; + + if (loadingConfig || loadingCondition || loadingStatus || sendingLog) + return; + + time_t now = time(nullptr); + timeReady = now > minTs && Firebase.ready(); + + if (now < minTs) + configTime(time_zone * 3600, config->daylight_offset_in_sec, firesense_token_t::ntp1, firesense_token_t::ntp2, NULL); + + now = time(nullptr); + timeReady = now > minTs && Firebase.ready(); + + if (timeReady) + { + _json.clear(); + _json.add(firesense_token_t::date, getDateTimeString().c_str()); + _json.add("ts", (int)time(nullptr)); + + printUpdate("", 2); + if (!Firebase.RTDB.updateNodeSilent(config->shared_fbdo, lastSeenPath().c_str(), &_json) || !Firebase.RTDB.set(config->shared_fbdo, terminalPath().c_str(), (int)now)) + printError(config->shared_fbdo); + _json.clear(); + } + else + { + if (config->debug) + Firebase.RTDB.set(config->shared_fbdo, terminalPath().c_str(), "Acquiring NTP time..."); + } + + if (config->close_session) + config->shared_fbdo->clear(); +} + +void FireSenseClass::addCondition(struct firesense_condition_t cond, bool addToDatabase) +{ + if (!configReady()) + return; + + struct conditions_info_t conds; + delay(0); + + if (cond.IF.length() > 0 && cond.THEN.length() > 0) + { + printUpdate("", 28); + parseCondition(cond.IF.c_str(), conds.conditions); + printUpdate("", 29); + parseStatement(cond.THEN.c_str(), conds.thenStatements); + } + + if (cond.IF.length() > 0 && cond.THEN.length() > 0 && cond.ELSE.length() > 0) + { + printUpdate("", 30); + parseStatement(cond.ELSE.c_str(), conds.elseStatements); + } + + if (cond.IF.length() > 0) + conditionsList.push_back(conds); + + delay(0); + if (addToDatabase) + { + _json.clear(); + if (cond.IF.length() > 0) + _json.add(firesense_token_t::s_if, cond.IF); + if (cond.THEN.length() > 0) + _json.add(firesense_token_t::s_then, cond.THEN); + if (cond.ELSE.length() > 0) + _json.add(firesense_token_t::s_else, cond.ELSE); + std::string path = conditionPath(); + path += firesense_token_t::slash; + path += String(conditionsList.size() - 1).c_str(); + delay(0); + + printUpdate("", 31); + if (!Firebase.RTDB.updateNodeSilent(config->shared_fbdo, path.c_str(), &_json)) + printError(config->shared_fbdo); + + if (config->close_session) + config->shared_fbdo->clear(); + + cond.IF.clear(); + cond.THEN.clear(); + cond.ELSE.clear(); + } +} + +void FireSenseClass::loadConditionsList() +{ + if (!configReady()) + return; + + if (loadingCondition) + return; + + loadingCondition = true; + + printUpdate("", 32); + + conditionsList.clear(); + + if (config->debug) + Firebase.RTDB.set(config->shared_fbdo, terminalPath().c_str(), "Loading conditions..."); + + printUpdate("", 42); + if (!Firebase.RTDB.getShallowData(config->shared_fbdo, conditionPath().c_str())) + { + printError(config->shared_fbdo); + loadingCondition = false; + + if (config->close_session) + config->shared_fbdo->clear(); + return; + } + + FirebaseJson *js = config->shared_fbdo->jsonObjectPtr(); + std::vector conditionIds = std::vector(); + + if (js) + { + size_t len = js->iteratorBegin(); + String key, value = ""; + int type = 0; + for (size_t i = 0; i < len; i++) + { + js->iteratorGet(i, type, key, value); + conditionIds.push_back(key); + } + js->iteratorEnd(); + } + + if (conditionIds.size() == 0) + { + printUpdate("", 33); + loadingCondition = false; + conditionsLoaded = true; + return; + } + + for (size_t i = 0; i < conditionIds.size(); i++) + { + std::string path = conditionPath(); + path += firesense_token_t::slash; + path += conditionIds[i].c_str(); + + printUpdate(String(i).c_str(), 34); + if (!Firebase.RTDB.get(config->shared_fbdo, path.c_str())) + { + printError(config->shared_fbdo); + + if (config->close_session) + config->shared_fbdo->clear(); + loadingCondition = false; + return; + } + + struct firesense_condition_t cond; + FirebaseJson *json = config->shared_fbdo->jsonObjectPtr(); + json->get(_jdat, firesense_token_t::s_if); + cond.IF = _jdat.stringValue; + json->get(_jdat, firesense_token_t::s_then); + cond.THEN = _jdat.stringValue; + json->get(_jdat, firesense_token_t::s_else); + cond.ELSE = _jdat.stringValue; + + if (config->close_session) + config->shared_fbdo->clear(); + addCondition(cond, false); + } + + sendReadyStatus(); + printUpdate("", 35); + loadingCondition = false; + conditionsLoaded = true; +} + +#if defined(ESP8266) +void FireSenseClass::set_scheduled_callback(callback_function_t callback) +{ + _callback_function = std::move([callback]() { schedule_function(callback); }); + _callback_function(); +} +#endif + +void FireSenseClass::printError(FirebaseData *fbdo) +{ + if (!configReady()) + return; + + if (!config->debug) + return; + + Serial.print(F("[DEBUG] Failed, ")); + Serial.println(fbdo->errorReason()); +} + +void FireSenseClass::printUpdate(const char *msg, int type, float value) +{ + if (!configReady()) + return; + + if (!config->debug) + return; + + switch (type) + { + case 0: + Serial.print(F("[DEBUG] Updating ")); + Serial.print(msg); + Serial.println(F(" status...")); + break; + case 1: + Serial.println(F("[DEBUG] Updating log...")); + break; + case 2: + Serial.println(F("[DEBUG] Updating lastSeen...")); + break; + case 3: + Serial.println(F("[DEBUG] Initializing...")); + break; + case 4: + Serial.println(F("[DEBUG] Failed, no FireSense config assigned.\n")); + break; + case 5: + Serial.println(F("[DEBUG] Failed, no Firebase Data objects assigned.\n")); + break; + case 6: + Serial.println(F("[DEBUG] Loading channels status from database...")); + break; + case 7: + Serial.println(F("[DEBUG] Failed, Firebase authentication token is not ready.")); + break; + case 8: + Serial.println(F("[DEBUG] Updating channel data...")); + break; + case 9: + Serial.println(F("[DEBUG] No channels status found.")); + break; + case 10: + Serial.println(F("[DEBUG] Channels status loaded.")); + break; + case 11: + Serial.println(F("[DEBUG] Update database channel status...")); + break; + case 12: + Serial.println(F("[DEBUG] Setup the database rules query index...")); + break; + case 13: + Serial.println(F("[DEBUG] Query index added.")); + break; + case 14: + Serial.println(F("[DEBUG] Acquiring NTP time...")); + break; + case 15: + Serial.println(F("[DEBUG] Checking databasse config and authentication...")); + break; + case 16: + Serial.println(F("[DEBUG] Failed, access denied, check the authentication.\n")); + break; + case 17: + Serial.println(F("[DEBUG] Config found.")); + break; + case 18: + Serial.println(F("[DEBUG] Initialization completed.")); + break; + case 19: + Serial.println(F("[DEBUG] Setup stream...")); + break; + case 20: + Serial.println(F("[DEBUG] Deleting old log data...")); + break; + case 21: + Serial.println(F("[DEBUG] Stream setup completed")); + break; + case 22: + Serial.println(F("[DEBUG] Clear log...")); + break; + case 23: + Serial.println(F("[DEBUG] Loading default config...")); + break; + case 24: + Serial.println(F("[DEBUG] Config loaded.")); + Serial.println(F("[DEBUG] Ready\n")); + break; + case 25: + Serial.println(F("[DEBUG] Loading database config...")); + break; + case 26: + Serial.println(F("[DEBUG] No config found.")); + break; + case 27: + Serial.println(F("[DEBUG] Loading channel item...")); + break; + case 28: + Serial.println(F("[DEBUG] Parsing IF conditions...")); + break; + case 29: + Serial.println(F("[DEBUG] Parsing THEN conditions...")); + break; + case 30: + Serial.println(F("[DEBUG] Parsing ELSE conditions...")); + break; + case 31: + Serial.println(F("[DEBUG] Adding condition to database...")); + break; + case 32: + Serial.println(F("[DEBUG] Loading conditions from database...")); + break; + case 33: + Serial.println(F("[DEBUG] No conditions found.")); + break; + case 34: + Serial.print(F("[DEBUG] Loading condition [")); + Serial.print(msg); + Serial.println(F("]...")); + break; + case 35: + Serial.println(F("[DEBUG] Conditions loaded.")); + break; + case 36: + Serial.print(F("[DEBUG] ")); + Serial.print(msg); + Serial.println(F(" -> true")); + break; + case 37: + Serial.print(F("[DEBUG] ")); + Serial.print(msg); + Serial.println(F(" -> false")); + break; + case 38: + Serial.print(F("[DEBUG] ")); + Serial.print(msg); + Serial.print(F(" -> ")); + Serial.println(value); + break; + case 39: + Serial.print(F("[DEBUG] Adding ")); + Serial.print(msg); + Serial.println(F(" channel...")); + break; + case 40: + Serial.println(F("[DEBUG] Backup config...")); + break; + case 41: + Serial.println(F("[DEBUG] Restore config...")); + break; + case 42: + Serial.println(F("[DEBUG] Get conditions list...")); + break; + case 43: + Serial.print(F("[DEBUG] Free Heap ")); + Serial.println(ESP.getFreeHeap()); + break; + default: + break; + } +} + +void FireSenseClass::setChannelValue(struct channel_info_t &channel, struct data_value_info_t value) +{ + if (!configReady()) + return; + + if (!timeReady) + return; + + delay(0); + + if (channel.type == channel_type_t::Input || channel.type == channel_type_t::Output || channel.type == channel_type_t::Analog_input || channel.type == channel_type_t::Value) + { + + if (channel.type == channel_type_t::Output) + { + if (channel.current_value.int_data == value.int_data) + return; + } + else + { + + if (millis() - channel.lastPolling < channel.pollingInterval) + return; + channel.lastPolling = millis(); + } + + std::string path = channelStatusPath(); + path += firesense_token_t::slash; + path += channel.id.c_str(); + + if (!channel.ready) + { + if (channel.type == channel_type_t::Input || channel.type == channel_type_t::Output) + { + if (channel.type == channel_type_t::Output) + pinMode(channel.gpio, OUTPUT); + else + pinMode(channel.gpio, INPUT); + channel.ready = true; + } + } + + if (channel.type == channel_type_t::Output) + { + digitalWrite(channel.gpio, channel.current_value.int_data > 0); + channel.current_value.int_data = value.int_data; + channel.current_value.float_data = (float)channel.current_value.int_data; + if (channel.current_value.int_data > 0) + printUpdate(channel.id.c_str(), 36); + else + printUpdate(channel.id.c_str(), 37); + + if (channel.status) + { + printUpdate(channel.id.c_str(), 0); + if (!Firebase.RTDB.set(config->shared_fbdo, path.c_str(), channel.current_value.int_data > 0)) + printError(config->shared_fbdo); + + if (config->close_session) + config->shared_fbdo->clear(); + printUpdate("", 43); + } + } + else if (channel.type == channel_type_t::Input) + { + + int v = digitalRead(channel.gpio); + + if (v == channel.current_value.int_data) + return; + + channel.current_value.int_data = v; + channel.current_value.float_data = (float)channel.current_value.int_data; + if (channel.status) + { + printUpdate(channel.id.c_str(), 0); + if (!Firebase.RTDB.set(config->shared_fbdo, path.c_str(), v)) + printError(config->shared_fbdo); + + if (config->close_session) + config->shared_fbdo->clear(); + printUpdate("", 43); + } + } + else if (channel.type == channel_type_t::Analog_input) + { + int v = analogRead(channel.gpio); + + if (v == channel.current_value.int_data) + return; + + channel.current_value.int_data = v; + channel.current_value.float_data = (float)channel.current_value.int_data; + if (channel.status) + { + printUpdate(channel.id.c_str(), 0); + if (!Firebase.RTDB.set(config->shared_fbdo, path.c_str(), v)) + printError(config->shared_fbdo); + + if (config->close_session) + config->shared_fbdo->clear(); + printUpdate("", 43); + } + } + else if (channel.type == channel_type_t::Value) + setUserValue(&channel, true, value); + } +} + +void FireSenseClass::setUserValue(struct channel_info_t *channel, bool fromUserValue, struct data_value_info_t val) +{ + if (channel->value_index > -1 && channel->value_index < (int)userValueList.size()) + { + if (fromUserValue) + { + if (userValueList[channel->value_index].type == data_type_byte) + { + val.int_data = *userValueList[channel->value_index].bytePtr; + val.float_data = (float)val.int_data; + } + else if (userValueList[channel->value_index].type == data_type_bool) + { + val.int_data = *userValueList[channel->value_index].boolPtr; + val.float_data = (float)val.int_data; + } + else if (userValueList[channel->value_index].type == data_type_int) + { + val.int_data = *userValueList[channel->value_index].intPtr; + val.float_data = (float)val.int_data; + } + else if (userValueList[channel->value_index].type == data_type_float) + { + val.float_data = *userValueList[channel->value_index].floatPtr; + val.int_data = (int)val.float_data; + } + } + else + { + if (userValueList[channel->value_index].type == data_type_byte) + *userValueList[channel->value_index].bytePtr = (uint8_t)val.int_data; + else if (userValueList[channel->value_index].type == data_type_bool) + *userValueList[channel->value_index].boolPtr = (bool)val.int_data; + else if (userValueList[channel->value_index].type == data_type_int) + *userValueList[channel->value_index].intPtr = val.int_data; + else if (userValueList[channel->value_index].type == data_type_float) + *userValueList[channel->value_index].floatPtr = val.float_data; + } + } + + if (val.int_data != channel->current_value.int_data || val.float_data != channel->current_value.float_data) + { + if (val.type == data_type_float) + { + printUpdate(channel->id.c_str(), 38, val.float_data); + channel->current_value.float_data = val.float_data; + channel->current_value.int_data = (int)channel->current_value.float_data; + } + else + { + printUpdate(channel->id.c_str(), 38, val.int_data); + channel->current_value.int_data = val.int_data; + channel->current_value.float_data = (float)channel->current_value.int_data; + } + + if (channel->status) + { + std::string path = channelStatusPath(); + path += firesense_token_t::slash; + path += channel->id.c_str(); + printUpdate(channel->id.c_str(), 0); + if (val.type == data_type_float) + { + if (!Firebase.RTDB.set(config->shared_fbdo, path.c_str(), val.float_data)) + printError(config->shared_fbdo); + } + else + { + if (!Firebase.RTDB.set(config->shared_fbdo, path.c_str(), val.int_data)) + printError(config->shared_fbdo); + } + + if (config->close_session) + config->shared_fbdo->clear(); + } + } +} + +void FireSenseClass::loadStatus() +{ + if (!configReady()) + return; + + if (loadingStatus) + return; + + loadingStatus = true; + + printUpdate("", 6); + + if (config->debug) + Firebase.RTDB.set(config->shared_fbdo, terminalPath().c_str(), "Loading channels status..."); + + if (Firebase.RTDB.getJSON(config->shared_fbdo, channelStatusPath().c_str())) + { + + FirebaseJson *json = config->shared_fbdo->jsonObjectPtr(); + + for (size_t i = 0; i < channelsList.size(); i++) + { + //Parse for each channel state + json->get(_jdat, channelsList[i].id); + + if (_jdat.success) + { + channel_info_t *channel = &channelsList[i]; + + if (channel->type == channel_type_t::Output) + { + digitalWrite(channel->gpio, _jdat.boolValue); + channel->current_value.int_data = _jdat.boolValue; + } + else if (channel->type == channel_type_t::Value) + { + struct data_value_info_t v; + v.type = channel->current_value.type; + if (_jdat.type == firesense_token_t::d_float || _jdat.type == firesense_token_t::d_double) + { + v.float_data = _jdat.floatValue; + v.int_data = (int)v.float_data; + } + else if (_jdat.type == firesense_token_t::d_boolean || _jdat.type == firesense_token_t::d_integer) + { + v.int_data = _jdat.intValue; + v.float_data = (float)v.int_data; + } + setUserValue(channel, false, v); + } + } + } + + if (config->close_session) + config->shared_fbdo->clear(); + } + else + printError(config->shared_fbdo); + + if (channelsList.size() == 0) + printUpdate("", 9); + else + printUpdate("", 10); + + loadingStatus = false; +} + +void FireSenseClass::readStream(StreamData *data) +{ + if (!configReady()) + return; + + if (data->dataType() == firesense_token_t::d_integer || data->dataType() == firesense_token_t::d_boolean || data->dataType() == firesense_token_t::d_float || data->dataType() == firesense_token_t::d_double) + { + for (size_t i = 0; i < channelsList.size(); i++) + { + if (!timeReady) + break; + String path = "/channels/" + channelsList[i].id; + if (data->dataPath() == path) + { + if (channelsList[i].type == channel_type_t::Output || channelsList[i].type == channel_type_t::Value) + { + if (channelsList[i].type == channel_type_t::Output) + { + struct data_value_info_t v; + if (data->dataType() == firesense_token_t::d_integer || data->dataType() == firesense_token_t::d_boolean) + { + v.int_data = data->intData(); + v.type = data_type_int; + v.float_data = (float)v.int_data; + setChannelValue(channelsList[i], v); + } + } + else if (data->dataType() == firesense_token_t::d_boolean || data->dataType() == firesense_token_t::d_integer || data->dataType() == firesense_token_t::d_float || data->dataType() == firesense_token_t::d_double) + { + struct data_value_info_t v; + if (data->dataType() == firesense_token_t::d_float || data->dataType() == firesense_token_t::d_double) + { + v.float_data = data->floatData(); + v.type = data_type_float; + v.int_data = (int)v.float_data; + } + else + { + v.int_data = data->intData(); + v.type = data_type_int; + v.float_data = (float)v.int_data; + } + setUserValue(&channelsList[i], false, v); + } + } + } + } + } + else if (data->dataPath() == "/cmd") + { + streamCmd = data->stringData().c_str(); +#if defined(ESP32) + checkCommand(); +#endif + } +} + +void FireSenseClass::readStream(FirebaseData *fbdo) +{ + if (!configReady()) + return; + + Firebase.RTDB.readStream(fbdo); + + if (fbdo->streamAvailable()) + { + if (fbdo->dataType() == firesense_token_t::d_integer || fbdo->dataType() == firesense_token_t::d_boolean || fbdo->dataType() == firesense_token_t::d_float || fbdo->dataType() == firesense_token_t::d_double) + { + for (size_t i = 0; i < channelsList.size(); i++) + { + if (!timeReady) + break; + String path = "/channels/" + channelsList[i].id; + if (fbdo->dataPath() == path) + { + if (channelsList[i].type == channel_type_t::Output || channelsList[i].type == channel_type_t::Value) + { + if (channelsList[i].type == channel_type_t::Output) + { + struct data_value_info_t v; + if (fbdo->dataType() == firesense_token_t::d_integer || fbdo->dataType() == firesense_token_t::d_boolean) + { + v.int_data = fbdo->intData(); + v.type = data_type_int; + v.float_data = (float)v.int_data; + setChannelValue(channelsList[i], v); + } + } + else if (fbdo->dataType() == firesense_token_t::d_boolean || fbdo->dataType() == firesense_token_t::d_integer || fbdo->dataType() == firesense_token_t::d_float || fbdo->dataType() == firesense_token_t::d_double) + { + struct data_value_info_t v; + if (fbdo->dataType() == firesense_token_t::d_float || fbdo->dataType() == firesense_token_t::d_double) + { + v.float_data = fbdo->floatData(); + v.type = data_type_float; + v.int_data = (int)v.float_data; + } + else + { + v.int_data = fbdo->intData(); + v.type = data_type_int; + v.float_data = (float)v.int_data; + } + setUserValue(&channelsList[i], false, v); + } + } + } + } + } + else if (fbdo->dataPath() == "/cmd") + { + streamCmd = fbdo->stringData().c_str(); +#if defined(ESP32) + checkCommand(); +#endif + } + } +} + +void FireSenseClass::addChannel(struct channel_info_t &channel, bool addToDatabase) +{ + if (!configReady()) + return; + printUpdate(channel.id.c_str(), 39); + channel.uid = randomUid(10).c_str(); + + if (channel.type == channel_type_t::Analog_input || channel.type == channel_type_t::Input) + { + channel.current_value.type = data_type_int; + channel.last_value.type = data_type_int; + } + if (channel.type == channel_type_t::Output) + { + channel.current_value.type = data_type_bool; + channel.last_value.type = data_type_bool; + } + + channelsList.push_back(channel); + if (addToDatabase) + addDBChannel(channel); +} + +void FireSenseClass::addDBChannel(struct channel_info_t &channel) +{ + if (!configReady()) + return; + + printUpdate("", 8); + delay(0); + std::string path; + _json.clear(); + _json.add(firesense_token_t::id, channel.id); + _json.add(firesense_token_t::name, channel.name); + _json.add(firesense_token_t::location, channel.location); + _json.add(firesense_token_t::uid, channel.uid); + _json.add(firesense_token_t::gpio, channel.gpio); + _json.add(firesense_token_t::type, channel.type); + _json.add(firesense_token_t::utype, (int)channel.unbinded_type); + _json.add(firesense_token_t::vIndex, channel.value_index); + _json.add(firesense_token_t::status, channel.status); + _json.add(firesense_token_t::log, channel.log); + path = channelConfigPath(); + path += firesense_token_t::slash; + path += String(channelsList.size() - 1).c_str(); + if (!Firebase.RTDB.updateNodeSilent(config->shared_fbdo, path.c_str(), &_json)) + { + printError(config->shared_fbdo); + + if (config->close_session) + config->shared_fbdo->clear(); + return; + } + _json.clear(); + delay(0); + + updateDBStatus(channel); +} + +void FireSenseClass::updateDBStatus(struct channel_info_t &channel) +{ + if (!configReady()) + return; + + printUpdate("", 11); + + std::string path; + + if (channel.type == channel_type_t::Output) + { + path = channelStatusPath(); + path += firesense_token_t::slash; + path += channel.id.c_str(); + if (channel.status) + { + printUpdate(channel.id.c_str(), 0); + if (channel.current_value.type == data_type_float) + { + if (!Firebase.RTDB.set(config->shared_fbdo, path.c_str(), channel.current_value.float_data)) + { + printError(config->shared_fbdo); + + if (config->close_session) + config->shared_fbdo->clear(); + return; + } + } + else + { + if (!Firebase.RTDB.set(config->shared_fbdo, path.c_str(), channel.current_value.int_data)) + { + printError(config->shared_fbdo); + + if (config->close_session) + config->shared_fbdo->clear(); + return; + } + } + } + + path = channelControlPath(); + path += firesense_token_t::slash; + path += channel.id.c_str(); + + Firebase.RTDB.set(config->shared_fbdo, path.c_str(), 0); + } + else if (channel.type == channel_type_t::Input) + { + path = channelControlPath(); + path += firesense_token_t::slash; + path += channel.id.c_str(); + Firebase.RTDB.deleteNode(config->shared_fbdo, path.c_str()); + + path = channelStatusPath(); + path += firesense_token_t::slash; + path += channel.id.c_str(); + if (channel.status) + { + printUpdate(channel.id.c_str(), 0); + + if (channel.current_value.type == data_type_float) + { + if (!Firebase.RTDB.set(config->shared_fbdo, path.c_str(), channel.current_value.float_data)) + { + printError(config->shared_fbdo); + + if (config->close_session) + config->shared_fbdo->clear(); + return; + } + } + else + { + if (!Firebase.RTDB.set(config->shared_fbdo, path.c_str(), channel.current_value.int_data)) + { + printError(config->shared_fbdo); + return; + } + } + } + } + else if (channel.type == channel_type_t::Analog_input) + { + path = channelControlPath(); + path += firesense_token_t::slash; + path += channel.id.c_str(); + Firebase.RTDB.deleteNode(config->shared_fbdo, path.c_str()); + + path = channelStatusPath(); + path += firesense_token_t::slash; + path += channel.id.c_str(); + if (channel.status) + { + printUpdate(channel.id.c_str(), 0); + + if (channel.current_value.type == data_type_float) + { + if (!Firebase.RTDB.set(config->shared_fbdo, path.c_str(), channel.current_value.float_data)) + printError(config->shared_fbdo); + } + else + { + if (!Firebase.RTDB.set(config->shared_fbdo, path.c_str(), channel.current_value.int_data)) + printError(config->shared_fbdo); + } + } + } + else if (channel.type == channel_type_t::Value) + { + path = channelControlPath(); + path += firesense_token_t::slash; + path += channel.id.c_str(); + Firebase.RTDB.set(config->shared_fbdo, path.c_str(), 0); + + if ((int)userValueList.size() > channel.value_index && channel.value_index > -1 && channel.status) + { + path = channelStatusPath(); + path += firesense_token_t::slash; + path += channel.id.c_str(); + struct data_value_info_t val; + if (channel.value_index != -1 && channel.value_index < (int)userValueList.size()) + { + if (userValueList[channel.value_index].type == data_type_bool) + { + val.int_data = *userValueList[channel.value_index].boolPtr; + val.type = data_type_int; + val.float_data = (float)val.int_data; + } + else if (userValueList[channel.value_index].type == data_type_byte) + { + val.int_data = *userValueList[channel.value_index].bytePtr; + val.type = data_type_int; + val.float_data = (float)val.int_data; + } + else if (userValueList[channel.value_index].type == data_type_int) + { + val.int_data = *userValueList[channel.value_index].intPtr; + val.type = data_type_int; + val.float_data = (float)val.int_data; + } + else if (userValueList[channel.value_index].type == data_type_float) + { + val.float_data = *userValueList[channel.value_index].floatPtr; + val.type = data_type_float; + val.int_data = (int)val.float_data; + } + } + + printUpdate(channel.id.c_str(), 0); + if (val.type == data_type_float) + { + if (!Firebase.RTDB.set(config->shared_fbdo, path.c_str(), val.float_data)) + printError(config->shared_fbdo); + } + else + { + if (!Firebase.RTDB.set(config->shared_fbdo, path.c_str(), val.int_data)) + printError(config->shared_fbdo); + } + } + } + + if (config->close_session) + config->shared_fbdo->clear(); +} + +void FireSenseClass::storeDBStatus() +{ + if (!configReady()) + return; + + for (size_t i = 0; i < channelsList.size(); i++) + updateDBStatus(channelsList[i]); +} + +std::string FireSenseClass::controlPath() +{ + if (!configReady()) + return ""; + + std::string s = config->basePath.c_str(); + s += "/controls/"; + s += deviceId; + return s; +} + +std::string FireSenseClass::channelControlPath() +{ + std::string s = controlPath(); + s += "/channels"; + return s; +} + +std::string FireSenseClass::configPath() +{ + if (!configReady()) + return ""; + + std::string s = config->basePath.c_str(); + s += "/config/devices/"; + s += deviceId; + return s; +} + +std::string FireSenseClass::conditionPath() +{ + std::string s = configPath(); + s += "/conditions"; + return s; +} + +std::string FireSenseClass::channelConfigPath() +{ + std::string s = configPath(); + s += "/channels"; + return s; +} + +std::string FireSenseClass::streamCmdPath() +{ + std::string s = controlPath(); + s += "/cmd"; + return s; +} + +std::string FireSenseClass::statusPath() +{ + if (!configReady()) + return ""; + + std::string s = config->basePath.c_str(); + s += "/status/"; + s += deviceId; + return s; +} + +std::string FireSenseClass::terminalPath() +{ + std::string s = statusPath(); + s += "/terminal"; + return s; +} + +std::string FireSenseClass::channelStatusPath() +{ + std::string s = statusPath(); + s += "/channels"; + return s; +} + +std::string FireSenseClass::lastSeenPath() +{ + std::string s = statusPath(); + s += "/lastSeen"; + return s; +} + +std::string FireSenseClass::logPath() +{ + if (!configReady()) + return ""; + + std::string s = config->basePath.c_str(); + s += "/log/"; + s += deviceId; + return s; +} + +String FireSenseClass::getDeviceId() +{ + return getChipId().c_str(); +} + +std::string FireSenseClass::getChipId() +{ +#if defined(ESP32) + uint32_t chipId = 0; + for (int i = 0; i < 17; i = i + 8) + chipId |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i; + String s = firesense_token_t::esp; + s += String(chipId, HEX); + s.toUpperCase(); + return s.c_str(); +#elif defined(ESP8266) + String s = firesense_token_t::esp; + s += String(ESP.getChipId(), HEX); + s.toUpperCase(); + return s.c_str(); +#endif +} + +std::string FireSenseClass::randomUid(uint8_t length) +{ + std::string s = ""; + for (uint8_t i = 0; i < length; i++) + s += letters[random(0, 36)]; + return s; +} + +std::string FireSenseClass::getDateTimeString() +{ + if (!configReady()) + return ""; + + struct tm timeinfo; + time_t now = time(nullptr); + localtime_r(&now, &timeinfo); + + String s; + + s = sdow[timeinfo.tm_wday]; + + s += ", "; + s += String(timeinfo.tm_mday); + s += " "; + s += months[timeinfo.tm_mon]; + + s += " "; + s += String(timeinfo.tm_year + 1900); + + s += " "; + if (timeinfo.tm_hour < 10) + s += "0"; + s += String(timeinfo.tm_hour); + s += ":"; + if (timeinfo.tm_min < 10) + s += "0"; + s += String(timeinfo.tm_min); + + s += ":"; + if (timeinfo.tm_sec < 10) + s += "0"; + s += String(timeinfo.tm_sec); + + int p = 1; + if (config->time_zone < 0) + p = -1; + int tz = config->time_zone; + float dif = (p * (config->time_zone - tz)) * 60.0; + if (config->time_zone < 0) + s += " -"; + else + s += " +"; + + if (tz < 10) + s += "0"; + s += String(tz); + + if (dif < 10) + s += "0"; + s += String((int)dif); + + return s.c_str(); +} + +void FireSenseClass::replaceAll(std::string &str, const char *find, const char *replace) +{ + size_t pos = 0; + while ((pos = str.find(find, pos)) != std::string::npos) + { + str.erase(pos, strlen(find)); + str.insert(pos, replace); + pos += strlen(replace); + } +} + +void FireSenseClass::replaceChannelsValues(std::string &str) +{ + String s, t; + for (size_t i = 0; i < channelsList.size(); i++) + { + s = firesense_token_t::left_bk; + s += channelsList[i].id.c_str(); + s += firesense_token_t::right_bk; + struct data_value_info_t val = getChannelValue(&channelsList[i]); + + if (val.type == data_type_float) + replaceAll(str, s.c_str(), String(val.float_data).c_str()); + else + replaceAll(str, s.c_str(), String(val.int_data).c_str()); + } +} + +void FireSenseClass::trim(const char *s, std::string &d, bool isExpression, const char beginTrim, const char endTrim) +{ + int p1 = -1, p2 = -1, p3 = -1, p4 = -1; + + if (isExpression) + { + p1 = 0; + p2 = 0; + p3 = 0; + p4 = 0; + for (size_t i = 0; i < strlen(s); i++) + { + if (s[i] == beginTrim) + { + p1 = i; + p3++; + } + else if (s[i] == endTrim) + { + p2 = i; + p4++; + } + } + + if (p3 != p4 || p1 > p2) + { + d.clear(); + return; + } + + p1 = -1; + p2 = -1; + p3 = -1; + p4 = -1; + } + + if (p3 != p4 || p1 > p2) + d = s; + + for (size_t i = 0; i < strlen(s); i++) + { + if (s[i] == ' ') + continue; + else if (s[i] != beginTrim) + { + p3 = i; + break; + } + else + { + p1 = i + 1; + break; + } + } + + for (size_t i = strlen(s) - 1; i >= 0; i--) + { + if (s[i] == ' ') + continue; + else if (s[i] != endTrim) + { + p4 = i; + break; + } + else + { + p2 = i - 1; + break; + } + } + + if ((p1 == -1 && p2 == -1)) + { + p1 = p3; + p2 = p4; + } + else if ((p1 != -1 && p2 == -1)) + { + p1--; + p2 = p4; + } + else if (p2 != -1 && p1 == -1) + { + p1 = p3; + p2++; + } + + std::string tmp; + + int i = 0; + while (i < p2 - p1 + 1) + { + d += s[p1 + i]; + i++; + } + p1 = 0; + p2 = 0; + p3 = 0; + p4 = 0; + for (size_t i = 0; i < d.length(); i++) + { + if (d[i] == beginTrim) + { + p1 = i; + p3++; + } + else if (d[i] == endTrim) + { + p2 = i; + p4++; + } + } + + if (p3 != p4 || p1 > p2) + d = s; +} + +void FireSenseClass::getCondition(const char *s, struct cond_item_data_t &data) +{ + if (!Firebase.ready()) + return; + + cond_comp_opr_type_t comp_type = cond_comp_opr_type_undefined; + int p1 = -1, p2 = -1; + std::string t, left, right; + + if (strlen(s) > 7) + { + t = s; + if (t.substr(0, 6) == firesense_token_t::change) + { + left = s; + size_t p1 = left.find(firesense_token_t::left_pr, 6); + if (p1 != std::string::npos) + { + p1++; + size_t p2 = left.find(firesense_token_t::right_pr, p1 + 1); + if (p2 != std::string::npos) + { + trim(left.substr(p1, p2 - p1).c_str(), right, false); + for (size_t j = 0; j < channelsList.size(); j++) + { + if (strcmp(right.c_str(), channelsList[j].id.c_str()) == 0) + { + data.left.type = cond_operand_type_changed; + data.right.type = cond_operand_type_changed; + data.left.channel = &channelsList[j]; + return; + } + } + } + } + } + } + + bool hasOp = false; + for (size_t i = 0; i < strlen(s); i++) + { + if (s[i] == '<' || s[i] == '>' || s[i] == '=') + hasOp = true; + + if (i + 1 < strlen(s)) + { + if (s[i] == '!' && s[i + 1] == '=') + hasOp = true; + } + } + + if (!hasOp) + { + left = s; + getConditionItem(data, left, right); + return; + } + + for (size_t i = 0; i < strlen(s); i++) + { + delay(0); + if (comp_type == cond_comp_opr_type_undefined) + { + if (s[i] == '<') + comp_type = cond_comp_opr_type_lt; + else if (s[i] == '>') + comp_type = cond_comp_opr_type_gt; + else if (s[i] == '!') + { + if (i + 1 < strlen(s)) + { + if (s[i + 1] == '=') + comp_type = cond_comp_opr_type_neq; + } + } + else if (s[i] == '=') + comp_type = cond_comp_opr_type_eq; + + if (comp_type != cond_comp_opr_type_undefined) + { + p1 = i; + p2 = i + 1; + } + + continue; + } + else + { + if (s[i] == '=' && comp_type == cond_comp_opr_type_lt) + { + comp_type = cond_comp_opr_type_lteq; + p2 = i + 1; + } + else if (s[i] == '=' && comp_type == cond_comp_opr_type_gt) + { + comp_type = cond_comp_opr_type_gteq; + p2 = i + 1; + } + else if (s[i] == '=' && (comp_type == cond_comp_opr_type_neq || comp_type == cond_comp_opr_type_eq)) + p2 = i + 1; + else if (s[i] == '=' && comp_type != cond_comp_opr_type_neq && comp_type != cond_comp_opr_type_eq) + comp_type = cond_comp_opr_type_undefined; + } + + if (comp_type != cond_comp_opr_type_undefined) + { + int i = 0; + std::string r, l; + while (i < p1) + { + l += s[i]; + i++; + } + + i = 0; + while (i < (int)strlen(s) - p2) + { + r += s[p2 + i]; + i++; + } + + if (l.length() > 0) + trim(l.c_str(), left, false); + if (r.length() > 0) + trim(r.c_str(), right, false); + + getConditionItem(data, left, right); + + data.comp = comp_type; + + return; + } + } +} + +void FireSenseClass::getConditionItem(struct cond_item_data_t &data, std::string &left, std::string &right) +{ + if (left.length() == 0) + return; + + if (left[0] == '!') + data.left.not_op = true; + if (left.length() > 1) + if (left[1] == ' ') + data.left.not_op = false; + + if (data.left.not_op) + left = left.substr(1, left.length() - 1); + + if (left == firesense_token_t::millis) + data.left.type = cond_operand_type_millis; + else if (left == firesense_token_t::micros) + data.left.type = cond_operand_type_micros; + else if (left == firesense_token_t::date || left == firesense_token_t::time || left == firesense_token_t::day || left == firesense_token_t::weekday || left == firesense_token_t::hour || left == firesense_token_t::hour || left == firesense_token_t::sec || left == firesense_token_t::year || left == firesense_token_t::month) + { + if (left == firesense_token_t::date) + { + data.left.type = cond_operand_type_date; + data.right.type = cond_operand_type_date; + } + else if (left == firesense_token_t::time) + { + data.left.type = cond_operand_type_time; + data.right.type = cond_operand_type_time; + } + else if (left == firesense_token_t::year) + { + data.left.type = cond_operand_type_year; + data.right.type = cond_operand_type_year; + } + else if (left == firesense_token_t::month) + { + data.left.type = cond_operand_type_month; + data.right.type = cond_operand_type_month; + } + else if (left == firesense_token_t::day) + { + data.left.type = cond_operand_type_day; + data.right.type = cond_operand_type_day; + } + else if (left == firesense_token_t::weekday) + { + data.left.type = cond_operand_type_weekday; + data.right.type = cond_operand_type_weekday; + } + else if (left == firesense_token_t::hour) + { + data.left.type = cond_operand_type_hour; + data.right.type = cond_operand_type_hour; + } + else if (left == firesense_token_t::hour) + { + data.left.type = cond_operand_type_min; + data.right.type = cond_operand_type_min; + } + else if (left == firesense_token_t::sec) + { + data.left.type = cond_operand_type_sec; + data.right.type = cond_operand_type_sec; + } + + parseDateTime(right.c_str(), data.left.type, data.left.time); + } + else + { + + if (data.left.type == cond_operand_type_undefined) + { + for (size_t j = 0; j < channelsList.size(); j++) + { + if (strcmp(left.c_str(), channelsList[j].id.c_str()) == 0) + { + data.left.type = cond_operand_type_channel; + data.left.channel = &channelsList[j]; + break; + } + } + } + } + + if (data.left.type == cond_operand_type_undefined) + { + parseExpression(left.c_str(), data.left.exprs.expressions); + data.left.type = cond_operand_type_expression; + } + + if (right.length() == 0) + return; + + if (left[0] == '!') + data.right.not_op = true; + if (left.length() > 1) + if (left[1] == ' ') + data.right.not_op = false; + + if (data.right.not_op) + right = right.substr(1, right.length() - 1); + + if (right == firesense_token_t::millis) + data.right.type = cond_operand_type_millis; + else if (right == firesense_token_t::micros) + data.right.type = cond_operand_type_micros; + else + { + for (size_t j = 0; j < channelsList.size(); j++) + { + if (strcmp(right.c_str(), channelsList[j].id.c_str()) == 0) + { + data.right.type = cond_operand_type_channel; + data.right.channel = &channelsList[j]; + break; + } + } + } + + if (data.right.type == cond_operand_type_undefined) + { + parseExpression(right.c_str(), data.right.exprs.expressions); + data.right.type = cond_operand_type_expression; + } +} + +void FireSenseClass::parseDateTime(const char *str, int type, struct tm &out) +{ + out.tm_sec = -1; + out.tm_min = -1; + out.tm_hour = -1; + out.tm_mday = -1; + out.tm_mon = -1; + out.tm_year = -1; + out.tm_wday = -1; + std::vector tmtk = std::vector(); + + if (type == cond_operand_type_day) + out.tm_mday = atoi(str); + else if (type == cond_operand_type_month) + out.tm_mon = atoi(str); + else if (type == cond_operand_type_year) + out.tm_year = atoi(str); + else if (type == cond_operand_type_weekday) + out.tm_wday = atoi(str); + else if (type == cond_operand_type_hour) + out.tm_hour = atoi(str); + else if (type == cond_operand_type_min) + out.tm_min = atoi(str); + else if (type == cond_operand_type_sec) + out.tm_sec = atoi(str); + else if (type == cond_operand_type_time) + { + split(tmtk, str, ':'); + if (tmtk.size() == 1) + out.tm_sec = atoi(tmtk[0].c_str()); + else if (tmtk.size() == 2) + { + out.tm_sec = atoi(tmtk[1].c_str()); + out.tm_min = atoi(tmtk[0].c_str()); + } + else if (tmtk.size() == 3) + { + out.tm_sec = atoi(tmtk[2].c_str()); + out.tm_min = atoi(tmtk[1].c_str()); + out.tm_hour = atoi(tmtk[0].c_str()); + } + } + else if (type == cond_operand_type_date) + { + split(tmtk, str, '/'); + if (tmtk.size() == 1) + out.tm_mday = atoi(tmtk[0].c_str()); + else if (tmtk.size() == 2) + { + out.tm_mday = atoi(tmtk[1].c_str()); + out.tm_mon = atoi(tmtk[0].c_str()); + } + else if (tmtk.size() == 3) + { + out.tm_year = atoi(tmtk[2].c_str()); + out.tm_mday = atoi(tmtk[1].c_str()); + out.tm_mon = atoi(tmtk[0].c_str()); + } + } +} + +void FireSenseClass::getExpression(const char *s, struct expr_item_data_t &data) +{ + std::string str = s; + + if (strlen(s) > 0) + { + if (s[0] == '!') + { + data.not_op = true; + str = str.substr(1, str.length() - 1); + } + } + + if (str == firesense_token_t::millis) + { + data.type = expr_operand_type_millis; + data.value.type = data_type_int; + data.value.int_data = millis(); + data.value.float_data = (float)data.value.int_data; + return; + } + else if (str == firesense_token_t::micros) + { + data.type = expr_operand_type_micros; + data.value.type = data_type_int; + data.value.int_data = micros(); + data.value.float_data = (float)data.value.int_data; + return; + } + else if (str == firesense_token_t::d_true || str == firesense_token_t::d_false) + { + data.type = expr_operand_type_value; + data.value.type = data_type_bool; + data.value.int_data = str == firesense_token_t::d_true ? 1 : 0; + data.value.float_data = (float)data.value.int_data; + return; + } + else + { + for (size_t i = 0; i < channelsList.size(); i++) + { + if (strcmp(s, channelsList[i].id.c_str()) == 0) + { + data.type = expr_operand_type_channel; + data.channel = &channelsList[i]; + data.value.type = data.channel->current_value.type; + return; + } + } + } + + data.type = expr_operand_type_value; + if (str.find(firesense_token_t::dot) != std::string::npos) + { + data.value.type = data_type_float; + data.value.float_data = atof(s); + data.value.int_data = (int)data.value.float_data; + } + else + { + data.value.type = data_type_int; + data.value.int_data = atoi(s); + data.value.float_data = (float)data.value.int_data; + } +} + +void FireSenseClass::parseExpression(const char *src, std::vector &expressions, int depth) +{ + if (!Firebase.ready()) + return; + + int orbk = 0, crbk = 0; + bool nested = false; + int aType = assignment_operator_type_undefined; + + std::string s, buf, t; + trim(src, s, true); + int dp = depth + 1; + bool not_op = false; + + for (size_t i = 0; i < s.length(); i++) + { + if (i + 1 < s.length()) + { + if (s[i] == '!' && s[i + 1] == '(') + { + not_op = true; + continue; + } + } + if (s[i] == '(') + orbk++; + else if (s[i] == ')') + crbk++; + else if (orbk - crbk == 0) + aType = getAssignOprType(s[i]); + + if (i + 1 < s.length()) + { + if ((aType == assignment_operator_type_left_shift && s[i + 1] != '<') || (aType == assignment_operator_type_right_shift && s[i] != '>')) + aType = assignment_operator_type_undefined; + + if (aType == assignment_operator_type_logic_and && s[i + 1] == '&') + aType = assignment_operator_type_and; + + if (aType == assignment_operator_type_logic_or && s[i + 1] == '|') + aType = assignment_operator_type_or; + } + + if ((aType == assignment_operator_type_undefined && (assignment_operator_type_t)getAssignOprType(s[i]) == assignment_operator_type_undefined) || orbk - crbk != 0) + { + if ((assignment_operator_type_t)getAssignOprType(s[i]) != assignment_operator_type_undefined) + nested = true; + buf += s[i]; + } + + if (aType != assignment_operator_type_undefined) + { + t.clear(); + trim(buf.c_str(), t, true); + if (t.length() > 0) + { + struct expression_item_info_t e; + e.is_nested = nested; + e.depth = depth; + e.next_ass_opr = (assignment_operator_type_t)aType; + e.not_op = not_op; + expressions.push_back(e); + if (nested) + parseExpression(t.c_str(), expressions[expressions.size() - 1].list, dp); + else + getExpression(t.c_str(), expressions[expressions.size() - 1].data); + } + aType = assignment_operator_type_undefined; + nested = false; + not_op = false; + buf.clear(); + continue; + } + } + + if (buf.length() > 0) + { + t.clear(); + trim(buf.c_str(), t, true); + if (t.length() > 0) + { + struct expression_item_info_t e; + e.is_nested = nested; + e.depth = depth; + e.next_ass_opr = (assignment_operator_type_t)aType; + e.not_op = not_op; + expressions.push_back(e); + if (nested) + parseExpression(t.c_str(), expressions[expressions.size() - 1].list, dp); + else + getExpression(t.c_str(), expressions[expressions.size() - 1].data); + } + } +} + +int FireSenseClass::getAssignOprType(const char c) +{ + assignment_operator_type_t ass = assignment_operator_type_undefined; + if (c == '+') + ass = assignment_operator_type_add; + else if (c == '-') + ass = assignment_operator_type_subtract; + else if (c == '*') + ass = assignment_operator_type_multiply; + else if (c == '/') + ass = assignment_operator_type_division; + else if (c == '%') + ass = assignment_operator_type_remainder; + else if (c == '<') + ass = assignment_operator_type_left_shift; + else if (c == '>') + ass = assignment_operator_type_right_shift; + else if (c == '|') + ass = assignment_operator_type_logic_or; + else if (c == '&') + ass = assignment_operator_type_logic_and; + return ass; +} + +int FireSenseClass::getCompareConditionType(const char c) +{ + next_comp_opr_t compr = next_comp_opr_none; + if (c == '|') + compr = next_comp_opr_or; + else if (c == '&') + compr = next_comp_opr_and; + return compr; +} + +void FireSenseClass::parseCondition(const char *src, std::vector &conditions, int depth) +{ + if (!Firebase.ready()) + return; + + int orbk = 0, crbk = 0; + bool nested = false; + std::string s, buf, t; + trim(src, s, false); + int dp = depth + 1; + bool not_op = false; + + next_comp_opr_t compr = next_comp_opr_none; + + for (size_t i = 0; i < s.length(); i++) + { + delay(0); + if (i + 1 < s.length()) + { + if (s[i] == '!' && s[i + 1] == '(') + { + not_op = true; + continue; + } + } + + if (s[i] == '(') + orbk++; + else if (s[i] == ')') + crbk++; + else if (orbk - crbk == 0) + compr = (next_comp_opr_t)getCompareConditionType(s[i]); + + if (i + 1 < s.length()) + { + if ((compr == next_comp_opr_or && s[i + 1] != '|') || (compr == next_comp_opr_and && s[i + 1] != '&')) + compr = next_comp_opr_none; + } + + if ((compr == next_comp_opr_none && (next_comp_opr_t)getCompareConditionType(s[i]) == next_comp_opr_none) || orbk - crbk != 0) + { + if ((next_comp_opr_t)getCompareConditionType(s[i]) != next_comp_opr_none) + nested = true; + buf += s[i]; + } + + if (compr != next_comp_opr_none) + { + t.clear(); + trim(buf.c_str(), t, false); + if (t.length() > 0) + { + struct condition_item_info_t e; + e.is_nested = nested; + e.depth = depth; + e.next_comp_opr = compr; + e.not_op = not_op; + //e.raw = t; + conditions.push_back(e); + if (nested) + parseCondition(t.c_str(), conditions[conditions.size() - 1].list, dp); + else + getCondition(t.c_str(), conditions[conditions.size() - 1].data); + } + nested = false; + not_op = false; + buf.clear(); + continue; + } + } + + if (buf.length() > 0) + { + t.clear(); + trim(buf.c_str(), t, false); + if (t.length() > 0) + { + struct condition_item_info_t e; + e.is_nested = nested; + e.depth = depth; + e.next_comp_opr = compr; + e.not_op = not_op; + //e.raw = t; + conditions.push_back(e); + + if (nested) + parseCondition(t.c_str(), conditions[conditions.size() - 1].list, dp); + else + getCondition(t.c_str(), conditions[conditions.size() - 1].data); + } + } +} + +void FireSenseClass::parseStatement(const char *src, std::vector &stm) +{ + if (!Firebase.ready()) + return; + + std::string s, t, left, right; + trim(src, s, false); + + std::vector stmTk = std::vector(); + split(stmTk, s.c_str(), ',', '(', ')'); + + for (size_t i = 0; i < stmTk.size(); i++) + { + delay(0); + t.clear(); + trim(stmTk[i].c_str(), t, false); + + struct statement_item_info_t item; + getStatement(t.c_str(), item.data); + + stm.push_back(item); + } +} + +void FireSenseClass::getStatement(const char *src, struct stm_item_t &data) +{ + if (!Firebase.ready()) + return; + + std::string s, t, left, right; + trim(src, s, false); + + int pos = 0; + size_t p1 = 0, p2 = 0; + delay(0); + + if (s.length() > 6) + { + if (s.substr(0, 5) == firesense_token_t::delay) + pos = 5; + else if (s.substr(0, 4) == firesense_token_t::func) + pos = 4; + + if (pos > 0) + { + p1 = s.find(firesense_token_t::left_pr, pos); + if (p1 != std::string::npos) + { + p1++; + p2 = s.rfind(firesense_token_t::right_pr, s.length() - 1); + if (p2 != std::string::npos && p2 > p1) + { + if (pos == 4) + { + data.left.type = stm_operand_type_function; + std::vector params = std::vector(); + split(params, s.substr(p1, p2 - p1).c_str(), ',', '\'', '\''); + int func_idx = -1; + + if (params.size() > 0) + { + func_idx = atoi(params[0].c_str()); + } + + if (params.size() > 1) + { + data.left.function.iteration_max = atoi(params[1].c_str()); + } + if (params.size() > 2) + { + std::string s; + trim(params[2].c_str(), s, false, '\'', '\''); + data.left.function.payload = s; + } + + if (func_idx > -1 && func_idx < (int)functionList.size()) + data.left.function.ptr = &functionList[func_idx]; + } + else if (pos == 5) + { + data.left.type = stm_operand_type_delay; + data.left.tmo = atoi(s.substr(p1, p2 - p1).c_str()); + } + return; + } + } + } + } + + assignment_operator_type_t ass_type = assignment_operator_type_undefined; + + for (size_t i = 0; i < s.length(); i++) + { + delay(0); + if (ass_type == assignment_operator_type_undefined) + { + if (s[i] == '=') + { + p2 = i + 1; + ass_type = assignment_operator_type_assignment; + } + else if (s[i] == '+') + ass_type = assignment_operator_type_add; + else if (s[i] == '-') + ass_type = assignment_operator_type_subtract; + else if (s[i] == '*') + ass_type = assignment_operator_type_multiply; + else if (s[i] == '/') + ass_type = assignment_operator_type_division; + else if (s[i] == '%') + ass_type = assignment_operator_type_remainder; + else if (s[i] == '<') + ass_type = assignment_operator_type_left_shift; + else if (s[i] == '>') + ass_type = assignment_operator_type_right_shift; + else if (s[i] == '&') + ass_type = assignment_operator_type_and; + else if (s[i] == '|') + ass_type = assignment_operator_type_or; + + if (ass_type != assignment_operator_type_undefined) + p1 = i; + + continue; + } + else + { + + bool valid = false; + + if (ass_type == assignment_operator_type_assignment) + valid = true; + else + { + if (s[i] == '=' && (ass_type == assignment_operator_type_add || ass_type == assignment_operator_type_subtract || ass_type == assignment_operator_type_multiply || ass_type == assignment_operator_type_division || ass_type == assignment_operator_type_remainder)) + { + valid = true; + p2 = i + 1; + } + else if (s[i] == '<' || s[i] == '>' || s[i] == '&' || s[i] == '|') + { + if (i + 1 < s.length()) + { + + if (s[i] == '<' && s[i + 1] == '=' && ass_type == assignment_operator_type_left_shift) + valid = true; + else if (s[i] == '>' && s[i + 1] == '=' && ass_type == assignment_operator_type_right_shift) + valid = true; + else if (s[i] == '|' && s[i + 1] == '=' && ass_type == assignment_operator_type_or) + valid = true; + else if (s[i] == '&' && s[i + 1] == '=' && ass_type == assignment_operator_type_and) + valid = true; + + if (valid) + p2 = i + 2; + } + } + } + + if (!valid) + ass_type = assignment_operator_type_undefined; + } + + if (ass_type != assignment_operator_type_undefined) + { + + int m = 0; + std::string r, l; + while (m < (int)p1) + { + delay(0); + l += s[m]; + m++; + } + + m = 0; + while (m < (int)s.length() - (int)p2) + { + delay(0); + r += s[p2 + m]; + m++; + } + + if (l.length() > 0) + trim(l.c_str(), left, false); + if (r.length() > 0) + trim(r.c_str(), right, false); + + for (size_t j = 0; j < channelsList.size(); j++) + { + if (strcmp(left.c_str(), channelsList[j].id.c_str()) == 0) + { + data.left.type = stm_operand_type_channel; + data.left.channel = &channelsList[j]; + break; + } + } + + for (size_t j = 0; j < channelsList.size(); j++) + { + if (strcmp(right.c_str(), channelsList[j].id.c_str()) == 0) + { + data.right.type = stm_operand_type_channel; + data.right.channel = &channelsList[j]; + break; + } + } + + if (data.right.type == stm_operand_type_undefined) + { + parseExpression(right.c_str(), data.right.exprs.expressions); + data.right.type = stm_operand_type_expression; + } + + data.ass = ass_type; + + return; + } + } +} + +void FireSenseClass::split(std::vector &out, const char *str, const char delim, const char beginEsc, const char endEsc) +{ + uint16_t index = 0; + uint16_t len = strlen(str); + size_t sz = len * 2; + char buf[sz]; + + size_t esc1 = 0, esc2 = 0; + + int next_stage = -1; + + for (uint16_t i = 0; i < len; i++) + { + if (beginEsc != endEsc) + { + if (str[i] == beginEsc) + esc1++; + else if (str[i] == endEsc) + esc2++; + } + else + { + if (str[i] == beginEsc && (next_stage == -1 || next_stage == 0)) + { + next_stage = 1; + esc1++; + } + else if (str[i] == endEsc && (next_stage == -1 || next_stage == 1)) + { + next_stage = 0; + esc2++; + } + } + + if (str[i] == delim && esc1 == esc2) + { + memset(buf, 0, sz); + strncpy(buf, (char *)str + index, i - index); + index = i + 1; + if (strlen(buf) > 0) + out.push_back(buf); + } + } + + if (index < len + 1 && esc1 == esc2) + { + memset(buf, 0, sz); + strncpy(buf, (char *)str + index, len - index); + if (strlen(buf) > 0) + out.push_back(buf); + } +} + +void FireSenseClass::setLogQueryIndex() +{ + + if (!configReady()) + return; + + printUpdate("", 12); + + delay(0); + + if (!Firebase.RTDB.setQueryIndex(config->shared_fbdo, logPath().c_str(), firesense_token_t::time, databaseSecret)) + { + printError(config->shared_fbdo); + if (config->debug) + Serial.println(); + } + else + printUpdate("", 13); + + if (config->close_session) + config->shared_fbdo->clear(); +} + +#endif \ No newline at end of file diff --git a/src/addons/FireSense/README.md b/src/addons/FireSense/README.md new file mode 100644 index 00000000..bea66d8e --- /dev/null +++ b/src/addons/FireSense/README.md @@ -0,0 +1,289 @@ +# FireSense for Firebase ESP Client. + +# The Programmable Data Logging and IO Control library v1.0.0 + + +This library supports ESP8266 and ESP32 MCU from Espressif. + + +## Functions and Usages + + + +#### Initiate the FireSense Class. + +param **`config`** The pointer to Firesense_Config data. + +param **`databaseSecret`** The database secret. + +return **`Boolean`** value, indicates the success of the operation. + +note: Due to query index need to be assign to the database rules, the admin rights access is needed. + +The database secret can be empty string if the sign-in sign-in method is OAuth2.0. + +```cpp +bool begin(struct firesense_config_t *config, const char *databaseSecret); +``` + + + + + +#### Load the device configurations. + +param **`defaultDataLoadCallback`** The callback function that called when no config found in the database. + +note: The callback function should add the channals or conditions manually or load from the device storage. + +```cpp +void loadConfig(callback_function_t defaultDataLoadCallback); +``` + + + + + + +#### Save the current config to the device storage. + +param **`filename`** The file path includes its name of file that will be saved. + +param **`storageType`** The enum of memory storage type e.g. mem_storage_type_flash and mem_storage_type_sd. The file systems can be changed in FirebaseFS.h. + +return **`Boolean`** value, indicates the success of the operation. + +```cpp +bool backupConfig(const String &filename, fb_esp_mem_storage_type storageType); +``` + + + + + + +#### Read the config from the device storage. + +param **`filename`** The file path includes its name of file that will be read. + +param **`storageType`** The enum of memory storage type e.g. mem_storage_type_flash and mem_storage_type_sd. The file systems can be changed in FirebaseFS.h. + +return **`Boolean`** value, indicates the success of the operation. + +```cpp +bool restoreConfig(const String &filename, fb_esp_mem_storage_type storageType); +``` + + + + + + +#### Enable (run) or disable (stop) the conditions checking tasks. + +param **`enable`** The boolean value to enable/disable. + +```cpp +void enableController(bool enable); +``` + + + + + +#### Add a channel to device config. + +param **`channel`** The FireSense_Channel data to add. + +param **`addToDatabase`** The boolean option, set to true to add the data to database. + +```cpp +void addChannel(struct channel_info_t &channel, bool addToDatabase = true); +``` + + + + + +#### Add a condition to device config. + +param **`cond`** The FireSense_Condition data to add. + +param **`addToDatabase`** The boolean option, set to true to add the data to database. + +The format of conditions (IF) and its expression. + +CONDITION1 + && or || LOGICAL OPERATOR + CONDITION2 + LOGICAL OPERATOR + CONDITION3 +... + +The condition checking and expression evaluation are from left to right + +The valid left, right operands and syntaxes are + +| Oerand and Syntaxes | Usages | +| ------------- | ------------- | +| | LED1 == false && STATUS == LED1 | +| values e.g. boolean, integer and float | HUMID1 > 70 \|\| LAMP1 == false | +| millis | millis > 200000 + VALUE1 | +| micros | VALUE1 < micros - 1000000 | +| time e.g. hour:min:sec | time > 12:00:00 && time < 15:30:00 | +| date e.g. month/day/year where month start with 0 | date == 5/28/2021 | +| weekday e.g. 1 for monday and 7 for sunday | weekday == 5 | +| day e.g. 1 to 31 | day > 24 | +| month e.g. 0 to 11 | month < 11 | +| year e.g. 2021 | year == 2021 | +| hour e.g. 0 to 23 | hour == 18 | +| min e.g. 0 to 59 | min == 30 | +| sec e.g. 0 to 59 | sec == 20 | +| change e.g the value of channel changed | change(VALUE1) | +| ! e.g. the opposite of expresion result | !LED1 \|\| !(time > 15:20:06) | +| year e.g. 2021 | year == 2021 | + + +The format of statements (THEN and ELSE) and its expression. + +STATEMENT1 + COMMA + STATEMENT2 +... + +The statement processing and expression evaluation are from left to right. + +The valid left, right operands and syntaxes are + +| Oerand and Syntaxes | Usages | +| ------------- | ------------- | +| | LED1 = false, STATUS = 5 * 10 | +| values e.g. boolean, integer and float | HUMID1 = 70 | +| millis | VALUE1 += millis | +| micros | VALUE1 \*= micros | +| delay | delay(1000), LED1 = true | +| | ;do non-blocking delay until timed out and set LED1 to true | +| func e.g. func(x,y,z) | func(0,10,'hello world') | +| where x is the index of callback function added with FireSense.addCallbackFunction | ;send the hello world text 10 times to function with index 0 | +| y is the number of iteration that function will be called as long as the conditions is true | | +| z is the message payload sent to the callback. | | +| The content of payload other than alphabet (A-Z, a-z and 1-9) should be in ''. | | +| Use {CHANNEL_ID} to insert the channel value into the text payload. | | + + + + +The supported assignment operators are ++=, -=, *=, /=, &=, |= + + +The supported comparision operators are +==, !=, >, <, >=, <= + + +```cpp +void addCondition(struct firesense_condition_t cond, bool addToDatabase = true); +``` + + + +#### Add a callback function used with func syntax in the conditions. + +param **`func`** The FireSense_Function callback. + +```cpp +void addCallbackFunction(FireSense_Function func); +``` + + + + +#### Clear all callback functions used with func syntax in the conditions. + +```cpp +void clearAllCallbackFunctions(); +``` + + + + +#### Add a pointer of uint8_t (byte) variable that bind to the channels. + +param **`value`** The uint8_t variable. + +```cpp +void addUserValue(uint8_t *value); +``` + + + + +#### Add a pointer of bool variable that bind to the channels. + +param **`value`** The bool variable. + +```cpp +void addUserValue(bool *value); +``` + + + + +#### Add a pointer of int variable that bind to the channels. + +param **`value`** The int variable. + +```cpp +void addUserValue(int *value); +``` + + + + +#### Add a pointer of float variable that bind to the channels. + +param **`value`** The float variable. + +```cpp +void addUserValue(float *value); +``` + + + + +#### Clear all user variable pointers that binded to the channels. + +```cpp +void clearAllUserValues(); +``` + + + + +#### Get the devivce id string. + +return **`String`** The unique id String of device. + +```cpp + String getDeviceId(); +``` + + + + +## License + +The MIT License (MIT) + +Copyright (c) 2021 K. Suwatchai (Mobizt) + + +Permission is hereby granted, free of charge, to any 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 do so, +subject to the following conditions: + +The above copyright notice 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 BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 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 USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/src/addons/FireSense/library.properties b/src/addons/FireSense/library.properties new file mode 100644 index 00000000..49be5a0a --- /dev/null +++ b/src/addons/FireSense/library.properties @@ -0,0 +1,17 @@ +name=FireSense Addon for Firebase ESP Client. + +version=1.0.0 + +author=Mobizt + +maintainer=Mobizt + +sentence=The Programmable Data Logging and IO Control library. + +paragraph=This addon library is the programmable IO controller which works with Firebase. + +category=Communication + +url=https://github.com/mobizt/Firebase-ESP-Client/src/addons/FireSense + +architectures=esp8266, esp32 diff --git a/src/addons/RTDBHelper.h b/src/addons/RTDBHelper.h new file mode 100644 index 00000000..27508fbd --- /dev/null +++ b/src/addons/RTDBHelper.h @@ -0,0 +1,267 @@ +#ifndef RTDBHelper_H +#define RTDBHelper_H +#include +#if defined(ESP32) +#include +#elif defined(ESP8266) +#include +#endif + +void printResult(FirebaseData &data) +{ + + if (data.dataType() == "int") + Serial.println(data.intData()); + else if (data.dataType() == "float") + Serial.println(data.floatData(), 5); + else if (data.dataType() == "double") + printf("%.9lf\n", data.doubleData()); + else if (data.dataType() == "boolean") + Serial.println(data.boolData() == 1 ? "true" : "false"); + else if (data.dataType() == "string") + Serial.println(data.stringData()); + else if (data.dataType() == "json") + { + Serial.println(); + FirebaseJson &json = data.jsonObject(); + //Print all object data + Serial.println("Pretty printed JSON data:"); + String jsonStr; + json.toString(jsonStr, true); + Serial.println(jsonStr); + Serial.println(); + Serial.println("Iterate JSON data:"); + Serial.println(); + size_t len = json.iteratorBegin(); + String key, value = ""; + int type = 0; + for (size_t i = 0; i < len; i++) + { + json.iteratorGet(i, type, key, value); + Serial.print(i); + Serial.print(", "); + Serial.print("Type: "); + Serial.print(type == FirebaseJson::JSON_OBJECT ? "object" : "array"); + if (type == FirebaseJson::JSON_OBJECT) + { + Serial.print(", Key: "); + Serial.print(key); + } + Serial.print(", Value: "); + Serial.println(value); + } + json.iteratorEnd(); + } + else if (data.dataType() == "array") + { + Serial.println(); + //get array data from FirebaseData using FirebaseJsonArray object + FirebaseJsonArray &arr = data.jsonArray(); + //Print all array values + Serial.println("Pretty printed Array:"); + String arrStr; + arr.toString(arrStr, true); + Serial.println(arrStr); + Serial.println(); + Serial.println("Iterate array values:"); + Serial.println(); + for (size_t i = 0; i < arr.size(); i++) + { + Serial.print(i); + Serial.print(", Value: "); + + FirebaseJsonData &jsonData = data.jsonData(); + //Get the result data from FirebaseJsonArray object + arr.get(jsonData, i); + if (jsonData.typeNum == FirebaseJson::JSON_BOOL) + Serial.println(jsonData.boolValue ? "true" : "false"); + else if (jsonData.typeNum == FirebaseJson::JSON_INT) + Serial.println(jsonData.intValue); + else if (jsonData.typeNum == FirebaseJson::JSON_FLOAT) + Serial.println(jsonData.floatValue); + else if (jsonData.typeNum == FirebaseJson::JSON_DOUBLE) + printf("%.9lf\n", jsonData.doubleValue); + else if (jsonData.typeNum == FirebaseJson::JSON_STRING || + jsonData.typeNum == FirebaseJson::JSON_NULL || + jsonData.typeNum == FirebaseJson::JSON_OBJECT || + jsonData.typeNum == FirebaseJson::JSON_ARRAY) + Serial.println(jsonData.stringValue); + } + } + else if (data.dataType() == "blob") + { + + Serial.println(); + + std::vector blob = data.blobData(); + Serial.println(); + for (size_t i = 0; i < blob.size(); i++) + { + if (i > 0 && i % 16 == 0) + Serial.println(); + if (blob[i] < 16) + Serial.print("0"); + Serial.print(blob[i], HEX); + Serial.print(" "); + } + Serial.println(); + } + else if (data.dataType() == "file") + { + + Serial.println(); + + File file = data.fileStream(); + int i = 0; + + while (file.available()) + { + if (i > 0 && i % 16 == 0) + Serial.println(); + + int v = file.read(); + + if (v < 16) + Serial.print("0"); + + Serial.print(v, HEX); + Serial.print(" "); + i++; + } + Serial.println(); + file.close(); + } + else + { + Serial.println(data.payload()); + } +} + +void printResult(StreamData &data) +{ + + if (data.dataType() == "int") + Serial.println(data.intData()); + else if (data.dataType() == "float") + Serial.println(data.floatData(), 5); + else if (data.dataType() == "double") + printf("%.9lf\n", data.doubleData()); + else if (data.dataType() == "boolean") + Serial.println(data.boolData() == 1 ? "true" : "false"); + else if (data.dataType() == "string" || data.dataType() == "null") + Serial.println(data.stringData()); + else if (data.dataType() == "json") + { + Serial.println(); + FirebaseJson *json = data.jsonObjectPtr(); + //Print all object data + Serial.println("Pretty printed JSON data:"); + String jsonStr; + json->toString(jsonStr, true); + Serial.println(jsonStr); + Serial.println(); + Serial.println("Iterate JSON data:"); + Serial.println(); + size_t len = json->iteratorBegin(); + String key, value = ""; + int type = 0; + for (size_t i = 0; i < len; i++) + { + json->iteratorGet(i, type, key, value); + Serial.print(i); + Serial.print(", "); + Serial.print("Type: "); + Serial.print(type == FirebaseJson::JSON_OBJECT ? "object" : "array"); + if (type == FirebaseJson::JSON_OBJECT) + { + Serial.print(", Key: "); + Serial.print(key); + } + Serial.print(", Value: "); + Serial.println(value); + } + json->iteratorEnd(); + } + else if (data.dataType() == "array") + { + Serial.println(); + //get array data from FirebaseData using FirebaseJsonArray object + FirebaseJsonArray *arr = data.jsonArrayPtr(); + //Print all array values + Serial.println("Pretty printed Array:"); + String arrStr; + arr->toString(arrStr, true); + Serial.println(arrStr); + Serial.println(); + Serial.println("Iterate array values:"); + Serial.println(); + + for (size_t i = 0; i < arr->size(); i++) + { + Serial.print(i); + Serial.print(", Value: "); + + FirebaseJsonData *jsonData = data.jsonDataPtr(); + //Get the result data from FirebaseJsonArray object + arr->get(*jsonData, i); + if (jsonData->typeNum == FirebaseJson::JSON_BOOL) + Serial.println(jsonData->boolValue ? "true" : "false"); + else if (jsonData->typeNum == FirebaseJson::JSON_INT) + Serial.println(jsonData->intValue); + else if (jsonData->typeNum == FirebaseJson::JSON_FLOAT) + Serial.println(jsonData->floatValue); + else if (jsonData->typeNum == FirebaseJson::JSON_DOUBLE) + printf("%.9lf\n", jsonData->doubleValue); + else if (jsonData->typeNum == FirebaseJson::JSON_STRING || + jsonData->typeNum == FirebaseJson::JSON_NULL || + jsonData->typeNum == FirebaseJson::JSON_OBJECT || + jsonData->typeNum == FirebaseJson::JSON_ARRAY) + Serial.println(jsonData->stringValue); + } + } + else if (data.dataType() == "blob") + { + + Serial.println(); + + std::vector blob = data.blobData(); + Serial.println(); + for (size_t i = 0; i < blob.size(); i++) + { + if (i > 0 && i % 16 == 0) + Serial.println(); + if (blob[i] < 16) + Serial.print("0"); + Serial.print(blob[i], HEX); + Serial.print(" "); + } + Serial.println(); + } + else if (data.dataType() == "file") + { + + Serial.println(); + + File file = data.fileStream(); + int i = 0; + + while (file.available()) + { + if (i > 0 && i % 16 == 0) + Serial.println(); + + int v = file.read(); + + if (v < 16) + Serial.print("0"); + + Serial.print(v, HEX); + Serial.print(" "); + i++; + } + Serial.println(); + file.close(); + } +} + +#endif \ No newline at end of file diff --git a/src/addons/TokenHelper.h b/src/addons/TokenHelper.h new file mode 100644 index 00000000..a02b2f68 --- /dev/null +++ b/src/addons/TokenHelper.h @@ -0,0 +1,103 @@ +#include +#if defined(ESP32) +#include +#elif defined(ESP8266) +#include +#endif + +//This header file includes the functions that provide the token generation process info. + +/* The helper function to get the token type string */ +String getTokenType(struct token_info_t info) +{ + switch (info.type) + { + case token_type_undefined: + return "undefined"; + + case token_type_legacy_token: + return "legacy token"; + + case token_type_id_token: + return "id token"; + + case token_type_custom_token: + return "custom token"; + + case token_type_oauth2_access_token: + return "OAuth2.0 access token"; + + default: + break; + } + return "undefined"; +} + +/* The helper function to get the token status string */ +String getTokenStatus(struct token_info_t info) +{ + switch (info.status) + { + case token_status_uninitialized: + return "uninitialized"; + + case token_status_on_initialize: + return "on initializing\n** NTP time acquiring **\n"; + + case token_status_on_signing: + +#if defined(ESP32) + return "on signing"; +#elif defined(ESP8266) + return "on signing\n** wdt reset may be occurred at this stage due to the BearSSL long calculation process **\n"; +#endif + + case token_status_on_request: + return "on request"; + + case token_status_on_refresh: + return "on refreshing"; + + case token_status_ready: + return "ready"; + + case token_status_error: + return "error"; + + default: + break; + } + return "uninitialized"; +} + +/* The helper function to get the token error string */ +String getTokenError(struct token_info_t info) +{ + String s = "code: "; + s += String(info.error.code); + s += ", message: "; + s += info.error.message.c_str(); + return s; +} + +void tokenStatusCallback(TokenInfo info) +{ + /** fb_esp_auth_token_status enum + * token_status_uninitialized, + * token_status_on_initialize, + * token_status_on_signing, + * token_status_on_request, + * token_status_on_refresh, + * token_status_ready, + * token_status_error + */ + if (info.status == token_status_error) + { + Serial.printf("Token info: type = %s, status = %s\n", getTokenType(info).c_str(), getTokenStatus(info).c_str()); + Serial.printf("Token error: %s\n", getTokenError(info).c_str()); + } + else + { + Serial.printf("Token info: type = %s, status = %s\n", getTokenType(info).c_str(), getTokenStatus(info).c_str()); + } +} diff --git a/src/common.h b/src/common.h index b41ea5c0..917c6fe6 100644 --- a/src/common.h +++ b/src/common.h @@ -1,12 +1,12 @@ /** - * Created April 3, 2021 + * Created May 1, 2021 * * This work is a part of Firebase ESP Client library - * Copyright (c) 2020, 2021 K. Suwatchai (Mobizt) + * Copyright (c) 2021 K. Suwatchai (Mobizt) * * The MIT License (MIT) - * Copyright (c) 2020, 2021 K. Suwatchai (Mobizt) + * Copyright (c) 2021 K. Suwatchai (Mobizt) * * * Permission is hereby granted, free of charge, to any person returning a copy of @@ -64,8 +64,7 @@ class FunctionsConfig; #define QUEUE_TASK_STACK_SIZE 8192 #define MAX_BLOB_PAYLOAD_SIZE 1024 #define MAX_EXCHANGE_TOKEN_ATTEMPTS 5 -#define ESP_DEFAULT_TS 1510644967 -#define ESP_SIGNER_DEFAULT_RESPONSE_BUFFER_SIZE 2560 +#define ESP_DEFAULT_TS 1618971013 enum fb_esp_fcm_msg_mode { @@ -406,6 +405,7 @@ struct fb_esp_auth_token_info_t std::string jwt; std::string scope; unsigned long expires = 0; + unsigned long last_millis = 0; fb_esp_auth_token_type token_type = token_type_undefined; fb_esp_auth_token_status status = token_status_uninitialized; struct fb_esp_auth_token_error_t error; @@ -591,7 +591,9 @@ typedef void (*TokenStatusCallback)(TokenInfo); struct fb_esp_cfg_t { struct fb_esp_service_account_t service_account; + //deprecated, use database_url instead std::string host; + std::string database_url; std::string api_key; float time_zone = 0; struct fb_esp_auth_cert_t cert; @@ -968,7 +970,7 @@ struct fb_esp_session_info_t const uint32_t conn_timeout = 3 * 60 * 1000; uint16_t resp_size = 2048; - int http_code = -1000; + int http_code = FIREBASE_ERROR_HTTP_CODE_UNDEFINED; int content_length = 0; std::string error = ""; struct fb_esp_rtdb_info_t rtdb; @@ -1682,6 +1684,12 @@ static const char fb_esp_pgm_str_544[] PROGMEM = "The index of recipient device static const char fb_esp_pgm_str_545[] PROGMEM = "create message digest"; static const char fb_esp_pgm_str_546[] PROGMEM = "tokenProcessingTask"; static const char fb_esp_pgm_str_547[] PROGMEM = "max token generation retry reached"; +static const char fb_esp_pgm_str_548[] PROGMEM = "0.0.0.0"; +static const char fb_esp_pgm_str_549[] PROGMEM = "error"; +static const char fb_esp_pgm_str_550[] PROGMEM = "rules"; +static const char fb_esp_pgm_str_551[] PROGMEM = "/.indexOn"; +static const char fb_esp_pgm_str_552[] PROGMEM = ".read"; +static const char fb_esp_pgm_str_553[] PROGMEM = ".write"; static const unsigned char fb_esp_base64_table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const char fb_esp_boundary_table[] PROGMEM = "=_abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; diff --git a/src/json/FirebaseJson.cpp b/src/json/FirebaseJson.cpp index 8e5085ea..4c753b86 100644 --- a/src/json/FirebaseJson.cpp +++ b/src/json/FirebaseJson.cpp @@ -1,9 +1,9 @@ /* - * FirebaseJson, version 2.3.13 + * FirebaseJson, version 2.3.14 * * The Easiest Arduino library to parse, create and edit JSON object using a relative path. * - * April 4, 2021 + * April 30, 2021 * * Features * - None recursive operations @@ -46,2677 +46,2711 @@ #if defined(__arm__) && defined(TEENSYDUINO) && (defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1062__)) extern "C" { - int __exidx_start() { return -1; } - int __exidx_end() { return -1; } + int __exidx_start() { return -1; } + int __exidx_end() { return -1; } } #endif FirebaseJson::FirebaseJson() { - _init(); + _init(); } FirebaseJson::FirebaseJson(std::string &data) { - _init(); - _setJsonData(data); + _init(); + _setJsonData(data); } FirebaseJson::~FirebaseJson() { - clear(); - _topLevelTkType = JSMN_OBJECT; - _parser.reset(); - _parser = nullptr; - _finalize(); - delete helper; + clear(); + _topLevelTkType = JSMN_OBJECT; + _parser.reset(); + _parser = nullptr; + _finalize(); + delete helper; } void FirebaseJson::_init() { - _finalize(); - _qt = helper->strP(fb_json_str_2); - _tab = helper->strP(fb_json_str_22); - _brk1 = helper->strP(fb_json_str_8); - _brk2 = helper->strP(fb_json_str_9); - _brk3 = helper->strP(fb_json_str_10); - _brk4 = helper->strP(fb_json_str_11); - _cm = helper->strP(fb_json_str_1); - _pr2 = helper->strP(fb_json_str_3); - _nl = helper->strP(fb_json_str_24); - _nll = helper->strP(fb_json_str_18); - _pr = helper->strP(fb_json_str_25); - _pd = helper->strP(fb_json_str_4); - _pf = helper->strP(fb_json_str_5); - _fls = helper->strP(fb_json_str_6); - _tr = helper->strP(fb_json_str_7); - _string = helper->strP(fb_json_str_12); - _int = helper->strP(fb_json_str_13); - _dbl = helper->strP(fb_json_str_14); - _bl = helper->strP(fb_json_str_15); - _obj = helper->strP(fb_json_str_16); - _arry = helper->strP(fb_json_str_17); - _undef = helper->strP(fb_json_str_19); - _dot = helper->strP(fb_json_str_20); + _finalize(); + _qt = helper->strP(fb_json_str_2); + _tab = helper->strP(fb_json_str_22); + _brk1 = helper->strP(fb_json_str_8); + _brk2 = helper->strP(fb_json_str_9); + _brk3 = helper->strP(fb_json_str_10); + _brk4 = helper->strP(fb_json_str_11); + _cm = helper->strP(fb_json_str_1); + _pr2 = helper->strP(fb_json_str_3); + _nl = helper->strP(fb_json_str_24); + _nll = helper->strP(fb_json_str_18); + _pr = helper->strP(fb_json_str_25); + _pd = helper->strP(fb_json_str_4); + _pf = helper->strP(fb_json_str_5); + _fls = helper->strP(fb_json_str_6); + _tr = helper->strP(fb_json_str_7); + _string = helper->strP(fb_json_str_12); + _int = helper->strP(fb_json_str_13); + _dbl = helper->strP(fb_json_str_14); + _bl = helper->strP(fb_json_str_15); + _obj = helper->strP(fb_json_str_16); + _arry = helper->strP(fb_json_str_17); + _undef = helper->strP(fb_json_str_19); + _dot = helper->strP(fb_json_str_20); } void FirebaseJson::_finalize() { - helper->delS(_qt); - helper->delS(_tab); - helper->delS(_brk1); - helper->delS(_brk2); - helper->delS(_brk3); - helper->delS(_brk4); - helper->delS(_cm); - helper->delS(_pr2); - helper->delS(_nl); - helper->delS(_nll); - helper->delS(_pr); - helper->delS(_pd); - helper->delS(_pf); - helper->delS(_fls); - helper->delS(_tr); - helper->delS(_string); - helper->delS(_int); - helper->delS(_dbl); - helper->delS(_bl); - helper->delS(_obj); - helper->delS(_arry); - helper->delS(_undef); - helper->delS(_dot); + helper->delS(_qt); + helper->delS(_tab); + helper->delS(_brk1); + helper->delS(_brk2); + helper->delS(_brk3); + helper->delS(_brk4); + helper->delS(_cm); + helper->delS(_pr2); + helper->delS(_nl); + helper->delS(_nll); + helper->delS(_pr); + helper->delS(_pd); + helper->delS(_pf); + helper->delS(_fls); + helper->delS(_tr); + helper->delS(_string); + helper->delS(_int); + helper->delS(_dbl); + helper->delS(_bl); + helper->delS(_obj); + helper->delS(_arry); + helper->delS(_undef); + helper->delS(_dot); } FirebaseJson &FirebaseJson::_setJsonData(std::string &data) { - return setJsonData(data.c_str()); + return setJsonData(data.c_str()); } FirebaseJson &FirebaseJson::setJsonData(const String &data) { - _topLevelTkType = JSMN_OBJECT; - if (data.length() > 0) - { - int p1 = helper->strpos(data.c_str(), _brk1, 0); - int p2 = helper->rstrpos(data.c_str(), _brk2, data.length() - 1); - if (p1 != -1) - p1 += 1; - if (p1 != -1 && p2 != -1) - _rawbuf = data.substring(p1, p2).c_str(); - else - { - p1 = helper->strpos(data.c_str(), _brk3, 0); - p2 = helper->rstrpos(data.c_str(), _brk4, data.length() - 1); - if (p1 != -1) - p1 += 1; - if (p1 != -1 && p2 != -1) - { - char *_r = helper->strP(fb_json_str_21); - _rawbuf = _r; - _rawbuf += data.c_str(); - helper->delS(_r); - _topLevelTkType = JSMN_ARRAY; - } - else - { - _rawbuf = data.c_str(); - _topLevelTkType = JSMN_PRIMITIVE; - } - } - } + _topLevelTkType = JSMN_OBJECT; + if (data.length() > 0) + { + int p1 = helper->strpos(data.c_str(), _brk1, 0); + int p2 = helper->rstrpos(data.c_str(), _brk2, data.length() - 1); + if (p1 != -1) + p1 += 1; + if (p1 != -1 && p2 != -1) + _rawbuf = data.substring(p1, p2).c_str(); else - _rawbuf.clear(); - - return *this; + { + p1 = helper->strpos(data.c_str(), _brk3, 0); + p2 = helper->rstrpos(data.c_str(), _brk4, data.length() - 1); + if (p1 != -1) + p1 += 1; + if (p1 != -1 && p2 != -1) + { + char *_r = helper->strP(fb_json_str_21); + _rawbuf = _r; + _rawbuf += data.c_str(); + helper->delS(_r); + _topLevelTkType = JSMN_ARRAY; + } + else + { + _rawbuf = data.c_str(); + _topLevelTkType = JSMN_PRIMITIVE; + } + } + } + else + _rawbuf.clear(); + + return *this; } FirebaseJson &FirebaseJson::clear() { - std::string().swap(_rawbuf); - std::string().swap(_jsonData._dbuf); - std::string().swap(_tbuf); - clearPathTk(); - _tokens.reset(); - _tokens = nullptr; - _topLevelTkType = JSMN_OBJECT; - return *this; + std::string().swap(_rawbuf); + std::string().swap(_jsonData._dbuf); + std::string().swap(_tbuf); + clearPathTk(); + _tokens.reset(); + _tokens = nullptr; + _topLevelTkType = JSMN_OBJECT; + return *this; } FirebaseJson &FirebaseJson::add(const String &key) { - _addNull(key.c_str()); - return *this; + _addNull(key.c_str()); + return *this; } FirebaseJson &FirebaseJson::add(const String &key, const String &value) { - _addString(key.c_str(), value.c_str()); - return *this; + _addString(key.c_str(), value.c_str()); + return *this; } FirebaseJson &FirebaseJson::add(const String &key, const char *value) { - _addString(key.c_str(), value); - return *this; + _addString(key.c_str(), value); + return *this; } FirebaseJson &FirebaseJson::add(const String &key, int value) { - _addInt(key.c_str(), value); - return *this; + _addInt(key.c_str(), value); + return *this; } FirebaseJson &FirebaseJson::add(const String &key, unsigned short value) { - _addInt(key.c_str(), value); - return *this; + _addInt(key.c_str(), value); + return *this; } FirebaseJson &FirebaseJson::add(const String &key, float value) { - _addFloat(key.c_str(), value); - return *this; + _addFloat(key.c_str(), value); + return *this; } FirebaseJson &FirebaseJson::add(const String &key, double value) { - _addDouble(key.c_str(), value); - return *this; + _addDouble(key.c_str(), value); + return *this; } FirebaseJson &FirebaseJson::add(const String &key, bool value) { - _addBool(key.c_str(), value); - return *this; + _addBool(key.c_str(), value); + return *this; } FirebaseJson &FirebaseJson::add(const String &key, FirebaseJson &json) { - _addJson(key.c_str(), &json); - return *this; + _addJson(key.c_str(), &json); + return *this; } FirebaseJson &FirebaseJson::add(const String &key, FirebaseJsonArray &arr) { - arr._lastErr = &_lastErr; - _addArray(key.c_str(), &arr); - return *this; + arr._lastErr = &_lastErr; + _addArray(key.c_str(), &arr); + return *this; } template FirebaseJson &FirebaseJson::add(const String &key, T value) { - if (std::is_same::value) - _addInt(key, value); - else if (std::is_same::value) - _addFloat(key, value); - else if (std::is_same::value) - _addDouble(key, value); - else if (std::is_same::value) - _addBool(key, value); - else if (std::is_same::value) - _addString(key, value); - else if (std::is_same::value) - _addJson(key, &value); - else if (std::is_same::value) - _addArray(key, &value); - return *this; + if (std::is_same::value) + _addInt(key, value); + else if (std::is_same::value) + _addFloat(key, value); + else if (std::is_same::value) + _addDouble(key, value); + else if (std::is_same::value) + _addBool(key, value); + else if (std::is_same::value) + _addString(key, value); + else if (std::is_same::value) + _addJson(key, &value); + else if (std::is_same::value) + _addArray(key, &value); + return *this; } void FirebaseJson::_addString(const std::string &key, const std::string &value) { - helper->clearLastError(); - _add(key.c_str(), value.c_str(), key.length(), value.length(), true, true); + helper->clearLastError(); + _add(key.c_str(), value.c_str(), key.length(), value.length(), true, true); } void FirebaseJson::_addInt(const std::string &key, int value) { - helper->clearLastError(); - char *buf = helper->intStr(value); - _add(key.c_str(), buf, key.length(), 60, false, true); - helper->delS(buf); + helper->clearLastError(); + char *buf = helper->intStr(value); + _add(key.c_str(), buf, key.length(), 60, false, true); + helper->delS(buf); } void FirebaseJson::_addFloat(const std::string &key, float value) { - helper->clearLastError(); - char *buf = helper->floatStr(value); - helper->trimDouble(buf); - _add(key.c_str(), buf, key.length(), 60, false, true); - helper->delS(buf); + helper->clearLastError(); + char *buf = helper->floatStr(value); + helper->trimDouble(buf); + _add(key.c_str(), buf, key.length(), 60, false, true); + helper->delS(buf); } void FirebaseJson::_addDouble(const std::string &key, double value) { - helper->clearLastError(); - char *buf = helper->doubleStr(value); - helper->trimDouble(buf); - _add(key.c_str(), buf, key.length(), 60, false, true); - helper->delS(buf); + helper->clearLastError(); + char *buf = helper->doubleStr(value); + helper->trimDouble(buf); + _add(key.c_str(), buf, key.length(), 60, false, true); + helper->delS(buf); } void FirebaseJson::_addBool(const std::string &key, bool value) { - helper->clearLastError(); - if (value) - _add(key.c_str(), _tr, key.length(), 6, false, true); - else - _add(key.c_str(), _fls, key.length(), 7, false, true); + helper->clearLastError(); + if (value) + _add(key.c_str(), _tr, key.length(), 6, false, true); + else + _add(key.c_str(), _fls, key.length(), 7, false, true); } void FirebaseJson::_addNull(const std::string &key) { - helper->clearLastError(); - _add(key.c_str(), _nll, key.length(), 6, false, true); + helper->clearLastError(); + _add(key.c_str(), _nll, key.length(), 6, false, true); } void FirebaseJson::_addJson(const std::string &key, FirebaseJson *json) { - helper->clearLastError(); - std::string s; - json->_toStdString(s); - _add(key.c_str(), s.c_str(), key.length(), s.length(), false, true); - std::string().swap(s); + helper->clearLastError(); + std::string s; + json->_toStdString(s); + _add(key.c_str(), s.c_str(), key.length(), s.length(), false, true); + std::string().swap(s); } void FirebaseJson::_addArray(const std::string &key, FirebaseJsonArray *arr) { - helper->clearLastError(); - arr->_lastErr = &_lastErr; - String arrStr; - arr->toString(arrStr); - _add(key.c_str(), arrStr.c_str(), key.length(), arrStr.length(), false, true); + helper->clearLastError(); + arr->_lastErr = &_lastErr; + String arrStr; + arr->toString(arrStr); + _add(key.c_str(), arrStr.c_str(), key.length(), arrStr.length(), false, true); } void FirebaseJson::toString(String &buf, bool prettify) { - if (prettify) - _parse("", PRINT_MODE_PRETTY); - else - _parse("", PRINT_MODE_PLAIN); - buf = _jsonData._dbuf.c_str(); - std::string().swap(_jsonData._dbuf); + if (prettify) + _parse("", PRINT_MODE_PRETTY); + else + _parse("", PRINT_MODE_PLAIN); + buf = _jsonData._dbuf.c_str(); + std::string().swap(_jsonData._dbuf); } void FirebaseJson::int_tostr(std::string &s, bool prettify) { - _tostr(s, prettify); + _tostr(s, prettify); } void FirebaseJson::_tostr(std::string &s, bool prettify) { - if (prettify) - _parse("", PRINT_MODE_PRETTY); - else - _parse("", PRINT_MODE_PLAIN); - s = _jsonData._dbuf; - std::string().swap(_jsonData._dbuf); + if (prettify) + _parse("", PRINT_MODE_PRETTY); + else + _parse("", PRINT_MODE_PLAIN); + s = _jsonData._dbuf; + std::string().swap(_jsonData._dbuf); } void FirebaseJson::int_toStdString(std::string &s, bool isJson) { - _toStdString(s, isJson); + _toStdString(s, isJson); } void FirebaseJson::setBufferLimit(size_t limit) { - if (limit >= 32 || limit <= 8192) - _parser_buff_len = limit; + if (limit >= 32 || limit <= 8192) + _parser_buff_len = limit; } void FirebaseJson::_toStdString(std::string &s, bool isJson) { - s.clear(); - size_t bufSize = 20; - char *buf = helper->newS(bufSize); - if (_topLevelTkType != JSMN_PRIMITIVE) - { - if (isJson) - strcat(buf, _brk1); - else - strcat(buf, _brk3); - } - - s += buf; - s += _rawbuf; - memset(buf, 0, bufSize); - if (_topLevelTkType != JSMN_PRIMITIVE) - { - if (isJson) - strcat(buf, _brk2); - else - strcat(buf, _brk4); - } - s += buf; - helper->delS(buf); + s.clear(); + size_t bufSize = 20; + char *buf = helper->newS(bufSize); + if (_topLevelTkType != JSMN_PRIMITIVE) + { + if (isJson) + strcat(buf, _brk1); + else + strcat(buf, _brk3); + } + + s += buf; + s += _rawbuf; + memset(buf, 0, bufSize); + if (_topLevelTkType != JSMN_PRIMITIVE) + { + if (isJson) + strcat(buf, _brk2); + else + strcat(buf, _brk4); + } + s += buf; + helper->delS(buf); } FirebaseJson &FirebaseJson::_add(const char *key, const char *value, size_t klen, size_t vlen, bool isString, bool isJson) { - helper->clearLastError(); - size_t bufSize = klen + vlen + _parser_buff_len; - char *buf = helper->newS(bufSize); - if (!buf) - { - helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); - return *this; - } - - if (_rawbuf.length() > 0) - strcpy_P(buf, fb_json_str_1); - if (isJson) - { - strcat(buf, _qt); - strcat(buf, key); - strcat(buf, _qt); - strcat_P(buf, _pr2); - } - if (isString) - strcat(buf, _qt); - strcat(buf, value); - if (isString) - strcat(buf, _qt); - _rawbuf += buf; - helper->delS(buf); + helper->clearLastError(); + size_t bufSize = klen + vlen + _parser_buff_len; + char *buf = helper->newS(bufSize); + if (!buf) + { + helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); return *this; + } + + if (_rawbuf.length() > 0) + strcpy_P(buf, fb_json_str_1); + if (isJson) + { + strcat(buf, _qt); + strcat(buf, key); + strcat(buf, _qt); + strcat_P(buf, _pr2); + } + if (isString) + strcat(buf, _qt); + strcat(buf, value); + if (isString) + strcat(buf, _qt); + _rawbuf += buf; + helper->delS(buf); + return *this; } FirebaseJson &FirebaseJson::_addArrayStr(const char *value, size_t len, bool isString) { - helper->clearLastError(); - _add("", value, 0, len, isString, false); - return *this; + helper->clearLastError(); + _add("", value, 0, len, isString, false); + return *this; } bool FirebaseJson::get(FirebaseJsonData &jsonData, const String &path, bool prettify) { - helper->clearLastError(); - clearPathTk(); - _strToTk(path.c_str(), _pathTk, '/'); - std::string().swap(_jsonData._dbuf); - std::string().swap(_tbuf); - if (prettify) - _parse(path.c_str(), PRINT_MODE_PRETTY); + helper->clearLastError(); + clearPathTk(); + _strToTk(path.c_str(), _pathTk, '/'); + std::string().swap(_jsonData._dbuf); + std::string().swap(_tbuf); + if (prettify) + _parse(path.c_str(), PRINT_MODE_PRETTY); + else + _parse(path.c_str(), PRINT_MODE_PLAIN); + if (_jsonData.success) + { + if (_jsonData._type == JSMN_STRING && _jsonData._dbuf.c_str()[0] == '"' && _jsonData._dbuf.c_str()[_jsonData._dbuf.length() - 1] == '"') + _jsonData.stringValue = _jsonData._dbuf.substr(1, _jsonData._dbuf.length() - 2).c_str(); else - _parse(path.c_str(), PRINT_MODE_PLAIN); - if (_jsonData.success) - { - if (_jsonData._type == JSMN_STRING && _jsonData._dbuf.c_str()[0] == '"' && _jsonData._dbuf.c_str()[_jsonData._dbuf.length() - 1] == '"') - _jsonData.stringValue = _jsonData._dbuf.substr(1, _jsonData._dbuf.length() - 2).c_str(); - else - _jsonData.stringValue = _jsonData._dbuf.c_str(); - } - jsonData = _jsonData; - std::string().swap(_jsonData._dbuf); - std::string().swap(_tbuf); - clearPathTk(); - _tokens.reset(); - _tokens = nullptr; - return _jsonData.success; + _jsonData.stringValue = _jsonData._dbuf.c_str(); + } + jsonData = _jsonData; + std::string().swap(_jsonData._dbuf); + std::string().swap(_tbuf); + clearPathTk(); + _tokens.reset(); + _tokens = nullptr; + return _jsonData.success; } size_t FirebaseJson::iteratorBegin(const char *data) { - helper->clearLastError(); - if (data) - setJsonData(data); - _fbjs_parse(true); - std::string s; - _toStdString(s); - int bufLen = s.length() + _parser_buff_len; - char *buf = helper->newS(bufLen); - if (!buf) - { - helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); - return 0; - } - strcpy(buf, s.c_str()); - std::string().swap(s); - int depth = -1; - _parser_info.collectTk = true; - _eltk.clear(); - for (uint16_t i = 0; i < _parser_info.tokenCount; i++) - _parseToken(i, buf, depth, "", -2, PRINT_MODE_NONE); - _el.clear(); - helper->delS(buf); - return _eltk.size(); + helper->clearLastError(); + if (data) + setJsonData(data); + _fbjs_parse(true); + std::string s; + _toStdString(s); + int bufLen = s.length() + _parser_buff_len; + char *buf = helper->newS(bufLen); + if (!buf) + { + helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); + return 0; + } + strcpy(buf, s.c_str()); + std::string().swap(s); + int depth = -1; + _parser_info.collectTk = true; + _eltk.clear(); + for (uint16_t i = 0; i < _parser_info.tokenCount; i++) + _parseToken(i, buf, depth, "", -2, PRINT_MODE_NONE); + _el.clear(); + helper->delS(buf); + return _eltk.size(); } void FirebaseJson::iteratorEnd() { - helper->clearLastError(); - _eltk.clear(); - clearPathTk(); - _jsonData.stringValue = ""; - std::string().swap(_jsonData._dbuf); - std::string().swap(_tbuf); - clearPathTk(); - _tokens.reset(); - _tokens = nullptr; + helper->clearLastError(); + _eltk.clear(); + clearPathTk(); + _jsonData.stringValue = ""; + std::string().swap(_jsonData._dbuf); + std::string().swap(_tbuf); + clearPathTk(); + _tokens.reset(); + _tokens = nullptr; } void FirebaseJson::iteratorGet(size_t index, int &type, String &key, String &value) { - helper->clearLastError(); - if (_eltk.size() < index + 1) - return; - std::string s; - _toStdString(s); - int bufLen = s.length() + _parser_buff_len; - char *buf = helper->newS(bufLen); - if (!buf) - { - helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); - return; - } - strcpy(buf, s.c_str()); - std::string().swap(s); - if (_eltk[index].type == 0) - { - FirebaseJson::fbjs_tok_t *h = &_tokens.get()[_eltk[index].index]; - size_t len = h->end - h->start + 3; - char *k = helper->newS(len); - if (!k) - { - helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); - return; - } - strncpy(k, buf + h->start, h->end - h->start); - FirebaseJson::fbjs_tok_t *g = &_tokens.get()[_eltk[index].index + 1]; - size_t len2 = g->end - g->start + 3; - char *v = helper->newS(len2); - if (!v) - { - helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); - return; - } - strncpy(v, buf + g->start, g->end - g->start); - key = k; - value = v; - type = JSON_OBJECT; - helper->delS(k); - helper->delS(v); - } - else if (_eltk[index].type == 1) - { - FirebaseJson::fbjs_tok_t *g = &_tokens.get()[_eltk[index].index]; - size_t len2 = g->end - g->start + 3; - char *v = helper->newS(len2); - if (!v) - { - helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); - return; - } - strncpy(v, buf + g->start, g->end - g->start); - value = v; - key = ""; - type = JSON_ARRAY; - helper->delS(v); - } - helper->delS(buf); + helper->clearLastError(); + if (_eltk.size() < index + 1) + return; + std::string s; + _toStdString(s); + int bufLen = s.length() + _parser_buff_len; + char *buf = helper->newS(bufLen); + if (!buf) + { + helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); + return; + } + strcpy(buf, s.c_str()); + std::string().swap(s); + if (_eltk[index].type == 0) + { + FirebaseJson::fbjs_tok_t *h = &_tokens.get()[_eltk[index].index]; + size_t len = h->end - h->start + 3; + char *k = helper->newS(len); + if (!k) + { + helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); + return; + } + strncpy(k, buf + h->start, h->end - h->start); + FirebaseJson::fbjs_tok_t *g = &_tokens.get()[_eltk[index].index + 1]; + size_t len2 = g->end - g->start + 3; + char *v = helper->newS(len2); + if (!v) + { + helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); + return; + } + strncpy(v, buf + g->start, g->end - g->start); + key = k; + value = v; + type = JSON_OBJECT; + helper->delS(k); + helper->delS(v); + } + else if (_eltk[index].type == 1) + { + FirebaseJson::fbjs_tok_t *g = &_tokens.get()[_eltk[index].index]; + size_t len2 = g->end - g->start + 3; + char *v = helper->newS(len2); + if (!v) + { + helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); + return; + } + strncpy(v, buf + g->start, g->end - g->start); + value = v; + key = ""; + type = JSON_ARRAY; + helper->delS(v); + } + helper->delS(buf); } void FirebaseJson::_fbjs_parse(bool collectTk) { - helper->clearLastError(); - std::string s; - _toStdString(s); - int bufLen = s.length() + _parser_buff_len; - char *buf = helper->newS(bufLen); - if (!buf) - { - helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); - return; - } - strcpy(buf, s.c_str()); - std::string().swap(s); - _tokens.reset(); - _parser_info.collectTk = collectTk; - _eltk.clear(); - int cnt = fbjs_parse(_parser.get(), buf, bufLen, (FirebaseJson::fbjs_tok_t *)NULL, 0); - if (cnt < 0) - { - /** Invalid character inside JSON string */ - if (cnt == JSMN_ERROR_INVAL) - helper->setLastError(-3, __FILE__, __LINE__, fb_json_str_29); - - /** The string is not a full JSON packet, more bytes expected */ - else if (cnt == JSMN_ERROR_PART) - helper->setLastError(-4, __FILE__, __LINE__, fb_json_str_30); - } - - int cnt2 = 0; - int a = 0; - int b = 0; - for (int i = 0; i < bufLen; i++) - { - if (buf[i] == ',') - a++; - else if (buf[i] == '[' || buf[i] == '{') - b++; - } - - cnt2 = 10 + (2 * (a + 1)) + b; - - if (cnt < cnt2) - cnt = cnt2; - - _tokens = std::shared_ptr(new FirebaseJson::fbjs_tok_t[cnt + 10]); - fbjs_init(_parser.get()); - _parser_info.tokenCount = fbjs_parse(_parser.get(), buf, bufLen, _tokens.get(), cnt + 10); - if (_parser_info.tokenCount < 0) - { - /** Not enough tokens were provided */ - if (cnt == JSMN_ERROR_NOMEM) - helper->setLastError(-2, __FILE__, __LINE__, fb_json_str_31); - } - - _parser_info.paresRes = true; - if (_parser_info.tokenCount < 0) - _parser_info.paresRes = false; - if (_parser_info.tokenCount < 1 || _tokens.get()[0].type != JSMN_OBJECT) - _parser_info.paresRes = false; - _jsonData.success = _parser_info.paresRes; - _parser_info.nextToken = 0; - _parser_info.nextDepth = 0; - _parser_info.tokenMatch = false; - _parser_info.refToken = -1; - _resetParseResult(); - _setElementType(); - helper->delS(buf); + helper->clearLastError(); + std::string s; + _toStdString(s); + int bufLen = s.length() + _parser_buff_len; + char *buf = helper->newS(bufLen); + if (!buf) + { + helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); + return; + } + strcpy(buf, s.c_str()); + std::string().swap(s); + _tokens.reset(); + _parser_info.collectTk = collectTk; + _eltk.clear(); + int cnt = fbjs_parse(_parser.get(), buf, bufLen, (FirebaseJson::fbjs_tok_t *)NULL, 0); + if (cnt < 0) + { + /** Invalid character inside JSON string */ + if (cnt == JSMN_ERROR_INVAL) + helper->setLastError(-3, __FILE__, __LINE__, fb_json_str_29); + + /** The string is not a full JSON packet, more bytes expected */ + else if (cnt == JSMN_ERROR_PART) + helper->setLastError(-4, __FILE__, __LINE__, fb_json_str_30); + } + + int cnt2 = 0; + int a = 0; + int b = 0; + for (int i = 0; i < bufLen; i++) + { + if (buf[i] == ',') + a++; + else if (buf[i] == '[' || buf[i] == '{') + b++; + } + + cnt2 = 10 + (2 * (a + 1)) + b; + + if (cnt < cnt2) + cnt = cnt2; + + _tokens = std::shared_ptr(new FirebaseJson::fbjs_tok_t[cnt + 10]); + fbjs_init(_parser.get()); + _parser_info.tokenCount = fbjs_parse(_parser.get(), buf, bufLen, _tokens.get(), cnt + 10); + if (_parser_info.tokenCount < 0) + { + /** Not enough tokens were provided */ + if (cnt == JSMN_ERROR_NOMEM) + helper->setLastError(-2, __FILE__, __LINE__, fb_json_str_31); + } + + _parser_info.paresRes = true; + if (_parser_info.tokenCount < 0) + _parser_info.paresRes = false; + if (_parser_info.tokenCount < 1 || _tokens.get()[0].type != JSMN_OBJECT) + _parser_info.paresRes = false; + _jsonData.success = _parser_info.paresRes; + _parser_info.nextToken = 0; + _parser_info.nextDepth = 0; + _parser_info.tokenMatch = false; + _parser_info.refToken = -1; + _resetParseResult(); + _setElementType(); + helper->delS(buf); } void FirebaseJson::_setMark(int depth, bool mark) { - for (size_t i = 0; i < _el.size(); i++) + for (size_t i = 0; i < _el.size(); i++) + { + if (_el[i].depth == depth - 1) { - if (_el[i].depth == depth - 1) - { - _el[i].omark = mark; - break; - } + _el[i].omark = mark; + break; } + } } void FirebaseJson::_setSkip(int depth, bool skip) { - for (size_t i = 0; i < _el.size(); i++) + for (size_t i = 0; i < _el.size(); i++) + { + if (_el[i].depth == depth - 1) { - if (_el[i].depth == depth - 1) - { - _el[i].skip = skip; - break; - } + _el[i].skip = skip; + break; } + } } void FirebaseJson::_setRef(int depth, bool ref) { - for (size_t i = 0; i < _el.size(); i++) + for (size_t i = 0; i < _el.size(); i++) + { + if (ref) { - if (ref) - { - if (_el[i].depth == depth - 1) - { - _el[i].ref = ref; - break; - } - } - else - _el[i].ref = false; + if (_el[i].depth == depth - 1) + { + _el[i].ref = ref; + break; + } } + else + _el[i].ref = false; + } } void FirebaseJson::_getTkIndex(int depth, tk_index_t &tk) { - tk.oindex = 0; - tk.olen = 0; - tk.omark = false; - tk.type = JSMN_UNDEFINED; - tk.depth = -1; - tk.skip = false; - tk.ref = false; - tk.index = -1; - for (size_t i = 0; i < _el.size(); i++) - { - if (_el[i].depth == depth - 1) - { - tk.index = _el[i].index; - tk.omark = _el[i].omark; - tk.ref = _el[i].ref; - tk.type = _el[i].type; - tk.depth = _el[i].depth; - tk.oindex = _el[i].oindex; - tk.olen = _el[i].olen; - tk.skip = _el[i].skip; - break; - } - } + tk.oindex = 0; + tk.olen = 0; + tk.omark = false; + tk.type = JSMN_UNDEFINED; + tk.depth = -1; + tk.skip = false; + tk.ref = false; + tk.index = -1; + for (size_t i = 0; i < _el.size(); i++) + { + if (_el[i].depth == depth - 1) + { + tk.index = _el[i].index; + tk.omark = _el[i].omark; + tk.ref = _el[i].ref; + tk.type = _el[i].type; + tk.depth = _el[i].depth; + tk.oindex = _el[i].oindex; + tk.olen = _el[i].olen; + tk.skip = _el[i].skip; + break; + } + } } bool FirebaseJson::_updateTkIndex(uint16_t index, int &depth, const char *searchKey, int searchIndex, const char *replace, PRINT_MODE printMode, bool advanceCount) { - int len = -1; - bool skip = false; - bool ref = false; - for (size_t i = 0; i < _el.size(); i++) + int len = -1; + bool skip = false; + bool ref = false; + for (size_t i = 0; i < _el.size(); i++) + { + if (_el[i].depth == depth - 1) { - if (_el[i].depth == depth - 1) + if (_el[i].type == JSMN_OBJECT || _el[i].type == JSMN_ARRAY) + { + _el[i].oindex++; + if (_el[i].oindex >= _el[i].olen) { - if (_el[i].type == JSMN_OBJECT || _el[i].type == JSMN_ARRAY) + depth = _el[i].depth; + len = _el[i].olen; + skip = _el[i].skip; + + if (!_parser_info.TkRefOk && _el[i].type == JSMN_OBJECT) + ref = _el[i].ref; + else if (!_parser_info.TkRefOk && _el[i].type == JSMN_ARRAY && searchIndex > -1) + ref = _el[i].ref; + + _el.erase(_el.begin() + i); + + if (printMode != PRINT_MODE_NONE && !skip) + { + if (len > 0 && !_parser_info.arrReplaced) { - _el[i].oindex++; - if (_el[i].oindex >= _el[i].olen) + if (ref) + _jsonData._dbuf += _cm; + if (_el[i].type == JSMN_OBJECT) + { + if (printMode == PRINT_MODE_PRETTY) + _jsonData._dbuf += _nl; + if (printMode == PRINT_MODE_PRETTY && !ref) + { + for (int j = 0; j < depth + 1; j++) + _jsonData._dbuf += _tab; + } + } + } + if (ref) + { + if (!advanceCount) + _parser_info.parseCompleted++; + + if (!_parser_info.arrReplaced) + { + if (_el[i].type == JSMN_OBJECT) + { + if (printMode == PRINT_MODE_PRETTY) + { + for (int j = 0; j < depth + 2; j++) + _jsonData._dbuf += _tab; + } + _jsonData._dbuf += _qt; + _jsonData._dbuf += searchKey; + _jsonData._dbuf += _qt; + if (printMode == PRINT_MODE_PRETTY) + _jsonData._dbuf += _pr; + else + _jsonData._dbuf += _pr2; + if (_parser_info.parseCompleted == (int)_pathTk.size()) + _jsonData._dbuf += replace; + else + _insertChilds(replace, printMode); + _parser_info.arrReplaced = true; + if (printMode == PRINT_MODE_PRETTY) + { + _jsonData._dbuf += _nl; + for (int j = 0; j < depth + 1; j++) + _jsonData._dbuf += _tab; + } + } + else { - depth = _el[i].depth; - len = _el[i].olen; - skip = _el[i].skip; - if (!_parser_info.TkRefOk && _el[i].type == JSMN_OBJECT) - ref = _el[i].ref; - else if (!_parser_info.TkRefOk && _el[i].type == JSMN_ARRAY && searchIndex > -1) - ref = _el[i].ref; - if (i > 0) - _el.erase(_el.begin() + i); + for (int k = _el[i].oindex - 1; k < searchIndex; k++) + { + if (printMode == PRINT_MODE_PRETTY) + { + _jsonData._dbuf += _nl; + for (int j = 0; j < depth + 2; j++) + _jsonData._dbuf += _tab; + } + if (k == searchIndex - 1) + { + if (_parser_info.parseCompleted == (int)_pathTk.size()) + _jsonData._dbuf += replace; + else + _insertChilds(replace, printMode); + _parser_info.arrReplaced = true; + } else - _el.erase(_el.begin()); - if (printMode != PRINT_MODE_NONE && !skip) { - if (len > 0 && !_parser_info.arrReplaced) - { - if (ref) - _jsonData._dbuf += _cm; - if (_el[i].type == JSMN_OBJECT) - { - if (printMode == PRINT_MODE_PRETTY) - _jsonData._dbuf += _nl; - if (printMode == PRINT_MODE_PRETTY && !ref) - { - for (int j = 0; j < depth + 1; j++) - _jsonData._dbuf += _tab; - } - } - } - if (ref) - { - if (!advanceCount) - _parser_info.parseCompleted++; - - if (!_parser_info.arrReplaced) - { - if (_el[i].type == JSMN_OBJECT) - { - if (printMode == PRINT_MODE_PRETTY) - { - for (int j = 0; j < depth + 2; j++) - _jsonData._dbuf += _tab; - } - _jsonData._dbuf += _qt; - _jsonData._dbuf += searchKey; - _jsonData._dbuf += _qt; - if (printMode == PRINT_MODE_PRETTY) - _jsonData._dbuf += _pr; - else - _jsonData._dbuf += _pr2; - if (_parser_info.parseCompleted == (int)_pathTk.size()) - _jsonData._dbuf += replace; - else - _insertChilds(replace, printMode); - _parser_info.arrReplaced = true; - if (printMode == PRINT_MODE_PRETTY) - { - _jsonData._dbuf += _nl; - for (int j = 0; j < depth + 1; j++) - _jsonData._dbuf += _tab; - } - } - else - { - for (int k = _el[i].oindex - 1; k < searchIndex; k++) - { - if (printMode == PRINT_MODE_PRETTY) - { - _jsonData._dbuf += _nl; - for (int j = 0; j < depth + 2; j++) - _jsonData._dbuf += _tab; - } - if (k == searchIndex - 1) - { - if (_parser_info.parseCompleted == (int)_pathTk.size()) - _jsonData._dbuf += replace; - else - _insertChilds(replace, printMode); - _parser_info.arrReplaced = true; - } - else - { - _jsonData._dbuf += _nll; - _jsonData._dbuf += _cm; - } - } - } - } - _setRef(depth, false); - if (!advanceCount) - _parser_info.parseCompleted = _pathTk.size(); - } - - if (_el[i].type == JSMN_OBJECT) - _jsonData._dbuf += _brk2; - else - { - if (len > 0) - { - if (printMode == PRINT_MODE_PRETTY) - { - _jsonData._dbuf += _nl; - for (int j = 0; j < depth + 1; j++) - _jsonData._dbuf += _tab; - } - } - _jsonData._dbuf += _brk4; - } + _jsonData._dbuf += _nll; + _jsonData._dbuf += _cm; } - return true; + } } + } + _setRef(depth, false); + if (!advanceCount) + _parser_info.parseCompleted = _pathTk.size(); } - break; + + if (_el[i].type == JSMN_OBJECT) + _jsonData._dbuf += _brk2; + else + { + if (len > 0) + { + if (printMode == PRINT_MODE_PRETTY) + { + _jsonData._dbuf += _nl; + for (int j = 0; j < depth + 1; j++) + _jsonData._dbuf += _tab; + } + } + _jsonData._dbuf += _brk4; + } + } + return true; } + } + break; } - return false; + } + return false; } bool FirebaseJson::_updateTkIndex2(std::string &str, uint16_t index, int &depth, const char *searchKey, int searchIndex, const char *replace, PRINT_MODE printMode) { - int len = -1; - bool skip = false; - bool ref = false; - for (size_t i = 0; i < _el.size(); i++) - { - if (_el[i].depth == depth - 1) - { - if (_el[i].type == JSMN_OBJECT || _el[i].type == JSMN_ARRAY) + int len = -1; + bool skip = false; + bool ref = false; + for (size_t i = 0; i < _el.size(); i++) + { + if (_el[i].depth == depth - 1) + { + if (_el[i].type == JSMN_OBJECT || _el[i].type == JSMN_ARRAY) + { + _el[i].oindex++; + if (_el[i].oindex >= _el[i].olen) + { + depth = _el[i].depth; + len = _el[i].olen; + skip = _el[i].skip; + if (!_parser_info.TkRefOk && _el[i].type == JSMN_OBJECT) + ref = _el[i].ref; + else if (!_parser_info.TkRefOk && _el[i].type == JSMN_ARRAY && searchIndex > -1) + ref = _el[i].ref; + + _el.erase(_el.begin() + i); + + if (printMode != PRINT_MODE_NONE && !skip) + { + if (len > 0) { - _el[i].oindex++; - if (_el[i].oindex >= _el[i].olen) + if (printMode == PRINT_MODE_PRETTY) + str += _nl; + if (_el[i].type == JSMN_OBJECT) + { + if (printMode == PRINT_MODE_PRETTY && !ref) { - depth = _el[i].depth; - len = _el[i].olen; - skip = _el[i].skip; - if (!_parser_info.TkRefOk && _el[i].type == JSMN_OBJECT) - ref = _el[i].ref; - else if (!_parser_info.TkRefOk && _el[i].type == JSMN_ARRAY && searchIndex > -1) - ref = _el[i].ref; - if (i > 0) - _el.erase(_el.begin() + i); - else - _el.erase(_el.begin()); - if (printMode != PRINT_MODE_NONE && !skip) - { - if (len > 0) - { - if (printMode == PRINT_MODE_PRETTY) - str += _nl; - if (_el[i].type == JSMN_OBJECT) - { - if (printMode == PRINT_MODE_PRETTY && !ref) - { - for (int j = 0; j < depth + 1; j++) - str += _tab; - } - } - else - { - if (printMode == PRINT_MODE_PRETTY) - { - for (int j = 0; j < depth + 1; j++) - str += _tab; - } - } - } - if (ref) - _setRef(depth, false); - if (_el[i].type == JSMN_OBJECT) - str += _brk2; - else - str += _brk4; - } - return true; + for (int j = 0; j < depth + 1; j++) + str += _tab; } + } + else + { + if (printMode == PRINT_MODE_PRETTY) + { + for (int j = 0; j < depth + 1; j++) + str += _tab; + } + } } - break; + if (ref) + _setRef(depth, false); + if (_el[i].type == JSMN_OBJECT) + str += _brk2; + else + str += _brk4; + } + return true; } + } + break; } - return false; + } + return false; } bool FirebaseJson::_updateTkIndex3(uint16_t index, int &depth, const char *searchKey, int searchIndex, PRINT_MODE printMode) { - int len = -1; - bool skip = false; - bool ref = false; - for (size_t i = 0; i < _el.size(); i++) - { - if (_el[i].depth == depth - 1) - { - if (_el[i].type == JSMN_OBJECT || _el[i].type == JSMN_ARRAY) + int len = -1; + bool skip = false; + bool ref = false; + for (size_t i = 0; i < _el.size(); i++) + { + if (_el[i].depth == depth - 1) + { + if (_el[i].type == JSMN_OBJECT || _el[i].type == JSMN_ARRAY) + { + _el[i].oindex++; + if (_el[i].oindex >= _el[i].olen) + { + depth = _el[i].depth; + len = _el[i].olen; + skip = _el[i].skip; + if (!_parser_info.TkRefOk && _el[i].type == JSMN_OBJECT) + ref = _el[i].ref; + else if (!_parser_info.TkRefOk && _el[i].type == JSMN_ARRAY && searchIndex > -1) + ref = _el[i].ref; + + _el.erase(_el.begin() + i); + + if (depth < _parser_info.skipDepth) + return false; + if (printMode != PRINT_MODE_NONE && skip) + { + if (len > 0) { - _el[i].oindex++; - if (_el[i].oindex >= _el[i].olen) + if (printMode == PRINT_MODE_PRETTY) + _jsonData._dbuf += _nl; + if (_el[i].type == JSMN_OBJECT) + { + if (printMode == PRINT_MODE_PRETTY && !ref) { - depth = _el[i].depth; - len = _el[i].olen; - skip = _el[i].skip; - if (!_parser_info.TkRefOk && _el[i].type == JSMN_OBJECT) - ref = _el[i].ref; - else if (!_parser_info.TkRefOk && _el[i].type == JSMN_ARRAY && searchIndex > -1) - ref = _el[i].ref; - if (i > 0) - _el.erase(_el.begin() + i); - else - _el.erase(_el.begin()); - if (depth < _parser_info.skipDepth) - return false; - if (printMode != PRINT_MODE_NONE && skip) - { - if (len > 0) - { - if (printMode == PRINT_MODE_PRETTY) - _jsonData._dbuf += _nl; - if (_el[i].type == JSMN_OBJECT) - { - if (printMode == PRINT_MODE_PRETTY && !ref) - { - for (int j = 0; j < depth + 1 - (_parser_info.skipDepth + 1); j++) - _jsonData._dbuf += _tab; - } - } - else - { - if (printMode == PRINT_MODE_PRETTY) - { - for (int j = 0; j < depth + 1 - (_parser_info.skipDepth + 1); j++) - _jsonData._dbuf += _tab; - } - } - } - if (ref) - _setRef(depth, false); - - if (_el[i].type == JSMN_OBJECT) - _jsonData._dbuf += _brk2; - else - _jsonData._dbuf += _brk4; - } - return true; + for (int j = 0; j < depth + 1 - (_parser_info.skipDepth + 1); j++) + _jsonData._dbuf += _tab; } + } + else + { + if (printMode == PRINT_MODE_PRETTY) + { + for (int j = 0; j < depth + 1 - (_parser_info.skipDepth + 1); j++) + _jsonData._dbuf += _tab; + } + } } - break; + if (ref) + _setRef(depth, false); + + if (_el[i].type == JSMN_OBJECT) + _jsonData._dbuf += _brk2; + else + _jsonData._dbuf += _brk4; + } + return true; } + } + break; } - return false; + } + return false; } void FirebaseJson::_insertChilds(const char *data, PRINT_MODE printMode) { - std::string str = ""; - for (int i = _pathTk.size() - 1; i > _parser_info.parseCompleted - 1; i--) + std::string str = ""; + for (int i = _pathTk.size() - 1; i > _parser_info.parseCompleted - 1; i--) + { + if (_isArrTk(i)) { - if (_isArrTk(i)) - { - std::string _str; - _addArrNodes(_str, str, i, data, printMode); - str = _str; - std::string().swap(_str); - } - else - { - std::string _str; - _addObjNodes(_str, str, i, data, printMode); - str = _str; - std::string().swap(_str); - } + std::string _str; + _addArrNodes(_str, str, i, data, printMode); + str = _str; + std::string().swap(_str); + } + else + { + std::string _str; + _addObjNodes(_str, str, i, data, printMode); + str = _str; + std::string().swap(_str); } - if ((int)_pathTk.size() == _parser_info.parseCompleted) - str = data; - _jsonData._dbuf += str; - std::string().swap(str); + } + if ((int)_pathTk.size() == _parser_info.parseCompleted) + str = data; + _jsonData._dbuf += str; + std::string().swap(str); } void FirebaseJson::_addArrNodes(std::string &str, std::string &str2, int index, const char *data, PRINT_MODE printMode) { - int i = _getArrIndex(index); - str += _brk3; + int i = _getArrIndex(index); + str += _brk3; + if (printMode == PRINT_MODE_PRETTY) + str += _nl; + for (int k = 0; k <= i; k++) + { if (printMode == PRINT_MODE_PRETTY) - str += _nl; - for (int k = 0; k <= i; k++) { - if (printMode == PRINT_MODE_PRETTY) - { - for (int j = 0; j < index + 1; j++) - str += _tab; - } - if (k == i) - { - if (index == (int)_pathTk.size() - 1) - str += data; - else - str += str2; - } - else - { - str += _nll; - str += _cm; - } - - if (printMode == PRINT_MODE_PRETTY) - str += _nl; + for (int j = 0; j < index + 1; j++) + str += _tab; } - - if (printMode == PRINT_MODE_PRETTY) + if (k == i) + { + if (index == (int)_pathTk.size() - 1) + str += data; + else + str += str2; + } + else { - for (int j = 0; j < index; j++) - str += _tab; + str += _nll; + str += _cm; } - str += _brk4; + + if (printMode == PRINT_MODE_PRETTY) + str += _nl; + } + + if (printMode == PRINT_MODE_PRETTY) + { + for (int j = 0; j < index; j++) + str += _tab; + } + str += _brk4; } void FirebaseJson::_addObjNodes(std::string &str, std::string &str2, int index, const char *data, PRINT_MODE printMode) { - str += _brk1; - if (printMode == PRINT_MODE_PRETTY) - { - str += _nl; - for (int j = 0; j < index + 1; j++) - str += _tab; - } - str += _qt; - str += _pathTk[index].tk.c_str(); - str += _qt; - if (printMode == PRINT_MODE_PRETTY) - str += _pr; - else - str += _pr2; - if (index == (int)_pathTk.size() - 1) - str += data; - else - str += str2; - if (printMode == PRINT_MODE_PRETTY) - { - str += _nl; - for (int j = 0; j < index; j++) - str += _tab; - } - str += _brk2; + str += _brk1; + if (printMode == PRINT_MODE_PRETTY) + { + str += _nl; + for (int j = 0; j < index + 1; j++) + str += _tab; + } + str += _qt; + str += _pathTk[index].tk.c_str(); + str += _qt; + if (printMode == PRINT_MODE_PRETTY) + str += _pr; + else + str += _pr2; + if (index == (int)_pathTk.size() - 1) + str += data; + else + str += str2; + if (printMode == PRINT_MODE_PRETTY) + { + str += _nl; + for (int j = 0; j < index; j++) + str += _tab; + } + str += _brk2; } void FirebaseJson::_parseToken(uint16_t &i, char *buf, int &depth, const char *searchKey, int searchIndex, PRINT_MODE printMode) { - helper->clearLastError(); - tk_index_t tk; - _getTkIndex(depth, tk); - FirebaseJson::fbjs_tok_t *h = &_tokens.get()[i]; - bool oskip = false; - bool ex = false; - size_t resLen = _jsonData._dbuf.length(); - if (searchIndex == -2) - tk.skip = true; - delay(0); - if (searchIndex > -1) - { - tk_index_t tk2; - int depth2 = depth - 1; - _getTkIndex(depth2, tk2); - if (tk.type == JSMN_ARRAY && _parser_info.parseDepth == depth && tk2.oindex == _parser_info.parentIndex) + helper->clearLastError(); + tk_index_t tk; + _getTkIndex(depth, tk); + FirebaseJson::fbjs_tok_t *h = &_tokens.get()[i]; + bool oskip = false; + bool ex = false; + size_t resLen = _jsonData._dbuf.length(); + if (searchIndex == -2) + tk.skip = true; + delay(0); + if (searchIndex > -1) + { + tk_index_t tk2; + int depth2 = depth - 1; + _getTkIndex(depth2, tk2); + if (tk.type == JSMN_ARRAY && _parser_info.parseDepth == depth && tk2.oindex == _parser_info.parentIndex) + { + if (tk.oindex == searchIndex) + { + _parser_info.nextToken = i; + _parser_info.nextDepth = depth; + _parser_info.parentIndex = tk.oindex; + + if ((int)_pathTk.size() != _parser_info.parseDepth + 1) + { + _parser_info.tokenMatch = true; + _parser_info.parseCompleted++; + } + else { - if (tk.oindex == searchIndex) + if (!_parser_info.TkRefOk) + { + _parser_info.parseCompleted++; + _parser_info.refTkIndex = i + 1; + _parser_info.refToken = i + 1; + _parser_info.TkRefOk = true; + char *dat1 = helper->newS(h->end - h->start + 10); + if (!dat1) { - _parser_info.nextToken = i; - _parser_info.nextDepth = depth; - _parser_info.parentIndex = tk.oindex; - - if ((int)_pathTk.size() != _parser_info.parseDepth + 1) - { - _parser_info.tokenMatch = true; - _parser_info.parseCompleted++; - } - else - { - if (!_parser_info.TkRefOk) - { - _parser_info.parseCompleted++; - _parser_info.refTkIndex = i + 1; - _parser_info.refToken = i + 1; - _parser_info.TkRefOk = true; - char *dat1 = helper->newS(h->end - h->start + 10); - if (!dat1) - { - helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); - return; - } - strncpy(dat1, buf + h->start, h->end - h->start); - _jsonData.stringValue = dat1; - helper->delS(dat1); - _jsonData._type = h->type; - _jsonData._k_start = h->start; - _jsonData._start = h->start; - _jsonData._end = h->end; - _jsonData._tokenIndex = i; - _jsonData._depth = depth; - _jsonData._len = h->size; - _jsonData.success = true; - _setElementType(); - if (printMode != PRINT_MODE_NONE) - _jsonData.stringValue = ""; - else - { - std::string().swap(_jsonData._dbuf); - std::string().swap(_tbuf); - _parser_info.tokenMatch = true; - ex = true; - } - } - } + helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); + return; } + strncpy(dat1, buf + h->start, h->end - h->start); + _jsonData.stringValue = dat1; + helper->delS(dat1); + _jsonData._type = h->type; + _jsonData._k_start = h->start; + _jsonData._start = h->start; + _jsonData._end = h->end; + _jsonData._tokenIndex = i; + _jsonData._depth = depth; + _jsonData._len = h->size; + _jsonData.success = true; + _setElementType(); + if (printMode != PRINT_MODE_NONE) + _jsonData.stringValue = ""; else { - if (tk.oindex + 1 == tk.olen) - { - _setRef(depth - 1, false); - _setRef(depth, true); - } + std::string().swap(_jsonData._dbuf); + std::string().swap(_tbuf); + _parser_info.tokenMatch = true; + ex = true; } + } } + } + else + { + if (tk.oindex + 1 == tk.olen) + { + _setRef(depth - 1, false); + _setRef(depth, true); + } + } } - else + } + else + { + char *key = helper->newS(h->end - h->start + 10); + if (!key) + { + helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); + return; + } + strncpy(key, buf + h->start, h->end - h->start); + if (tk.type != JSMN_UNDEFINED && _parser_info.parseDepth == depth) { - char *key = helper->newS(h->end - h->start + 10); - if (!key) + if (strcmp(searchKey, key) == 0) + { + _parser_info.nextToken = i + 1; + _parser_info.nextDepth = depth; + _parser_info.parentIndex = tk.oindex; + if ((int)_pathTk.size() != _parser_info.parseDepth + 1) { - helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); - return; + _parser_info.tokenMatch = true; + _parser_info.parseCompleted++; } - strncpy(key, buf + h->start, h->end - h->start); - if (tk.type != JSMN_UNDEFINED && _parser_info.parseDepth == depth) + else { - if (strcmp(searchKey, key) == 0) + if (!_parser_info.TkRefOk) + { + _parser_info.parseCompleted++; + _parser_info.refTkIndex = i + 1; + _parser_info.refToken = i + 1; + _parser_info.TkRefOk = true; + h = &_tokens.get()[i + 1]; + char *dat2 = helper->newS(h->end - h->start + 10); + if (!dat2) { - _parser_info.nextToken = i + 1; - _parser_info.nextDepth = depth; - _parser_info.parentIndex = tk.oindex; - if ((int)_pathTk.size() != _parser_info.parseDepth + 1) - { - _parser_info.tokenMatch = true; - _parser_info.parseCompleted++; - } - else - { - if (!_parser_info.TkRefOk) - { - _parser_info.parseCompleted++; - _parser_info.refTkIndex = i + 1; - _parser_info.refToken = i + 1; - _parser_info.TkRefOk = true; - h = &_tokens.get()[i + 1]; - char *dat2 = helper->newS(h->end - h->start + 10); - if (!dat2) - { - helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); - return; - } - strncpy(dat2, buf + h->start, h->end - h->start); - _jsonData.stringValue = dat2; - helper->delS(dat2); - _jsonData._type = h->type; - _jsonData._k_start = h->start; - _jsonData._start = h->start; - _jsonData._end = h->end; - _jsonData._tokenIndex = i; - _jsonData._depth = depth; - _jsonData._len = h->size; - _jsonData.success = true; - _setElementType(); - if (printMode != PRINT_MODE_NONE) - _jsonData.stringValue = ""; - else - { - std::string().swap(_jsonData._dbuf); - std::string().swap(_tbuf); - _parser_info.tokenMatch = true; - ex = true; - } - } - } + helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); + return; } + strncpy(dat2, buf + h->start, h->end - h->start); + _jsonData.stringValue = dat2; + helper->delS(dat2); + _jsonData._type = h->type; + _jsonData._k_start = h->start; + _jsonData._start = h->start; + _jsonData._end = h->end; + _jsonData._tokenIndex = i; + _jsonData._depth = depth; + _jsonData._len = h->size; + _jsonData.success = true; + _setElementType(); + if (printMode != PRINT_MODE_NONE) + _jsonData.stringValue = ""; else { - if (tk.oindex + 1 == tk.olen) - { - _setRef(depth - 1, false); - _setRef(depth, true); - } + std::string().swap(_jsonData._dbuf); + std::string().swap(_tbuf); + _parser_info.tokenMatch = true; + ex = true; } - } - helper->delS(key); + } + } + } + else + { + if (tk.oindex + 1 == tk.olen) + { + _setRef(depth - 1, false); + _setRef(depth, true); + } + } + } + helper->delS(key); + } + if (ex) + return; + if (_parser_info.refTkIndex == i + 1) + { + if (tk.type == JSMN_OBJECT) + oskip = true; + tk.skip = true; + _parser_info.skipDepth = depth; + } + h = &_tokens.get()[i]; + if (h->type == JSMN_OBJECT || h->type == JSMN_ARRAY) + { + if (printMode != PRINT_MODE_NONE && (tk.skip || _parser_info.refTkIndex == i + 1)) + { + if (!tk.omark && i > 0 && resLen > 0) + { + if (tk.oindex > 0) + _jsonData._dbuf += _cm; + if (printMode == PRINT_MODE_PRETTY && h->size >= 0) + _jsonData._dbuf += _nl; + if (printMode == PRINT_MODE_PRETTY && h->size >= 0) + { + for (int j = 0; j < depth - (_parser_info.skipDepth + 1); j++) + _jsonData._dbuf += _tab; + _jsonData._dbuf += _tab; + } + } + if (h->type == JSMN_OBJECT) + _jsonData._dbuf += _brk1; + else + _jsonData._dbuf += _brk3; + } + el_t e; + e.index = i; + e.olen = h->size; + e.type = h->type; + e.oindex = 0; + e.depth = depth; + e.omark = false; + e.ref = false; + if (_parser_info.refToken != -1) + e.skip = true; + else + e.skip = tk.skip; + _el.push_back(e); + depth++; + if (h->size == 0) + { + while (_updateTkIndex3(i, depth, searchKey, searchIndex, printMode)) + { + delay(0); + } } - if (ex) - return; - if (_parser_info.refTkIndex == i + 1) + } + else + { + char *tmp = helper->newS(h->end - h->start + 10); + if (!tmp) { - if (tk.type == JSMN_OBJECT) - oskip = true; - tk.skip = true; - _parser_info.skipDepth = depth; + helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); + return; } - h = &_tokens.get()[i]; - if (h->type == JSMN_OBJECT || h->type == JSMN_ARRAY) + if (buf[h->start - 1] != '"') + strncpy(tmp, buf + h->start, h->end - h->start); + else + strncpy(tmp, buf + h->start - 1, h->end - h->start + 2); + if (h->size > 0) { - if (printMode != PRINT_MODE_NONE && (tk.skip || _parser_info.refTkIndex == i + 1)) + if (printMode != PRINT_MODE_NONE && tk.skip && !oskip) + { + if (tk.oindex > 0) + _jsonData._dbuf += _cm; + if (printMode == PRINT_MODE_PRETTY) + _jsonData._dbuf += _nl; + if (printMode == PRINT_MODE_PRETTY && h->size > 0) { - if (!tk.omark && i > 0 && resLen > 0) - { - if (tk.oindex > 0) - _jsonData._dbuf += _cm; - if (printMode == PRINT_MODE_PRETTY && h->size >= 0) - _jsonData._dbuf += _nl; - if (printMode == PRINT_MODE_PRETTY && h->size >= 0) - { - for (int j = 0; j < depth - (_parser_info.skipDepth + 1); j++) - _jsonData._dbuf += _tab; - _jsonData._dbuf += _tab; - } - } - if (h->type == JSMN_OBJECT) - _jsonData._dbuf += _brk1; - else - _jsonData._dbuf += _brk3; + for (int j = 0; j < depth - (_parser_info.skipDepth + 1); j++) + _jsonData._dbuf += _tab; + _jsonData._dbuf += _tab; } - el_t e; - e.index = i; - e.olen = h->size; - e.type = h->type; - e.oindex = 0; - e.depth = depth; - e.omark = false; - e.ref = false; - if (_parser_info.refToken != -1) - e.skip = true; + _jsonData._dbuf += tmp; + if (printMode == PRINT_MODE_PRETTY) + _jsonData._dbuf += _pr; else - e.skip = tk.skip; - _el.push_back(e); - depth++; - if (h->size == 0) + _jsonData._dbuf += _pr2; + } + if (_parser_info.collectTk) + { + eltk_t el; + el.index = i; + el.type = 0; + _eltk.push_back(el); + } + char *tmp2 = helper->newS(h->end - h->start + 10); + if (!tmp2) + { + helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); + return; + } + strncpy(tmp2, buf + h->start, h->end - h->start); + h = &_tokens.get()[i + 1]; + helper->delS(tmp2); + + if (h->type != JSMN_OBJECT && h->type != JSMN_ARRAY) + { + + char *tmp2 = helper->newS(h->end - h->start + 10); + if (!tmp2) { - while (_updateTkIndex3(i, depth, searchKey, searchIndex, printMode)) - { - delay(0); - } + helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); + return; } + strncpy(tmp2, buf + h->start, h->end - h->start); + if (printMode != PRINT_MODE_NONE && tk.skip) + { + if (buf[h->start - 1] != '"') + strncpy(tmp2, buf + h->start, h->end - h->start); + else + strncpy(tmp2, buf + h->start - 1, h->end - h->start + 2); + _jsonData._dbuf += tmp2; + } + helper->delS(tmp2); + i++; + while (_updateTkIndex3(i, depth, searchKey, searchIndex, printMode)) + { + delay(0); + } + } + else + { + if (_parser_info.refToken == i + 1) + { + _setSkip(depth, true); + } + _setMark(depth, true); + } } else { - char *tmp = helper->newS(h->end - h->start + 10); - if (!tmp) + if (printMode != PRINT_MODE_NONE && tk.skip) + { + if (tk.oindex > 0 && resLen > 0) { - helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); - return; + _jsonData._dbuf += _cm; } - if (buf[h->start - 1] != '"') - strncpy(tmp, buf + h->start, h->end - h->start); - else - strncpy(tmp, buf + h->start - 1, h->end - h->start + 2); - if (h->size > 0) - { - if (printMode != PRINT_MODE_NONE && tk.skip && !oskip) - { - if (tk.oindex > 0) - _jsonData._dbuf += _cm; - if (printMode == PRINT_MODE_PRETTY) - _jsonData._dbuf += _nl; - if (printMode == PRINT_MODE_PRETTY && h->size > 0) - { - for (int j = 0; j < depth - (_parser_info.skipDepth + 1); j++) - _jsonData._dbuf += _tab; - _jsonData._dbuf += _tab; - } - _jsonData._dbuf += tmp; - if (printMode == PRINT_MODE_PRETTY) - _jsonData._dbuf += _pr; - else - _jsonData._dbuf += _pr2; - } - if (_parser_info.collectTk) - { - eltk_t el; - el.index = i; - el.type = 0; - _eltk.push_back(el); - } - char *tmp2 = helper->newS(h->end - h->start + 10); - if (!tmp2) - { - helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); - return; - } - strncpy(tmp2, buf + h->start, h->end - h->start); - h = &_tokens.get()[i + 1]; - helper->delS(tmp2); - - if (h->type != JSMN_OBJECT && h->type != JSMN_ARRAY) - { + if (printMode == PRINT_MODE_PRETTY && resLen > 0) + _jsonData._dbuf += _nl; - char *tmp2 = helper->newS(h->end - h->start + 10); - if (!tmp2) - { - helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); - return; - } - strncpy(tmp2, buf + h->start, h->end - h->start); - if (printMode != PRINT_MODE_NONE && tk.skip) - { - if (buf[h->start - 1] != '"') - strncpy(tmp2, buf + h->start, h->end - h->start); - else - strncpy(tmp2, buf + h->start - 1, h->end - h->start + 2); - _jsonData._dbuf += tmp2; - } - helper->delS(tmp2); - i++; - while (_updateTkIndex3(i, depth, searchKey, searchIndex, printMode)) - { - delay(0); - } - } - else - { - if (_parser_info.refToken == i + 1) - { - _setSkip(depth, true); - } - _setMark(depth, true); - } - } - else + if (printMode == PRINT_MODE_PRETTY && tk.olen > 0 && resLen > 0) { - if (printMode != PRINT_MODE_NONE && tk.skip) - { - if (tk.oindex > 0 && resLen > 0) - { - _jsonData._dbuf += _cm; - } - if (printMode == PRINT_MODE_PRETTY && resLen > 0) - _jsonData._dbuf += _nl; - - if (printMode == PRINT_MODE_PRETTY && tk.olen > 0 && resLen > 0) - { - for (int j = 0; j < depth - (_parser_info.skipDepth + 1); j++) - _jsonData._dbuf += _tab; - _jsonData._dbuf += _tab; - } - _jsonData._dbuf += tmp; - } - while (_updateTkIndex3(i, depth, searchKey, searchIndex, printMode)) - { - delay(0); - } - if (_parser_info.collectTk) - { - eltk_t el; - el.index = i; - el.type = 1; - _eltk.push_back(el); - } + for (int j = 0; j < depth - (_parser_info.skipDepth + 1); j++) + _jsonData._dbuf += _tab; + _jsonData._dbuf += _tab; } - helper->delS(tmp); - - if (_parser_info.refToken == -1 && _parser_info.skipDepth == depth) - _setSkip(depth, false); + _jsonData._dbuf += tmp; + } + while (_updateTkIndex3(i, depth, searchKey, searchIndex, printMode)) + { + delay(0); + } + if (_parser_info.collectTk) + { + eltk_t el; + el.index = i; + el.type = 1; + _eltk.push_back(el); + } } - _parser_info.nextToken = i + 1; - _parser_info.refToken = -1; + helper->delS(tmp); + + if (_parser_info.refToken == -1 && _parser_info.skipDepth == depth) + _setSkip(depth, false); + } + _parser_info.nextToken = i + 1; + _parser_info.refToken = -1; } void FirebaseJson::_compileToken(uint16_t &i, char *buf, int &depth, const char *searchKey, int searchIndex, PRINT_MODE printMode, const char *replace, int refTokenIndex, bool removeTk) { - helper->clearLastError(); - if (_parser_info.tokenMatch) - return; - tk_index_t tk; - _getTkIndex(depth, tk); - FirebaseJson::fbjs_tok_t *h = &_tokens.get()[i]; - bool insertFlag = false; - bool ex = false; - delay(0); - if (searchIndex > -1) - { - tk_index_t tk2; - int depth2 = depth - 1; - _getTkIndex(depth2, tk2); - if (tk.type == JSMN_ARRAY && _parser_info.parseDepth == depth && tk2.oindex == _parser_info.parentIndex) - { - if (tk.oindex == searchIndex) - { - _parser_info.nextToken = i; - _parser_info.nextDepth = depth; - _parser_info.parentIndex = tk.oindex; - if ((int)_pathTk.size() != _parser_info.parseDepth + 1) - { - _parser_info.tokenMatch = true; - _parser_info.parseCompleted++; - _parser_info.refTkIndex = i + 1; - } - else - { - if (!_parser_info.TkRefOk) - { - _parser_info.parseCompleted++; - _parser_info.refTkIndex = i + 1; - _parser_info.refToken = i + 1; - _parser_info.TkRefOk = true; - single_child_parent_t p = _findSCParent(depth); - if (p.success) - { - _parser_info.remTkIndex = p.index + 1; - _parser_info.remFirstTk = p.firstTk; - _parser_info.remLastTk = p.lastTk; - } - else - { - _parser_info.remTkIndex = i + 1; - _parser_info.remFirstTk = tk.oindex == 0; - _parser_info.remLastTk = tk.oindex + 1 == tk.olen; - } - } - } - } - else - { - if (tk.oindex + 1 == tk.olen) - { - _setRef(depth - 1, false); - _setRef(depth, true); - } - } + helper->clearLastError(); + if (_parser_info.tokenMatch) + return; + tk_index_t tk; + _getTkIndex(depth, tk); + FirebaseJson::fbjs_tok_t *h = &_tokens.get()[i]; + bool insertFlag = false; + bool ex = false; + delay(0); + if (searchIndex > -1) + { + tk_index_t tk2; + int depth2 = depth - 1; + _getTkIndex(depth2, tk2); + if (tk.type == JSMN_ARRAY && _parser_info.parseDepth == depth && tk2.oindex == _parser_info.parentIndex) + { + if (tk.oindex == searchIndex) + { + _parser_info.nextToken = i; + _parser_info.nextDepth = depth; + _parser_info.parentIndex = tk.oindex; + if ((int)_pathTk.size() != _parser_info.parseDepth + 1) + { + _parser_info.tokenMatch = true; + _parser_info.parseCompleted++; + _parser_info.refTkIndex = i + 1; } - } - else - { - char *key = helper->newS(h->end - h->start + 10); - if (!key) - { - helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); - return; - } - strncpy(key, buf + h->start, h->end - h->start); - if (tk.type != JSMN_UNDEFINED && _parser_info.parseDepth == depth) + else { - if (strcmp(searchKey, key) == 0) + if (!_parser_info.TkRefOk) + { + _parser_info.parseCompleted++; + _parser_info.refTkIndex = i + 1; + _parser_info.refToken = i + 1; + _parser_info.TkRefOk = true; + single_child_parent_t p = _findSCParent(depth); + if (p.success) { - _parser_info.nextToken = i + 1; - _parser_info.nextDepth = depth; - _parser_info.parentIndex = tk.oindex; - if ((int)_pathTk.size() != _parser_info.parseDepth + 1) - { - _parser_info.tokenMatch = true; - _parser_info.parseCompleted++; - _parser_info.refTkIndex = i + 1; - } - else - { - if (!_parser_info.TkRefOk) - { - _parser_info.parseCompleted++; - _parser_info.refTkIndex = i + 1; - _parser_info.refToken = i + 1; - _parser_info.TkRefOk = true; - single_child_parent_t p = _findSCParent(depth); - if (p.success) - { - _parser_info.remTkIndex = p.index + 1; - _parser_info.remFirstTk = p.firstTk; - _parser_info.remLastTk = p.lastTk; - } - else - { - _parser_info.remTkIndex = i + 1; - _parser_info.remFirstTk = tk.oindex == 0; - _parser_info.remLastTk = tk.oindex + 1 == tk.olen; - } - } - } + _parser_info.remTkIndex = p.index + 1; + _parser_info.remFirstTk = p.firstTk; + _parser_info.remLastTk = p.lastTk; } else { - if (tk.oindex + 1 == tk.olen) - { - _setRef(depth - 1, false); - _setRef(depth, true); - } + _parser_info.remTkIndex = i + 1; + _parser_info.remFirstTk = tk.oindex == 0; + _parser_info.remLastTk = tk.oindex + 1 == tk.olen; } + } } - else + } + else + { + if (tk.oindex + 1 == tk.olen) { - if (_parser_info.tokenCount == 1 && h->size == 0 && !removeTk) - { - _insertChilds(replace, printMode); - _parser_info.nextToken = i + 1; - _parser_info.nextDepth = 0; - _parser_info.parseCompleted = _pathTk.size(); - _parser_info.tokenMatch = true; - ex = true; - } + _setRef(depth - 1, false); + _setRef(depth, true); } - helper->delS(key); + } } - if (ex) - return; - - h = &_tokens.get()[i]; - if (h->type == JSMN_OBJECT || h->type == JSMN_ARRAY) + } + else + { + char *key = helper->newS(h->end - h->start + 10); + if (!key) { - if (printMode != PRINT_MODE_NONE && !tk.skip) - { - if (!tk.omark && i > 0) - { - if (tk.oindex > 0) - _jsonData._dbuf += _cm; - if (printMode == PRINT_MODE_PRETTY && h->size >= 0) - _jsonData._dbuf += _nl; - if (printMode == PRINT_MODE_PRETTY && h->size >= 0) - { - for (int j = 0; j < depth; j++) - _jsonData._dbuf += _tab; - _jsonData._dbuf += _tab; - } - } - if (_parser_info.refToken == -1) - { - if (h->type == JSMN_OBJECT) - _jsonData._dbuf += _brk1; - else - _jsonData._dbuf += _brk3; - } - else if (_parser_info.refToken != -1 && searchIndex > -1) - _jsonData._dbuf += replace; - } - el_t e; - e.index = i; - e.olen = h->size; - e.type = h->type; - e.oindex = 0; - e.depth = depth; - e.omark = false; - e.ref = false; - if (_parser_info.refToken != -1) - e.skip = true; - else - e.skip = tk.skip; - _el.push_back(e); - depth++; - if (h->size == 0) - { - while (_updateTkIndex(i, depth, searchKey, searchIndex, replace, printMode, removeTk)) - { - delay(0); - } - } + helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); + return; } - else + strncpy(key, buf + h->start, h->end - h->start); + if (tk.type != JSMN_UNDEFINED && _parser_info.parseDepth == depth) { - if (_parser_info.refTkIndex == refTokenIndex && refTokenIndex > -1) - { - _parser_info.refToken = refTokenIndex; - _parser_info.refTkIndex = -1; - insertFlag = true; - } - char *tmp = helper->newS(h->end - h->start + 10); - if (!tmp) + if (strcmp(searchKey, key) == 0) + { + _parser_info.nextToken = i + 1; + _parser_info.nextDepth = depth; + _parser_info.parentIndex = tk.oindex; + if ((int)_pathTk.size() != _parser_info.parseDepth + 1) { - helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); - return; + _parser_info.tokenMatch = true; + _parser_info.parseCompleted++; + _parser_info.refTkIndex = i + 1; } - if (buf[h->start - 1] != '"') - strncpy(tmp, buf + h->start, h->end - h->start); else - strncpy(tmp, buf + h->start - 1, h->end - h->start + 2); - if (h->size > 0) { - if (printMode != PRINT_MODE_NONE && !tk.skip) + if (!_parser_info.TkRefOk) + { + _parser_info.parseCompleted++; + _parser_info.refTkIndex = i + 1; + _parser_info.refToken = i + 1; + _parser_info.TkRefOk = true; + single_child_parent_t p = _findSCParent(depth); + if (p.success) { - if (tk.oindex > 0) - _jsonData._dbuf += _cm; - if (printMode == PRINT_MODE_PRETTY) - _jsonData._dbuf += _nl; - if (printMode == PRINT_MODE_PRETTY && h->size > 0) - { - for (int j = 0; j < depth; j++) - _jsonData._dbuf += _tab; - _jsonData._dbuf += _tab; - } - _jsonData._dbuf += tmp; - if (printMode == PRINT_MODE_PRETTY) - _jsonData._dbuf += _pr; - else - _jsonData._dbuf += _pr2; - } - char *tmp2 = helper->newS(h->end - h->start + 10); - if (!tmp2) - { - helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); - return; - } - strncpy(tmp2, buf + h->start, h->end - h->start); - h = &_tokens.get()[i + 1]; - helper->delS(tmp2); - - if (h->type != JSMN_OBJECT && h->type != JSMN_ARRAY) - { - char *tmp2 = helper->newS(h->end - h->start + 10); - if (!tmp2) - { - helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); - return; - } - strncpy(tmp2, buf + h->start, h->end - h->start); - - if (printMode != PRINT_MODE_NONE && !tk.skip) - { - if (buf[h->start - 1] != '"') - strncpy(tmp2, buf + h->start, h->end - h->start); - else - strncpy(tmp2, buf + h->start - 1, h->end - h->start + 2); - if (_parser_info.refToken == i + 1) - { - if (!insertFlag) - _jsonData._dbuf += replace; - else - _insertChilds(replace, printMode); - } - else - _jsonData._dbuf += tmp2; - } - helper->delS(tmp2); - i++; - while (_updateTkIndex(i, depth, searchKey, searchIndex, replace, printMode, removeTk)) - { - delay(0); - } + _parser_info.remTkIndex = p.index + 1; + _parser_info.remFirstTk = p.firstTk; + _parser_info.remLastTk = p.lastTk; } else { - if (_parser_info.refToken == i + 1) - { - _setSkip(depth, true); - _parser_info.skipDepth = depth; - if (!insertFlag) - _jsonData._dbuf += replace; - else - _insertChilds(replace, printMode); - if (printMode != PRINT_MODE_NONE && (depth > 0 || tk.oindex == tk.olen - 1)) - { - if (printMode == PRINT_MODE_PRETTY) - _jsonData._dbuf += _nl; - if (printMode == PRINT_MODE_PRETTY) - { - for (int j = 0; j < depth; j++) - _jsonData._dbuf += _tab; - } - _jsonData._dbuf += _brk2; - } - } - _setMark(depth, true); + _parser_info.remTkIndex = i + 1; + _parser_info.remFirstTk = tk.oindex == 0; + _parser_info.remLastTk = tk.oindex + 1 == tk.olen; } + } } - else + } + else + { + if (tk.oindex + 1 == tk.olen) { - if (printMode != PRINT_MODE_NONE && !tk.skip) - { - if (tk.oindex > 0) - _jsonData._dbuf += _cm; - if (printMode == PRINT_MODE_PRETTY) - _jsonData._dbuf += _nl; - if (printMode == PRINT_MODE_PRETTY && tk.olen > 0) - { - for (int j = 0; j < depth; j++) - _jsonData._dbuf += _tab; - _jsonData._dbuf += _tab; - } - - if (_parser_info.refToken == i + 1 && !_parser_info.arrInserted) - { - if (!insertFlag) - _jsonData._dbuf += replace; - else - _insertChilds(replace, printMode); - _parser_info.arrInserted = true; - } - else - _jsonData._dbuf += tmp; - } - while (_updateTkIndex(i, depth, searchKey, searchIndex, replace, printMode, removeTk)) - { - delay(0); - } + _setRef(depth - 1, false); + _setRef(depth, true); } - helper->delS(tmp); - - if (_parser_info.refToken == -1 && _parser_info.skipDepth == depth) - _setSkip(depth, false); + } } - _parser_info.nextToken = i + 1; - _parser_info.refToken = -1; -} - -void FirebaseJson::_removeToken(uint16_t &i, char *buf, int &depth, const char *searchKey, int searchIndex, PRINT_MODE printMode, const char *replace, int refTokenIndex, bool removeTk) -{ - helper->clearLastError(); - bool ncm = false; - tk_index_t tk; - _getTkIndex(depth, tk); - FirebaseJson::fbjs_tok_t *h = &_tokens.get()[i]; - delay(0); - if (refTokenIndex == i && refTokenIndex > -1) - ncm = _parser_info.remFirstTk; - if (refTokenIndex != i || (refTokenIndex == i && _parser_info.remLastTk)) - _jsonData._dbuf += _tbuf; - _tbuf.clear(); - bool flag = tk.oindex > 0 && !ncm && _jsonData._dbuf.c_str()[_jsonData._dbuf.length() - 1] != '{' && _jsonData._dbuf.c_str()[_jsonData._dbuf.length() - 1] != '['; - if (refTokenIndex == i + 1 && refTokenIndex > -1) + else { - _parser_info.refToken = refTokenIndex; - _parser_info.refTkIndex = -1; - tk.skip = true; + if (_parser_info.tokenCount == 1 && h->size == 0 && !removeTk) + { + _insertChilds(replace, printMode); + _parser_info.nextToken = i + 1; + _parser_info.nextDepth = 0; + _parser_info.parseCompleted = _pathTk.size(); + _parser_info.tokenMatch = true; + ex = true; + } + } + helper->delS(key); + } + if (ex) + return; + + h = &_tokens.get()[i]; + if (h->type == JSMN_OBJECT || h->type == JSMN_ARRAY) + { + if (printMode != PRINT_MODE_NONE && !tk.skip) + { + if (!tk.omark && i > 0) + { + if (tk.oindex > 0) + _jsonData._dbuf += _cm; + if (printMode == PRINT_MODE_PRETTY && h->size >= 0) + _jsonData._dbuf += _nl; + if (printMode == PRINT_MODE_PRETTY && h->size >= 0) + { + for (int j = 0; j < depth; j++) + _jsonData._dbuf += _tab; + _jsonData._dbuf += _tab; + } + } + if (_parser_info.refToken == -1) + { + if (h->type == JSMN_OBJECT) + _jsonData._dbuf += _brk1; + else + _jsonData._dbuf += _brk3; + } + else if (_parser_info.refToken != -1 && searchIndex > -1) + _jsonData._dbuf += replace; + } + el_t e; + e.index = i; + e.olen = h->size; + e.type = h->type; + e.oindex = 0; + e.depth = depth; + e.omark = false; + e.ref = false; + if (_parser_info.refToken != -1) + e.skip = true; + else + e.skip = tk.skip; + _el.push_back(e); + depth++; + if (h->size == 0) + { + while (_updateTkIndex(i, depth, searchKey, searchIndex, replace, printMode, removeTk)) + { + delay(0); + } } - h = &_tokens.get()[i]; - if (h->type == JSMN_OBJECT || h->type == JSMN_ARRAY) + } + else + { + if (_parser_info.refTkIndex == refTokenIndex && refTokenIndex > -1) { - if (printMode != PRINT_MODE_NONE && !tk.skip) - { - if (!tk.omark && i > 0) - { - if (flag) - _tbuf += _cm; - if (printMode == PRINT_MODE_PRETTY && h->size >= 0) - _tbuf += _nl; - if (printMode == PRINT_MODE_PRETTY && h->size >= 0) - { - for (int j = 0; j < depth; j++) - _tbuf += _tab; - _tbuf += _tab; - } - } - if (_parser_info.refToken == -1) - { - if (h->type == JSMN_OBJECT) - _tbuf += _brk1; - else - _tbuf += _brk3; - } - else if (_parser_info.refToken != -1 && searchIndex > -1) - _tbuf += replace; - } - el_t e; - e.index = i; - e.olen = h->size; - e.type = h->type; - e.oindex = 0; - e.depth = depth; - e.omark = false; - e.ref = false; - if (_parser_info.refToken != -1) - e.skip = true; - else - e.skip = tk.skip; - _el.push_back(e); - depth++; - if (h->size == 0) - { - while (_updateTkIndex2(_tbuf, i, depth, searchKey, searchIndex, replace, printMode)) - { - delay(0); - } - } + _parser_info.refToken = refTokenIndex; + _parser_info.refTkIndex = -1; + insertFlag = true; + } + char *tmp = helper->newS(h->end - h->start + 10); + if (!tmp) + { + helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); + return; } + if (buf[h->start - 1] != '"') + strncpy(tmp, buf + h->start, h->end - h->start); else + strncpy(tmp, buf + h->start - 1, h->end - h->start + 2); + if (h->size > 0) { - char *tmp = helper->newS(h->end - h->start + 10); - if (!tmp) + if (printMode != PRINT_MODE_NONE && !tk.skip) + { + if (tk.oindex > 0) + _jsonData._dbuf += _cm; + if (printMode == PRINT_MODE_PRETTY) + _jsonData._dbuf += _nl; + if (printMode == PRINT_MODE_PRETTY && h->size > 0) { - helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); - return; + for (int j = 0; j < depth; j++) + _jsonData._dbuf += _tab; + _jsonData._dbuf += _tab; } - if (buf[h->start - 1] != '"') - strncpy(tmp, buf + h->start, h->end - h->start); + _jsonData._dbuf += tmp; + if (printMode == PRINT_MODE_PRETTY) + _jsonData._dbuf += _pr; else - strncpy(tmp, buf + h->start - 1, h->end - h->start + 2); - if (h->size > 0) + _jsonData._dbuf += _pr2; + } + char *tmp2 = helper->newS(h->end - h->start + 10); + if (!tmp2) + { + helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); + return; + } + strncpy(tmp2, buf + h->start, h->end - h->start); + h = &_tokens.get()[i + 1]; + helper->delS(tmp2); + + if (h->type != JSMN_OBJECT && h->type != JSMN_ARRAY) + { + char *tmp2 = helper->newS(h->end - h->start + 10); + if (!tmp2) { - if (printMode != PRINT_MODE_NONE && !tk.skip) - { - if (flag) - _tbuf += _cm; - if (printMode == PRINT_MODE_PRETTY) - _tbuf += _nl; - if (printMode == PRINT_MODE_PRETTY && h->size > 0) - { - for (int j = 0; j < depth; j++) - _tbuf += _tab; - _tbuf += _tab; - } - _tbuf += tmp; - if (printMode == PRINT_MODE_PRETTY) - _tbuf += _pr; - else - _tbuf += _pr2; - } + helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); + return; + } + strncpy(tmp2, buf + h->start, h->end - h->start); - char *tmp2 = helper->newS(h->end - h->start + 10); - if (!tmp2) - { - helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); - return; - } + if (printMode != PRINT_MODE_NONE && !tk.skip) + { + if (buf[h->start - 1] != '"') strncpy(tmp2, buf + h->start, h->end - h->start); - h = &_tokens.get()[i + 1]; - helper->delS(tmp2); - if (h->type != JSMN_OBJECT && h->type != JSMN_ARRAY) - { - char *tmp2 = helper->newS(h->end - h->start + 10); - if (!tmp2) - { - helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); - return; - } - strncpy(tmp2, buf + h->start, h->end - h->start); - if (printMode != PRINT_MODE_NONE && !tk.skip) - { - if (buf[h->start - 1] != '"') - strncpy(tmp2, buf + h->start, h->end - h->start); - else - strncpy(tmp2, buf + h->start - 1, h->end - h->start + 2); - _tbuf += tmp2; - } - helper->delS(tmp2); - i++; - while (_updateTkIndex2(_tbuf, i, depth, searchKey, searchIndex, replace, printMode)) - { - delay(0); - } - } + else + strncpy(tmp2, buf + h->start - 1, h->end - h->start + 2); + if (_parser_info.refToken == i + 1) + { + if (!insertFlag) + _jsonData._dbuf += replace; else - { - if (_parser_info.refToken == i + 1) - { - _setSkip(depth, true); - _parser_info.skipDepth = depth; - _tbuf += replace; - if (printMode != PRINT_MODE_NONE && (depth > 0 || tk.oindex == tk.olen - 1)) - { - if (printMode == PRINT_MODE_PRETTY) - _tbuf += _nl; - if (printMode == PRINT_MODE_PRETTY) - { - for (int j = 0; j < depth; j++) - _tbuf += _tab; - } - _tbuf += _brk2; - } - } - _setMark(depth, true); - } + _insertChilds(replace, printMode); + } + else + _jsonData._dbuf += tmp2; } - else - { - if (printMode != PRINT_MODE_NONE && !tk.skip) - { - if (flag) - _tbuf += _cm; - if (printMode == PRINT_MODE_PRETTY) - _tbuf += _nl; - if (printMode == PRINT_MODE_PRETTY && tk.olen > 0) - { - for (int j = 0; j < depth; j++) - _tbuf += _tab; - _tbuf += _tab; - } - _tbuf += tmp; - } - while (_updateTkIndex2(_tbuf, i, depth, searchKey, searchIndex, replace, printMode)) + helper->delS(tmp2); + i++; + while (_updateTkIndex(i, depth, searchKey, searchIndex, replace, printMode, removeTk)) + { + delay(0); + } + } + else + { + if (_parser_info.refToken == i + 1) + { + _setSkip(depth, true); + _parser_info.skipDepth = depth; + if (!insertFlag) + _jsonData._dbuf += replace; + else + _insertChilds(replace, printMode); + if (printMode != PRINT_MODE_NONE && (depth > 0 || tk.oindex == tk.olen - 1)) + { + if (printMode == PRINT_MODE_PRETTY) + _jsonData._dbuf += _nl; + if (printMode == PRINT_MODE_PRETTY) { - delay(0); + for (int j = 0; j < depth; j++) + _jsonData._dbuf += _tab; } + _jsonData._dbuf += _brk2; + } } - helper->delS(tmp); - - if (_parser_info.refToken == -1 && _parser_info.skipDepth == depth) - _setSkip(depth, false); + _setMark(depth, true); + } } - _parser_info.nextToken = i + 1; - _parser_info.refToken = -1; - _lastTk.olen = tk.olen; - _lastTk.oindex = tk.oindex; - _lastTk.type = tk.type; - _lastTk.depth = tk.depth; - _lastTk.index = tk.index; - _lastTk.skip = tk.skip; -} - -FirebaseJson::single_child_parent_t FirebaseJson::_findSCParent(int depth) -{ - single_child_parent_t res; - res.index = -1; - res.firstTk = false; - res.lastTk = false; - res.success = false; - for (int i = depth; i >= 0; i--) + else { - bool match = false; - for (size_t j = 0; j < _el.size(); j++) + if (printMode != PRINT_MODE_NONE && !tk.skip) + { + if (tk.oindex > 0) + _jsonData._dbuf += _cm; + if (printMode == PRINT_MODE_PRETTY) + _jsonData._dbuf += _nl; + if (printMode == PRINT_MODE_PRETTY && tk.olen > 0) { - if (_el[j].depth == i - 1 && _el[i].olen == 1) - { - match = true; - res.index = _el[i].index; - res.firstTk = _el[j].oindex == 0; - res.lastTk = _el[j].oindex + 1 == _el[j].olen; - res.success = true; - } + for (int j = 0; j < depth; j++) + _jsonData._dbuf += _tab; + _jsonData._dbuf += _tab; } - if (!match) - break; + + if (_parser_info.refToken == i + 1 && !_parser_info.arrInserted) + { + if (!insertFlag) + _jsonData._dbuf += replace; + else + _insertChilds(replace, printMode); + _parser_info.arrInserted = true; + } + else + _jsonData._dbuf += tmp; + } + while (_updateTkIndex(i, depth, searchKey, searchIndex, replace, printMode, removeTk)) + { + delay(0); + } } - return res; + helper->delS(tmp); + + if (_parser_info.refToken == -1 && _parser_info.skipDepth == depth) + _setSkip(depth, false); + } + _parser_info.nextToken = i + 1; + _parser_info.refToken = -1; } -void FirebaseJson::_get(const char *key, int depth, int index) +void FirebaseJson::_removeToken(uint16_t &i, char *buf, int &depth, const char *searchKey, int searchIndex, PRINT_MODE printMode, const char *replace, int refTokenIndex, bool removeTk) { - helper->clearLastError(); - _parser_info.tokenMatch = false; - if (_parser_info.paresRes) + helper->clearLastError(); + bool ncm = false; + tk_index_t tk; + _getTkIndex(depth, tk); + FirebaseJson::fbjs_tok_t *h = &_tokens.get()[i]; + delay(0); + if (refTokenIndex == i && refTokenIndex > -1) + ncm = _parser_info.remFirstTk; + if (refTokenIndex != i || (refTokenIndex == i && _parser_info.remLastTk)) + _jsonData._dbuf += _tbuf; + _tbuf.clear(); + bool flag = tk.oindex > 0 && !ncm && _jsonData._dbuf.c_str()[_jsonData._dbuf.length() - 1] != '{' && _jsonData._dbuf.c_str()[_jsonData._dbuf.length() - 1] != '['; + if (refTokenIndex == i + 1 && refTokenIndex > -1) + { + _parser_info.refToken = refTokenIndex; + _parser_info.refTkIndex = -1; + tk.skip = true; + } + h = &_tokens.get()[i]; + if (h->type == JSMN_OBJECT || h->type == JSMN_ARRAY) + { + if (printMode != PRINT_MODE_NONE && !tk.skip) + { + if (!tk.omark && i > 0) + { + if (flag) + _tbuf += _cm; + if (printMode == PRINT_MODE_PRETTY && h->size >= 0) + _tbuf += _nl; + if (printMode == PRINT_MODE_PRETTY && h->size >= 0) + { + for (int j = 0; j < depth; j++) + _tbuf += _tab; + _tbuf += _tab; + } + } + if (_parser_info.refToken == -1) + { + if (h->type == JSMN_OBJECT) + _tbuf += _brk1; + else + _tbuf += _brk3; + } + else if (_parser_info.refToken != -1 && searchIndex > -1) + _tbuf += replace; + } + el_t e; + e.index = i; + e.olen = h->size; + e.type = h->type; + e.oindex = 0; + e.depth = depth; + e.omark = false; + e.ref = false; + if (_parser_info.refToken != -1) + e.skip = true; + else + e.skip = tk.skip; + _el.push_back(e); + depth++; + if (h->size == 0) + { + while (_updateTkIndex2(_tbuf, i, depth, searchKey, searchIndex, replace, printMode)) + { + delay(0); + } + } + } + else + { + char *tmp = helper->newS(h->end - h->start + 10); + if (!tmp) + { + helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); + return; + } + if (buf[h->start - 1] != '"') + strncpy(tmp, buf + h->start, h->end - h->start); + else + strncpy(tmp, buf + h->start - 1, h->end - h->start + 2); + if (h->size > 0) { - std::string s; - _toStdString(s); - int bufLen = s.length() + _parser_buff_len; - char *buf = helper->newS(bufLen); - if (!buf) + if (printMode != PRINT_MODE_NONE && !tk.skip) + { + if (flag) + _tbuf += _cm; + if (printMode == PRINT_MODE_PRETTY) + _tbuf += _nl; + if (printMode == PRINT_MODE_PRETTY && h->size > 0) { - helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); - return; + for (int j = 0; j < depth; j++) + _tbuf += _tab; + _tbuf += _tab; } - strcpy(buf, s.c_str()); - std::string().swap(s); + _tbuf += tmp; + if (printMode == PRINT_MODE_PRETTY) + _tbuf += _pr; + else + _tbuf += _pr2; + } - if (_jsonData.success) + char *tmp2 = helper->newS(h->end - h->start + 10); + if (!tmp2) + { + helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); + return; + } + strncpy(tmp2, buf + h->start, h->end - h->start); + h = &_tokens.get()[i + 1]; + helper->delS(tmp2); + if (h->type != JSMN_OBJECT && h->type != JSMN_ARRAY) + { + char *tmp2 = helper->newS(h->end - h->start + 10); + if (!tmp2) { - _jsonData._dbuf.clear(); - _parser_info.parseDepth = depth; - if (_parser_info.nextToken < 0) - _parser_info.nextToken = 0; - for (uint16_t i = _parser_info.nextToken; i < _parser_info.tokenCount; i++) + helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); + return; + } + strncpy(tmp2, buf + h->start, h->end - h->start); + if (printMode != PRINT_MODE_NONE && !tk.skip) + { + if (buf[h->start - 1] != '"') + strncpy(tmp2, buf + h->start, h->end - h->start); + else + strncpy(tmp2, buf + h->start - 1, h->end - h->start + 2); + _tbuf += tmp2; + } + helper->delS(tmp2); + i++; + while (_updateTkIndex2(_tbuf, i, depth, searchKey, searchIndex, replace, printMode)) + { + delay(0); + } + } + else + { + if (_parser_info.refToken == i + 1) + { + _setSkip(depth, true); + _parser_info.skipDepth = depth; + _tbuf += replace; + if (printMode != PRINT_MODE_NONE && (depth > 0 || tk.oindex == tk.olen - 1)) + { + if (printMode == PRINT_MODE_PRETTY) + _tbuf += _nl; + if (printMode == PRINT_MODE_PRETTY) { - _parseToken(i, buf, _parser_info.nextDepth, (char *)key, index, PRINT_MODE_NONE); - if (_parser_info.tokenMatch) - break; + for (int j = 0; j < depth; j++) + _tbuf += _tab; } + _tbuf += _brk2; + } } - helper->delS(buf); - if (!_parser_info.tokenMatch) + _setMark(depth, true); + } + } + else + { + if (printMode != PRINT_MODE_NONE && !tk.skip) + { + if (flag) + _tbuf += _cm; + if (printMode == PRINT_MODE_PRETTY) + _tbuf += _nl; + if (printMode == PRINT_MODE_PRETTY && tk.olen > 0) { - _parser_info.paresRes = false; - _jsonData.success = false; - _resetParseResult(); + for (int j = 0; j < depth; j++) + _tbuf += _tab; + _tbuf += _tab; } + _tbuf += tmp; + } + while (_updateTkIndex2(_tbuf, i, depth, searchKey, searchIndex, replace, printMode)) + { + delay(0); + } } + helper->delS(tmp); + + if (_parser_info.refToken == -1 && _parser_info.skipDepth == depth) + _setSkip(depth, false); + } + _parser_info.nextToken = i + 1; + _parser_info.refToken = -1; + _lastTk.olen = tk.olen; + _lastTk.oindex = tk.oindex; + _lastTk.type = tk.type; + _lastTk.depth = tk.depth; + _lastTk.index = tk.index; + _lastTk.skip = tk.skip; } -void FirebaseJson::_strToTk(const std::string &str, std::vector &tk, char delim) +FirebaseJson::single_child_parent_t FirebaseJson::_findSCParent(int depth) +{ + single_child_parent_t res; + res.index = -1; + res.firstTk = false; + res.lastTk = false; + res.success = false; + for (int i = depth; i >= 0; i--) + { + bool match = false; + for (size_t j = 0; j < _el.size(); j++) + { + if (_el[j].depth == i - 1 && _el[i].olen == 1) + { + match = true; + res.index = _el[i].index; + res.firstTk = _el[j].oindex == 0; + res.lastTk = _el[j].oindex + 1 == _el[j].olen; + res.success = true; + } + } + if (!match) + break; + } + return res; +} + +void FirebaseJson::_get(const char *key, int depth, int index) { - std::size_t current, previous = 0; - current = str.find(delim); + helper->clearLastError(); + _parser_info.tokenMatch = false; + if (_parser_info.paresRes) + { std::string s; - while (current != std::string::npos) + _toStdString(s); + int bufLen = s.length() + _parser_buff_len; + char *buf = helper->newS(bufLen); + if (!buf) { - s = str.substr(previous, current - previous); - _trim(s); - if (s.length() > 0) - { - path_tk_t tk_t; - tk_t.tk = s; - tk.push_back(tk_t); - } + helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); + return; + } + strcpy(buf, s.c_str()); + std::string().swap(s); - previous = current + 1; - current = str.find(delim, previous); - delay(0); + if (_jsonData.success) + { + _jsonData._dbuf.clear(); + _parser_info.parseDepth = depth; + if (_parser_info.nextToken < 0) + _parser_info.nextToken = 0; + for (uint16_t i = _parser_info.nextToken; i < _parser_info.tokenCount; i++) + { + _parseToken(i, buf, _parser_info.nextDepth, (char *)key, index, PRINT_MODE_NONE); + if (_parser_info.tokenMatch) + break; + } + } + helper->delS(buf); + if (!_parser_info.tokenMatch) + { + _parser_info.paresRes = false; + _jsonData.success = false; + _resetParseResult(); } + } +} + +void FirebaseJson::_strToTk(const std::string &str, std::vector &tk, char delim) +{ + std::size_t current, previous = 0; + current = str.find(delim); + std::string s; + while (current != std::string::npos) + { s = str.substr(previous, current - previous); _trim(s); if (s.length() > 0) { - path_tk_t tk_t; - tk_t.tk = s; - tk.push_back(tk_t); + path_tk_t tk_t; + tk_t.tk = s; + tk.push_back(tk_t); } - std::string().swap(s); + + previous = current + 1; + current = str.find(delim, previous); + delay(0); + } + s = str.substr(previous, current - previous); + _trim(s); + if (s.length() > 0) + { + path_tk_t tk_t; + tk_t.tk = s; + tk.push_back(tk_t); + } + std::string().swap(s); } void FirebaseJson::_ltrim(std::string &str, const std::string &chars) { - str.erase(0, str.find_first_not_of(chars)); + str.erase(0, str.find_first_not_of(chars)); } void FirebaseJson::_rtrim(std::string &str, const std::string &chars) { - str.erase(str.find_last_not_of(chars) + 1); + str.erase(str.find_last_not_of(chars) + 1); } void FirebaseJson::_trim(std::string &str, const std::string &chars) { - _ltrim(str, chars); - _rtrim(str, chars); + _ltrim(str, chars); + _rtrim(str, chars); } void FirebaseJson::int_parse(const char *path, PRINT_MODE printMode) { - _parse(path, printMode); + _parse(path, printMode); } void FirebaseJson::_parse(const char *path, PRINT_MODE printMode) { - helper->clearLastError(); - clearPathTk(); - std::string _path; - - if (_topLevelTkType == JSMN_ARRAY) - { - char *_root = helper->strP(fb_json_str_26); - char *_slash = helper->strP(fb_json_str_27); - _path = _root; - _path += _slash; - _path += path; - helper->delS(_root); - helper->delS(_slash); - } - else - _path = path; - - _strToTk(_path.c_str(), _pathTk, '/'); - _fbjs_parse(); - std::string().swap(_path); - if (!_jsonData.success) - return; - _jsonData.success = false; - int len = _pathTk.size(); - - _resetParsserInfo(); - - _parser_info.remTkIndex = -1; - _parser_info.remFirstTk = false; - _parser_info.remLastTk = false; - _el.clear(); - _eltk.clear(); - if (len == 0) - { - _parse("", 0, -2, printMode); - _jsonData.success = true; - } - else + helper->clearLastError(); + clearPathTk(); + std::string _path; + + if (_topLevelTkType == JSMN_ARRAY) + { + char *_root = helper->strP(fb_json_str_26); + char *_slash = helper->strP(fb_json_str_27); + _path = _root; + _path += _slash; + _path += path; + helper->delS(_root); + helper->delS(_slash); + } + else + _path = path; + + _strToTk(_path.c_str(), _pathTk, '/'); + _fbjs_parse(); + std::string().swap(_path); + if (!_jsonData.success) + return; + _jsonData.success = false; + int len = _pathTk.size(); + + _resetParsserInfo(); + + _parser_info.remTkIndex = -1; + _parser_info.remFirstTk = false; + _parser_info.remLastTk = false; + _el.clear(); + _eltk.clear(); + if (len == 0) + { + _parse("", 0, -2, printMode); + _jsonData.success = true; + } + else + { + for (int i = 0; i < len; i++) { - for (int i = 0; i < len; i++) - { - if (_isStrTk(i)) - _parse(_pathTk[i].tk.c_str(), i, -1, printMode); - else if (_isArrTk(i)) - _parse("", i, _getArrIndex(i), printMode); - else - _parse(_pathTk[i].tk.c_str(), i, -1, printMode); - } - _jsonData.success = _parser_info.parseCompleted == len; - } - _el.clear(); - _eltk.clear(); - clearPathTk(); - std::string().swap(_tbuf); - _tokens.reset(); - _tokens = nullptr; + if (_isStrTk(i)) + _parse(_pathTk[i].tk.c_str(), i, -1, printMode); + else if (_isArrTk(i)) + _parse("", i, _getArrIndex(i), printMode); + else + _parse(_pathTk[i].tk.c_str(), i, -1, printMode); + } + _jsonData.success = _parser_info.parseCompleted == len; + } + _el.clear(); + _eltk.clear(); + clearPathTk(); + std::string().swap(_tbuf); + _tokens.reset(); + _tokens = nullptr; } void FirebaseJson::int_clearPathTk() { - clearPathTk(); + clearPathTk(); } void FirebaseJson::clearPathTk() { - size_t len = _pathTk.size(); - for (size_t i = 0; i < len; i++) - std::string().swap(_pathTk[i].tk); - for (size_t i = 0; i < len; i++) - _pathTk.erase(_pathTk.end()); - _pathTk.clear(); - std::vector().swap(_pathTk); + size_t len = _pathTk.size(); + for (size_t i = 0; i < len; i++) + std::string().swap(_pathTk[i].tk); + for (size_t i = 0; i < len; i++) + _pathTk.erase(_pathTk.end()); + _pathTk.clear(); + std::vector().swap(_pathTk); } void FirebaseJson::int_clearTokens() { - _tokens.reset(); - _tokens = nullptr; + _tokens.reset(); + _tokens = nullptr; } size_t FirebaseJson::int_get_jsondata_len() { - return _jsonData._len; + return _jsonData._len; } void FirebaseJson::_parse(const char *key, int depth, int index, PRINT_MODE printMode) { - helper->clearLastError(); - _parser_info.tokenMatch = false; - if (_parser_info.paresRes) + helper->clearLastError(); + _parser_info.tokenMatch = false; + if (_parser_info.paresRes) + { + std::string s; + _toStdString(s); + int bufLen = s.length() + _parser_buff_len; + char *buf = helper->newS(bufLen); + if (!buf) { - std::string s; - _toStdString(s); - int bufLen = s.length() + _parser_buff_len; - char *buf = helper->newS(bufLen); - if (!buf) - { - helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); - return; - } - strcpy(buf, s.c_str()); - std::string().swap(s); - _parser_info.parseDepth = depth; - if (_parser_info.nextToken < 0) - _parser_info.nextToken = 0; - - for (uint16_t i = _parser_info.nextToken; i < _parser_info.tokenCount; i++) - { - - int oDepth = _parser_info.nextDepth; + helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); + return; + } + strcpy(buf, s.c_str()); + std::string().swap(s); + _parser_info.parseDepth = depth; + if (_parser_info.nextToken < 0) + _parser_info.nextToken = 0; - _parseToken(i, buf, _parser_info.nextDepth, (char *)key, index, printMode); + for (uint16_t i = _parser_info.nextToken; i < _parser_info.tokenCount; i++) + { - if (index > -1 && oDepth == _parser_info.nextDepth && _parser_info.tokenMatch) - { - _parser_info.tokenMatch = false; - break; - } + int oDepth = _parser_info.nextDepth; - if (oDepth > _parser_info.nextDepth && index == -1) - { - if (_parser_info.nextDepth > -1 && _parser_info.nextDepth < (int)_pathTk.size()) - { - if (_pathTk[_parser_info.nextDepth].matched) - { - _parser_info.tokenMatch = false; - break; - } - } - } + _parseToken(i, buf, _parser_info.nextDepth, (char *)key, index, printMode); - if (_parser_info.tokenMatch) - { - _pathTk[depth].matched = true; - break; - } - } + if (index > -1 && oDepth == _parser_info.nextDepth && _parser_info.tokenMatch) + { + _parser_info.tokenMatch = false; + break; + } - helper->delS(buf); - if (!_parser_info.tokenMatch) + if (oDepth > _parser_info.nextDepth && index == -1) + { + if (_parser_info.nextDepth > -1 && _parser_info.nextDepth < (int)_pathTk.size()) { - _parser_info.paresRes = false; - _jsonData.success = false; + if (_pathTk[_parser_info.nextDepth].matched) + { + _parser_info.tokenMatch = false; + break; + } } + } + + if (_parser_info.tokenMatch) + { + _pathTk[depth].matched = true; + break; + } + } + + helper->delS(buf); + if (!_parser_info.tokenMatch) + { + _parser_info.paresRes = false; + _jsonData.success = false; } + } } void FirebaseJson::_compile(const char *key, int depth, int index, const char *replace, PRINT_MODE printMode, int refTokenIndex, bool removeTk) { - helper->clearLastError(); - _parser_info.tokenMatch = false; - if (_parser_info.paresRes) + helper->clearLastError(); + _parser_info.tokenMatch = false; + if (_parser_info.paresRes) + { + std::string s; + _toStdString(s); + int bufLen = s.length() + _parser_buff_len; + char *buf = helper->newS(bufLen); + if (!buf) { - std::string s; - _toStdString(s); - int bufLen = s.length() + _parser_buff_len; - char *buf = helper->newS(bufLen); - if (!buf) - { - helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); - return; - } - strcpy(buf, s.c_str()); - std::string().swap(s); - _parser_info.parseDepth = depth; - if (_parser_info.nextToken < 0) - _parser_info.nextToken = 0; - for (uint16_t i = _parser_info.nextToken; i < _parser_info.tokenCount; i++) - { - _compileToken(i, buf, _parser_info.nextDepth, key, index, printMode, replace, refTokenIndex, removeTk); - if (_parser_info.tokenMatch) - break; - } - helper->delS(buf); - if (!_parser_info.tokenMatch) - { - _parser_info.paresRes = false; - _jsonData.success = false; - } + helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); + return; + } + strcpy(buf, s.c_str()); + std::string().swap(s); + _parser_info.parseDepth = depth; + if (_parser_info.nextToken < 0) + _parser_info.nextToken = 0; + for (uint16_t i = _parser_info.nextToken; i < _parser_info.tokenCount; i++) + { + _compileToken(i, buf, _parser_info.nextDepth, key, index, printMode, replace, refTokenIndex, removeTk); + if (_parser_info.tokenMatch) + break; + } + helper->delS(buf); + if (!_parser_info.tokenMatch) + { + _parser_info.paresRes = false; + _jsonData.success = false; } + } } void FirebaseJson::_remove(const char *key, int depth, int index, const char *replace, int refTokenIndex, bool removeTk) { - helper->clearLastError(); - if (_parser_info.paresRes) + helper->clearLastError(); + if (_parser_info.paresRes) + { + std::string s; + _toStdString(s); + int bufLen = s.length() + _parser_buff_len; + char *buf = helper->newS(bufLen); + if (!buf) { - std::string s; - _toStdString(s); - int bufLen = s.length() + _parser_buff_len; - char *buf = helper->newS(bufLen); - if (!buf) - { - helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); - return; - } - strcpy(buf, s.c_str()); - std::string().swap(s); - _parser_info.parseDepth = depth; - if (_parser_info.nextToken < 0) - _parser_info.nextToken = 0; - for (uint16_t i = _parser_info.nextToken; i < _parser_info.tokenCount; i++) - { - _removeToken(i, buf, _parser_info.nextDepth, (char *)key, index, PRINT_MODE_PLAIN, (char *)replace, refTokenIndex, removeTk); - } - helper->delS(buf); + helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); + return; + } + strcpy(buf, s.c_str()); + std::string().swap(s); + _parser_info.parseDepth = depth; + if (_parser_info.nextToken < 0) + _parser_info.nextToken = 0; + for (uint16_t i = _parser_info.nextToken; i < _parser_info.tokenCount; i++) + { + _removeToken(i, buf, _parser_info.nextDepth, (char *)key, index, PRINT_MODE_PLAIN, (char *)replace, refTokenIndex, removeTk); } + helper->delS(buf); + } } bool FirebaseJson::_isArrTk(int index) { - if (index < (int)_pathTk.size()) - return _pathTk[index].tk.c_str()[0] == '[' && _pathTk[index].tk.c_str()[_pathTk[index].tk.length() - 1] == ']'; - else - return false; + if (index < (int)_pathTk.size()) + return _pathTk[index].tk.c_str()[0] == '[' && _pathTk[index].tk.c_str()[_pathTk[index].tk.length() - 1] == ']'; + else + return false; } bool FirebaseJson::_isStrTk(int index) { - if (index < (int)_pathTk.size()) - return _pathTk[index].tk.c_str()[0] == '"' && _pathTk[index].tk.c_str()[_pathTk[index].tk.length() - 1] == '"'; - else - return false; + if (index < (int)_pathTk.size()) + return _pathTk[index].tk.c_str()[0] == '"' && _pathTk[index].tk.c_str()[_pathTk[index].tk.length() - 1] == '"'; + else + return false; } int FirebaseJson::_getArrIndex(int index) { - int res = -1; - if (index < (int)_pathTk.size()) - { - res = atoi(_pathTk[index].tk.substr(1, _pathTk[index].tk.length() - 2).c_str()); - if (res < 0) - res = 0; - } - return res; + int res = -1; + if (index < (int)_pathTk.size()) + { + res = atoi(_pathTk[index].tk.substr(1, _pathTk[index].tk.length() - 2).c_str()); + if (res < 0) + res = 0; + } + return res; } void FirebaseJson::set(const String &path) { - helper->clearLastError(); - _setNull(path.c_str()); + helper->clearLastError(); + _setNull(path.c_str()); } void FirebaseJson::set(const String &path, const String &value) { - helper->clearLastError(); - _setString(path.c_str(), value.c_str()); + helper->clearLastError(); + _setString(path.c_str(), value.c_str()); } void FirebaseJson::set(const String &path, const char *value) { - helper->clearLastError(); - _setString(path.c_str(), value); + helper->clearLastError(); + _setString(path.c_str(), value); } void FirebaseJson::set(const String &path, int value) { - helper->clearLastError(); - _setInt(path.c_str(), value); + helper->clearLastError(); + _setInt(path.c_str(), value); } void FirebaseJson::set(const String &path, unsigned short value) { - helper->clearLastError(); - _setInt(path.c_str(), value); + helper->clearLastError(); + _setInt(path.c_str(), value); } void FirebaseJson::set(const String &path, float value) { - helper->clearLastError(); - _setFloat(path.c_str(), value); + helper->clearLastError(); + _setFloat(path.c_str(), value); } void FirebaseJson::set(const String &path, double value) { - helper->clearLastError(); - _setDouble(path.c_str(), value); + helper->clearLastError(); + _setDouble(path.c_str(), value); } void FirebaseJson::set(const String &path, bool value) { - helper->clearLastError(); - _setBool(path.c_str(), value); + helper->clearLastError(); + _setBool(path.c_str(), value); } void FirebaseJson::set(const String &path, FirebaseJson &json) { - helper->clearLastError(); - _setJson(path.c_str(), &json); + helper->clearLastError(); + _setJson(path.c_str(), &json); } void FirebaseJson::set(const String &path, FirebaseJsonArray &arr) { - helper->clearLastError(); - arr._lastErr = &_lastErr; - _setArray(path.c_str(), &arr); + helper->clearLastError(); + arr._lastErr = &_lastErr; + _setArray(path.c_str(), &arr); } template bool FirebaseJson::set(const String &path, T value) { - if (std::is_same::value) - return _setInt(path, value); - else if (std::is_same::value) - return _setFloat(path, value); - else if (std::is_same::value) - return _setDouble(path, value); - else if (std::is_same::value) - return _setBool(path, value); - else if (std::is_same::value) - return _setString(path, value); - else if (std::is_same::value) - return _setJson(path, &value); - else if (std::is_same::value) - return _setArray(path, &value); + if (std::is_same::value) + return _setInt(path, value); + else if (std::is_same::value) + return _setFloat(path, value); + else if (std::is_same::value) + return _setDouble(path, value); + else if (std::is_same::value) + return _setBool(path, value); + else if (std::is_same::value) + return _setString(path, value); + else if (std::is_same::value) + return _setJson(path, &value); + else if (std::is_same::value) + return _setArray(path, &value); } void FirebaseJson::_setString(const std::string &path, const std::string &value) { - helper->clearLastError(); - char *tmp = helper->newS(value.length() + _parser_buff_len); - if (!tmp) - { - helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); - return; - } - strcpy(tmp, _qt); - strcat(tmp, value.c_str()); - strcat(tmp, _qt); - _set(path.c_str(), tmp); - helper->delS(tmp); - std::string().swap(_jsonData._dbuf); + helper->clearLastError(); + char *tmp = helper->newS(value.length() + _parser_buff_len); + if (!tmp) + { + helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); + return; + } + strcpy(tmp, _qt); + strcat(tmp, value.c_str()); + strcat(tmp, _qt); + _set(path.c_str(), tmp); + helper->delS(tmp); + std::string().swap(_jsonData._dbuf); } void FirebaseJson::_setInt(const std::string &path, int value) { - char *tmp = helper->intStr(value); - _set(path.c_str(), tmp); - helper->delS(tmp); - std::string().swap(_jsonData._dbuf); + char *tmp = helper->intStr(value); + _set(path.c_str(), tmp); + helper->delS(tmp); + std::string().swap(_jsonData._dbuf); } void FirebaseJson::_setFloat(const std::string &path, float value) { - char *tmp = helper->floatStr(value); - helper->trimDouble(tmp); - _set(path.c_str(), tmp); - helper->delS(tmp); - std::string().swap(_jsonData._dbuf); + char *tmp = helper->floatStr(value); + helper->trimDouble(tmp); + _set(path.c_str(), tmp); + helper->delS(tmp); + std::string().swap(_jsonData._dbuf); } void FirebaseJson::_setDouble(const std::string &path, double value) { - char *tmp = helper->doubleStr(value); - helper->trimDouble(tmp); - _set(path.c_str(), tmp); - helper->delS(tmp); - std::string().swap(_jsonData._dbuf); + char *tmp = helper->doubleStr(value); + helper->trimDouble(tmp); + _set(path.c_str(), tmp); + helper->delS(tmp); + std::string().swap(_jsonData._dbuf); } void FirebaseJson::_setBool(const std::string &path, bool value) { - if (value) - _set(path.c_str(), _tr); - else - _set(path.c_str(), _fls); - std::string().swap(_jsonData._dbuf); + if (value) + _set(path.c_str(), _tr); + else + _set(path.c_str(), _fls); + std::string().swap(_jsonData._dbuf); } void FirebaseJson::_setNull(const std::string &path) { - _set(path.c_str(), _nll); - std::string().swap(_jsonData._dbuf); + _set(path.c_str(), _nll); + std::string().swap(_jsonData._dbuf); } void FirebaseJson::_setJson(const std::string &path, FirebaseJson *json) { - std::string s; - json->_toStdString(s); - _set(path.c_str(), s.c_str()); - std::string().swap(s); + std::string s; + json->_toStdString(s); + _set(path.c_str(), s.c_str()); + std::string().swap(s); } void FirebaseJson::_setArray(const std::string &path, FirebaseJsonArray *arr) { - arr->_lastErr = &_lastErr; - std::string s; - arr->_toStdString(s); - _set(path.c_str(), s.c_str()); - std::string().swap(s); + arr->_lastErr = &_lastErr; + std::string s; + arr->_toStdString(s); + _set(path.c_str(), s.c_str()); + std::string().swap(s); } void FirebaseJson::_set(const char *path, const char *data) { - helper->clearLastError(); - clearPathTk(); - std::string _path; - - if (_topLevelTkType == JSMN_ARRAY) - { - char *_root = helper->strP(fb_json_str_26); - char *_slash = helper->strP(fb_json_str_27); - _path = _root; - _path += _slash; - _path += path; - helper->delS(_root); - helper->delS(_slash); - } + helper->clearLastError(); + clearPathTk(); + std::string _path; + + if (_topLevelTkType == JSMN_ARRAY) + { + char *_root = helper->strP(fb_json_str_26); + char *_slash = helper->strP(fb_json_str_27); + _path = _root; + _path += _slash; + _path += path; + helper->delS(_root); + helper->delS(_slash); + } + else + _path = path; + + _strToTk(_path.c_str(), _pathTk, '/'); + _fbjs_parse(); + std::string().swap(_path); + if (!_jsonData.success) + return; + _jsonData.success = false; + int len = _pathTk.size(); + + _resetParsserInfo(); + + _parser_info.remTkIndex = -1; + _parser_info.remFirstTk = false; + _parser_info.remLastTk = false; + _el.clear(); + _eltk.clear(); + for (int i = 0; i < len; i++) + { + if (_isStrTk(i)) + _compile(_pathTk[i].tk.c_str(), i, -1, data, PRINT_MODE_PLAIN); + else if (_isArrTk(i)) + _compile("", i, _getArrIndex(i), data, PRINT_MODE_PLAIN); else - _path = path; - - _strToTk(_path.c_str(), _pathTk, '/'); - _fbjs_parse(); - std::string().swap(_path); - if (!_jsonData.success) - return; - _jsonData.success = false; - int len = _pathTk.size(); + _compile(_pathTk[i].tk.c_str(), i, -1, data, PRINT_MODE_PLAIN); + } + _el.clear(); + _eltk.clear(); + if (_parser_info.parseCompleted != len) + { + std::string().swap(_jsonData._dbuf); + std::string().swap(_tbuf); + int refTokenIndex = _parser_info.refTkIndex; _resetParsserInfo(); - _parser_info.remTkIndex = -1; - _parser_info.remFirstTk = false; - _parser_info.remLastTk = false; - _el.clear(); - _eltk.clear(); + _parser_info.tokenMatch = false; + _parser_info.paresRes = true; for (int i = 0; i < len; i++) { - if (_isStrTk(i)) - _compile(_pathTk[i].tk.c_str(), i, -1, data, PRINT_MODE_PLAIN); - else if (_isArrTk(i)) - _compile("", i, _getArrIndex(i), data, PRINT_MODE_PLAIN); - else - _compile(_pathTk[i].tk.c_str(), i, -1, data, PRINT_MODE_PLAIN); + if (_isStrTk(i)) + _compile(_pathTk[i].tk.c_str(), i, -1, data, PRINT_MODE_PLAIN, refTokenIndex); + else if (_isArrTk(i)) + _compile("", i, _getArrIndex(i), data, PRINT_MODE_PLAIN, refTokenIndex); + else + _compile(_pathTk[i].tk.c_str(), i, -1, data, PRINT_MODE_PLAIN, refTokenIndex); } _el.clear(); _eltk.clear(); - if (_parser_info.parseCompleted != len) - { - std::string().swap(_jsonData._dbuf); - std::string().swap(_tbuf); - int refTokenIndex = _parser_info.refTkIndex; - - _resetParsserInfo(); - - _parser_info.tokenMatch = false; - _parser_info.paresRes = true; - for (int i = 0; i < len; i++) - { - if (_isStrTk(i)) - _compile(_pathTk[i].tk.c_str(), i, -1, data, PRINT_MODE_PLAIN, refTokenIndex); - else if (_isArrTk(i)) - _compile("", i, _getArrIndex(i), data, PRINT_MODE_PLAIN, refTokenIndex); - else - _compile(_pathTk[i].tk.c_str(), i, -1, data, PRINT_MODE_PLAIN, refTokenIndex); - } - _el.clear(); - _eltk.clear(); - } - if (_jsonData._dbuf.length() >= 2) - { - _jsonData.success = true; - _rawbuf = _jsonData._dbuf.substr(1, _jsonData._dbuf.length() - 2); - } - else - _rawbuf.clear(); - clearPathTk(); - std::string().swap(_jsonData._dbuf); - std::string().swap(_tbuf); - _tokens.reset(); - _tokens = nullptr; + } + if (_jsonData._dbuf.length() >= 2) + { + _jsonData.success = true; + _rawbuf = _jsonData._dbuf.substr(1, _jsonData._dbuf.length() - 2); + } + else + _rawbuf.clear(); + clearPathTk(); + std::string().swap(_jsonData._dbuf); + std::string().swap(_tbuf); + _tokens.reset(); + _tokens = nullptr; } bool FirebaseJson::remove(const String &path) { - helper->clearLastError(); - clearPathTk(); - std::string _path; + helper->clearLastError(); + clearPathTk(); + std::string _path; + + if (_topLevelTkType == JSMN_ARRAY) + { + char *_root = helper->strP(fb_json_str_26); + char *_slash = helper->strP(fb_json_str_27); + _path = _root; + _path += _slash; + _path += path.c_str(); + helper->delS(_root); + helper->delS(_slash); + } + else + _path = path.c_str(); + + _strToTk(_path.c_str(), _pathTk, '/'); + _fbjs_parse(); + std::string().swap(_path); + if (!_jsonData.success) + return false; - if (_topLevelTkType == JSMN_ARRAY) - { - char *_root = helper->strP(fb_json_str_26); - char *_slash = helper->strP(fb_json_str_27); - _path = _root; - _path += _slash; - _path += path.c_str(); - helper->delS(_root); - helper->delS(_slash); - } + _jsonData.success = false; + int len = _pathTk.size(); + + _resetParsserInfo(); + + _parser_info.remTkIndex = -1; + _parser_info.remFirstTk = false; + _parser_info.remLastTk = false; + _el.clear(); + _eltk.clear(); + for (int i = 0; i < len; i++) + { + if (_isStrTk(i)) + _compile(_pathTk[i].tk.c_str(), i, -1, "", PRINT_MODE_NONE, -1, true); + else if (_isArrTk(i)) + _compile("", i, _getArrIndex(i), "", PRINT_MODE_NONE, -1, true); else - _path = path.c_str(); - - _strToTk(_path.c_str(), _pathTk, '/'); - _fbjs_parse(); - std::string().swap(_path); - if (!_jsonData.success) - return false; - - _jsonData.success = false; - int len = _pathTk.size(); + _compile(_pathTk[i].tk.c_str(), i, -1, "", PRINT_MODE_NONE, -1, true); + } + _el.clear(); + _eltk.clear(); + std::string().swap(_jsonData._dbuf); + int refTokenIndex = _parser_info.remTkIndex; + if (_parser_info.parseCompleted == len) + { _resetParsserInfo(); - _parser_info.remTkIndex = -1; - _parser_info.remFirstTk = false; - _parser_info.remLastTk = false; - _el.clear(); - _eltk.clear(); - for (int i = 0; i < len; i++) - { - if (_isStrTk(i)) - _compile(_pathTk[i].tk.c_str(), i, -1, "", PRINT_MODE_NONE, -1, true); - else if (_isArrTk(i)) - _compile("", i, _getArrIndex(i), "", PRINT_MODE_NONE, -1, true); - else - _compile(_pathTk[i].tk.c_str(), i, -1, "", PRINT_MODE_NONE, -1, true); - } + _parser_info.tokenMatch = false; + _parser_info.paresRes = true; + _jsonData.success = true; + _lastTk.skip = false; + _lastTk.olen = 0; + _lastTk.oindex = 0; + if (_isStrTk(len - 1)) + _remove(_pathTk[len - 1].tk.c_str(), -1, -1, "", refTokenIndex, true); + else + _remove("", -1, _getArrIndex(len - 1), "", refTokenIndex, true); + _jsonData._dbuf += _tbuf; _el.clear(); _eltk.clear(); - std::string().swap(_jsonData._dbuf); - int refTokenIndex = _parser_info.remTkIndex; - if (_parser_info.parseCompleted == len) - { - - _resetParsserInfo(); - - _parser_info.tokenMatch = false; - _parser_info.paresRes = true; - _jsonData.success = true; - _lastTk.skip = false; - _lastTk.olen = 0; - _lastTk.oindex = 0; - if (_isStrTk(len - 1)) - _remove(_pathTk[len - 1].tk.c_str(), -1, -1, "", refTokenIndex, true); - else - _remove("", -1, _getArrIndex(len - 1), "", refTokenIndex, true); - _jsonData._dbuf += _tbuf; - _el.clear(); - _eltk.clear(); - } - if (_jsonData._dbuf.length() >= 2) - _rawbuf = _jsonData._dbuf.substr(1, _jsonData._dbuf.length() - 2); - else - _rawbuf.clear(); - clearPathTk(); - std::string().swap(_jsonData._dbuf); - std::string().swap(_tbuf); - _tokens.reset(); - _tokens = nullptr; - return _jsonData.success; + } + if (_jsonData._dbuf.length() >= 2) + _rawbuf = _jsonData._dbuf.substr(1, _jsonData._dbuf.length() - 2); + else + _rawbuf.clear(); + + //fix for the remaining parent when all childs removed + if (_rawbuf.length() > 0) + { + char *temp = helper->strP(fb_json_str_32); + size_t p1 = _rawbuf.find(temp); + helper->delS(temp); + + if (p1 == std::string::npos) + { + temp = helper->strP(fb_json_str_33); + p1 = _rawbuf.find(temp); + helper->delS(temp); + } + + if (p1 != std::string::npos) + { + int p3 = p1; + if (p3 > 0) + p3--; + temp = helper->strP(fb_json_str_2); + size_t p2 = _rawbuf.rfind(temp, p3); + helper->delS(temp); + if (p2 != std::string::npos) + { + if (p2 > 0) + { + if (_rawbuf[p2 - 1] == ',') + p2--; + } + p1 += 2; + _rawbuf.replace(p2, p1 - p2, ""); + } + } + } + + clearPathTk(); + std::string().swap(_jsonData._dbuf); + std::string().swap(_tbuf); + _tokens.reset(); + _tokens = nullptr; + return _jsonData.success; } fb_json_last_error_t FirebaseJson::getLastError() { - return _lastErr; + return _lastErr; } void FirebaseJson::_resetParsserInfo() { - _parser_info.nextDepth = -1; - _parser_info.nextToken = 0; - _parser_info.skipDepth = -1; - _parser_info.parentIndex = -1; - _parser_info.TkRefOk = false; - _parser_info.parseCompleted = 0; - _parser_info.arrReplaced = false; - _parser_info.refTkIndex = -1; -} - -void FirebaseJson::_resetParseResult() -{ - _jsonData._type = 0; - _jsonData.type = ""; - _jsonData.typeNum = 0; - _jsonData.stringValue = ""; - _jsonData._dbuf = ""; - _jsonData.intValue = 0; - _jsonData.floatValue = 0; - _jsonData.doubleValue = 0; - _jsonData.boolValue = false; + _parser_info.nextDepth = -1; + _parser_info.nextToken = 0; + _parser_info.skipDepth = -1; + _parser_info.parentIndex = -1; + _parser_info.TkRefOk = false; + _parser_info.parseCompleted = 0; + _parser_info.arrReplaced = false; + _parser_info.refTkIndex = -1; } - -void FirebaseJson::_setElementType() -{ - helper->clearLastError(); - bool typeSet = false; - char *buf = helper->newS(_parser_buff_len); - char *tmp = helper->newS(_parser_buff_len); - if (!buf || !tmp) - { - helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); - return; - } - char *tmp2 = nullptr; - if (_jsonData._type == JSMN_PRIMITIVE) - { - tmp2 = helper->newS(_jsonData.stringValue.length() + 1); - if (!tmp2) - { - helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); - return; - } - strcpy(tmp2, _jsonData.stringValue.c_str()); - } - switch (_jsonData._type) - { - case JSMN_UNDEFINED: - strcpy(buf, _undef); - _jsonData.typeNum = JSON_UNDEFINED; - break; - case JSMN_OBJECT: - strcpy(buf, _obj); - _jsonData.typeNum = JSON_OBJECT; - break; - case JSMN_ARRAY: - strcpy(buf, _arry); - _jsonData.typeNum = JSON_ARRAY; - break; - case JSMN_STRING: - strcpy(buf, _string); - _jsonData.typeNum = JSON_STRING; - break; - case JSMN_PRIMITIVE: - if (!typeSet && strcmp(tmp2, _tr) == 0) - { - typeSet = true; - strcpy(buf, _bl); - _jsonData.typeNum = JSON_BOOL; - _jsonData.boolValue = true; - _jsonData.floatValue = 1.0f; - _jsonData.doubleValue = 1.0; - _jsonData.intValue = 1; - } - else - { - if (!typeSet && strcmp(tmp2, _fls) == 0) - { - typeSet = true; - strcpy(buf, _bl); - _jsonData.typeNum = JSON_BOOL; - _jsonData.boolValue = false; - _jsonData.floatValue = 0.0f; - _jsonData.doubleValue = 0.0; - _jsonData.intValue = 0; - } - } - - if (!typeSet && strcmp(tmp2, _nll) == 0) - { - typeSet = true; - strcpy(buf, _nll); - _jsonData.typeNum = JSON_NULL; - } - if (!typeSet) - { - typeSet = true; - strcpy(tmp, _dot); - double d = atof(tmp2); - if (d > 0x7fffffff) - { - strcpy(buf, _dbl); - _jsonData.floatValue = (float)d; - _jsonData.doubleValue = d; - _jsonData.intValue = atoi(tmp2); - _jsonData.boolValue = atof(tmp2) > 0 ? true : false; - _jsonData.typeNum = JSON_DOUBLE; - } - else - { - if (helper->strpos(tmp2, tmp, 0) > -1) - { - strcpy(buf, _dbl); - _jsonData.floatValue = (float)d; - _jsonData.doubleValue = d; - _jsonData.intValue = atoi(tmp2); - _jsonData.boolValue = atof(tmp2) > 0 ? true : false; - _jsonData.typeNum = JSON_FLOAT; - } - else - { - _jsonData.intValue = atoi(tmp2); - _jsonData.floatValue = atof(tmp2); - _jsonData.doubleValue = atof(tmp2); - _jsonData.boolValue = atof(tmp2) > 0 ? true : false; - strcpy(buf, _int); - _jsonData.typeNum = JSON_INT; - } - } - } - break; - default: - break; + +void FirebaseJson::_resetParseResult() +{ + _jsonData._type = 0; + _jsonData.type = ""; + _jsonData.typeNum = 0; + _jsonData.stringValue = ""; + _jsonData._dbuf = ""; + _jsonData.intValue = 0; + _jsonData.floatValue = 0; + _jsonData.doubleValue = 0; + _jsonData.boolValue = false; +} + +void FirebaseJson::_setElementType() +{ + helper->clearLastError(); + bool typeSet = false; + char *buf = helper->newS(_parser_buff_len); + char *tmp = helper->newS(_parser_buff_len); + if (!buf || !tmp) + { + helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); + return; + } + char *tmp2 = nullptr; + if (_jsonData._type == JSMN_PRIMITIVE) + { + tmp2 = helper->newS(_jsonData.stringValue.length() + 1); + if (!tmp2) + { + helper->setLastError(-1, __FILE__, __LINE__, fb_json_str_28); + return; + } + strcpy(tmp2, _jsonData.stringValue.c_str()); + } + switch (_jsonData._type) + { + case JSMN_UNDEFINED: + strcpy(buf, _undef); + _jsonData.typeNum = JSON_UNDEFINED; + break; + case JSMN_OBJECT: + strcpy(buf, _obj); + _jsonData.typeNum = JSON_OBJECT; + break; + case JSMN_ARRAY: + strcpy(buf, _arry); + _jsonData.typeNum = JSON_ARRAY; + break; + case JSMN_STRING: + strcpy(buf, _string); + _jsonData.typeNum = JSON_STRING; + break; + case JSMN_PRIMITIVE: + if (!typeSet && strcmp(tmp2, _tr) == 0) + { + typeSet = true; + strcpy(buf, _bl); + _jsonData.typeNum = JSON_BOOL; + _jsonData.boolValue = true; + _jsonData.floatValue = 1.0f; + _jsonData.doubleValue = 1.0; + _jsonData.intValue = 1; } - _jsonData.type = buf; - helper->delS(buf); - helper->delS(tmp); - if (tmp2) - helper->delS(tmp2); + else + { + if (!typeSet && strcmp(tmp2, _fls) == 0) + { + typeSet = true; + strcpy(buf, _bl); + _jsonData.typeNum = JSON_BOOL; + _jsonData.boolValue = false; + _jsonData.floatValue = 0.0f; + _jsonData.doubleValue = 0.0; + _jsonData.intValue = 0; + } + } + + if (!typeSet && strcmp(tmp2, _nll) == 0) + { + typeSet = true; + strcpy(buf, _nll); + _jsonData.typeNum = JSON_NULL; + } + if (!typeSet) + { + typeSet = true; + strcpy(tmp, _dot); + double d = atof(tmp2); + if (d > 0x7fffffff) + { + strcpy(buf, _dbl); + _jsonData.floatValue = (float)d; + _jsonData.doubleValue = d; + _jsonData.intValue = atoi(tmp2); + _jsonData.boolValue = atof(tmp2) > 0 ? true : false; + _jsonData.typeNum = JSON_DOUBLE; + } + else + { + if (helper->strpos(tmp2, tmp, 0) > -1) + { + strcpy(buf, _dbl); + _jsonData.floatValue = (float)d; + _jsonData.doubleValue = d; + _jsonData.intValue = atoi(tmp2); + _jsonData.boolValue = atof(tmp2) > 0 ? true : false; + _jsonData.typeNum = JSON_FLOAT; + } + else + { + _jsonData.intValue = atoi(tmp2); + _jsonData.floatValue = atof(tmp2); + _jsonData.doubleValue = atof(tmp2); + _jsonData.boolValue = atof(tmp2) > 0 ? true : false; + strcpy(buf, _int); + _jsonData.typeNum = JSON_INT; + } + } + } + break; + default: + break; + } + _jsonData.type = buf; + helper->delS(buf); + helper->delS(tmp); + if (tmp2) + helper->delS(tmp2); } /** @@ -2725,18 +2759,18 @@ void FirebaseJson::_setElementType() FirebaseJson::fbjs_tok_t *FirebaseJson::fbjs_alloc_token(fbjs_parser *parser, FirebaseJson::fbjs_tok_t *tokens, size_t num_tokens) { - FirebaseJson::fbjs_tok_t *tok; - if (parser->toknext >= num_tokens) - { - return NULL; - } - tok = &tokens[parser->toknext++]; - tok->start = tok->end = -1; - tok->size = 0; + FirebaseJson::fbjs_tok_t *tok; + if (parser->toknext >= num_tokens) + { + return NULL; + } + tok = &tokens[parser->toknext++]; + tok->start = tok->end = -1; + tok->size = 0; #ifdef JSMN_PARENT_LINKS - tok->parent = -1; + tok->parent = -1; #endif - return tok; + return tok; } /** @@ -2745,10 +2779,10 @@ FirebaseJson::fbjs_tok_t *FirebaseJson::fbjs_alloc_token(fbjs_parser *parser, void FirebaseJson::fbjs_fill_token(fbjs_tok_t *token, fbjs_type_t type, int start, int end) { - token->type = type; - token->start = start; - token->end = end; - token->size = 0; + token->type = type; + token->start = start; + token->end = end; + token->size = 0; } /** @@ -2757,58 +2791,58 @@ void FirebaseJson::fbjs_fill_token(fbjs_tok_t *token, fbjs_type_t type, int FirebaseJson::fbjs_parse_primitive(fbjs_parser *parser, const char *js, size_t len, fbjs_tok_t *tokens, size_t num_tokens) { - fbjs_tok_t *token; - int start; + fbjs_tok_t *token; + int start; - start = parser->pos; + start = parser->pos; - for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) + { + switch (js[parser->pos]) { - switch (js[parser->pos]) - { #ifndef JSMN_STRICT - /* In strict mode primitive must be followed by "," or "}" or "]" */ - case ':': + /* In strict mode primitive must be followed by "," or "}" or "]" */ + case ':': #endif - case '\t': - case '\r': - case '\n': - case ' ': - case ',': - case ']': - case '}': - goto found; - } - if (js[parser->pos] < 32 || js[parser->pos] >= 127) - { - parser->pos = start; - return JSMN_ERROR_INVAL; - } + case '\t': + case '\r': + case '\n': + case ' ': + case ',': + case ']': + case '}': + goto found; } + if (js[parser->pos] < 32 || js[parser->pos] >= 127) + { + parser->pos = start; + return JSMN_ERROR_INVAL; + } + } #ifdef JSMN_STRICT - /* In strict mode primitive must be followed by a comma/object/array */ - parser->pos = start; - return JSMN_ERROR_PART; + /* In strict mode primitive must be followed by a comma/object/array */ + parser->pos = start; + return JSMN_ERROR_PART; #endif found: - if (tokens == NULL) - { - parser->pos--; - return 0; - } - token = fbjs_alloc_token(parser, tokens, num_tokens); - if (token == NULL) - { - parser->pos = start; - return JSMN_ERROR_NOMEM; - } - fbjs_fill_token(token, JSMN_PRIMITIVE, start, parser->pos); -#ifdef JSMN_PARENT_LINKS - token->parent = parser->toksuper; -#endif + if (tokens == NULL) + { parser->pos--; return 0; + } + token = fbjs_alloc_token(parser, tokens, num_tokens); + if (token == NULL) + { + parser->pos = start; + return JSMN_ERROR_NOMEM; + } + fbjs_fill_token(token, JSMN_PRIMITIVE, start, parser->pos); +#ifdef JSMN_PARENT_LINKS + token->parent = parser->toksuper; +#endif + parser->pos--; + return 0; } /** @@ -2817,80 +2851,80 @@ int FirebaseJson::fbjs_parse_primitive(fbjs_parser *parser, const char *js, int FirebaseJson::fbjs_parse_string(fbjs_parser *parser, const char *js, size_t len, fbjs_tok_t *tokens, size_t num_tokens) { - fbjs_tok_t *token; + fbjs_tok_t *token; - int start = parser->pos; + int start = parser->pos; - parser->pos++; + parser->pos++; - /* Skip starting quote */ - for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) - { - char c = js[parser->pos]; + /* Skip starting quote */ + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) + { + char c = js[parser->pos]; - /* Quote: end of string */ - if (c == '\"') - { - if (tokens == NULL) - { - return 0; - } - token = fbjs_alloc_token(parser, tokens, num_tokens); - if (token == NULL) - { - parser->pos = start; - return JSMN_ERROR_NOMEM; - } - fbjs_fill_token(token, JSMN_STRING, start + 1, parser->pos); + /* Quote: end of string */ + if (c == '\"') + { + if (tokens == NULL) + { + return 0; + } + token = fbjs_alloc_token(parser, tokens, num_tokens); + if (token == NULL) + { + parser->pos = start; + return JSMN_ERROR_NOMEM; + } + fbjs_fill_token(token, JSMN_STRING, start + 1, parser->pos); #ifdef JSMN_PARENT_LINKS - token->parent = parser->toksuper; + token->parent = parser->toksuper; #endif - return 0; - } - - /* Backslash: Quoted symbol expected */ - if (c == '\\' && parser->pos + 1 < len) - { - int i; - parser->pos++; - switch (js[parser->pos]) - { - /* Allowed escaped symbols */ - case '\"': - case '/': - case '\\': - case 'b': - case 'f': - case 'r': - case 'n': - case 't': - break; - /* Allows escaped symbol \uXXXX */ - case 'u': - parser->pos++; - for (i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) - { - /* If it isn't a hex character we have an error */ - if (!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */ - (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */ - (js[parser->pos] >= 97 && js[parser->pos] <= 102))) - { /* a-f */ - parser->pos = start; - return JSMN_ERROR_INVAL; - } - parser->pos++; - } - parser->pos--; - break; - /* Unexpected symbol */ - default: - parser->pos = start; - return JSMN_ERROR_INVAL; - } + return 0; + } + + /* Backslash: Quoted symbol expected */ + if (c == '\\' && parser->pos + 1 < len) + { + int i; + parser->pos++; + switch (js[parser->pos]) + { + /* Allowed escaped symbols */ + case '\"': + case '/': + case '\\': + case 'b': + case 'f': + case 'r': + case 'n': + case 't': + break; + /* Allows escaped symbol \uXXXX */ + case 'u': + parser->pos++; + for (i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) + { + /* If it isn't a hex character we have an error */ + if (!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */ + (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */ + (js[parser->pos] >= 97 && js[parser->pos] <= 102))) + { /* a-f */ + parser->pos = start; + return JSMN_ERROR_INVAL; + } + parser->pos++; } + parser->pos--; + break; + /* Unexpected symbol */ + default: + parser->pos = start; + return JSMN_ERROR_INVAL; + } } - parser->pos = start; - return JSMN_ERROR_PART; + } + parser->pos = start; + return JSMN_ERROR_PART; } /** @@ -2899,204 +2933,204 @@ int FirebaseJson::fbjs_parse_string(fbjs_parser *parser, const char *js, int FirebaseJson::fbjs_parse(fbjs_parser *parser, const char *js, size_t len, fbjs_tok_t *tokens, unsigned int num_tokens) { - int r; - int i; - fbjs_tok_t *token; - int count = parser->toknext; + int r; + int i; + fbjs_tok_t *token; + int count = parser->toknext; - for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) - { - char c; - fbjs_type_t type; + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) + { + char c; + fbjs_type_t type; - c = js[parser->pos]; - switch (c) - { - case '{': - case '[': - count++; - if (tokens == NULL) - { - break; - } - token = fbjs_alloc_token(parser, tokens, num_tokens); - if (token == NULL) - return JSMN_ERROR_NOMEM; - if (parser->toksuper != -1) - { - tokens[parser->toksuper].size++; + c = js[parser->pos]; + switch (c) + { + case '{': + case '[': + count++; + if (tokens == NULL) + { + break; + } + token = fbjs_alloc_token(parser, tokens, num_tokens); + if (token == NULL) + return JSMN_ERROR_NOMEM; + if (parser->toksuper != -1) + { + tokens[parser->toksuper].size++; #ifdef JSMN_PARENT_LINKS - token->parent = parser->toksuper; + token->parent = parser->toksuper; #endif - } - token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY); - token->start = parser->pos; - parser->toksuper = parser->toknext - 1; - if (parser->pos > 0) - if (js[parser->pos - 1] == '{' && js[parser->pos] == '[') - return JSMN_ERROR_INVAL; - break; - case '}': - case ']': - if (tokens == NULL) - break; - type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); + } + token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY); + token->start = parser->pos; + parser->toksuper = parser->toknext - 1; + if (parser->pos > 0) + if (js[parser->pos - 1] == '{' && js[parser->pos] == '[') + return JSMN_ERROR_INVAL; + break; + case '}': + case ']': + if (tokens == NULL) + break; + type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); #ifdef JSMN_PARENT_LINKS - if (parser->toknext < 1) - { - return JSMN_ERROR_INVAL; - } - token = &tokens[parser->toknext - 1]; - for (;;) - { - if (token->start != -1 && token->end == -1) - { - if (token->type != type) - { - return JSMN_ERROR_INVAL; - } - token->end = parser->pos + 1; - parser->toksuper = token->parent; - break; - } - if (token->parent == -1) - { - if (token->type != type || parser->toksuper == -1) - { - return JSMN_ERROR_INVAL; - } - break; - } - token = &tokens[token->parent]; - } + if (parser->toknext < 1) + { + return JSMN_ERROR_INVAL; + } + token = &tokens[parser->toknext - 1]; + for (;;) + { + if (token->start != -1 && token->end == -1) + { + if (token->type != type) + { + return JSMN_ERROR_INVAL; + } + token->end = parser->pos + 1; + parser->toksuper = token->parent; + break; + } + if (token->parent == -1) + { + if (token->type != type || parser->toksuper == -1) + { + return JSMN_ERROR_INVAL; + } + break; + } + token = &tokens[token->parent]; + } #else - for (i = parser->toknext - 1; i >= 0; i--) - { - token = &tokens[i]; - if (token->start != -1 && token->end == -1) - { - if (token->type != type) - { - return JSMN_ERROR_INVAL; - } - parser->toksuper = -1; - token->end = parser->pos + 1; - break; - } - } - /* Error if unmatched closing bracket */ - if (i == -1) - return JSMN_ERROR_INVAL; - for (; i >= 0; i--) - { - token = &tokens[i]; - if (token->start != -1 && token->end == -1) - { - parser->toksuper = i; - break; - } - } + for (i = parser->toknext - 1; i >= 0; i--) + { + token = &tokens[i]; + if (token->start != -1 && token->end == -1) + { + if (token->type != type) + { + return JSMN_ERROR_INVAL; + } + parser->toksuper = -1; + token->end = parser->pos + 1; + break; + } + } + /* Error if unmatched closing bracket */ + if (i == -1) + return JSMN_ERROR_INVAL; + for (; i >= 0; i--) + { + token = &tokens[i]; + if (token->start != -1 && token->end == -1) + { + parser->toksuper = i; + break; + } + } #endif - break; - case '\"': - r = fbjs_parse_string(parser, js, len, tokens, num_tokens); - if (r < 0) - return r; - count++; - if (parser->toksuper != -1 && tokens != NULL) - tokens[parser->toksuper].size++; - break; - case '\t': - case '\r': - case '\n': - case ' ': - break; - case ':': - parser->toksuper = parser->toknext - 1; - break; - case ',': - if (tokens != NULL && parser->toksuper != -1 && - tokens[parser->toksuper].type != JSMN_ARRAY && - tokens[parser->toksuper].type != JSMN_OBJECT) - { + break; + case '\"': + r = fbjs_parse_string(parser, js, len, tokens, num_tokens); + if (r < 0) + return r; + count++; + if (parser->toksuper != -1 && tokens != NULL) + tokens[parser->toksuper].size++; + break; + case '\t': + case '\r': + case '\n': + case ' ': + break; + case ':': + parser->toksuper = parser->toknext - 1; + break; + case ',': + if (tokens != NULL && parser->toksuper != -1 && + tokens[parser->toksuper].type != JSMN_ARRAY && + tokens[parser->toksuper].type != JSMN_OBJECT) + { #ifdef JSMN_PARENT_LINKS - parser->toksuper = tokens[parser->toksuper].parent; + parser->toksuper = tokens[parser->toksuper].parent; #else - for (i = parser->toknext - 1; i >= 0; i--) - { - if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) - { - if (tokens[i].start != -1 && tokens[i].end == -1) - { - parser->toksuper = i; - break; - } - } - } -#endif - } - break; -#ifdef JSMN_STRICT - /* In strict mode primitives are: numbers and booleans */ - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case 't': - case 'f': - case 'n': - - /* And they must not be keys of the object */ - if (tokens != NULL && parser->toksuper != -1) + for (i = parser->toknext - 1; i >= 0; i--) + { + if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) + { + if (tokens[i].start != -1 && tokens[i].end == -1) { - fbjs_tok_t *t = &tokens[parser->toksuper]; - if (t->type == JSMN_OBJECT || - (t->type == JSMN_STRING && t->size != 0)) - { - return JSMN_ERROR_INVAL; - } + parser->toksuper = i; + break; } + } + } +#endif + } + break; +#ifdef JSMN_STRICT + /* In strict mode primitives are: numbers and booleans */ + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case 't': + case 'f': + case 'n': + + /* And they must not be keys of the object */ + if (tokens != NULL && parser->toksuper != -1) + { + fbjs_tok_t *t = &tokens[parser->toksuper]; + if (t->type == JSMN_OBJECT || + (t->type == JSMN_STRING && t->size != 0)) + { + return JSMN_ERROR_INVAL; + } + } #else - /* In non-strict mode every unquoted value is a primitive */ - default: + /* In non-strict mode every unquoted value is a primitive */ + default: #endif - r = fbjs_parse_primitive(parser, js, len, tokens, num_tokens); - if (r < 0) - return r; - count++; - if (parser->toksuper != -1 && tokens != NULL) - tokens[parser->toksuper].size++; - break; + r = fbjs_parse_primitive(parser, js, len, tokens, num_tokens); + if (r < 0) + return r; + count++; + if (parser->toksuper != -1 && tokens != NULL) + tokens[parser->toksuper].size++; + break; #ifdef JSMN_STRICT - /* Unexpected char in strict mode */ - default: - return JSMN_ERROR_INVAL; + /* Unexpected char in strict mode */ + default: + return JSMN_ERROR_INVAL; #endif - } } + } - if (tokens != NULL) + if (tokens != NULL) + { + for (i = parser->toknext - 1; i >= 0; i--) { - for (i = parser->toknext - 1; i >= 0; i--) - { - /* Unmatched opened object or array */ - if (tokens[i].start != -1 && tokens[i].end == -1) - { - return JSMN_ERROR_PART; - } - } + /* Unmatched opened object or array */ + if (tokens[i].start != -1 && tokens[i].end == -1) + { + return JSMN_ERROR_PART; + } } + } - return count; + return count; } /** @@ -3105,730 +3139,730 @@ int FirebaseJson::fbjs_parse(fbjs_parser *parser, const char *js, size_t len, */ void FirebaseJson::fbjs_init(fbjs_parser *parser) { - parser->pos = 0; - parser->toknext = 0; - parser->toksuper = -1; + parser->pos = 0; + parser->toknext = 0; + parser->toksuper = -1; } FirebaseJsonArray::FirebaseJsonArray() { - _init(); + _init(); } FirebaseJsonArray::FirebaseJsonArray(fb_json_last_error_t *lastErr, size_t bufLimit) { - if (bufLimit >= 32 || bufLimit <= 8192) - _parser_buff_len = bufLimit; - _lastErr = lastErr; + if (bufLimit >= 32 || bufLimit <= 8192) + _parser_buff_len = bufLimit; + _lastErr = lastErr; }; FirebaseJsonArray::~FirebaseJsonArray() { - _finalize(); - std::string().swap(_jbuf); - delete helper; + _finalize(); + std::string().swap(_jbuf); + delete helper; }; void FirebaseJsonArray::_init() { - _finalize(); + _finalize(); - _pd = helper->strP(fb_json_str_4); - _pf = helper->strP(fb_json_str_5); - _fls = helper->strP(fb_json_str_6); - _tr = helper->strP(fb_json_str_7); - _brk3 = helper->strP(fb_json_str_10); - _brk4 = helper->strP(fb_json_str_11); - _nll = helper->strP(fb_json_str_18); - _root = helper->strP(fb_json_str_21); - _root2 = helper->strP(fb_json_str_26); - _qt = helper->strP(fb_json_str_2); - _slash = helper->strP(fb_json_str_27); - helper->clearLastError(); + _pd = helper->strP(fb_json_str_4); + _pf = helper->strP(fb_json_str_5); + _fls = helper->strP(fb_json_str_6); + _tr = helper->strP(fb_json_str_7); + _brk3 = helper->strP(fb_json_str_10); + _brk4 = helper->strP(fb_json_str_11); + _nll = helper->strP(fb_json_str_18); + _root = helper->strP(fb_json_str_21); + _root2 = helper->strP(fb_json_str_26); + _qt = helper->strP(fb_json_str_2); + _slash = helper->strP(fb_json_str_27); + helper->clearLastError(); } std::string *FirebaseJsonArray::int_dbuf() { - return &_json._jsonData._dbuf; + return &_json._jsonData._dbuf; } std::string *FirebaseJsonArray::int_tbuf() { - return &_json._tbuf; + return &_json._tbuf; } std::string *FirebaseJsonArray::int_jbuf() { - return &_jbuf; + return &_jbuf; } std::string *FirebaseJsonArray::int_rawbuf() { - return &_json._rawbuf; + return &_json._rawbuf; } FirebaseJson *FirebaseJsonArray::int_json() { - return &_json; + return &_json; } void FirebaseJsonArray::int_set_arr_len(size_t len) { - _arrLen = len; + _arrLen = len; } void FirebaseJsonArray::_finalize() { - helper->delS(_pd); - helper->delS(_pf); - helper->delS(_fls); - helper->delS(_tr); - helper->delS(_brk3); - helper->delS(_brk4); - helper->delS(_nll); - helper->delS(_root); - helper->delS(_root2); - helper->delS(_qt); - helper->delS(_slash); + helper->delS(_pd); + helper->delS(_pf); + helper->delS(_fls); + helper->delS(_tr); + helper->delS(_brk3); + helper->delS(_brk4); + helper->delS(_nll); + helper->delS(_root); + helper->delS(_root2); + helper->delS(_qt); + helper->delS(_slash); } FirebaseJsonArray &FirebaseJsonArray::add() { - _addNull(); - return *this; + _addNull(); + return *this; } FirebaseJsonArray &FirebaseJsonArray::add(const String &value) { - _addString(value.c_str()); - return *this; + _addString(value.c_str()); + return *this; } FirebaseJsonArray &FirebaseJsonArray::add(const char *value) { - _addString(value); - return *this; + _addString(value); + return *this; } FirebaseJsonArray &FirebaseJsonArray::add(int value) { - _addInt(value); - return *this; + _addInt(value); + return *this; } FirebaseJsonArray &FirebaseJsonArray::add(unsigned short value) { - _addInt(value); - return *this; + _addInt(value); + return *this; } FirebaseJsonArray &FirebaseJsonArray::add(float value) { - _addFloat(value); - return *this; + _addFloat(value); + return *this; } FirebaseJsonArray &FirebaseJsonArray::add(double value) { - _addDouble(value); - return *this; + _addDouble(value); + return *this; } FirebaseJsonArray &FirebaseJsonArray::add(bool value) { - _addBool(value); - return *this; + _addBool(value); + return *this; } FirebaseJsonArray &FirebaseJsonArray::add(FirebaseJson &json) { - _addJson(&json); - return *this; + _addJson(&json); + return *this; } FirebaseJsonArray &FirebaseJsonArray::add(FirebaseJsonArray &arr) { - _addArray(&arr); - return *this; + _addArray(&arr); + return *this; } template FirebaseJsonArray &FirebaseJsonArray::add(T value) { - if (std::is_same::value) - _addInt(value); - else if (std::is_same::value) - _addFloat(value); - else if (std::is_same::value) - _addDouble(value); - else if (std::is_same::value) - _addBool(value); - else if (std::is_same::value) - _addString(value); - else if (std::is_same::value) - _addJson(&value); - else if (std::is_same::value) - _addArray(&value); - return *this; + if (std::is_same::value) + _addInt(value); + else if (std::is_same::value) + _addFloat(value); + else if (std::is_same::value) + _addDouble(value); + else if (std::is_same::value) + _addBool(value); + else if (std::is_same::value) + _addString(value); + else if (std::is_same::value) + _addJson(&value); + else if (std::is_same::value) + _addArray(&value); + return *this; } void FirebaseJsonArray::_addString(const std::string &value) { - _arrLen++; - _json._addArrayStr(value.c_str(), value.length(), true); + _arrLen++; + _json._addArrayStr(value.c_str(), value.length(), true); } void FirebaseJsonArray::_addInt(int value) { - _arrLen++; - char *buf = helper->intStr(value); - sprintf(buf, _pd, value); - _json._addArrayStr(buf, 60, false); - helper->delS(buf); + _arrLen++; + char *buf = helper->intStr(value); + sprintf(buf, _pd, value); + _json._addArrayStr(buf, 60, false); + helper->delS(buf); } void FirebaseJsonArray::_addFloat(float value) { - _arrLen++; - char *buf = helper->floatStr(value); - helper->trimDouble(buf); - _json._addArrayStr(buf, 60, false); - helper->delS(buf); + _arrLen++; + char *buf = helper->floatStr(value); + helper->trimDouble(buf); + _json._addArrayStr(buf, 60, false); + helper->delS(buf); } void FirebaseJsonArray::_addDouble(double value) { - _arrLen++; - char *buf = helper->doubleStr(value); - helper->trimDouble(buf); - _json._addArrayStr(buf, 60, false); - helper->delS(buf); + _arrLen++; + char *buf = helper->doubleStr(value); + helper->trimDouble(buf); + _json._addArrayStr(buf, 60, false); + helper->delS(buf); } void FirebaseJsonArray::_addBool(bool value) { - _arrLen++; - if (value) - _json._addArrayStr(_tr, 6, false); - else - _json._addArrayStr(_fls, 7, false); + _arrLen++; + if (value) + _json._addArrayStr(_tr, 6, false); + else + _json._addArrayStr(_fls, 7, false); } void FirebaseJsonArray::_addNull() { - _arrLen++; - _json._addArrayStr(_nll, 6, false); + _arrLen++; + _json._addArrayStr(_nll, 6, false); } void FirebaseJsonArray::_addJson(FirebaseJson *json) { - _arrLen++; - std::string s; - json->_toStdString(s); - _json._addArrayStr(s.c_str(), s.length(), false); - std::string().swap(s); + _arrLen++; + std::string s; + json->_toStdString(s); + _json._addArrayStr(s.c_str(), s.length(), false); + std::string().swap(s); } void FirebaseJsonArray::_addArray(FirebaseJsonArray *arr) { - _arrLen++; - String arrStr; - arr->toString(arrStr); - _json._addArrayStr(arrStr.c_str(), arrStr.length(), false); + _arrLen++; + String arrStr; + arr->toString(arrStr); + _json._addArrayStr(arrStr.c_str(), arrStr.length(), false); } FirebaseJsonArray &FirebaseJsonArray::setJsonArrayData(const String &data) { - int start_pos = data.indexOf('['); - int end_pos = data.indexOf(']'); - - if (start_pos != -1 && end_pos != -1 && start_pos != end_pos) - { - char *r = helper->strP(fb_json_str_21); - _json._rawbuf = r; - _json._rawbuf += data.c_str(); - helper->delS(r); - r = helper->strP(fb_json_str_26); - FirebaseJsonData data(_parser_buff_len); - _json.get(data, r); - helper->delS(r); - data.getArray(*this); - data.stringValue = ""; - } - return *this; + int start_pos = data.indexOf('['); + int end_pos = data.indexOf(']'); + + if (start_pos != -1 && end_pos != -1 && start_pos != end_pos) + { + char *r = helper->strP(fb_json_str_21); + _json._rawbuf = r; + _json._rawbuf += data.c_str(); + helper->delS(r); + r = helper->strP(fb_json_str_26); + FirebaseJsonData data(_parser_buff_len); + _json.get(data, r); + helper->delS(r); + data.getArray(*this); + data.stringValue = ""; + } + return *this; } bool FirebaseJsonArray::get(FirebaseJsonData &jsonData, const String &path) { - return _get(jsonData, path.c_str()); + return _get(jsonData, path.c_str()); } bool FirebaseJsonArray::get(FirebaseJsonData &jsonData, int index) { - char *tmp = helper->intStr(index); - std::string path = ""; - path += _brk3; - path += tmp; - path += _brk4; - bool ret = _get(jsonData, path.c_str()); - std::string().swap(path); - helper->delS(tmp); - return ret; + char *tmp = helper->intStr(index); + std::string path = ""; + path += _brk3; + path += tmp; + path += _brk4; + bool ret = _get(jsonData, path.c_str()); + std::string().swap(path); + helper->delS(tmp); + return ret; } bool FirebaseJsonArray::_get(FirebaseJsonData &jsonData, const char *path) { - _json._toStdString(_jbuf, false); - _json._rawbuf = _root; - _json._rawbuf += _jbuf; - std::string path2 = _root2; - path2 += _slash; - path2 += path; - _json.clearPathTk(); - _json._strToTk(path2.c_str(), _json._pathTk, '/'); - if (!_json._isArrTk(1)) - { - _json._jsonData.success = false; - goto ex_; - } - if (_json._getArrIndex(1) < 0) - { - _json._jsonData.success = false; - goto ex_; - } - _json._parse(path2.c_str(), FirebaseJson::PRINT_MODE_NONE); - if (_json._jsonData.success) - { - _json._rawbuf = _jbuf.substr(1, _jbuf.length() - 2).c_str(); - if (_json._jsonData._type == FirebaseJson::JSMN_STRING && _json._jsonData.stringValue.c_str()[0] == '"' && _json._jsonData.stringValue.c_str()[_json._jsonData.stringValue.length() - 1] == '"') - _json._jsonData.stringValue = _json._jsonData.stringValue.substring(1, _json._jsonData.stringValue.length() - 1).c_str(); - jsonData = _json._jsonData; - } + _json._toStdString(_jbuf, false); + _json._rawbuf = _root; + _json._rawbuf += _jbuf; + std::string path2 = _root2; + path2 += _slash; + path2 += path; + _json.clearPathTk(); + _json._strToTk(path2.c_str(), _json._pathTk, '/'); + if (!_json._isArrTk(1)) + { + _json._jsonData.success = false; + goto ex_; + } + if (_json._getArrIndex(1) < 0) + { + _json._jsonData.success = false; + goto ex_; + } + _json._parse(path2.c_str(), FirebaseJson::PRINT_MODE_NONE); + if (_json._jsonData.success) + { + _json._rawbuf = _jbuf.substr(1, _jbuf.length() - 2).c_str(); + if (_json._jsonData._type == FirebaseJson::JSMN_STRING && _json._jsonData.stringValue.c_str()[0] == '"' && _json._jsonData.stringValue.c_str()[_json._jsonData.stringValue.length() - 1] == '"') + _json._jsonData.stringValue = _json._jsonData.stringValue.substring(1, _json._jsonData.stringValue.length() - 1).c_str(); + jsonData = _json._jsonData; + } ex_: - _json.clearPathTk(); - _json._tokens.reset(); - _json._tokens = nullptr; - return _json._jsonData.success; + _json.clearPathTk(); + _json._tokens.reset(); + _json._tokens = nullptr; + return _json._jsonData.success; } size_t FirebaseJsonArray::size() { - return _arrLen; + return _arrLen; } void FirebaseJsonArray::toString(String &buf, bool prettify) { - char *tmp = helper->newS(_parser_buff_len); - std::string().swap(_json._jsonData._dbuf); - std::string().swap(_json._tbuf); - _json._toStdString(_jbuf, false); - _json._rawbuf = _root; - _json._rawbuf += _jbuf; - if (prettify) - _json._parse(_root2, FirebaseJson::PRINT_MODE_PRETTY); - else - _json._parse(_root2, FirebaseJson::PRINT_MODE_PLAIN); - std::string().swap(_json._tbuf); - std::string().swap(_jbuf); - _json.clearPathTk(); - _json._tokens.reset(); - _json._tokens = nullptr; - helper->delS(tmp); - _json._rawbuf = _json._jsonData._dbuf.substr(1, _json._jsonData._dbuf.length() - 2); - buf = _json._jsonData._dbuf.c_str(); - std::string().swap(_json._jsonData._dbuf); + char *tmp = helper->newS(_parser_buff_len); + std::string().swap(_json._jsonData._dbuf); + std::string().swap(_json._tbuf); + _json._toStdString(_jbuf, false); + _json._rawbuf = _root; + _json._rawbuf += _jbuf; + if (prettify) + _json._parse(_root2, FirebaseJson::PRINT_MODE_PRETTY); + else + _json._parse(_root2, FirebaseJson::PRINT_MODE_PLAIN); + std::string().swap(_json._tbuf); + std::string().swap(_jbuf); + _json.clearPathTk(); + _json._tokens.reset(); + _json._tokens = nullptr; + helper->delS(tmp); + _json._rawbuf = _json._jsonData._dbuf.substr(1, _json._jsonData._dbuf.length() - 2); + buf = _json._jsonData._dbuf.c_str(); + std::string().swap(_json._jsonData._dbuf); } FirebaseJsonArray &FirebaseJsonArray::clear() { - _json.clear(); - std::string().swap(_jbuf); - _json._jsonData.success = false; - _json._jsonData.stringValue = ""; - _json._jsonData.boolValue = false; - _json._jsonData.doubleValue = 0; - _json._jsonData.intValue = 0; - _json._jsonData.floatValue = 0; - _json._jsonData._len = 0; - _arrLen = 0; - return *this; + _json.clear(); + std::string().swap(_jbuf); + _json._jsonData.success = false; + _json._jsonData.stringValue = ""; + _json._jsonData.boolValue = false; + _json._jsonData.doubleValue = 0; + _json._jsonData.intValue = 0; + _json._jsonData.floatValue = 0; + _json._jsonData._len = 0; + _arrLen = 0; + return *this; } void FirebaseJsonArray::_set2(int index, const char *value, bool isStr) { - char *tmp = helper->newS(50); - std::string path = _brk3; - sprintf(tmp, "%d", index); - path += tmp; - path += _brk4; - _set(path.c_str(), value, isStr); - std::string().swap(path); - helper->delS(tmp); + char *tmp = helper->newS(50); + std::string path = _brk3; + sprintf(tmp, "%d", index); + path += tmp; + path += _brk4; + _set(path.c_str(), value, isStr); + std::string().swap(path); + helper->delS(tmp); } void FirebaseJsonArray::_set(const char *path, const char *value, bool isStr) { - _json._jsonData.success = false; - _json._toStdString(_jbuf, false); - _json._rawbuf = _root; - _json._rawbuf += _jbuf; - char *tmp2 = helper->newS(strlen(value) + 10); - if (isStr) - strcpy_P(tmp2, _qt); - strcat(tmp2, value); - if (isStr) - strcat_P(tmp2, _qt); - std::string path2 = _root2; - path2 += _slash; - path2 += path; - _json.clearPathTk(); - _json._strToTk(path2, _json._pathTk, '/'); - if (!_json._isArrTk(1)) - { - helper->delS(tmp2); - goto ex_2; - } - - if (_json._getArrIndex(1) < 0) - { - helper->delS(tmp2); - goto ex_2; - } + _json._jsonData.success = false; + _json._toStdString(_jbuf, false); + _json._rawbuf = _root; + _json._rawbuf += _jbuf; + char *tmp2 = helper->newS(strlen(value) + 10); + if (isStr) + strcpy_P(tmp2, _qt); + strcat(tmp2, value); + if (isStr) + strcat_P(tmp2, _qt); + std::string path2 = _root2; + path2 += _slash; + path2 += path; + _json.clearPathTk(); + _json._strToTk(path2, _json._pathTk, '/'); + if (!_json._isArrTk(1)) + { + helper->delS(tmp2); + goto ex_2; + } - _json._set(path2.c_str(), tmp2); + if (_json._getArrIndex(1) < 0) + { helper->delS(tmp2); - std::string().swap(path2); + goto ex_2; + } + + _json._set(path2.c_str(), tmp2); + helper->delS(tmp2); + std::string().swap(path2); + if (_json._jsonData.success) + { + std::string().swap(_json._jsonData._dbuf); + std::string().swap(_json._tbuf); + _json._parse(_root2, FirebaseJson::PRINT_MODE_PLAIN); if (_json._jsonData.success) { - std::string().swap(_json._jsonData._dbuf); - std::string().swap(_json._tbuf); - _json._parse(_root2, FirebaseJson::PRINT_MODE_PLAIN); - if (_json._jsonData.success) - { - _arrLen = _json._jsonData._len; - _json._rawbuf = _json._jsonData._dbuf.substr(1, _json._jsonData._dbuf.length() - 2); - } + _arrLen = _json._jsonData._len; + _json._rawbuf = _json._jsonData._dbuf.substr(1, _json._jsonData._dbuf.length() - 2); } - else - _json._rawbuf = _jbuf.substr(1, _jbuf.length() - 2); + } + else + _json._rawbuf = _jbuf.substr(1, _jbuf.length() - 2); ex_2: - std::string().swap(_json._jsonData._dbuf); - std::string().swap(_json._tbuf); - std::string().swap(_jbuf); - _json.clearPathTk(); - _json._tokens.reset(); - _json._tokens = nullptr; + std::string().swap(_json._jsonData._dbuf); + std::string().swap(_json._tbuf); + std::string().swap(_jbuf); + _json.clearPathTk(); + _json._tokens.reset(); + _json._tokens = nullptr; } void FirebaseJsonArray::set(int index) { - return _setNull(index); + return _setNull(index); } void FirebaseJsonArray::set(const String &path) { - _setNull(path); + _setNull(path); } void FirebaseJsonArray::set(int index, const String &value) { - _setString(index, value.c_str()); + _setString(index, value.c_str()); } void FirebaseJsonArray::set(const String &path, const String &value) { - _setString(path, value.c_str()); + _setString(path, value.c_str()); } void FirebaseJsonArray::set(int index, const char *value) { - _setString(index, value); + _setString(index, value); } void FirebaseJsonArray::set(const String &path, const char *value) { - _setString(path, value); + _setString(path, value); } void FirebaseJsonArray::set(int index, int value) { - _setInt(index, value); + _setInt(index, value); } void FirebaseJsonArray::set(int index, unsigned short value) { - _setInt(index, value); + _setInt(index, value); } void FirebaseJsonArray::set(const String &path, int value) { - _setInt(path, value); + _setInt(path, value); } void FirebaseJsonArray::set(const String &path, unsigned short value) { - _setInt(path, value); + _setInt(path, value); } void FirebaseJsonArray::set(int index, float value) { - _setFloat(index, value); + _setFloat(index, value); } void FirebaseJsonArray::set(const String &path, float value) { - _setFloat(path, value); + _setFloat(path, value); } void FirebaseJsonArray::set(int index, double value) { - _setDouble(index, value); + _setDouble(index, value); } void FirebaseJsonArray::set(const String &path, double value) { - _setDouble(path, value); + _setDouble(path, value); } void FirebaseJsonArray::set(int index, bool value) { - _setBool(index, value); + _setBool(index, value); } void FirebaseJsonArray::set(const String &path, bool value) { - _setBool(path, value); + _setBool(path, value); } void FirebaseJsonArray::set(int index, FirebaseJson &json) { - _setJson(index, &json); + _setJson(index, &json); } void FirebaseJsonArray::set(const String &path, FirebaseJson &json) { - _setJson(path, &json); + _setJson(path, &json); } void FirebaseJsonArray::set(int index, FirebaseJsonArray &arr) { - arr._lastErr = _lastErr; - _setArray(index, &arr); + arr._lastErr = _lastErr; + _setArray(index, &arr); } void FirebaseJsonArray::set(const String &path, FirebaseJsonArray &arr) { - arr._lastErr = _lastErr; - _setArray(path, &arr); + arr._lastErr = _lastErr; + _setArray(path, &arr); } template void FirebaseJsonArray::set(int index, T value) { - if (std::is_same::value) - _setInt(index, value); - else if (std::is_same::value) - _setFloat(index, value); - else if (std::is_same::value) - _setDouble(index, value); - else if (std::is_same::value) - _setBool(index, value); - else if (std::is_same::value) - _setString(index, value); - else if (std::is_same::value) - _setJson(index, &value); - else if (std::is_same::value) - _setArray(index, &value); + if (std::is_same::value) + _setInt(index, value); + else if (std::is_same::value) + _setFloat(index, value); + else if (std::is_same::value) + _setDouble(index, value); + else if (std::is_same::value) + _setBool(index, value); + else if (std::is_same::value) + _setString(index, value); + else if (std::is_same::value) + _setJson(index, &value); + else if (std::is_same::value) + _setArray(index, &value); } template void FirebaseJsonArray::set(const String &path, T value) { - if (std::is_same::value) - _setInt(path, value); - else if (std::is_same::value) - _setFloat(path, value); - else if (std::is_same::value) - _setDouble(path, value); - else if (std::is_same::value) - _setBool(path, value); - else if (std::is_same::value) - _setString(path, value); - else if (std::is_same::value) - _setJson(path, &value); - else if (std::is_same::value) - _setArray(path, &value); + if (std::is_same::value) + _setInt(path, value); + else if (std::is_same::value) + _setFloat(path, value); + else if (std::is_same::value) + _setDouble(path, value); + else if (std::is_same::value) + _setBool(path, value); + else if (std::is_same::value) + _setString(path, value); + else if (std::is_same::value) + _setJson(path, &value); + else if (std::is_same::value) + _setArray(path, &value); } void FirebaseJsonArray::_setString(int index, const std::string &value) { - _set2(index, value.c_str(), true); + _set2(index, value.c_str(), true); } void FirebaseJsonArray::_setString(const String &path, const std::string &value) { - _set(path.c_str(), value.c_str(), true); + _set(path.c_str(), value.c_str(), true); } void FirebaseJsonArray::_setInt(int index, int value) { - char *tmp = helper->intStr(value); - _set2(index, tmp, false); - helper->delS(tmp); + char *tmp = helper->intStr(value); + _set2(index, tmp, false); + helper->delS(tmp); } void FirebaseJsonArray::_setInt(const String &path, int value) { - char *tmp = helper->intStr(value); - _set(path.c_str(), tmp, false); - helper->delS(tmp); + char *tmp = helper->intStr(value); + _set(path.c_str(), tmp, false); + helper->delS(tmp); } void FirebaseJsonArray::_setFloat(int index, float value) { - char *tmp = helper->floatStr(value); - helper->trimDouble(tmp); - _set2(index, tmp, false); - helper->delS(tmp); + char *tmp = helper->floatStr(value); + helper->trimDouble(tmp); + _set2(index, tmp, false); + helper->delS(tmp); } void FirebaseJsonArray::_setFloat(const String &path, float value) { - char *tmp = helper->floatStr(value); - helper->trimDouble(tmp); - _set(path.c_str(), tmp, false); - helper->delS(tmp); + char *tmp = helper->floatStr(value); + helper->trimDouble(tmp); + _set(path.c_str(), tmp, false); + helper->delS(tmp); } void FirebaseJsonArray::_setDouble(int index, double value) { - char *tmp = helper->doubleStr(value); - helper->trimDouble(tmp); - _set2(index, tmp, false); - helper->delS(tmp); + char *tmp = helper->doubleStr(value); + helper->trimDouble(tmp); + _set2(index, tmp, false); + helper->delS(tmp); } void FirebaseJsonArray::_setDouble(const String &path, double value) { - char *tmp = helper->doubleStr(value); - helper->trimDouble(tmp); - _set(path.c_str(), tmp, false); - helper->delS(tmp); + char *tmp = helper->doubleStr(value); + helper->trimDouble(tmp); + _set(path.c_str(), tmp, false); + helper->delS(tmp); } void FirebaseJsonArray::_setBool(int index, bool value) { - if (value) - _set2(index, _tr, false); - else - _set2(index, _fls, false); + if (value) + _set2(index, _tr, false); + else + _set2(index, _fls, false); } void FirebaseJsonArray::_setBool(const String &path, bool value) { - if (value) - _set(path.c_str(), _tr, false); - else - _set(path.c_str(), _fls, false); + if (value) + _set(path.c_str(), _tr, false); + else + _set(path.c_str(), _fls, false); } void FirebaseJsonArray::_setNull(int index) { - _set2(index, _nll, false); + _set2(index, _nll, false); } void FirebaseJsonArray::_setNull(const String &path) { - _set(path.c_str(), _nll, false); + _set(path.c_str(), _nll, false); } void FirebaseJsonArray::_setJson(int index, FirebaseJson *json) { - std::string s; - json->_toStdString(s); - _set2(index, s.c_str(), false); - std::string().swap(s); + std::string s; + json->_toStdString(s); + _set2(index, s.c_str(), false); + std::string().swap(s); } void FirebaseJsonArray::_setJson(const String &path, FirebaseJson *json) { - std::string s; - json->_toStdString(s); - _set(path.c_str(), s.c_str(), false); - std::string().swap(s); + std::string s; + json->_toStdString(s); + _set(path.c_str(), s.c_str(), false); + std::string().swap(s); } void FirebaseJsonArray::_setArray(int index, FirebaseJsonArray *arr) { - arr->_lastErr = _lastErr; - std::string s; - arr->_toStdString(s); - _set2(index, s.c_str(), false); - std::string().swap(s); + arr->_lastErr = _lastErr; + std::string s; + arr->_toStdString(s); + _set2(index, s.c_str(), false); + std::string().swap(s); } void FirebaseJsonArray::_setArray(const String &path, FirebaseJsonArray *arr) { - arr->_lastErr = _lastErr; - std::string s; - arr->_toStdString(s); - _set(path.c_str(), s.c_str(), false); - std::string().swap(s); + arr->_lastErr = _lastErr; + std::string s; + arr->_toStdString(s); + _set(path.c_str(), s.c_str(), false); + std::string().swap(s); } bool FirebaseJsonArray::remove(int index) { - char *tmp = helper->intStr(index); - std::string path = ""; - path += _brk3; - path += tmp; - path += _brk4; - bool ret = _remove(path.c_str()); - std::string().swap(path); - helper->delS(tmp); - return ret; + char *tmp = helper->intStr(index); + std::string path = ""; + path += _brk3; + path += tmp; + path += _brk4; + bool ret = _remove(path.c_str()); + std::string().swap(path); + helper->delS(tmp); + return ret; } bool FirebaseJsonArray::remove(const String &path) { - return _remove(path.c_str()); + return _remove(path.c_str()); } bool FirebaseJsonArray::_remove(const char *path) { - _json._toStdString(_jbuf, false); - _json._rawbuf = _root; - _json._rawbuf += _jbuf; - std::string path2 = _root2; - path2 += _slash; - path2 += path; - _json._jsonData.success = _json.remove(path2.c_str()); - std::string().swap(path2); - bool success = _json._jsonData.success; + _json._toStdString(_jbuf, false); + _json._rawbuf = _root; + _json._rawbuf += _jbuf; + std::string path2 = _root2; + path2 += _slash; + path2 += path; + _json._jsonData.success = _json.remove(path2.c_str()); + std::string().swap(path2); + bool success = _json._jsonData.success; + if (_json._jsonData.success) + { + std::string().swap(_json._jsonData._dbuf); + std::string().swap(_json._tbuf); + _json._parse(_root2, FirebaseJson::PRINT_MODE_PLAIN); if (_json._jsonData.success) { - std::string().swap(_json._jsonData._dbuf); - std::string().swap(_json._tbuf); - _json._parse(_root2, FirebaseJson::PRINT_MODE_PLAIN); - if (_json._jsonData.success) - { - _arrLen = _json._jsonData._len; - _json._rawbuf = _json._jsonData._dbuf.substr(1, _json._jsonData._dbuf.length() - 2); - } + _arrLen = _json._jsonData._len; + _json._rawbuf = _json._jsonData._dbuf.substr(1, _json._jsonData._dbuf.length() - 2); } - else - _json._rawbuf = _jbuf.substr(1, _jbuf.length() - 2); + } + else + _json._rawbuf = _jbuf.substr(1, _jbuf.length() - 2); - if (_json._rawbuf.length() == 0) - { - _json._jsonData.success = success; - _arrLen = 0; - } + if (_json._rawbuf.length() == 0) + { + _json._jsonData.success = success; + _arrLen = 0; + } - return _json._jsonData.success; + return _json._jsonData.success; } void FirebaseJsonArray::int_toStdString(std::string &s) { - _json._toStdString(s); + _json._toStdString(s); } void FirebaseJsonArray::_toStdString(std::string &s) { - _json._toStdString(s, false); + _json._toStdString(s, false); } FirebaseJsonData::FirebaseJsonData() @@ -3837,46 +3871,46 @@ FirebaseJsonData::FirebaseJsonData() FirebaseJsonData::FirebaseJsonData(size_t bufLimit) { - if (bufLimit >= 32 || bufLimit <= 8192) - _parser_buff_len = bufLimit; + if (bufLimit >= 32 || bufLimit <= 8192) + _parser_buff_len = bufLimit; } FirebaseJsonData::~FirebaseJsonData() { - std::string().swap(_dbuf); + std::string().swap(_dbuf); } bool FirebaseJsonData::getArray(FirebaseJsonArray &jsonArray) { - if (typeNum != FirebaseJson::JSON_ARRAY || !success) - return false; - char *tmp = new char[_parser_buff_len]; - memset(tmp, 0, _parser_buff_len); - char *nbuf = new char[2]; - memset(nbuf, 0, 2); - strcpy_P(tmp, fb_json_str_21); - jsonArray._json._toStdString(jsonArray._jbuf, false); - jsonArray._json._rawbuf = tmp; - jsonArray._json._rawbuf += stringValue.c_str(); - memset(tmp, 0, _parser_buff_len); - strcpy_P(tmp, fb_json_str_26); - std::string().swap(jsonArray._json._jsonData._dbuf); - std::string().swap(jsonArray._json._tbuf); - jsonArray._json._parse(tmp, FirebaseJson::PRINT_MODE_PLAIN); - jsonArray._json._rawbuf = jsonArray._json._jsonData._dbuf.substr(1, jsonArray._json._jsonData._dbuf.length() - 2).c_str(); - jsonArray._arrLen = jsonArray._json._jsonData._len; - delete[] tmp; - delete[] nbuf; - return jsonArray._json._jsonData.success; + if (typeNum != FirebaseJson::JSON_ARRAY || !success) + return false; + char *tmp = new char[_parser_buff_len]; + memset(tmp, 0, _parser_buff_len); + char *nbuf = new char[2]; + memset(nbuf, 0, 2); + strcpy_P(tmp, fb_json_str_21); + jsonArray._json._toStdString(jsonArray._jbuf, false); + jsonArray._json._rawbuf = tmp; + jsonArray._json._rawbuf += stringValue.c_str(); + memset(tmp, 0, _parser_buff_len); + strcpy_P(tmp, fb_json_str_26); + std::string().swap(jsonArray._json._jsonData._dbuf); + std::string().swap(jsonArray._json._tbuf); + jsonArray._json._parse(tmp, FirebaseJson::PRINT_MODE_PLAIN); + jsonArray._json._rawbuf = jsonArray._json._jsonData._dbuf.substr(1, jsonArray._json._jsonData._dbuf.length() - 2).c_str(); + jsonArray._arrLen = jsonArray._json._jsonData._len; + delete[] tmp; + delete[] nbuf; + return jsonArray._json._jsonData.success; } bool FirebaseJsonData::getJSON(FirebaseJson &json) { - if (typeNum != FirebaseJson::JSON_OBJECT || !success) - return false; - json.setJsonData(stringValue); - json._fbjs_parse(); - return json._jsonData.success; + if (typeNum != FirebaseJson::JSON_OBJECT || !success) + return false; + json.setJsonData(stringValue); + json._fbjs_parse(); + return json._jsonData.success; } #endif \ No newline at end of file diff --git a/src/json/FirebaseJson.h b/src/json/FirebaseJson.h index f5bc7f71..d524fda9 100644 --- a/src/json/FirebaseJson.h +++ b/src/json/FirebaseJson.h @@ -1,9 +1,9 @@ -/** - * FirebaseJson, version 2.3.13 +/* + * FirebaseJson, version 2.3.14 * * The Easiest Arduino library to parse, create and edit JSON object using a relative path. * - * April 4, 2021 + * April 30, 2021 * * Features * - None recursive operations @@ -87,53 +87,55 @@ static const char fb_json_str_28[] PROGMEM = "memory allocation error"; static const char fb_json_str_29[] PROGMEM = "invalid character inside JSON object or array"; static const char fb_json_str_30[] PROGMEM = "incompleted JSON object or array"; static const char fb_json_str_31[] PROGMEM = "token array buffer is to small"; +static const char fb_json_str_32[] PROGMEM = "\":}"; +static const char fb_json_str_33[] PROGMEM = "\":,"; class FirebaseJson; class FirebaseJsonArray; typedef struct { - int code = 0; - std::string function = ""; - int line = 0; - std::string messagge = ""; + int code = 0; + std::string function = ""; + int line = 0; + std::string messagge = ""; } fb_json_last_error_t; typedef struct { - int nextDepth = 0; - int nextToken = 0; - int skipDepth = -1; - int parentIndex = -1; - bool TkRefOk = false; - int parseCompleted = -1; - bool arrReplaced = false; - bool arrInserted = false; - int refTkIndex = -1; - int remTkIndex = -1; - bool remFirstTk = false; - bool remLastTk = false; - - int refToken = -1; - int parseDepth = 0; - int tokenCount = 0; - bool tokenMatch = false; - bool collectTk = false; - bool paresRes = false; + int nextDepth = 0; + int nextToken = 0; + int skipDepth = -1; + int parentIndex = -1; + bool TkRefOk = false; + int parseCompleted = -1; + bool arrReplaced = false; + bool arrInserted = false; + int refTkIndex = -1; + int remTkIndex = -1; + bool remFirstTk = false; + bool remLastTk = false; + + int refToken = -1; + int parseDepth = 0; + int tokenCount = 0; + bool tokenMatch = false; + bool collectTk = false; + bool paresRes = false; } fb_json_parser_info_t; class FirebaseJsonHelper { public: - FirebaseJsonHelper(fb_json_last_error_t *err) { last_err = err; }; - ~FirebaseJsonHelper(){}; + FirebaseJsonHelper(fb_json_last_error_t *err) { last_err = err; }; + ~FirebaseJsonHelper(){}; - /*** dtostrf function is taken from + /*** dtostrf function is taken from * https://github.com/stm32duino/Arduino_Core_STM32/blob/master/cores/arduino/avr/dtostrf.c */ - /*** + /*** * dtostrf - Emulation for dtostrf function from avr-libc * Copyright (c) 2013 Arduino. All rights reserved. * Written by Cristian Maglie @@ -150,581 +152,581 @@ class FirebaseJsonHelper * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ - char *dtostrf(double val, signed char width, unsigned char prec, char *sout) - { - //Commented code is the original version - /*** + char *dtostrf(double val, signed char width, unsigned char prec, char *sout) + { + //Commented code is the original version + /*** char fmt[20]; sprintf(fmt, "%%%d.%df", width, prec); sprintf(sout, fmt, val); return sout; */ - // Handle negative numbers - uint8_t negative = 0; - if (val < 0.0) - { - negative = 1; - val = -val; - } - - // Round correctly so that print(1.999, 2) prints as "2.00" - double rounding = 0.5; - for (int i = 0; i < prec; ++i) - { - rounding /= 10.0; - } - - val += rounding; - - // Extract the integer part of the number - unsigned long int_part = (unsigned long)val; - double remainder = val - (double)int_part; - - if (prec > 0) - { - // Extract digits from the remainder - unsigned long dec_part = 0; - double decade = 1.0; - for (int i = 0; i < prec; i++) - { - decade *= 10.0; - } - remainder *= decade; - dec_part = (int)remainder; - - if (negative) - { - sprintf(sout, "-%ld.%0*ld", int_part, prec, dec_part); - } - else - { - sprintf(sout, "%ld.%0*ld", int_part, prec, dec_part); - } - } - else - { - if (negative) - { - sprintf(sout, "-%ld", int_part); - } - else - { - sprintf(sout, "%ld", int_part); - } - } - // Handle minimum field width of the output string - // width is signed value, negative for left adjustment. - // Range -128,127 - char fmt[129] = ""; - unsigned int w = width; - if (width < 0) - { - negative = 1; - w = -width; - } - else - { - negative = 0; - } - - if (strlen(sout) < w) - { - memset(fmt, ' ', 128); - fmt[w - strlen(sout)] = '\0'; - if (negative == 0) - { - char *tmp = (char *)malloc(strlen(sout) + 1); - strcpy(tmp, sout); - strcpy(sout, fmt); - strcat(sout, tmp); - free(tmp); - } - else - { - // left adjustment - strcat(sout, fmt); - } - } - - return sout; - } - - char *strP(PGM_P pgm) + // Handle negative numbers + uint8_t negative = 0; + if (val < 0.0) { - size_t len = strlen_P(pgm) + 1; - char *buf = newS(len); - strcpy_P(buf, pgm); - buf[len - 1] = 0; - return buf; + negative = 1; + val = -val; } - void setLastError(int code, const char *file, int line, PGM_P msg) + // Round correctly so that print(1.999, 2) prints as "2.00" + double rounding = 0.5; + for (int i = 0; i < prec; ++i) { - if (last_err) - { - last_err->code = code; - last_err->function = file; - last_err->line = line; - char *tmp = strP(msg); - last_err->messagge = tmp; - delS(tmp); - } + rounding /= 10.0; } - void clearLastError() + val += rounding; + + // Extract the integer part of the number + unsigned long int_part = (unsigned long)val; + double remainder = val - (double)int_part; + + if (prec > 0) { - if (last_err) - { - last_err->code = 0; - last_err->function = ""; - last_err->line = 0; - last_err->messagge = ""; - } + // Extract digits from the remainder + unsigned long dec_part = 0; + double decade = 1.0; + for (int i = 0; i < prec; i++) + { + decade *= 10.0; + } + remainder *= decade; + dec_part = (int)remainder; + + if (negative) + { + sprintf(sout, "-%ld.%0*ld", int_part, prec, dec_part); + } + else + { + sprintf(sout, "%ld.%0*ld", int_part, prec, dec_part); + } } - - int strpos(const char *haystack, const char *needle, int offset) + else { - size_t len = strlen(haystack); - size_t len2 = strlen(needle); - if (len == 0 || len < len2 || len2 == 0) - return -1; - char *_haystack = newS(len - offset + 1); - if (!_haystack) - { - setLastError(-1, __FILE__, __LINE__, fb_json_str_28); - return -1; - } - _haystack[len - offset] = 0; - strncpy(_haystack, haystack + offset, len - offset); - char *p = strstr(_haystack, needle); - int r = -1; - if (p) - r = p - _haystack + offset; - delS(_haystack); - return r; + if (negative) + { + sprintf(sout, "-%ld", int_part); + } + else + { + sprintf(sout, "%ld", int_part); + } } - - int rstrpos(const char *haystack, const char *needle, int offset) + // Handle minimum field width of the output string + // width is signed value, negative for left adjustment. + // Range -128,127 + char fmt[129] = ""; + unsigned int w = width; + if (width < 0) { - size_t len = strlen(haystack); - size_t len2 = strlen(needle); - if (len == 0 || len < len2 || len2 == 0) - return -1; - char *_haystack = newS(len - offset + 1); - if (!_haystack) - { - setLastError(-1, __FILE__, __LINE__, fb_json_str_28); - return -1; - } - _haystack[len - offset] = 0; - strncpy(_haystack, haystack + offset, len - offset); - char *p = rstrstr(_haystack, needle); - int r = -1; - if (p) - r = p - _haystack + offset; - delS(_haystack); - return r; + negative = 1; + w = -width; } - - char *rstrstr(const char *haystack, const char *needle) + else { - size_t needle_length = strlen(needle); - const char *haystack_end = haystack + strlen(haystack) - needle_length; - const char *p; - size_t i; - for (p = haystack_end; p >= haystack; --p) - { - for (i = 0; i < needle_length; ++i) - { - if (p[i] != needle[i]) - goto next; - } - return (char *)p; - next:; - } - return 0; + negative = 0; } - void delS(char *p) + if (strlen(sout) < w) { - if (p != nullptr) - delete[] p; + memset(fmt, ' ', 128); + fmt[w - strlen(sout)] = '\0'; + if (negative == 0) + { + char *tmp = (char *)malloc(strlen(sout) + 1); + strcpy(tmp, sout); + strcpy(sout, fmt); + strcat(sout, tmp); + free(tmp); + } + else + { + // left adjustment + strcat(sout, fmt); + } } - char *newS(size_t len) + return sout; + } + + char *strP(PGM_P pgm) + { + size_t len = strlen_P(pgm) + 1; + char *buf = newS(len); + strcpy_P(buf, pgm); + buf[len - 1] = 0; + return buf; + } + + void setLastError(int code, const char *file, int line, PGM_P msg) + { + if (last_err) { - char *p = new char[len]; - memset(p, 0, len); - return p; + last_err->code = code; + last_err->function = file; + last_err->line = line; + char *tmp = strP(msg); + last_err->messagge = tmp; + delS(tmp); } + } - char *floatStr(float value) + void clearLastError() + { + if (last_err) { - char *buf = newS(36); - dtostrf(value, 7, 6, buf); - return buf; + last_err->code = 0; + last_err->function = ""; + last_err->line = 0; + last_err->messagge = ""; } - - char *intStr(int value) + } + + int strpos(const char *haystack, const char *needle, int offset) + { + size_t len = strlen(haystack); + size_t len2 = strlen(needle); + if (len == 0 || len < len2 || len2 == 0) + return -1; + char *_haystack = newS(len - offset + 1); + if (!_haystack) { - char *buf = newS(36); - sprintf(buf, "%d", value); - return buf; + setLastError(-1, __FILE__, __LINE__, fb_json_str_28); + return -1; } - - char *boolStr(bool value) + _haystack[len - offset] = 0; + strncpy(_haystack, haystack + offset, len - offset); + char *p = strstr(_haystack, needle); + int r = -1; + if (p) + r = p - _haystack + offset; + delS(_haystack); + return r; + } + + int rstrpos(const char *haystack, const char *needle, int offset) + { + size_t len = strlen(haystack); + size_t len2 = strlen(needle); + if (len == 0 || len < len2 || len2 == 0) + return -1; + char *_haystack = newS(len - offset + 1); + if (!_haystack) { - char *buf = nullptr; - if (value) - buf = strP(fb_json_str_7); - else - buf = strP(fb_json_str_6); - return buf; + setLastError(-1, __FILE__, __LINE__, fb_json_str_28); + return -1; } - - char *doubleStr(double value) + _haystack[len - offset] = 0; + strncpy(_haystack, haystack + offset, len - offset); + char *p = rstrstr(_haystack, needle); + int r = -1; + if (p) + r = p - _haystack + offset; + delS(_haystack); + return r; + } + + char *rstrstr(const char *haystack, const char *needle) + { + size_t needle_length = strlen(needle); + const char *haystack_end = haystack + strlen(haystack) - needle_length; + const char *p; + size_t i; + for (p = haystack_end; p >= haystack; --p) { - char *buf = newS(36); - dtostrf(value, 12, 9, buf); - return buf; + for (i = 0; i < needle_length; ++i) + { + if (p[i] != needle[i]) + goto next; + } + return (char *)p; + next:; } - - void trimDouble(char *buf) + return 0; + } + + void delS(char *p) + { + if (p != nullptr) + delete[] p; + } + + char *newS(size_t len) + { + char *p = new char[len]; + memset(p, 0, len); + return p; + } + + char *floatStr(float value) + { + char *buf = newS(36); + dtostrf(value, 7, 6, buf); + return buf; + } + + char *intStr(int value) + { + char *buf = newS(36); + sprintf(buf, "%d", value); + return buf; + } + + char *boolStr(bool value) + { + char *buf = nullptr; + if (value) + buf = strP(fb_json_str_7); + else + buf = strP(fb_json_str_6); + return buf; + } + + char *doubleStr(double value) + { + char *buf = newS(36); + dtostrf(value, 12, 9, buf); + return buf; + } + + void trimDouble(char *buf) + { + size_t i = strlen(buf) - 1; + while (buf[i] == '0' && i > 0) { - size_t i = strlen(buf) - 1; - while (buf[i] == '0' && i > 0) - { - if (buf[i - 1] == '.') - { - i--; - break; - } - if (buf[i - 1] != '0') - break; - i--; - } - if (i < strlen(buf) - 1) - buf[i] = '\0'; + if (buf[i - 1] == '.') + { + i--; + break; + } + if (buf[i - 1] != '0') + break; + i--; } + if (i < strlen(buf) - 1) + buf[i] = '\0'; + } private: - fb_json_last_error_t *last_err = nullptr; + fb_json_last_error_t *last_err = nullptr; }; class FirebaseJsonData { - friend class FirebaseJson; - friend class FirebaseJsonArray; + friend class FirebaseJson; + friend class FirebaseJsonArray; public: - FirebaseJsonData(); - FirebaseJsonData(size_t bufLimit); - ~FirebaseJsonData(); + FirebaseJsonData(); + FirebaseJsonData(size_t bufLimit); + ~FirebaseJsonData(); - /** + /** * Get array data as FirebaseJsonArray object from FirebaseJsonData object. * * @param jsonArray - The returning FirebaseJsonArray object. * @return bool status for successful operation. * This should call after parse or get function. */ - bool getArray(FirebaseJsonArray &jsonArray); + bool getArray(FirebaseJsonArray &jsonArray); - /** + /** * Get array data as FirebaseJson object from FirebaseJsonData object. * * @param jsonArray - The returning FirebaseJson object. * @return bool status for successful operation. * This should call after parse or get function. */ - bool getJSON(FirebaseJson &json); + bool getJSON(FirebaseJson &json); - /** + /** * The String value of parses data. */ - String stringValue = ""; + String stringValue = ""; - /** + /** * The int value of parses data. */ - int intValue = 0; + int intValue = 0; - /** + /** * The float value of parses data. */ - float floatValue = 0.0f; + float floatValue = 0.0f; - /** + /** * The double value of parses data. */ - double doubleValue = 0.0; + double doubleValue = 0.0; - /** + /** * The bool value of parses data. */ - bool boolValue = false; + bool boolValue = false; - /** + /** * The type String of parses data. */ - String type = ""; + String type = ""; - /** + /** * The type (number) of parses data. */ - uint8_t typeNum = 0; + uint8_t typeNum = 0; - /** + /** * The success flag of parsing data. */ - bool success = false; + bool success = false; private: - size_t _parser_buff_len = FB_JSON_EXTRAS_BUFFER_LENGTH; - int _type = 0; - int _k_start = 0; - int _start = 0; - int _end = 0; - int _tokenIndex = 0; - int _depth = 0; - int _len = 0; - std::string _dbuf = ""; + size_t _parser_buff_len = FB_JSON_EXTRAS_BUFFER_LENGTH; + int _type = 0; + int _k_start = 0; + int _start = 0; + int _end = 0; + int _tokenIndex = 0; + int _depth = 0; + int _len = 0; + std::string _dbuf = ""; }; class FirebaseJson { - friend class FirebaseJsonArray; - friend class FirebaseJsonData; + friend class FirebaseJsonArray; + friend class FirebaseJsonData; public: - typedef enum - { - JSON_UNDEFINED = 0, - JSON_OBJECT = 1, - JSON_ARRAY = 2, - JSON_STRING = 3, - JSON_INT = 4, - JSON_FLOAT = 5, - JSON_DOUBLE = 6, - JSON_BOOL = 7, - JSON_NULL = 8 - } jsonDataType; - - typedef enum - { - PRINT_MODE_NONE = -1, - PRINT_MODE_PLAIN = 0, - PRINT_MODE_PRETTY = 1 - } PRINT_MODE; - - typedef struct - { - bool matched = false; - std::string tk = ""; - } path_tk_t; - - typedef struct - { - int index; - bool firstTk; - bool lastTk; - bool success; - } single_child_parent_t; - - typedef struct - { - uint16_t index; - uint8_t type; - } eltk_t; - - typedef struct - { - uint16_t index; - uint8_t type; - uint16_t olen; - uint16_t oindex; - int depth; - bool omark; - bool ref; - bool skip; - } el_t; - - typedef struct - { - int index; - uint16_t oindex; - uint16_t olen; - uint8_t type; - int depth; - bool omark; - bool ref; - bool skip; - } tk_index_t; - - /*** + typedef enum + { + JSON_UNDEFINED = 0, + JSON_OBJECT = 1, + JSON_ARRAY = 2, + JSON_STRING = 3, + JSON_INT = 4, + JSON_FLOAT = 5, + JSON_DOUBLE = 6, + JSON_BOOL = 7, + JSON_NULL = 8 + } jsonDataType; + + typedef enum + { + PRINT_MODE_NONE = -1, + PRINT_MODE_PLAIN = 0, + PRINT_MODE_PRETTY = 1 + } PRINT_MODE; + + typedef struct + { + bool matched = false; + std::string tk = ""; + } path_tk_t; + + typedef struct + { + int index; + bool firstTk; + bool lastTk; + bool success; + } single_child_parent_t; + + typedef struct + { + uint16_t index; + uint8_t type; + } eltk_t; + + typedef struct + { + uint16_t index; + uint8_t type; + uint16_t olen; + uint16_t oindex; + int depth; + bool omark; + bool ref; + bool skip; + } el_t; + + typedef struct + { + int index; + uint16_t oindex; + uint16_t olen; + uint8_t type; + int depth; + bool omark; + bool ref; + bool skip; + } tk_index_t; + + /*** * JSON type identifier. Basic types are: * o Object * o Array * o String * o Other primitive: number, boolean (true/false) or null */ - typedef enum - { - JSMN_UNDEFINED = 0, - JSMN_OBJECT = 1, - JSMN_ARRAY = 2, - JSMN_STRING = 3, - JSMN_PRIMITIVE = 4 - } fbjs_type_t; - - enum fbjs_err - { - /** Not enough tokens were provided */ - JSMN_ERROR_NOMEM = -1, - /** Invalid character inside JSON string */ - JSMN_ERROR_INVAL = -2, - /** The string is not a full JSON packet, more bytes expected */ - JSMN_ERROR_PART = -3 - }; - - /*** + typedef enum + { + JSMN_UNDEFINED = 0, + JSMN_OBJECT = 1, + JSMN_ARRAY = 2, + JSMN_STRING = 3, + JSMN_PRIMITIVE = 4 + } fbjs_type_t; + + enum fbjs_err + { + /** Not enough tokens were provided */ + JSMN_ERROR_NOMEM = -1, + /** Invalid character inside JSON string */ + JSMN_ERROR_INVAL = -2, + /** The string is not a full JSON packet, more bytes expected */ + JSMN_ERROR_PART = -3 + }; + + /*** * JSON token description. * type type (object, array, string etc.) * start start position in JSON data string * end end position in JSON data string */ - typedef struct - { - fbjs_type_t type; - int start; - int end; - int size; + typedef struct + { + fbjs_type_t type; + int start; + int end; + int size; #ifdef JSMN_PARENT_LINKS - int parent; + int parent; #endif - } fbjs_tok_t; + } fbjs_tok_t; - /*** + /*** * JSON parser. Contains an array of token blocks available. Also stores * the string being parsed now and current position in that string */ - typedef struct - { - unsigned int pos; /** offset in the JSON string */ - unsigned int toknext; /** next token to allocate */ - int toksuper; /** superior token node, e.g parent object or array */ - } fbjs_parser; + typedef struct + { + unsigned int pos; /** offset in the JSON string */ + unsigned int toknext; /** next token to allocate */ + int toksuper; /** superior token node, e.g parent object or array */ + } fbjs_parser; - FirebaseJson(); - FirebaseJson(std::string &data); - ~FirebaseJson(); + FirebaseJson(); + FirebaseJson(std::string &data); + ~FirebaseJson(); - /** + /** * Clear internal buffer of FirebaseJson object. * * @return instance of an object. */ - FirebaseJson &clear(); + FirebaseJson &clear(); - /** + /** * Set JSON data (JSON object string) to FirebaseJson object. * * @param data - The JSON object string. * @return instance of an object. */ - FirebaseJson &setJsonData(const String &data); + FirebaseJson &setJsonData(const String &data); - /** + /** * Add null to FirebaseJson object. * * @param key - The new key string that null to be added. * @return instance of an object. */ - FirebaseJson &add(const String &key); + FirebaseJson &add(const String &key); - /** + /** * Add string to FirebaseJson object. * * @param key - The new key string that string value to be added. * @param value - The string value for the new specified key. * @return instance of an object. */ - FirebaseJson &add(const String &key, const String &value); + FirebaseJson &add(const String &key, const String &value); - /** + /** * Add string (chars array) to FirebaseJson object. * * @param key - The new key string that string (chars array) value to be added. * @param value - The char array for the new specified key. * @return instance of an object. */ - FirebaseJson &add(const String &key, const char *value); + FirebaseJson &add(const String &key, const char *value); - /** + /** * Add integer/unsigned short to FirebaseJson object. * * @param key - The new key string in which value to be added. * @param value - The integer/unsigned short value for the new specified key. * @return instance of an object. */ - FirebaseJson &add(const String &key, int value); - FirebaseJson &add(const String &key, unsigned short value); + FirebaseJson &add(const String &key, int value); + FirebaseJson &add(const String &key, unsigned short value); - /** + /** * Add float to FirebaseJson object. * * @param key - The new key string that double value to be added. * @param value - The double value for the new specified key. * @return instance of an object. */ - FirebaseJson &add(const String &key, float value); + FirebaseJson &add(const String &key, float value); - /** + /** * Add double to FirebaseJson object. * * @param key - The new key string that double value to be added. * @param value - The double value for the new specified key. * @return instance of an object. */ - FirebaseJson &add(const String &key, double value); + FirebaseJson &add(const String &key, double value); - /** + /** * Add boolean to FirebaseJson object. * * @param key - The new key string that bool value to be added. * @param value - The boolean value for the new specified key. * @return instance of an object. */ - FirebaseJson &add(const String &key, bool value); + FirebaseJson &add(const String &key, bool value); - /** + /** * Add nested FirebaseJson object into FirebaseJson object. * * @param key - The new key string that FirebaseJson object to be added. * @param json - The FirebaseJson object for the new specified key. * @return instance of an object. */ - FirebaseJson &add(const String &key, FirebaseJson &json); + FirebaseJson &add(const String &key, FirebaseJson &json); - /** + /** * Add nested FirebaseJsonArray object into FirebaseJson object. * * @param key - The new key string that FirebaseJsonArray object to be added. * @param arr - The FirebaseJsonArray for the new specified key. * @return instance of an object. */ - FirebaseJson &add(const String &key, FirebaseJsonArray &arr); + FirebaseJson &add(const String &key, FirebaseJsonArray &arr); - /** + /** * Get the FirebaseJson object serialized string. * * @param buf - The returning String object. * @param prettify - Boolean flag for return the pretty format string i.e. with text indentation and newline. */ - void toString(String &buf, bool prettify = false); + void toString(String &buf, bool prettify = false); - /** + /** * Get the value from the specified node path in FirebaseJson object. * * @param jsonData - The returning FirebaseJsonData that holds the returned data. @@ -753,17 +755,17 @@ class FirebaseJson * FirebaseJson::BOOL = 7 and * FirebaseJson::NULL = 8 */ - bool get(FirebaseJsonData &jsonData, const String &path, bool prettify = false); + bool get(FirebaseJsonData &jsonData, const String &path, bool prettify = false); - /** + /** * Parse and collect all node/array elements in FirebaseJson object. * * @param data - The JSON data string to parse (optional to replace the internal buffer with new data). * @return number of child/array elements in FirebaseJson object. */ - size_t iteratorBegin(const char *data = NULL); + size_t iteratorBegin(const char *data = NULL); - /** + /** * Get child/array elements from FirebaseJson objects at specified index. * * @param index - The element index to get. @@ -771,23 +773,23 @@ class FirebaseJson * @param key - The string which holds the key/name of an object, can return empty String if the data type is an array. * @param value - The string which holds the value for the element key or array. */ - void iteratorGet(size_t index, int &type, String &key, String &value); + void iteratorGet(size_t index, int &type, String &key, String &value); - /** + /** * Clear all iterator buffer (should be called since iteratorBegin was called). */ - void iteratorEnd(); + void iteratorEnd(); - /** + /** * Set null to FirebaseJson object at the specified node path. * * @param path - The relative path that null to be set. * The relative path can be mixed with array index (number placed inside square brackets) and node names * e.g. /myRoot/[2]/Sensor1/myData/[3]. */ - void set(const String &path); + void set(const String &path); - /** + /** * Set String value to FirebaseJson object at the specified node path. * * @param path - The relative path that string value to be set. @@ -796,9 +798,9 @@ class FirebaseJson * The relative path can be mixed with array index (number placed inside square brackets) and node names * e.g. /myRoot/[2]/Sensor1/myData/[3]. */ - void set(const String &path, const String &value); + void set(const String &path, const String &value); - /** + /** * Set string (chars array) value to FirebaseJson object at the specified node path. * * @param path - The relative path that string (chars array) to be set. @@ -806,9 +808,9 @@ class FirebaseJson * The relative path can be mixed with array index (number placed inside square brackets) and node names * e.g. /myRoot/[2]/Sensor1/myData/[3]. */ - void set(const String &path, const char *value); + void set(const String &path, const char *value); - /** + /** * Set integer/unsigned short value to FirebaseJson object at specified node path. * * @param path - The relative path that int value to be set. @@ -816,10 +818,10 @@ class FirebaseJson * The relative path can be mixed with array index (number placed inside square brackets) and node names * e.g. /myRoot/[2]/Sensor1/myData/[3]. */ - void set(const String &path, int value); - void set(const String &path, unsigned short value); + void set(const String &path, int value); + void set(const String &path, unsigned short value); - /** + /** * Set the float value to FirebaseJson object at the specified node path. * * @param path - The relative path that float value to be set. @@ -827,9 +829,9 @@ class FirebaseJson * The relative path can be mixed with array index (number placed inside square brackets) and node names * e.g. /myRoot/[2]/Sensor1/myData/[3]. */ - void set(const String &path, float value); + void set(const String &path, float value); - /** + /** * Set the double value to FirebaseJson object at the specified node path. * * @param path - The relative path that double value to be set. @@ -837,9 +839,9 @@ class FirebaseJson * The relative path can be mixed with array index (number placed inside square brackets) and node names * e.g. /myRoot/[2]/Sensor1/myData/[3]. */ - void set(const String &path, double value); + void set(const String &path, double value); - /** + /** * Set boolean value to FirebaseJson object at the specified node path. * * @param path - The relative path that bool value to be set. @@ -847,9 +849,9 @@ class FirebaseJson * The relative path can be mixed with array index (number placed inside square brackets) and node names * e.g. /myRoot/[2]/Sensor1/myData/[3]. */ - void set(const String &path, bool value); + void set(const String &path, bool value); - /** + /** * Set nested FirebaseJson object to FirebaseJson object at the specified node path. * * @param path - The relative path that nested FirebaseJson object to be set. @@ -857,9 +859,9 @@ class FirebaseJson * The relative path can be mixed with array index (number placed inside square brackets) and node names * e.g. /myRoot/[2]/Sensor1/myData/[3]. */ - void set(const String &path, FirebaseJson &json); + void set(const String &path, FirebaseJson &json); - /** + /** * Set nested FirebaseJsonAtrray object to FirebaseJson object at specified node path. * * @param path - The relative path that nested FirebaseJsonAtrray object to be set. @@ -867,262 +869,262 @@ class FirebaseJson * The relative path can be mixed with array index (number placed inside square brackets) and node names * e.g. /myRoot/[2]/Sensor1/myData/[3]. */ - void set(const String &path, FirebaseJsonArray &arr); + void set(const String &path, FirebaseJsonArray &arr); - /** + /** * Remove the specified node and its content. * * @param path - The relative path to remove its contents/children. * @return bool value represents the success operation. */ - bool remove(const String &path); + bool remove(const String &path); - /** + /** * Set the parser internal buffer length limit * * @param limit The size of internal parer buffer (32 to 8192 bytes) */ - void setBufferLimit(size_t limit); + void setBufferLimit(size_t limit); - /** + /** * Get last error of operation. * * @return fb_json_last_error_t structured data of error */ - fb_json_last_error_t getLastError(); + fb_json_last_error_t getLastError(); - template - FirebaseJson &add(const String &key, T value); + template + FirebaseJson &add(const String &key, T value); - template - bool set(const String &path, T value); + template + bool set(const String &path, T value); - void int_parse(const char *path, PRINT_MODE printMode); - void int_clearPathTk(); - void int_clearTokens(); - size_t int_get_jsondata_len(); - void int_tostr(std::string &s, bool prettify = false); - void int_toStdString(std::string &s, bool isJson = true); + void int_parse(const char *path, PRINT_MODE printMode); + void int_clearPathTk(); + void int_clearTokens(); + size_t int_get_jsondata_len(); + void int_tostr(std::string &s, bool prettify = false); + void int_toStdString(std::string &s, bool isJson = true); private: - size_t _parser_buff_len = FB_JSON_EXTRAS_BUFFER_LENGTH; - - fb_json_last_error_t _lastErr; - - FirebaseJsonHelper *helper = new FirebaseJsonHelper(&_lastErr); - - fbjs_type_t _topLevelTkType = JSMN_OBJECT; - - fb_json_parser_info_t _parser_info; - - char *_qt = nullptr; - char *_tab = nullptr; - char *_brk1 = nullptr; - char *_brk2 = nullptr; - char *_brk3 = nullptr; - char *_brk4 = nullptr; - char *_cm = nullptr; - char *_nl = nullptr; - char *_nll = nullptr; - char *_pr = nullptr; - char *_pr2 = nullptr; - char *_pd = nullptr; - char *_pf = nullptr; - char *_fls = nullptr; - char *_tr = nullptr; - char *_string = nullptr; - char *_int = nullptr; - char *_dbl = nullptr; - char *_bl = nullptr; - char *_obj = nullptr; - char *_arry = nullptr; - char *_undef = nullptr; - char *_dot = nullptr; - - std::string _rawbuf = ""; - std::string _tbuf = ""; - tk_index_t _lastTk; - std::vector _pathTk = std::vector(); - std::vector _eltk = std::vector(); - std::vector _el = std::vector(); - FirebaseJsonData _jsonData; - - std::shared_ptr _parser = std::shared_ptr(new fbjs_parser()); - std::shared_ptr _tokens = nullptr; - - void _init(); - void _finalize(); - FirebaseJson &_setJsonData(std::string &data); - FirebaseJson &_add(const char *key, const char *value, size_t klen, size_t vlen, bool isString = true, bool isJson = true); - FirebaseJson &_addArrayStr(const char *value, size_t len, bool isString); - void _resetParsserInfo(); - void _resetParseResult(); - void _setElementType(); - void _addString(const std::string &key, const std::string &value); - void _addArray(const std::string &key, FirebaseJsonArray *arr); - void _addInt(const std::string &key, int value); - void _addFloat(const std::string &key, float value); - void _addDouble(const std::string &key, double value); - void _addBool(const std::string &key, bool value); - void _addNull(const std::string &key); - void _addJson(const std::string &key, FirebaseJson *json); - void _setString(const std::string &path, const std::string &value); - void _setInt(const std::string &path, int value); - void _setFloat(const std::string &path, float value); - void _setDouble(const std::string &path, double value); - void _setBool(const std::string &path, bool value); - void _setNull(const std::string &path); - void _setJson(const std::string &path, FirebaseJson *json); - void _setArray(const std::string &path, FirebaseJsonArray *arr); - void _set(const char *path, const char *data); - void clearPathTk(); - void _parse(const char *path, PRINT_MODE printMode); - void _parse(const char *key, int depth, int index, PRINT_MODE printMode); - void _compile(const char *key, int depth, int index, const char *replace, PRINT_MODE printMode, int refTokenIndex = -1, bool removeTk = false); - void _remove(const char *key, int depth, int index, const char *replace, int refTokenIndex = -1, bool removeTk = false); - void _fbjs_parse(bool collectTk = false); - bool _updateTkIndex(uint16_t index, int &depth, const char *searchKey, int searchIndex, const char *replace, PRINT_MODE printMode, bool advanceCount); - bool _updateTkIndex2(std::string &str, uint16_t index, int &depth, const char *searchKey, int searchIndex, const char *replace, PRINT_MODE printMode); - bool _updateTkIndex3(uint16_t index, int &depth, const char *searchKey, int searchIndex, PRINT_MODE printMode); - void _getTkIndex(int depth, tk_index_t &tk); - void _setMark(int depth, bool mark); - void _setSkip(int depth, bool skip); - void _setRef(int depth, bool ref); - void _insertChilds(const char *data, PRINT_MODE printMode); - void _addObjNodes(std::string &str, std::string &str2, int index, const char *data, PRINT_MODE printMode); - void _addArrNodes(std::string &str, std::string &str2, int index, const char *data, PRINT_MODE printMode); - void _compileToken(uint16_t &i, char *buf, int &depth, const char *searchKey, int searchIndex, PRINT_MODE printMode, const char *replace, int refTokenIndex = -1, bool removeTk = false); - void _parseToken(uint16_t &i, char *buf, int &depth, const char *searchKey, int searchIndex, PRINT_MODE printMode); - void _removeToken(uint16_t &i, char *buf, int &depth, const char *searchKey, int searchIndex, PRINT_MODE printMode, const char *replace, int refTokenIndex = -1, bool removeTk = false); - single_child_parent_t _findSCParent(int depth); - bool _isArrTk(int index); - bool _isStrTk(int index); - int _getArrIndex(int index); - void _get(const char *key, int depth, int index = -1); - void _ltrim(std::string &str, const std::string &chars = " "); - void _rtrim(std::string &str, const std::string &chars = " "); - void _trim(std::string &str, const std::string &chars = " "); - void _toStdString(std::string &s, bool isJson = true); - void _tostr(std::string &s, bool prettify = false); - void _strToTk(const std::string &str, std::vector &tk, char delim); - - void fbjs_init(fbjs_parser *parser); - int fbjs_parse(fbjs_parser *parser, const char *js, size_t len, - fbjs_tok_t *tokens, unsigned int num_tokens); - int fbjs_parse_string(fbjs_parser *parser, const char *js, - size_t len, fbjs_tok_t *tokens, size_t num_tokens); - int fbjs_parse_primitive(fbjs_parser *parser, const char *js, - size_t len, fbjs_tok_t *tokens, size_t num_tokens); - void fbjs_fill_token(fbjs_tok_t *token, fbjs_type_t type, - int start, int end); - fbjs_tok_t *fbjs_alloc_token(fbjs_parser *parser, - fbjs_tok_t *tokens, size_t num_tokens); + size_t _parser_buff_len = FB_JSON_EXTRAS_BUFFER_LENGTH; + + fb_json_last_error_t _lastErr; + + FirebaseJsonHelper *helper = new FirebaseJsonHelper(&_lastErr); + + fbjs_type_t _topLevelTkType = JSMN_OBJECT; + + fb_json_parser_info_t _parser_info; + + char *_qt = nullptr; + char *_tab = nullptr; + char *_brk1 = nullptr; + char *_brk2 = nullptr; + char *_brk3 = nullptr; + char *_brk4 = nullptr; + char *_cm = nullptr; + char *_nl = nullptr; + char *_nll = nullptr; + char *_pr = nullptr; + char *_pr2 = nullptr; + char *_pd = nullptr; + char *_pf = nullptr; + char *_fls = nullptr; + char *_tr = nullptr; + char *_string = nullptr; + char *_int = nullptr; + char *_dbl = nullptr; + char *_bl = nullptr; + char *_obj = nullptr; + char *_arry = nullptr; + char *_undef = nullptr; + char *_dot = nullptr; + + std::string _rawbuf = ""; + std::string _tbuf = ""; + tk_index_t _lastTk; + std::vector _pathTk = std::vector(); + std::vector _eltk = std::vector(); + std::vector _el = std::vector(); + FirebaseJsonData _jsonData; + + std::shared_ptr _parser = std::shared_ptr(new fbjs_parser()); + std::shared_ptr _tokens = nullptr; + + void _init(); + void _finalize(); + FirebaseJson &_setJsonData(std::string &data); + FirebaseJson &_add(const char *key, const char *value, size_t klen, size_t vlen, bool isString = true, bool isJson = true); + FirebaseJson &_addArrayStr(const char *value, size_t len, bool isString); + void _resetParsserInfo(); + void _resetParseResult(); + void _setElementType(); + void _addString(const std::string &key, const std::string &value); + void _addArray(const std::string &key, FirebaseJsonArray *arr); + void _addInt(const std::string &key, int value); + void _addFloat(const std::string &key, float value); + void _addDouble(const std::string &key, double value); + void _addBool(const std::string &key, bool value); + void _addNull(const std::string &key); + void _addJson(const std::string &key, FirebaseJson *json); + void _setString(const std::string &path, const std::string &value); + void _setInt(const std::string &path, int value); + void _setFloat(const std::string &path, float value); + void _setDouble(const std::string &path, double value); + void _setBool(const std::string &path, bool value); + void _setNull(const std::string &path); + void _setJson(const std::string &path, FirebaseJson *json); + void _setArray(const std::string &path, FirebaseJsonArray *arr); + void _set(const char *path, const char *data); + void clearPathTk(); + void _parse(const char *path, PRINT_MODE printMode); + void _parse(const char *key, int depth, int index, PRINT_MODE printMode); + void _compile(const char *key, int depth, int index, const char *replace, PRINT_MODE printMode, int refTokenIndex = -1, bool removeTk = false); + void _remove(const char *key, int depth, int index, const char *replace, int refTokenIndex = -1, bool removeTk = false); + void _fbjs_parse(bool collectTk = false); + bool _updateTkIndex(uint16_t index, int &depth, const char *searchKey, int searchIndex, const char *replace, PRINT_MODE printMode, bool advanceCount); + bool _updateTkIndex2(std::string &str, uint16_t index, int &depth, const char *searchKey, int searchIndex, const char *replace, PRINT_MODE printMode); + bool _updateTkIndex3(uint16_t index, int &depth, const char *searchKey, int searchIndex, PRINT_MODE printMode); + void _getTkIndex(int depth, tk_index_t &tk); + void _setMark(int depth, bool mark); + void _setSkip(int depth, bool skip); + void _setRef(int depth, bool ref); + void _insertChilds(const char *data, PRINT_MODE printMode); + void _addObjNodes(std::string &str, std::string &str2, int index, const char *data, PRINT_MODE printMode); + void _addArrNodes(std::string &str, std::string &str2, int index, const char *data, PRINT_MODE printMode); + void _compileToken(uint16_t &i, char *buf, int &depth, const char *searchKey, int searchIndex, PRINT_MODE printMode, const char *replace, int refTokenIndex = -1, bool removeTk = false); + void _parseToken(uint16_t &i, char *buf, int &depth, const char *searchKey, int searchIndex, PRINT_MODE printMode); + void _removeToken(uint16_t &i, char *buf, int &depth, const char *searchKey, int searchIndex, PRINT_MODE printMode, const char *replace, int refTokenIndex = -1, bool removeTk = false); + single_child_parent_t _findSCParent(int depth); + bool _isArrTk(int index); + bool _isStrTk(int index); + int _getArrIndex(int index); + void _get(const char *key, int depth, int index = -1); + void _ltrim(std::string &str, const std::string &chars = " "); + void _rtrim(std::string &str, const std::string &chars = " "); + void _trim(std::string &str, const std::string &chars = " "); + void _toStdString(std::string &s, bool isJson = true); + void _tostr(std::string &s, bool prettify = false); + void _strToTk(const std::string &str, std::vector &tk, char delim); + + void fbjs_init(fbjs_parser *parser); + int fbjs_parse(fbjs_parser *parser, const char *js, size_t len, + fbjs_tok_t *tokens, unsigned int num_tokens); + int fbjs_parse_string(fbjs_parser *parser, const char *js, + size_t len, fbjs_tok_t *tokens, size_t num_tokens); + int fbjs_parse_primitive(fbjs_parser *parser, const char *js, + size_t len, fbjs_tok_t *tokens, size_t num_tokens); + void fbjs_fill_token(fbjs_tok_t *token, fbjs_type_t type, + int start, int end); + fbjs_tok_t *fbjs_alloc_token(fbjs_parser *parser, + fbjs_tok_t *tokens, size_t num_tokens); }; class FirebaseJsonArray { - friend class FirebaseJson; - friend class FirebaseJsonData; + friend class FirebaseJson; + friend class FirebaseJsonData; public: - FirebaseJsonArray(); - FirebaseJsonArray(fb_json_last_error_t *lastErr, size_t bufLimit = FB_JSON_EXTRAS_BUFFER_LENGTH); - ~FirebaseJsonArray(); - void _init(); - void _finalize(); + FirebaseJsonArray(); + FirebaseJsonArray(fb_json_last_error_t *lastErr, size_t bufLimit = FB_JSON_EXTRAS_BUFFER_LENGTH); + ~FirebaseJsonArray(); + void _init(); + void _finalize(); - /** + /** * Add null to FirebaseJsonArray object. * * @return instance of an object. */ - FirebaseJsonArray &add(); + FirebaseJsonArray &add(); - /** + /** * Add string to FirebaseJsonArray object. * * @param value - The string value to add. * @return instance of an object. */ - FirebaseJsonArray &add(const String &value); + FirebaseJsonArray &add(const String &value); - /** + /** * Add string (chars arrar) to FirebaseJsonArray object. * * @param value - The char array to add. * @return instance of an object. */ - FirebaseJsonArray &add(const char *value); + FirebaseJsonArray &add(const char *value); - /** + /** * Add integer/unsigned short to FirebaseJsonArray object. * * @param value - The integer/unsigned short value to add. * @return instance of an object. */ - FirebaseJsonArray &add(int value); - FirebaseJsonArray &add(unsigned short value); + FirebaseJsonArray &add(int value); + FirebaseJsonArray &add(unsigned short value); - /** + /** * Add float to FirebaseJsonArray object. * * @param value - The float value to add. * @return instance of an object. */ - FirebaseJsonArray &add(float value); + FirebaseJsonArray &add(float value); - /** + /** * Add double to FirebaseJsonArray object. * * @param value - The double value to add. * @return instance of an object. */ - FirebaseJsonArray &add(double value); + FirebaseJsonArray &add(double value); - /** + /** * Add boolean to FirebaseJsonArray object. * * @param value - The boolean value to add. * @return instance of an object. */ - FirebaseJsonArray &add(bool value); + FirebaseJsonArray &add(bool value); - /** + /** * Add nested FirebaseJson object to FirebaseJsonArray object. * * @param json - The FirebaseJson object to add. * @return instance of an object. */ - FirebaseJsonArray &add(FirebaseJson &json); + FirebaseJsonArray &add(FirebaseJson &json); - /** + /** * Add nested FirebaseJsonArray object to FirebaseJsonArray object. * * @param arr - The FirebaseJsonArray object to add. * @return instance of an object. */ - FirebaseJsonArray &add(FirebaseJsonArray &arr); + FirebaseJsonArray &add(FirebaseJsonArray &arr); - /** + /** * Set JSON array data (JSON array string) to FirebaseJsonArray object. * * @param data - The JSON array string. * @return instance of an object. */ - FirebaseJsonArray &setJsonArrayData(const String &data); + FirebaseJsonArray &setJsonArrayData(const String &data); - /** + /** * Get the array value at the specified index from the FirebaseJsonArray object. * * @param jsonData - The returning FirebaseJsonData object that holds data at the specified index. * @param index - Index of data in FirebaseJsonArray object. * @return boolean status of the operation. */ - bool get(FirebaseJsonData &jsonData, int index); - bool get(FirebaseJsonData *jsonData, int index); + bool get(FirebaseJsonData &jsonData, int index); + bool get(FirebaseJsonData *jsonData, int index); - /** + /** * Get the array value at the specified path from FirebaseJsonArray object. * * @param jsonData - The returning FirebaseJsonData object that holds data at the specified path. @@ -1131,112 +1133,112 @@ class FirebaseJsonArray * The relative path must begin with array index (number placed inside square brackets) followed by * other array indexes or node names e.g. /[2]/myData would get the data from myData key inside the array indexes 2 */ - bool get(FirebaseJsonData &jsonData, const String &path); + bool get(FirebaseJsonData &jsonData, const String &path); - /** + /** * Get the length of the array in FirebaseJsonArray object. * * @return length of the array. */ - size_t size(); + size_t size(); - /** + /** * Get the FirebaseJsonArray object serialized string. * * @param buf - The returning String object. * @param prettify - Boolean flag for return the pretty format string i.e. with text indentation and newline. */ - void toString(String &buf, bool prettify = false); + void toString(String &buf, bool prettify = false); - /** + /** * Clear all array in FirebaseJsonArray object. * * @return instance of an object. */ - FirebaseJsonArray &clear(); + FirebaseJsonArray &clear(); - /** + /** * Set null to FirebaseJsonArray object at specified index. * * @param index - The array index that null to be set. */ - void set(int index); + void set(int index); - /** + /** * Set String to FirebaseJsonArray object at the specified index. * * @param index - The array index that String value to be set. * @param value - The String to set. */ - void set(int index, const String &value); + void set(int index, const String &value); - /** + /** * Set string (chars array) to FirebaseJsonArray object at specified index. * * @param index - The array index that string (chars array) to be set. * @param value - The char array to set. */ - void set(int index, const char *value); + void set(int index, const char *value); - /** + /** * Set integer/unsigned short value to FirebaseJsonArray object at specified index. * * @param index - The array index that int/unsigned short to be set. * @param value - The integer/unsigned short value to set. */ - void set(int index, int value); - void set(int index, unsigned short value); + void set(int index, int value); + void set(int index, unsigned short value); - /** + /** * Set float value to FirebaseJsonArray object at specified index. * * @param index - The array index that float value to be set. * @param value - The float value to set. */ - void set(int index, float value); + void set(int index, float value); - /** + /** * Set double value to FirebaseJsonArray object at specified index. * * @param index - The array index that double value to be set. * @param value - The double value to set. */ - void set(int index, double value); + void set(int index, double value); - /** + /** * Set boolean value to FirebaseJsonArray object at specified index. * * @param index - The array index that bool value to be set. * @param value - The boolean value to set. */ - void set(int index, bool value); + void set(int index, bool value); - /** + /** * Set nested FirebaseJson object to FirebaseJsonArray object at specified index. * * @param index - The array index that nested FirebaseJson object to be set. * @param value - The FirebaseJson object to set. */ - void set(int index, FirebaseJson &json); + void set(int index, FirebaseJson &json); - /** + /** * Set nested FirebaseJsonArray object to FirebaseJsonArray object at specified index. * * @param index - The array index that nested FirebaseJsonArray object to be set. * @param value - The FirebaseJsonArray object to set. */ - void set(int index, FirebaseJsonArray &arr); + void set(int index, FirebaseJsonArray &arr); - /** + /** * Set null to FirebaseJson object at the specified path. * * @param path - The relative path that null to be set. * The relative path must begin with array index (number placed inside square brackets) followed by * other array indexes or node names e.g. /[2]/myData would get the data from myData key inside the array indexes 2. */ - void set(const String &path); + void set(const String &path); - /** + /** * Set String to FirebaseJsonArray object at the specified path. * * @param path - The relative path that string value to be set. @@ -1244,9 +1246,9 @@ class FirebaseJsonArray * The relative path must begin with array index (number placed inside square brackets) followed by * other array indexes or node names e.g. /[2]/myData would get the data from myData key inside the array indexes 2. */ - void set(const String &path, const String &value); + void set(const String &path, const String &value); - /** + /** * Set string (chars array) to FirebaseJsonArray object at the specified path. * * @param path - The relative path that string (chars array) value to be set. @@ -1254,9 +1256,9 @@ class FirebaseJsonArray * The relative path must begin with array index (number places inside square brackets) followed by * other array indexes or node names e.g. /[2]/myData would get the data from myData key inside the array indexes 2. */ - void set(const String &path, const char *value); + void set(const String &path, const char *value); - /** + /** * Set integer/unsigned short value to FirebaseJsonArray object at specified path. * * @param path - The relative path that integer/unsigned short value to be set. @@ -1264,10 +1266,10 @@ class FirebaseJsonArray * The relative path must begin with array index (number placed inside square brackets) followed by * other array indexes or node names e.g. /[2]/myData would get the data from myData key inside the array indexes 2. */ - void set(const String &path, int value); - void set(const String &path, unsigned short value); + void set(const String &path, int value); + void set(const String &path, unsigned short value); - /** + /** * Set float value to FirebaseJsonArray object at specified path. * * @param path - The relative path that float value to be set. @@ -1275,9 +1277,9 @@ class FirebaseJsonArray * The relative path must begin with array index (number placed inside square brackets) followed by * other array indexes or node names e.g. /[2]/myData would get the data from myData key inside the array indexes 2. */ - void set(const String &path, float value); + void set(const String &path, float value); - /** + /** * Set double value to FirebaseJsonArray object at specified path. * * @param path - The relative path that double value to be set. @@ -1285,9 +1287,9 @@ class FirebaseJsonArray * The relative path must begin with array index (number placed inside square brackets) followed by * other array indexes or node names e.g. /[2]/myData would get the data from myData key inside the array indexes 2. */ - void set(const String &path, double value); + void set(const String &path, double value); - /** + /** * Set boolean value to FirebaseJsonArray object at specified path. * * @param path - The relative path that bool value to be set. @@ -1295,9 +1297,9 @@ class FirebaseJsonArray * The relative path must begin with array index (number placed inside square brackets) followed by * other array indexes or node names e.g. /[2]/myData would get the data from myData key inside the array indexes 2. */ - void set(const String &path, bool value); + void set(const String &path, bool value); - /** + /** * Set the nested FirebaseJson object to FirebaseJsonArray object at the specified path. * * @param path - The relative path that nested FirebaseJson object to be set. @@ -1305,9 +1307,9 @@ class FirebaseJsonArray * The relative path must begin with array index (number placed inside square brackets) followed by * other array indexes or node names e.g. /[2]/myData would get the data from myData key inside the array indexes 2. */ - void set(const String &path, FirebaseJson &json); + void set(const String &path, FirebaseJson &json); - /** + /** * Set the nested FirebaseJsonArray object to FirebaseJsonArray object at specified path. * * @param path - The relative path that nested FirebaseJsonArray object to be set. @@ -1315,17 +1317,17 @@ class FirebaseJsonArray * The relative path must begin with array index (number placed inside square brackets) followed by * other array indexes or node names e.g. /[2]/myData would get the data from myData key inside the array indexes 2. */ - void set(const String &path, FirebaseJsonArray &arr); + void set(const String &path, FirebaseJsonArray &arr); - /** + /** * Remove the array value at the specified index from the FirebaseJsonArray object. * * @param index - The array index to be removed. * @return bool value represents the successful operation. */ - bool remove(int index); + bool remove(int index); - /** + /** * Remove the array value at the specified path from FirebaseJsonArray object. * * @param path - The relative path to array in FirebaseJsonArray object to be removed. @@ -1333,71 +1335,71 @@ class FirebaseJsonArray * The relative path must begin with array index (number placed inside square brackets) followed by * other array indexes or node names e.g. /[2]/myData would remove the data of myData key inside the array indexes 2. */ - bool remove(const String &path); + bool remove(const String &path); - template - void set(int index, T value); - template - void set(const String &path, T value); - template - FirebaseJsonArray &add(T value); + template + void set(int index, T value); + template + void set(const String &path, T value); + template + FirebaseJsonArray &add(T value); - std::string *int_dbuf(); - std::string *int_tbuf(); - std::string *int_jbuf(); - std::string *int_rawbuf(); - FirebaseJson *int_json(); - void int_set_arr_len(size_t len); - void int_toStdString(std::string &s); + std::string *int_dbuf(); + std::string *int_tbuf(); + std::string *int_jbuf(); + std::string *int_rawbuf(); + FirebaseJson *int_json(); + void int_set_arr_len(size_t len); + void int_toStdString(std::string &s); private: - fb_json_last_error_t *_lastErr = nullptr; - size_t _parser_buff_len = FB_JSON_EXTRAS_BUFFER_LENGTH; - FirebaseJsonHelper *helper = new FirebaseJsonHelper(_lastErr); - std::string _jbuf = ""; - FirebaseJson _json; - size_t _arrLen = 0; - char *_pd = nullptr; - char *_pf = nullptr; - char *_fls = nullptr; - char *_tr = nullptr; - char *_brk3 = nullptr; - char *_brk4 = nullptr; - char *_nll = nullptr; - char *_root = nullptr; - char *_root2 = nullptr; - char *_qt = nullptr; - char *_slash = nullptr; - - void _addString(const std::string &value); - void _addInt(int value); - void _addFloat(float value); - void _addDouble(double value); - void _addBool(bool value); - void _addNull(); - void _addJson(FirebaseJson *json); - void _addArray(FirebaseJsonArray *arr); - void _setString(int index, const std::string &value); - void _setString(const String &path, const std::string &value); - void _setInt(int index, int value); - void _setInt(const String &path, int value); - void _setFloat(int index, float value); - void _setFloat(const String &path, float value); - void _setDouble(int index, double value); - void _setDouble(const String &path, double value); - void _setBool(int index, bool value); - void _setBool(const String &path, bool value); - void _setNull(int index); - void _setNull(const String &path); - void _setJson(int index, FirebaseJson *json); - void _setJson(const String &path, FirebaseJson *json); - void _setArray(int index, FirebaseJsonArray *arr); - void _setArray(const String &path, FirebaseJsonArray *arr); - void _toStdString(std::string &s); - void _set2(int index, const char *value, bool isStr = true); - void _set(const char *path, const char *value, bool isStr = true); - bool _get(FirebaseJsonData &jsonData, const char *path); - bool _remove(const char *path); + fb_json_last_error_t *_lastErr = nullptr; + size_t _parser_buff_len = FB_JSON_EXTRAS_BUFFER_LENGTH; + FirebaseJsonHelper *helper = new FirebaseJsonHelper(_lastErr); + std::string _jbuf = ""; + FirebaseJson _json; + size_t _arrLen = 0; + char *_pd = nullptr; + char *_pf = nullptr; + char *_fls = nullptr; + char *_tr = nullptr; + char *_brk3 = nullptr; + char *_brk4 = nullptr; + char *_nll = nullptr; + char *_root = nullptr; + char *_root2 = nullptr; + char *_qt = nullptr; + char *_slash = nullptr; + + void _addString(const std::string &value); + void _addInt(int value); + void _addFloat(float value); + void _addDouble(double value); + void _addBool(bool value); + void _addNull(); + void _addJson(FirebaseJson *json); + void _addArray(FirebaseJsonArray *arr); + void _setString(int index, const std::string &value); + void _setString(const String &path, const std::string &value); + void _setInt(int index, int value); + void _setInt(const String &path, int value); + void _setFloat(int index, float value); + void _setFloat(const String &path, float value); + void _setDouble(int index, double value); + void _setDouble(const String &path, double value); + void _setBool(int index, bool value); + void _setBool(const String &path, bool value); + void _setNull(int index); + void _setNull(const String &path); + void _setJson(int index, FirebaseJson *json); + void _setJson(const String &path, FirebaseJson *json); + void _setArray(int index, FirebaseJsonArray *arr); + void _setArray(const String &path, FirebaseJsonArray *arr); + void _toStdString(std::string &s); + void _set2(int index, const char *value, bool isStr = true); + void _set(const char *path, const char *value, bool isStr = true); + bool _get(FirebaseJsonData &jsonData, const char *path); + bool _remove(const char *path); }; #endif \ No newline at end of file diff --git a/src/rtdb/FB_RTDB.cpp b/src/rtdb/FB_RTDB.cpp index 12c4958f..e61834a4 100644 --- a/src/rtdb/FB_RTDB.cpp +++ b/src/rtdb/FB_RTDB.cpp @@ -1,9 +1,9 @@ /** - * Google's Firebase Realtime Database class, FB_RTDB.cpp version 1.0.9 + * Google's Firebase Realtime Database class, FB_RTDB.cpp version 1.0.12 * * This library supports Espressif ESP8266 and ESP32 * - * Created April 4, 2021 + * Created May 1, 2021 * * This work is a part of Firebase ESP Client library * Copyright (c) 2021 K. Suwatchai (Mobizt) @@ -87,6 +87,184 @@ bool FB_RTDB::setRules(FirebaseData *fbdo, const char *rules) return handleRequest(fbdo, &req); } +bool FB_RTDB::setQueryIndex(FirebaseData *fbdo, const char *path, const char *node, const char *databaseSecret) +{ + return int_setQueryIndex(fbdo, path, node, databaseSecret); +} + +bool FB_RTDB::removeQueryIndex(FirebaseData *fbdo, const char *path, const char *databaseSecret) +{ + return int_setQueryIndex(fbdo, path, "", databaseSecret); +} + +bool FB_RTDB::int_setQueryIndex(FirebaseData *fbdo, const char *path, const char *node, const char *databaseSecret) +{ + if (fbdo->_ss.rtdb.pause) + return true; + + if (!fbdo->reconnect()) + return false; + + if (!fbdo->tokenReady()) + return false; + + std::string s; + bool ret = false; + + fb_esp_auth_token_type tk = Signer.getTokenType(); + + if (strlen(databaseSecret) && tk != token_type_oauth2_access_token && tk != token_type_legacy_token) + { + Signer.config->signer.tokens.legacy_token = databaseSecret; + Signer.config->signer.tokens.token_type = token_type_legacy_token; + Signer.handleToken(); + } + + if (getRules(fbdo)) + { + ret = true; + FirebaseJsonData data; + FirebaseJson *json = fbdo->jsonObjectPtr(); + bool ruleExisted = false; + + s.clear(); + ut->appendP(s, fb_esp_pgm_str_550); + if (path[0] != '/') + s += '/'; + s += path; + ut->appendP(s, fb_esp_pgm_str_551); + + json->get(data, s.c_str()); + + if (data.success && strcmp(data.stringValue.c_str(), node) == 0) + ruleExisted = true; + + if (strlen(node) == 0) + json->remove(s.c_str()); + else + json->set(s.c_str(), node); + + if (!ruleExisted || (ruleExisted && strlen(node) == 0)) + { + String rules; + json->toString(rules, true); + ret = setRules(fbdo, rules.c_str()); + } + + json->clear(); + } + + if (strlen(databaseSecret) && tk != token_type_oauth2_access_token && tk != token_type_legacy_token) + { + if (tk != token_type_legacy_token) + Signer.config->signer.tokens.legacy_token.clear(); + + Signer.config->signer.tokens.token_type = tk; + Signer.handleToken(); + } + + std::string().swap(s); + + return ret; +} + +bool FB_RTDB::setReadWriteRules(FirebaseData *fbdo, const char *path, const char *var, const char *readVal, const char *writeVal, const char *databaseSecret) +{ + if (fbdo->_ss.rtdb.pause) + return true; + + if (!fbdo->reconnect()) + return false; + + if (!fbdo->tokenReady()) + return false; + + std::string s; + bool ret = false; + + fb_esp_auth_token_type tk = Signer.getTokenType(); + + if (strlen(databaseSecret) && tk != token_type_oauth2_access_token && tk != token_type_legacy_token) + { + Signer.config->signer.tokens.legacy_token = databaseSecret; + Signer.config->signer.tokens.token_type = token_type_legacy_token; + Signer.handleToken(); + } + + if (getRules(fbdo)) + { + ret = true; + FirebaseJsonData data; + FirebaseJson &json = fbdo->jsonObject(); + bool rd = false, wr = false; + + std::string s; + ut->appendP(s, fb_esp_pgm_str_550); + if (path[0] != '/') + ut->appendP(s, fb_esp_pgm_str_1); + s += path; + ut->appendP(s, fb_esp_pgm_str_1); + s += var; + + if (strlen(readVal) > 0) + { + rd = true; + std::string r = s; + ut->appendP(r, fb_esp_pgm_str_1); + ut->appendP(r, fb_esp_pgm_str_552); + json.get(data, r.c_str()); + if (data.success) + if (strcmp(data.stringValue.c_str(), readVal) == 0) + rd = false; + } + + if (strlen(writeVal) > 0) + { + wr = true; + std::string w = s; + ut->appendP(w, fb_esp_pgm_str_1); + ut->appendP(w, fb_esp_pgm_str_553); + json.get(data, w.c_str()); + if (data.success) + if (strcmp(data.stringValue.c_str(), writeVal) == 0) + wr = false; + } + + //modify if the rules changed or does not exist. + if (wr || rd) + { + FirebaseJson js; + std::string r, w; + ut->appendP(r, fb_esp_pgm_str_552); + ut->appendP(w, fb_esp_pgm_str_553); + if (rd) + js.add(r.c_str(), readVal); + + if (wr) + js.add(w.c_str(), writeVal); + + json.set(s.c_str(), js); + String rules; + json.toString(rules, true); + ret = setRules(fbdo, rules.c_str()); + } + + json.clear(); + } + + if (strlen(databaseSecret) && tk != token_type_oauth2_access_token && tk != token_type_legacy_token) + { + if (tk != token_type_legacy_token) + Signer.config->signer.tokens.legacy_token.clear(); + + Signer.config->signer.tokens.token_type = tk; + Signer.handleToken(); + } + + std::string().swap(s); + return ret; +} + bool FB_RTDB::pathExisted(FirebaseData *fbdo, const char *path) { fbdo->queryFilter.clear(); @@ -2090,6 +2268,67 @@ bool FB_RTDB::deleteNode(FirebaseData *fbdo, const char *path, const char *ETag) return handleRequest(fbdo, &req); } +bool FB_RTDB::deleteNodesByTimestamp(FirebaseData *fbdo, const char *path, const char *timestampNode, size_t limit, unsigned long dataRetentionPeriod) +{ + + if (fbdo->_ss.rtdb.pause) + return true; + + if (!fbdo->reconnect()) + return false; + + if (!fbdo->tokenReady()) + return false; + + time_t current_ts = time(nullptr); + + if (current_ts < ESP_DEFAULT_TS) + return false; + + bool ret = false; + + if (limit > 30) + limit = 30; + + QueryFilter query; + + double lastTS = current_ts - dataRetentionPeriod; + + query.orderBy(timestampNode).startAt(0).endAt(lastTS).limitToLast((int)limit); + + if (getJSON(fbdo, path, &query)) + { + ret = true; + if (fbdo->_ss.rtdb.resp_data_type == d_json && fbdo->jsonString().length() > 4) + { + FirebaseJson *js = fbdo->jsonObjectPtr(); + size_t len = js->iteratorBegin(); + String key, value; + int otype = 0; + std::string nodes[len]; + for (size_t i = 0; i < len; i++) + { + js->iteratorGet(i, otype, key, value); + if (otype == FirebaseJson::JSON_OBJECT && key.length() > 1) + nodes[i] = key.c_str(); + } + js->iteratorEnd(); + js->clear(); + + for (size_t i = 0; i < len; i++) + { + std::string s = path; + ut->appendP(s, fb_esp_pgm_str_1); + s += nodes[i]; + deleteNode(fbdo, s.c_str()); + } + } + } + + query.clear(); + return ret; +} + bool FB_RTDB::beginStream(FirebaseData *fbdo, const char *path) { @@ -2177,7 +2416,7 @@ bool FB_RTDB::handleStreamRead(FirebaseData *fbdo) //trying to reconnect the stream when required at some interval as running in the loop if (millis() - STREAM_RECONNECT_INTERVAL > fbdo->_ss.rtdb.stream_resume_millis) { - reconnectStream = (fbdo->_ss.rtdb.data_tmo && !fbdo->_ss.connected) || fbdo->_ss.con_mode != fb_esp_con_mode_rtdb_stream; + reconnectStream = (fbdo->_ss.rtdb.data_tmo && !fbdo->_ss.connected) || fbdo->_ss.http_code >= 400 || fbdo->_ss.con_mode != fb_esp_con_mode_rtdb_stream; if (fbdo->_ss.rtdb.data_tmo) fbdo->closeSession(); @@ -3252,12 +3491,6 @@ int FB_RTDB::sendRequest(FirebaseData *fbdo, struct fb_esp_rtdb_request_info_t * if (!fbdo->reconnect()) return FIREBASE_ERROR_HTTPC_ERROR_CONNECTION_LOST; - if (Signer.config->host.length() == 0) - { - fbdo->_ss.http_code = FIREBASE_ERROR_UNINITIALIZED; - return false; - } - if (!fbdo->tokenReady()) return FIREBASE_ERROR_TOKEN_NOT_READY; @@ -3272,7 +3505,7 @@ int FB_RTDB::sendRequest(FirebaseData *fbdo, struct fb_esp_rtdb_request_info_t * uint8_t attempts = 0; uint8_t maxRetry = 5; - size_t buffSize = 32; + size_t buffSize = 128; char *tmp = nullptr; char *buf = nullptr; @@ -3283,7 +3516,7 @@ int FB_RTDB::sendRequest(FirebaseData *fbdo, struct fb_esp_rtdb_request_info_t * std::string payloadBuf = ""; std::string header = ""; - rescon(fbdo, Signer.getCfg()->host.c_str(), req); + rescon(fbdo, Signer.getCfg()->database_url.c_str(), req); if (req->method == fb_esp_method::m_stream) { @@ -3318,7 +3551,7 @@ int FB_RTDB::sendRequest(FirebaseData *fbdo, struct fb_esp_rtdb_request_info_t * return FIREBASE_ERROR_CANNOT_CONFIG_TIME; } #endif - fbdo->httpClient.begin(Signer.getCfg()->host.c_str(), FIREBASE_PORT); + fbdo->httpClient.begin(Signer.getCfg()->database_url.c_str(), FIREBASE_PORT); //Prepare for string and JSON payloads preparePayload(req, payloadBuf); @@ -3587,7 +3820,7 @@ bool FB_RTDB::waitResponse(FirebaseData *fbdo) //if currently perform stream payload handling process, skip it. if (Signer.getCfg()->_int.fb_processing && fbdo->_ss.con_mode == fb_esp_con_mode_rtdb_stream) return true; - + //set the blocking flag Signer.getCfg()->_int.fb_processing = true; bool ret = handleResponse(fbdo); @@ -3621,8 +3854,8 @@ bool FB_RTDB::handleResponse(FirebaseData *fbdo) char *pChunk = nullptr; char *tmp = nullptr; - char *header = nullptr; - char *payload = nullptr; + std::string header; + std::string payload; bool isHeader = false; struct server_response_data_t response; @@ -3631,17 +3864,15 @@ bool FB_RTDB::handleResponse(FirebaseData *fbdo) int pChunkIdx = 0; int payloadLen = fbdo->_ss.resp_size; int pBufPos = 0; - int hBufPos = 0; int chunkBufSize = stream->available(); - int hstate = 0; - int pstate = 0; bool redirect = false; int chunkedDataState = 0; int chunkedDataSize = 0; int chunkedDataLen = 0; int defaultChunkSize = fbdo->_ss.resp_size; - fbdo->_ss.http_code = FIREBASE_ERROR_HTTP_CODE_OK; + if (fbdo->_ss.http_code == FIREBASE_ERROR_HTTP_CODE_UNDEFINED) + fbdo->_ss.http_code = FIREBASE_ERROR_HTTP_CODE_OK; fbdo->_ss.content_length = -1; fbdo->_ss.rtdb.push_name.clear(); fbdo->_ss.rtdb.data_mismatch = false; @@ -3692,41 +3923,30 @@ bool FB_RTDB::handleResponse(FirebaseData *fbdo) if (chunkIdx == 0) { + if (!stream) + break; + //the first chunk can be stream event data (no header) or http response header - header = ut->newS(chunkBufSize); - if (header) - { - hstate = 1; - int readLen = ut->readLine(stream, header, chunkBufSize); - int pos = 0; + ut->readLine(stream, header); + int pos = 0; - response.noEvent = fbdo->_ss.con_mode != fb_esp_con_mode_rtdb_stream; + response.noEvent = fbdo->_ss.con_mode != fb_esp_con_mode_rtdb_stream; - tmp = ut->getHeader(header, fb_esp_pgm_str_5, fb_esp_pgm_str_6, pos, 0); - delay(0); - dataTime = millis(); - if (tmp) - { - //http response header with http response code - isHeader = true; - hBufPos = readLen; - response.httpCode = atoi(tmp); - fbdo->_ss.http_code = response.httpCode; - ut->delS(tmp); - } - else - { - //stream payload data - payload = ut->newS(payloadLen); - if (payload) - { - pstate = 1; - memcpy(payload, header, readLen); - pBufPos = readLen; - ut->delS(header); - hstate = 0; - } - } + tmp = ut->getHeader(header.c_str(), fb_esp_pgm_str_5, fb_esp_pgm_str_6, pos, 0); + delay(0); + dataTime = millis(); + if (tmp) + { + //http response header with http response code + isHeader = true; + response.httpCode = atoi(tmp); + fbdo->_ss.http_code = response.httpCode; + ut->delS(tmp); + } + else + { + //stream payload data + payload = header; } } else @@ -3742,6 +3962,12 @@ bool FB_RTDB::handleResponse(FirebaseData *fbdo) int readLen = 0; if (tmp) { + if (!stream) + { + ut->delS(tmp); + break; + } + readLen = ut->readLine(stream, tmp, chunkBufSize); //check is it the end of http header (\n or \r\n)? @@ -3758,20 +3984,41 @@ bool FB_RTDB::handleResponse(FirebaseData *fbdo) { //parse header string to get the header field isHeader = false; - ut->parseRespHeader(header, response); + ut->parseRespHeader(header.c_str(), response); fbdo->_ss.rtdb.resp_etag = response.etag; - if (hstate == 1) - ut->delS(header); - hstate = 0; + std::string().swap(header); + + if (response.httpCode == 401) + Signer.authenticated = false; + else if (response.httpCode < 300) + Signer.authenticated = true; //error in request or server if (response.httpCode >= 400) { + if (ut->strposP(response.contentType.c_str(), fb_esp_pgm_str_74, 0) < 0) { - fbdo->closeSession(); - break; + if (stream) + { + size_t len = stream->available(); + char buf[len]; + stream->readBytes(buf, len); + while (stream->available()) + { + delay(0); + stream->read(); + } + if (tmp) + ut->delS(tmp); + return false; + } + else + { + if (tmp) + ut->delS(tmp); + } } } @@ -3803,8 +4050,7 @@ bool FB_RTDB::handleResponse(FirebaseData *fbdo) if (tmp) { //accumulate the remaining header field - memcpy(header + hBufPos, tmp, readLen); - hBufPos += readLen; + header += tmp; } } if (tmp) @@ -3820,18 +4066,18 @@ bool FB_RTDB::handleResponse(FirebaseData *fbdo) pChunk = ut->newS(chunkBufSize + 10); - if (!payload || pstate == 0) - { - pstate = 1; - payload = ut->newS(payloadLen + 10); - } - - if (!pChunk || !payload) + if (!pChunk) break; //read the avilable data int readLen = 0; + if (!stream) + { + ut->delS(pChunk); + break; + } + //chunk transfer encoding? if (response.isChunkedEnc) readLen = ut->readChunkedData(stream, pChunk, chunkedDataState, chunkedDataSize, chunkedDataLen, chunkBufSize); @@ -3844,31 +4090,10 @@ bool FB_RTDB::handleResponse(FirebaseData *fbdo) if (readLen > 0) { - fbdo->checkOvf(pBufPos + readLen, response); + fbdo->checkOvf(payload.length() + readLen, response); if (!fbdo->_ss.buffer_ovf) - { - if (pBufPos + readLen <= payloadLen) - memcpy(payload + pBufPos, pChunk, readLen); - else - { - //in case of the accumulated payload size is bigger than the char array - //reallocate the char array - - char *buf = ut->newS(pBufPos + readLen + 1); - if (buf) - { - memcpy(buf, payload, pBufPos); - memcpy(buf + pBufPos, pChunk, readLen); - payloadLen = pBufPos + readLen; - ut->delS(payload); - payload = ut->newS(payloadLen + 1); - if (payload) - memcpy(payload, buf, payloadLen); - ut->delS(buf); - } - } - } + payload += pChunk; } if (!fbdo->_ss.rtdb.data_tmo && !fbdo->_ss.buffer_ovf) @@ -3877,9 +4102,9 @@ bool FB_RTDB::handleResponse(FirebaseData *fbdo) if (response.dataType == 0 && !response.isEvent && !response.noContent) { if (fbdo->_ss.rtdb.req_data_type == fb_esp_data_type::d_blob || fbdo->_ss.rtdb.req_method == fb_esp_method::m_download || (fbdo->_ss.rtdb.req_data_type == fb_esp_data_type::d_file && fbdo->_ss.rtdb.req_method == fb_esp_method::m_get)) - ut->parseRespPayload(payload, response, true); + ut->parseRespPayload(payload.c_str(), response, true); else - ut->parseRespPayload(payload, response, false); + ut->parseRespPayload(payload.c_str(), response, false); fbdo->_ss.error = response.fbError; if (fbdo->_ss.rtdb.req_method == fb_esp_method::m_download || fbdo->_ss.rtdb.req_method == fb_esp_method::m_restore) @@ -3895,10 +4120,8 @@ bool FB_RTDB::handleResponse(FirebaseData *fbdo) ut->delS(tmp); } - if (hstate == 1) - ut->delS(header); - if (pstate == 1) - ut->delS(payload); + std::string().swap(header); + std::string().swap(payload); ut->closeFileHandle(fbdo->_ss.rtdb.storage_type == mem_storage_type_sd); fbdo->closeSession(); return false; @@ -3915,8 +4138,16 @@ bool FB_RTDB::handleResponse(FirebaseData *fbdo) { if (fbdo->_ss.rtdb.file_name.length() == 0) { + size_t writeLen = 0; if (Signer.getCfg()->_int.fb_file) - Signer.getCfg()->_int.fb_file.write((uint8_t *)payload, readLen); + writeLen = Signer.getCfg()->_int.fb_file.write((uint8_t *)payload.c_str(), readLen); + + fbdo->_ss.rtdb.backup_file_size = writeLen; + if (stream->available() == 0) + { + fbdo->closeSession(); + break; + } } else { @@ -3930,9 +4161,9 @@ bool FB_RTDB::handleResponse(FirebaseData *fbdo) payload[len - 1] = 0; if (fbdo->_ss.rtdb.storage_type == mem_storage_type_flash) - ut->decodeBase64Flash(payload + ofs, len, Signer.getCfg()->_int.fb_file); + ut->decodeBase64Flash(payload.c_str() + ofs, len, Signer.getCfg()->_int.fb_file); else if (fbdo->_ss.rtdb.storage_type == mem_storage_type_sd) - ut->decodeBase64Stream(payload + ofs, len, Signer.getCfg()->_int.fb_file); + ut->decodeBase64Stream(payload.c_str() + ofs, len, Signer.getCfg()->_int.fb_file); } } else @@ -3957,17 +4188,15 @@ bool FB_RTDB::handleResponse(FirebaseData *fbdo) payload[len - 1] = 0; if (fbdo->_ss.rtdb.storage_type == mem_storage_type_flash) - ut->decodeBase64Flash(payload + ofs, len, Signer.getCfg()->_int.fb_file); + ut->decodeBase64Flash(payload.c_str() + ofs, len, Signer.getCfg()->_int.fb_file); else if (fbdo->_ss.rtdb.storage_type == mem_storage_type_sd) - ut->decodeBase64Stream(payload + ofs, len, Signer.getCfg()->_int.fb_file); + ut->decodeBase64Stream(payload.c_str() + ofs, len, Signer.getCfg()->_int.fb_file); } } if (response.dataType > 0) { - if (pstate == 1) - ut->delS(payload); - pstate = 0; + std::string().swap(payload); pBufPos = 0; readLen = 0; } @@ -3990,6 +4219,8 @@ bool FB_RTDB::handleResponse(FirebaseData *fbdo) } else { + if (!stream) + break; //read all the rest data while (stream->available() > 0) stream->read(); @@ -4001,13 +4232,12 @@ bool FB_RTDB::handleResponse(FirebaseData *fbdo) } } - if (hstate == 1) - ut->delS(header); + std::string().swap(header); if (!fbdo->_ss.rtdb.data_tmo && !fbdo->_ss.buffer_ovf) { //parse the payload - if (payload) + if (payload.length() > 0) { if (response.isEvent) { @@ -4017,7 +4247,7 @@ bool FB_RTDB::handleResponse(FirebaseData *fbdo) while (pos > -1) { - pos = ut->strposP(payload, fb_esp_pgm_str_13, ofs); + pos = ut->strposP(payload.c_str(), fb_esp_pgm_str_13, ofs); if (pos > -1) { ofs = pos + 1; @@ -4028,32 +4258,29 @@ bool FB_RTDB::handleResponse(FirebaseData *fbdo) if (num > 1) { std::vector payloadList = std::vector(); - splitStreamPayload(payload, payloadList); + splitStreamPayload(payload.c_str(), payloadList); for (size_t i = 0; i < payloadList.size(); i++) { if (ut->validJS(payloadList[i].c_str())) { valid = true; parseStreamPayload(fbdo, payloadList[i].c_str()); - if (fbdo->streamAvailable()) - sendCB(fbdo); + sendCB(fbdo); } } payloadList.clear(); } else { - valid = ut->validJS(payload); + valid = ut->validJS(payload.c_str()); if (valid) { - parseStreamPayload(fbdo, payload); - if (fbdo->streamAvailable()) - sendCB(fbdo); + parseStreamPayload(fbdo, payload.c_str()); + sendCB(fbdo); } } - if (pstate == 1) - ut->delS(payload); + std::string().swap(payload); if (valid) { @@ -4076,9 +4303,9 @@ bool FB_RTDB::handleResponse(FirebaseData *fbdo) if (response.dataType == 0 && !response.noContent) { if (fbdo->_ss.rtdb.req_data_type == fb_esp_data_type::d_blob || fbdo->_ss.rtdb.req_method == fb_esp_method::m_download || (fbdo->_ss.rtdb.req_data_type == fb_esp_data_type::d_file && fbdo->_ss.rtdb.req_method == fb_esp_method::m_get)) - ut->parseRespPayload(payload, response, true); + ut->parseRespPayload(payload.c_str(), response, true); else - ut->parseRespPayload(payload, response, false); + ut->parseRespPayload(payload.c_str(), response, false); fbdo->_ss.error = response.fbError; } @@ -4094,7 +4321,7 @@ bool FB_RTDB::handleResponse(FirebaseData *fbdo) std::vector().swap(fbdo->_ss.rtdb.blob); fbdo->_ss.rtdb.data.clear(); fbdo->_ss.rtdb.data2.clear(); - ut->decodeBase64Str((const char *)payload + response.payloadOfs, fbdo->_ss.rtdb.blob); + ut->decodeBase64Str((const char *)payload.c_str() + response.payloadOfs, fbdo->_ss.rtdb.blob); } else if (fbdo->_ss.rtdb.resp_data_type == fb_esp_data_type::d_file || Signer.getCfg()->_int.fb_file) { @@ -4105,12 +4332,8 @@ bool FB_RTDB::handleResponse(FirebaseData *fbdo) if (fbdo->_ss.rtdb.req_method == fb_esp_method::m_set_rules) { - if (ut->stringCompare(payload, 0, fb_esp_pgm_str_104)) - { - if (pstate == 1) - ut->delS(payload); - pstate = 0; - } + if (ut->stringCompare(payload.c_str(), 0, fb_esp_pgm_str_104)) + std::string().swap(payload); } if (fbdo->_ss.http_code == FIREBASE_ERROR_HTTP_CODE_OK || fbdo->_ss.http_code == FIREBASE_ERROR_HTTP_CODE_PRECONDITION_FAILED) @@ -4120,7 +4343,7 @@ bool FB_RTDB::handleResponse(FirebaseData *fbdo) { if (fbdo->_ss.rtdb.resp_data_type != fb_esp_data_type::d_blob && fbdo->_ss.rtdb.resp_data_type != fb_esp_data_type::d_file) { - handlePayload(fbdo, response, payload); + handlePayload(fbdo, response, payload.c_str()); if (fbdo->_ss.rtdb.priority_val_flag) { @@ -4196,8 +4419,7 @@ bool FB_RTDB::handleResponse(FirebaseData *fbdo) ut->closeFileHandle(fbdo->_ss.rtdb.storage_type == mem_storage_type_sd); - if (pstate == 1) - ut->delS(payload); + std::string().swap(payload); if (!redirect) { @@ -4234,7 +4456,17 @@ bool FB_RTDB::handleResponse(FirebaseData *fbdo) void FB_RTDB::sendCB(FirebaseData *fbdo) { - //to allow other subsequence request which can be occurred in the user stream callback + + // prevent the data available and stream data changed flags reset by + // streamAvailable without stream callbacks assigned. + if (!fbdo->_dataAvailableCallback && !fbdo->_multiPathDataCallback) + return; + + if (!fbdo->streamAvailable()) + return; + + // to allow other subsequence request which can be occurred in the user stream + // callback Signer.getCfg()->_int.fb_processing = false; if (fbdo->_dataAvailableCallback) @@ -4255,7 +4487,7 @@ void FB_RTDB::sendCB(FirebaseData *fbdo) if (fbdo->_ss.rtdb.resp_data_type == fb_esp_data_type::d_blob) { s.sif->blob = fbdo->_ss.rtdb.blob; - //Free memory in case of the callback blob data was used + // Free memory in case of the callback blob data was used fbdo->_ss.rtdb.blob.clear(); } fbdo->_dataAvailableCallback(s); @@ -4624,7 +4856,7 @@ void FB_RTDB::prepareHeader(FirebaseData *fbdo, struct fb_esp_rtdb_request_info_ ut->appendP(header, fb_esp_pgm_str_30); ut->appendP(header, fb_esp_pgm_str_31); - header += Signer.getCfg()->host; + header += Signer.getCfg()->database_url; ut->appendP(header, fb_esp_pgm_str_21); ut->appendP(header, fb_esp_pgm_str_32); diff --git a/src/rtdb/FB_RTDB.h b/src/rtdb/FB_RTDB.h index c95b89fc..c9a05428 100644 --- a/src/rtdb/FB_RTDB.h +++ b/src/rtdb/FB_RTDB.h @@ -1,9 +1,9 @@ /** - * Google's Firebase Realtime Database class, FB_RTDB.h version 1.0.9 + * Google's Firebase Realtime Database class, FB_RTDB.h version 1.0.12 * * This library supports Espressif ESP8266 and ESP32 * - * Created April 4, 2021 + * Created May 1, 2021 * * This work is a part of Firebase ESP Client library * Copyright (c) 2021 K. Suwatchai (Mobizt) @@ -101,6 +101,46 @@ class FB_RTDB */ bool setRules(FirebaseData *fbdo, const char *rules); + /** Set the .read and .write database rules. + * + * @param fbdo The pointer to Firebase Data Object. + * @param path The parent path of child's node that the .read and .write rules are being set. + * @param var The child node key that the .read and .write rules are being set. + * @param readVal The child node key .read value. + * @param writeVal The child node key .write value. + * @param databaseSecret The database secret. + * @return Boolean value, indicates the success of the operation. + * + * @note The databaseSecret can be empty if the auth type is OAuth2.0 or legacy and required if auth type + * is Email/Password sign-in. + */ + bool setReadWriteRules(FirebaseData *fbdo, const char *path, const char *var, const char *readVal, const char *writeVal, const char *databaseSecret); + + /** Set the query index to the database rules. + * + * @param fbdo The pointer to Firebase Data Object. + * @param path The parent path of child's node that being query. + * @param node The child node key that being query. + * @param databaseSecret The database secret. + * @return Boolean value, indicates the success of the operation. + * + * @note The databaseSecret can be empty if the auth type is OAuth2.0 or legacy and required if auth type + * is Email/Password sign-in. + */ + bool setQueryIndex(FirebaseData *fbdo, const char *path, const char *node, const char *databaseSecret); + + /** Remove the query index from the database rules. + * + * @param fbdo The pointer to Firebase Data Object. + * @param path The parent path of child's node that the index is being removed. + * @param databaseSecret The database secret. + * @return Boolean value, indicates the success of the operation. + * + * @note The databaseSecret can be empty if the auth type is OAuth2.0 or legacy and required if auth type + * is Email/Password sign-in. + */ + bool removeQueryIndex(FirebaseData *fbdo, const char *path, const char *databaseSecret); + /** Determine the existent of the defined node. * * @param fbdo The pointer to Firebase Data Object. @@ -1212,6 +1252,20 @@ class FB_RTDB */ bool deleteNode(FirebaseData *fbdo, const char *path, const char *ETag); + /** Delete nodes that its timestamp node exceeded the data retaining period. + * + * @param fbdo The pointer to Firebase Data Object. + * @param path The parent path of children nodes that being delete. + * @param timestampNode The sub-child node that keep the timestamp. + * @param limit The maximum number of children nodes to delete at once, 30 is maximum. + * @param dataRetentionPeriod The period in seconds of data in the past which will be retained. + * @return Boolean value, indicates the success of the operation. + * + * @note The databaseSecret can be empty if the auth type is OAuth2.0 or legacy and required if auth type + * is Email/Password sign-in. + */ + bool deleteNodesByTimestamp(FirebaseData *fbdo, const char *path, const char *timestampNode, size_t limit, unsigned long dataRetentionPeriod); + /** Subscribe to the value changes on the defined node. * * @param fbdo The pointer to Firebase Data Object. @@ -1544,6 +1598,7 @@ class FB_RTDB void sendCB(FirebaseData *fbdo); void splitStreamPayload(const char *payloads, std::vector &payload); void parseStreamPayload(FirebaseData *fbdo, const char *payload); + bool int_setQueryIndex(FirebaseData *fbdo, const char *path, const char *node, const char *databaseSecret); #if defined(ESP32) void runStreamTask(FirebaseData *fbdo, const char *taskName); #elif defined(ESP8266) diff --git a/src/rtdb/QueryFilter.cpp b/src/rtdb/QueryFilter.cpp index 51b1df44..b931733a 100644 --- a/src/rtdb/QueryFilter.cpp +++ b/src/rtdb/QueryFilter.cpp @@ -1,15 +1,15 @@ /** - * Google's Firebase QueryFilter class, QueryFilter.cpp version 1.0.0 + * Google's Firebase QueryFilter class, QueryFilter.cpp version 1.0.2 * * This library supports Espressif ESP8266 and ESP32 * - * Created January 12, 2021 + * Created May 1, 2021 * * This work is a part of Firebase ESP Client library - * Copyright (c) 2020, 2021 K. Suwatchai (Mobizt) + * Copyright (c) 2021 K. Suwatchai (Mobizt) * * The MIT License (MIT) - * Copyright (c) 2020, 2021 K. Suwatchai (Mobizt) + * Copyright (c) 2021 K. Suwatchai (Mobizt) * * * Permission is hereby granted, free of charge, to any person returning a copy of @@ -42,10 +42,6 @@ QueryFilter::~QueryFilter() { clear(); } -void QueryFilter::begin(UtilsClass *u) -{ - ut = u; -} QueryFilter &QueryFilter::clear() { @@ -60,74 +56,119 @@ QueryFilter &QueryFilter::clear() QueryFilter &QueryFilter::orderBy(const String &val) { - ut->appendP(_orderBy, fb_esp_pgm_str_3, true); + appendP(_orderBy, fb_esp_pgm_str_3, true); _orderBy += val.c_str(); - ut->appendP(_orderBy, fb_esp_pgm_str_3); + appendP(_orderBy, fb_esp_pgm_str_3); return *this; } QueryFilter &QueryFilter::limitToFirst(int val) { - char *num = ut->intStr(val); + char *num = intStr(val); _limitToFirst = num; - ut->delS(num); + delS(num); return *this; } QueryFilter &QueryFilter::limitToLast(int val) { - char *num = ut->intStr(val); + char *num = intStr(val); _limitToLast = num; - ut->delS(num); + delS(num); return *this; } QueryFilter &QueryFilter::startAt(float val) { - char *num = ut->floatStr(val); + char *num = floatStr(val); _startAt = num; - ut->delS(num); + delS(num); return *this; } QueryFilter &QueryFilter::endAt(float val) { - char *num = ut->floatStr(val); + char *num = floatStr(val); _endAt = num; - ut->delS(num); + delS(num); return *this; } QueryFilter &QueryFilter::startAt(const String &val) { - ut->appendP(_startAt, fb_esp_pgm_str_3, true); + appendP(_startAt, fb_esp_pgm_str_3, true); _startAt += val.c_str(); - ut->appendP(_startAt, fb_esp_pgm_str_3); + appendP(_startAt, fb_esp_pgm_str_3); return *this; } QueryFilter &QueryFilter::endAt(const String &val) { - ut->appendP(_endAt, fb_esp_pgm_str_3, true); + appendP(_endAt, fb_esp_pgm_str_3, true); _startAt += val.c_str(); - ut->appendP(_endAt, fb_esp_pgm_str_3); + appendP(_endAt, fb_esp_pgm_str_3); return *this; } QueryFilter &QueryFilter::equalTo(int val) { - char *num = ut->intStr(val); + char *num = intStr(val); _equalTo = num; - ut->delS(num); + delS(num); return *this; } QueryFilter &QueryFilter::equalTo(const String &val) { - ut->appendP(_equalTo, fb_esp_pgm_str_3, true); + appendP(_equalTo, fb_esp_pgm_str_3, true); _equalTo += val.c_str(); - ut->appendP(_equalTo, fb_esp_pgm_str_3); + appendP(_equalTo, fb_esp_pgm_str_3); return *this; } +char *QueryFilter::strP(PGM_P pgm) +{ + size_t len = strlen_P(pgm) + 5; + char *buf = newS(len); + strcpy_P(buf, pgm); + buf[strlen_P(pgm)] = 0; + return buf; +} + +char *QueryFilter::newS(size_t len) +{ + char *p = new char[len]; + memset(p, 0, len); + return p; +} + +void QueryFilter::appendP(std::string &buf, PGM_P p, bool empty) +{ + if (empty) + buf.clear(); + char *b = strP(p); + buf += b; + delS(b); +} + +void QueryFilter::delS(char *p) +{ + if (p != nullptr) + delete[] p; +} + +char *QueryFilter::floatStr(float value) +{ + char *buf = newS(36); + dtostrf(value, 7, 9, buf); + return buf; +} + +char *QueryFilter::intStr(int value) +{ + char *buf = newS(36); + itoa(value, buf, 10); + return buf; +} + #endif \ No newline at end of file diff --git a/src/rtdb/QueryFilter.h b/src/rtdb/QueryFilter.h index 0c3d945a..0342e076 100644 --- a/src/rtdb/QueryFilter.h +++ b/src/rtdb/QueryFilter.h @@ -1,15 +1,15 @@ /** - * Google's Firebase QueryFilter class, QueryFilter.h version 1.0.0 + * Google's Firebase QueryFilter class, QueryFilter.h version 1.0.2 * * This library supports Espressif ESP8266 and ESP32 * - * Created January 12, 2021 + * Created May 1, 2021 * * This work is a part of Firebase ESP Client library - * Copyright (c) 2020, 2021 K. Suwatchai (Mobizt) + * Copyright (c) 2021 K. Suwatchai (Mobizt) * * The MIT License (MIT) - * Copyright (c) 2020, 2021 K. Suwatchai (Mobizt) + * Copyright (c) 2021 K. Suwatchai (Mobizt) * * * Permission is hereby granted, free of charge, to any person returning a copy of @@ -63,9 +63,13 @@ class QueryFilter std::string _startAt = ""; std::string _endAt = ""; std::string _equalTo = ""; - UtilsClass *ut = nullptr; - void begin(UtilsClass *u); + char *strP(PGM_P pgm); + char *newS(size_t len); + void appendP(std::string &buf, PGM_P p, bool empty = false); + void delS(char *p); + char *floatStr(float value); + char *intStr(int value); }; #endif \ No newline at end of file diff --git a/src/session/FB_Session.cpp b/src/session/FB_Session.cpp index ed8179c6..bdf00f7c 100644 --- a/src/session/FB_Session.cpp +++ b/src/session/FB_Session.cpp @@ -1,9 +1,9 @@ /** - * Google's Firebase Data class, FB_Session.cpp version 1.0.7 + * Google's Firebase Data class, FB_Session.cpp version 1.0.9 * * This library supports Espressif ESP8266 and ESP32 * - * Created March 31, 2021 + * Created May 1, 2021 * * This work is a part of Firebase ESP Client library * Copyright (c) 2021 K. Suwatchai (Mobizt) @@ -115,28 +115,31 @@ void FirebaseData::setResponseSize(uint16_t len) bool FirebaseData::pauseFirebase(bool pause) { - if (WiFi.status() != WL_CONNECTED && !ut->ethLinkUp()) + if ((WiFi.status() != WL_CONNECTED && !ut->ethLinkUp()) || !httpClient.stream()) + { + _ss.connected = false; + _ss.rtdb.pause = true; return false; + } - if (httpClient.connected() && pause != _ss.rtdb.pause) + if (pause == _ss.rtdb.pause) + return true; + + _ss.rtdb.pause = pause; + + if (pause) { if (httpClient.stream()->connected()) httpClient.stream()->stop(); - _ss.connected = false; - - if (!httpClient.connected()) - { - _ss.rtdb.pause = pause; - return true; - } - return false; - } - else - { - _ss.rtdb.pause = pause; - return true; } + + return true; +} + +bool FirebaseData::isPause() +{ + return _ss.rtdb.pause; } void FirebaseData::stopWiFiClient() @@ -674,7 +677,7 @@ void FirebaseData::setSecure() bool FirebaseData::validRequest(const std::string &path) { - if (path.length() == 0 || Signer.getCfg()->host.length() == 0 || (Signer.getToken(token_type_legacy_token).length() == 0 && Signer.getToken(token_type_id_token).length() == 0 && Signer.getToken(token_type_oauth2_access_token).length() == 0)) + if (path.length() == 0 || (Signer.getCfg()->database_url.length() == 0 && Signer.getCfg()->host.length() == 0) || (Signer.getToken(token_type_legacy_token).length() == 0 && Signer.getToken(token_type_id_token).length() == 0 && Signer.getToken(token_type_oauth2_access_token).length() == 0)) { _ss.http_code = FIREBASE_ERROR_HTTP_CODE_BAD_REQUEST; return false; @@ -815,7 +818,14 @@ void FCMObject::begin(UtilsClass *u) void FCMObject::begin(const String &serverKey) { if (!init()) - return; + { + if (_ut) + delete _ut; + + _ut = new UtilsClass(&_cfg_); + + Signer.begin(_ut, &_cfg_, &_auth_); + } _server_key = serverKey.c_str(); } diff --git a/src/session/FB_Session.h b/src/session/FB_Session.h index c728ff02..8c0cfbe5 100644 --- a/src/session/FB_Session.h +++ b/src/session/FB_Session.h @@ -1,9 +1,9 @@ /** - * Google's Firebase Data class, FB_Session.h version 1.0.7 + * Google's Firebase Data class, FB_Session.h version 1.0.9 * * This library supports Espressif ESP8266 and ESP32 * - * Created March 31, 2021 + * Created May 1, 2021 * * This work is a part of Firebase ESP Client library * Copyright (c) 2021 K. Suwatchai (Mobizt) @@ -195,6 +195,8 @@ class FCMObject uint16_t _port = FIREBASE_PORT; std::vector _deviceToken; UtilsClass *_ut = nullptr; + FirebaseAuth _auth_; + FirebaseConfig _cfg_; }; class FirebaseData @@ -241,6 +243,12 @@ class FirebaseData */ bool pauseFirebase(bool pause); + /** Check the pause status of Firebase Data object. + * + * @return Boolean type value of pause status. + */ + bool isPause(); + /** Get a WiFi client instance. * * @return WiFi client instance. diff --git a/src/signer/Signer.cpp b/src/signer/Signer.cpp index 74c37d76..5aeed509 100644 --- a/src/signer/Signer.cpp +++ b/src/signer/Signer.cpp @@ -1,9 +1,9 @@ /** - * Google's Firebase Token Generation class, Signer.cpp version 1.0.8 + * Google's Firebase Token Generation class, Signer.cpp version 1.0.10 * * This library supports Espressif ESP8266 and ESP32 * - * Created April 4, 2021 + * Created May 1, 2021 * * This work is a part of Firebase ESP Client library * Copyright (c) 2020, 2021 K. Suwatchai (Mobizt) @@ -204,8 +204,9 @@ bool Firebase_Signer::handleToken() if (!config || !auth) return false; - if (config->host.length() == 0) - return false; + //if the time was set (changed) after token has been generated, update its expiration + if (config->signer.tokens.expires > 0 && config->signer.tokens.expires < ESP_DEFAULT_TS && time(nullptr) > ESP_DEFAULT_TS) + config->signer.tokens.expires += time(nullptr) - (millis() - config->signer.tokens.last_millis) / 1000 - 60; if (config->signer.preRefreshSeconds > config->signer.tokens.expires && config->signer.tokens.expires > 0) config->signer.preRefreshSeconds = 60; @@ -613,7 +614,7 @@ bool Firebase_Signer::refreshToken() config->signer.json->get(*config->signer.data, tmp); ut->delS(tmp); if (config->signer.data->success) - config->signer.tokens.expires = time(nullptr) + atoi(config->signer.data->stringValue.c_str()); + getExpiration(config->signer.data->stringValue); tmp = ut->strP(fb_esp_pgm_str_175); config->signer.json->get(*config->signer.data, tmp); @@ -1427,7 +1428,7 @@ bool Firebase_Signer::getIdToken(bool createUser, const char *email, const char config->signer.json->get(*config->signer.data, tmp); ut->delS(tmp); if (config->signer.data->success) - config->signer.tokens.expires = time(nullptr) + atoi(config->signer.data->stringValue.c_str()); + getExpiration(config->signer.data->stringValue); tmp = ut->strP(fb_esp_pgm_str_175); config->signer.json->get(*config->signer.data, tmp); @@ -1603,7 +1604,7 @@ bool Firebase_Signer::requestTokens() config->signer.json->get(*config->signer.data, tmp); ut->delS(tmp); if (config->signer.data->success) - config->signer.tokens.expires = time(nullptr) + atoi(config->signer.data->stringValue.c_str()); + getExpiration(config->signer.data->stringValue); } else if (config->signer.tokens.token_type == token_type_oauth2_access_token) { @@ -1623,7 +1624,7 @@ bool Firebase_Signer::requestTokens() config->signer.json->get(*config->signer.data, tmp); ut->delS(tmp); if (config->signer.data->success) - config->signer.tokens.expires = time(nullptr) + atoi(config->signer.data->stringValue.c_str()); + getExpiration(config->signer.data->stringValue); } return handleSignerError(0); } @@ -1633,6 +1634,14 @@ bool Firebase_Signer::requestTokens() return handleSignerError(3); } +void Firebase_Signer::getExpiration(const String &exp) +{ + time_t ts = time(nullptr); + unsigned long ms = millis(); + config->signer.tokens.expires = ts + atoi(config->signer.data->stringValue.c_str()); + config->signer.tokens.last_millis = ms; +} + bool Firebase_Signer::handleEmailSending(const char *payload, fb_esp_user_email_sending_type type) { if (config->_int.fb_reconnect_wifi) @@ -1788,8 +1797,10 @@ void Firebase_Signer::checkToken() { if (!config || !auth) return; - if (config->host.length() == 0) - return; + + //if the time was set (changed) after token has been generated, update its expiration + if (config->signer.tokens.expires > 0 && config->signer.tokens.expires < ESP_DEFAULT_TS && time(nullptr) > ESP_DEFAULT_TS) + config->signer.tokens.expires += time(nullptr) - (millis() - config->signer.tokens.last_millis) / 1000 - 60; if (config->signer.preRefreshSeconds > config->signer.tokens.expires && config->signer.tokens.expires > 0) config->signer.preRefreshSeconds = 60; @@ -1802,8 +1813,7 @@ bool Firebase_Signer::tokenReady() { if (!auth || !config) return false; - if (config->host.length() == 0) - return false; + checkToken(); return config->signer.tokens.status == token_status_ready; }; diff --git a/src/signer/Signer.h b/src/signer/Signer.h index db1e9525..f7ac8221 100644 --- a/src/signer/Signer.h +++ b/src/signer/Signer.h @@ -1,9 +1,9 @@ /** - * Google's Firebase Token Generation class, Signer.h version 1.0.8 + * Google's Firebase Token Generation class, Signer.h version 1.0.10 * * This library supports Espressif ESP8266 and ESP32 * - * Created April 4, 2021 + * Created May 1, 2021 * * This work is a part of Firebase ESP Client library * Copyright (c) 2020, 2021 K. Suwatchai (Mobizt) @@ -62,7 +62,10 @@ class Firebase_Signer FirebaseAuth *auth = nullptr; callback_function_t _cb = nullptr; struct token_info_t tokenInfo; + bool authenticated = false; bool _token_processing_task_enable = false; + unsigned long unauthen_millis = 0; + unsigned long unauthen_pause_duration = 3000; void begin(UtilsClass *ut, FirebaseConfig *config, FirebaseAuth *auth); bool parseSAFile(); @@ -80,6 +83,7 @@ class Firebase_Signer bool getIdToken(bool createUser, const char *email, const char *password); bool requestTokens(); void checkToken(); + void getExpiration(const String &exp); bool handleEmailSending(const char *payload, fb_esp_user_email_sending_type type); void errorToString(int httpCode, std::string &buff); bool tokenReady(); diff --git a/src/wcs/HTTPCode.h b/src/wcs/HTTPCode.h index e2342b33..929acc5e 100644 --- a/src/wcs/HTTPCode.h +++ b/src/wcs/HTTPCode.h @@ -74,6 +74,8 @@ #define FIREBASE_ERROR_HTTPC_NO_FCM_DEVICE_TOKEN_PROVIDED -38 #define FIREBASE_ERROR_HTTPC_NO_FCM_INDEX_NOT_FOUND_IN_DEVICE_TOKEN_PROVIDED -39 +#define FIREBASE_ERROR_HTTP_CODE_UNDEFINED -1000 + /// HTTP codes see RFC7231 #define FIREBASE_ERROR_HTTP_CODE_OK 200