diff --git a/README.md b/README.md index 5d1378ce..41769a0d 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/mobizt/FirebaseClient/.github%2Fworkflows%2Fcompile_library.yml?logo=github&label=compile) [![Github Stars](https://img.shields.io/github/stars/mobizt/FirebaseClient?logo=github)](https://github.com/mobizt/FirebaseClient/stargazers) ![Github Issues](https://img.shields.io/github/issues/mobizt/FirebaseClient?logo=github) -![GitHub Release](https://img.shields.io/github/v/release/mobizt/FirebaseClient) ![Arduino](https://img.shields.io/badge/Arduino-v1.5.3-57C207?logo=arduino) ![PlatformIO](https://badges.registry.platformio.org/packages/mobizt/library/FirebaseClient.svg) ![GitHub Release Date](https://img.shields.io/github/release-date/mobizt/FirebaseClient) +![GitHub Release](https://img.shields.io/github/v/release/mobizt/FirebaseClient) ![Arduino](https://img.shields.io/badge/Arduino-v1.5.4-57C207?logo=arduino) ![PlatformIO](https://badges.registry.platformio.org/packages/mobizt/library/FirebaseClient.svg) ![GitHub Release Date](https://img.shields.io/github/release-date/mobizt/FirebaseClient) [![GitHub Sponsors](https://img.shields.io/github/sponsors/mobizt?logo=github)](https://github.com/sponsors/mobizt) @@ -802,17 +802,15 @@ If the size of payload string from the async reseut is large, to access the inte
-The `SSE mode (HTTP Streaming)` event payload might contain many events data due to the events are constantly changing. The data in this case can be obtained from the specific index. - The specific `Realtime Database` server response payload and `SSE mode (HTTP Streaming)` event data (`RealtimeDatabaseResult`) can be obtained from `AsyncResult::to()` which are included the following. - `bool RealtimeDatabaseResult::isStream()` returns true if the result is from `SSE mode (HTTP Streaming)` task. -- `String RealtimeDatabaseResult::event()` returns the `SSE mode (HTTP Streaming)` event type strings at the specific index which included `put`, `patch`, `keep-alive`, `cancel` and `auth_revoked`. +- `String RealtimeDatabaseResult::event()` returns the `SSE mode (HTTP Streaming)` event type strings include `put`, `patch`, `keep-alive`, `cancel` and `auth_revoked`. -- `String RealtimeDatabaseResult::dataPath()` returns the `SSE mode (HTTP Streaming)` event data path (at the specific index) which is the relative path of the changed value in the database. The absolute path of the changed value can be obtained from the concatenation of `AsyncResult::path()` and `RealtimeDatabaseResult::dataPath()` e.g. `AsyncResult::path() + "/" + RealtimeDatabaseResult::dataPath()`. +- `String RealtimeDatabaseResult::dataPath()` returns the `SSE mode (HTTP Streaming)` event data path which is the relative path of the changed value in the database. The absolute path of the changed value can be obtained from the concatenation of `AsyncResult::path()` and `RealtimeDatabaseResult::dataPath()` e.g. `AsyncResult::path() + "/" + RealtimeDatabaseResult::dataPath()`. -- `realtime_database_data_type RealtimeDatabaseResult::type()` returns the `realtime_database_data_type` enum (see below) at the specific index represents the type of `Realtime Database` response payload and event data (`HTTP Streaming`). +- `realtime_database_data_type RealtimeDatabaseResult::type()` returns the `realtime_database_data_type` enum (see below) represents the type of `Realtime Database` response payload and event data (`HTTP Streaming`). - `RealtimeDatabaseResult::name()` returns the name (random UID) of the node that will be creaated after from `RealtimeDatabase::Push`. @@ -2032,6 +2030,7 @@ The following section will provide the basic (bare minimum) code example and the * [SimpleNoAuth](/examples/RealtimeDatabase/Simple/SimpleNoAuth/) * [StreamDatabaseSecret](/examples/RealtimeDatabase/Simple/StreamDatabaseSecret/) * [StreamNoAuth](/examples/RealtimeDatabase/Simple/StreamNoAuth/) + * [Simple](/examples/RealtimeDatabase/StreamPerformanceTest/) * [Sync](/examples/RealtimeDatabase/Sync/) * [CustomPushID](/examples/RealtimeDatabase/Sync/CustomPushID/) * [ETAG](/examples/RealtimeDatabase/Sync/ETAG/) diff --git a/examples/README.md b/examples/README.md index 763b056a..1b3d149a 100644 --- a/examples/README.md +++ b/examples/README.md @@ -337,6 +337,7 @@ │ │ ├───SimpleNoAuth │ │ ├───StreamDatabaseSecret │ │ └───StreamNoAuth +│ ├───StreamPerformancetest │ └───Sync │ ├───CustomPushID │ ├───ETAG diff --git a/examples/RealtimeDatabase/Async/Callback/Stream/Stream.ino b/examples/RealtimeDatabase/Async/Callback/Stream/Stream.ino index 9686f70c..c50fb931 100644 --- a/examples/RealtimeDatabase/Async/Callback/Stream/Stream.ino +++ b/examples/RealtimeDatabase/Async/Callback/Stream/Stream.ino @@ -1,7 +1,7 @@ /** * ABOUT: * - * The non-blocking (async) example to listen to the changes of value (from a node) stores in your database + * The non-blocking (async) example to listen to the changes of value (from a node) stores in your database * via SSE Streaming connection. * * This example uses the UserAuth class for authentication, and the DefaultNetwork class for network interface configuration. @@ -195,25 +195,17 @@ void printResult(AsyncResult &aResult) { Serial.println("----------------------------"); Firebase.printf("task: %s\n", aResult.uid().c_str()); - - // The Stream payload might contain many events data due to - // the events are constantly changing. - Firebase.printf("event count: %d\n", RTDB.eventCount()); - for (uint32_t i = 0; i < RTDB.eventCount(); i++) - { - Firebase.printf("event: %s\n", RTDB.event(i).c_str()); - Firebase.printf("path: %s\n", RTDB.dataPath(i).c_str()); - Firebase.printf("data: %s\n", RTDB.to(i)); - Firebase.printf("type: %d\n", RTDB.type(i)); - Serial.println(); - - // The stream event from RealtimeDatabaseResult can be converted to the values as following. - bool v1 = RTDB.to(i); - int v2 = RTDB.to(i); - float v3 = RTDB.to(i); - double v4 = RTDB.to(i); - String v5 = RTDB.to(i); - } + Firebase.printf("event: %s\n", RTDB.event().c_str()); + Firebase.printf("path: %s\n", RTDB.dataPath().c_str()); + Firebase.printf("data: %s\n", RTDB.to()); + Firebase.printf("type: %d\n", RTDB.type()); + + // The stream event from RealtimeDatabaseResult can be converted to the values as following. + bool v1 = RTDB.to(); + int v2 = RTDB.to(); + float v3 = RTDB.to(); + double v4 = RTDB.to(); + String v5 = RTDB.to(); } else { diff --git a/examples/RealtimeDatabase/Async/Callback/StreamConcurentcy/StreamConcurentcy.ino b/examples/RealtimeDatabase/Async/Callback/StreamConcurentcy/StreamConcurentcy.ino index 2029de32..eea50350 100644 --- a/examples/RealtimeDatabase/Async/Callback/StreamConcurentcy/StreamConcurentcy.ino +++ b/examples/RealtimeDatabase/Async/Callback/StreamConcurentcy/StreamConcurentcy.ino @@ -1,7 +1,7 @@ /** * ABOUT: * - * The non-blocking (async) example to listen to the changes of values (from various nodes) store in your database + * The non-blocking (async) example to listen to the changes of values (from various nodes) store in your database * via SSE Streaming connection. * * This example uses the UserAuth class for authentication, and the DefaultNetwork class for network interface configuration. @@ -212,25 +212,17 @@ void printResult(AsyncResult &aResult) { Serial.println("----------------------------"); Firebase.printf("task: %s\n", aResult.uid().c_str()); - - // The Stream payload might contain many events data due to - // the events are constantly changing. - Firebase.printf("event count: %d\n", RTDB.eventCount()); - for (uint32_t i = 0; i < RTDB.eventCount(); i++) - { - Firebase.printf("event: %s\n", RTDB.event(i).c_str()); - Firebase.printf("path: %s\n", RTDB.dataPath(i).c_str()); - Firebase.printf("data: %s\n", RTDB.to(i)); - Firebase.printf("type: %d\n", RTDB.type(i)); - Serial.println(); - - // The stream event from RealtimeDatabaseResult can be converted to the values as following. - bool v1 = RTDB.to(i); - int v2 = RTDB.to(i); - float v3 = RTDB.to(i); - double v4 = RTDB.to(i); - String v5 = RTDB.to(i); - } + Firebase.printf("event: %s\n", RTDB.event().c_str()); + Firebase.printf("path: %s\n", RTDB.dataPath().c_str()); + Firebase.printf("data: %s\n", RTDB.to()); + Firebase.printf("type: %d\n", RTDB.type()); + + // The stream event from RealtimeDatabaseResult can be converted to the values as following. + bool v1 = RTDB.to(); + int v2 = RTDB.to(); + float v3 = RTDB.to(); + double v4 = RTDB.to(); + String v5 = RTDB.to(); } else { diff --git a/examples/RealtimeDatabase/Async/Callback/StreamGSM/StreamGSM.ino b/examples/RealtimeDatabase/Async/Callback/StreamGSM/StreamGSM.ino index 7eec5754..611b8f9e 100644 --- a/examples/RealtimeDatabase/Async/Callback/StreamGSM/StreamGSM.ino +++ b/examples/RealtimeDatabase/Async/Callback/StreamGSM/StreamGSM.ino @@ -248,25 +248,17 @@ void printResult(AsyncResult &aResult) { Serial.println("----------------------------"); Firebase.printf("task: %s\n", aResult.uid().c_str()); - - // The Stream payload might contain many events data due to - // the events are constantly changing. - Firebase.printf("event count: %d\n", RTDB.eventCount()); - for (uint32_t i = 0; i < RTDB.eventCount(); i++) - { - Firebase.printf("event: %s\n", RTDB.event(i).c_str()); - Firebase.printf("path: %s\n", RTDB.dataPath(i).c_str()); - Firebase.printf("data: %s\n", RTDB.to(i)); - Firebase.printf("type: %d\n", RTDB.type(i)); - Serial.println(); - - // The stream event from RealtimeDatabaseResult can be converted to the values as following. - bool v1 = RTDB.to(i); - int v2 = RTDB.to(i); - float v3 = RTDB.to(i); - double v4 = RTDB.to(i); - String v5 = RTDB.to(i); - } + Firebase.printf("event: %s\n", RTDB.event().c_str()); + Firebase.printf("path: %s\n", RTDB.dataPath().c_str()); + Firebase.printf("data: %s\n", RTDB.to()); + Firebase.printf("type: %d\n", RTDB.type()); + + // The stream event from RealtimeDatabaseResult can be converted to the values as following. + bool v1 = RTDB.to(); + int v2 = RTDB.to(); + float v3 = RTDB.to(); + double v4 = RTDB.to(); + String v5 = RTDB.to(); } else { diff --git a/examples/RealtimeDatabase/Async/Callback/StreamPPP/StreamPPP.ino b/examples/RealtimeDatabase/Async/Callback/StreamPPP/StreamPPP.ino index 86bcc798..d57b1d53 100644 --- a/examples/RealtimeDatabase/Async/Callback/StreamPPP/StreamPPP.ino +++ b/examples/RealtimeDatabase/Async/Callback/StreamPPP/StreamPPP.ino @@ -317,25 +317,17 @@ void printResult(AsyncResult &aResult) { Serial.println("----------------------------"); Firebase.printf("task: %s\n", aResult.uid().c_str()); - - // The Stream payload might contain many events data due to - // the events are constantly changing. - Firebase.printf("event count: %d\n", RTDB.eventCount()); - for (uint32_t i = 0; i < RTDB.eventCount(); i++) - { - Firebase.printf("event: %s\n", RTDB.event(i).c_str()); - Firebase.printf("path: %s\n", RTDB.dataPath(i).c_str()); - Firebase.printf("data: %s\n", RTDB.to(i)); - Firebase.printf("type: %d\n", RTDB.type(i)); - Serial.println(); - - // The stream event from RealtimeDatabaseResult can be converted to the values as following. - bool v1 = RTDB.to(i); - int v2 = RTDB.to(i); - float v3 = RTDB.to(i); - double v4 = RTDB.to(i); - String v5 = RTDB.to(i); - } + Firebase.printf("event: %s\n", RTDB.event().c_str()); + Firebase.printf("path: %s\n", RTDB.dataPath().c_str()); + Firebase.printf("data: %s\n", RTDB.to()); + Firebase.printf("type: %d\n", RTDB.type()); + + // The stream event from RealtimeDatabaseResult can be converted to the values as following. + bool v1 = RTDB.to(); + int v2 = RTDB.to(); + float v3 = RTDB.to(); + double v4 = RTDB.to(); + String v5 = RTDB.to(); } else { diff --git a/examples/RealtimeDatabase/Async/NoCallback/Stream/Stream.ino b/examples/RealtimeDatabase/Async/NoCallback/Stream/Stream.ino index 42fa1e84..d2e2b746 100644 --- a/examples/RealtimeDatabase/Async/NoCallback/Stream/Stream.ino +++ b/examples/RealtimeDatabase/Async/NoCallback/Stream/Stream.ino @@ -196,25 +196,17 @@ void printResult(AsyncResult &aResult) { Serial.println("----------------------------"); Firebase.printf("task: %s\n", aResult.uid().c_str()); - - // The Stream payload might contain many events data due to - // the events are constantly changing. - Firebase.printf("event count: %d\n", RTDB.eventCount()); - for (uint32_t i = 0; i < RTDB.eventCount(); i++) - { - Firebase.printf("event: %s\n", RTDB.event(i).c_str()); - Firebase.printf("path: %s\n", RTDB.dataPath(i).c_str()); - Firebase.printf("data: %s\n", RTDB.to(i)); - Firebase.printf("type: %d\n", RTDB.type(i)); - Serial.println(); - - // The stream event from RealtimeDatabaseResult can be converted to the values as following. - bool v1 = RTDB.to(i); - int v2 = RTDB.to(i); - float v3 = RTDB.to(i); - double v4 = RTDB.to(i); - String v5 = RTDB.to(i); - } + Firebase.printf("event: %s\n", RTDB.event().c_str()); + Firebase.printf("path: %s\n", RTDB.dataPath().c_str()); + Firebase.printf("data: %s\n", RTDB.to()); + Firebase.printf("type: %d\n", RTDB.type()); + + // The stream event from RealtimeDatabaseResult can be converted to the values as following. + bool v1 = RTDB.to(); + int v2 = RTDB.to(); + float v3 = RTDB.to(); + double v4 = RTDB.to(); + String v5 = RTDB.to(); } else { diff --git a/examples/RealtimeDatabase/Async/NoCallback/StreamConcurentcy/StreamConcurentcy.ino b/examples/RealtimeDatabase/Async/NoCallback/StreamConcurentcy/StreamConcurentcy.ino index 664080c5..2d4ffb32 100644 --- a/examples/RealtimeDatabase/Async/NoCallback/StreamConcurentcy/StreamConcurentcy.ino +++ b/examples/RealtimeDatabase/Async/NoCallback/StreamConcurentcy/StreamConcurentcy.ino @@ -211,25 +211,17 @@ void printResult(AsyncResult &aResult) { Serial.println("----------------------------"); Firebase.printf("task: %s\n", aResult.uid().c_str()); - - // The Stream payload might contain many events data due to - // the events are constantly changing. - Firebase.printf("event count: %d\n", RTDB.eventCount()); - for (uint32_t i = 0; i < RTDB.eventCount(); i++) - { - Firebase.printf("event: %s\n", RTDB.event(i).c_str()); - Firebase.printf("path: %s\n", RTDB.dataPath(i).c_str()); - Firebase.printf("data: %s\n", RTDB.to(i)); - Firebase.printf("type: %d\n", RTDB.type(i)); - Serial.println(); - - // The stream event from RealtimeDatabaseResult can be converted to the values as following. - bool v1 = RTDB.to(i); - int v2 = RTDB.to(i); - float v3 = RTDB.to(i); - double v4 = RTDB.to(i); - String v5 = RTDB.to(i); - } + Firebase.printf("event: %s\n", RTDB.event().c_str()); + Firebase.printf("path: %s\n", RTDB.dataPath().c_str()); + Firebase.printf("data: %s\n", RTDB.to()); + Firebase.printf("type: %d\n", RTDB.type()); + + // The stream event from RealtimeDatabaseResult can be converted to the values as following. + bool v1 = RTDB.to(); + int v2 = RTDB.to(); + float v3 = RTDB.to(); + double v4 = RTDB.to(); + String v5 = RTDB.to(); } else { diff --git a/examples/RealtimeDatabase/Async/NoCallback/StreamGSM/StreamGSM.ino b/examples/RealtimeDatabase/Async/NoCallback/StreamGSM/StreamGSM.ino index 717cc069..a09519b3 100644 --- a/examples/RealtimeDatabase/Async/NoCallback/StreamGSM/StreamGSM.ino +++ b/examples/RealtimeDatabase/Async/NoCallback/StreamGSM/StreamGSM.ino @@ -247,25 +247,17 @@ void printResult(AsyncResult &aResult) { Serial.println("----------------------------"); Firebase.printf("task: %s\n", aResult.uid().c_str()); - - // The Stream payload might contain many events data due to - // the events are constantly changing. - Firebase.printf("event count: %d\n", RTDB.eventCount()); - for (uint32_t i = 0; i < RTDB.eventCount(); i++) - { - Firebase.printf("event: %s\n", RTDB.event(i).c_str()); - Firebase.printf("path: %s\n", RTDB.dataPath(i).c_str()); - Firebase.printf("data: %s\n", RTDB.to(i)); - Firebase.printf("type: %d\n", RTDB.type(i)); - Serial.println(); - - // The stream event from RealtimeDatabaseResult can be converted to the values as following. - bool v1 = RTDB.to(i); - int v2 = RTDB.to(i); - float v3 = RTDB.to(i); - double v4 = RTDB.to(i); - String v5 = RTDB.to(i); - } + Firebase.printf("event: %s\n", RTDB.event().c_str()); + Firebase.printf("path: %s\n", RTDB.dataPath().c_str()); + Firebase.printf("data: %s\n", RTDB.to()); + Firebase.printf("type: %d\n", RTDB.type()); + + // The stream event from RealtimeDatabaseResult can be converted to the values as following. + bool v1 = RTDB.to(); + int v2 = RTDB.to(); + float v3 = RTDB.to(); + double v4 = RTDB.to(); + String v5 = RTDB.to(); } else { diff --git a/examples/RealtimeDatabase/Async/NoCallback/StreamPPP/StreamPPP.ino b/examples/RealtimeDatabase/Async/NoCallback/StreamPPP/StreamPPP.ino index 251124c2..54f0201f 100644 --- a/examples/RealtimeDatabase/Async/NoCallback/StreamPPP/StreamPPP.ino +++ b/examples/RealtimeDatabase/Async/NoCallback/StreamPPP/StreamPPP.ino @@ -318,25 +318,17 @@ void printResult(AsyncResult &aResult) { Serial.println("----------------------------"); Firebase.printf("task: %s\n", aResult.uid().c_str()); - - // The Stream payload might contain many events data due to - // the events are constantly changing. - Firebase.printf("event count: %d\n", RTDB.eventCount()); - for (uint32_t i = 0; i < RTDB.eventCount(); i++) - { - Firebase.printf("event: %s\n", RTDB.event(i).c_str()); - Firebase.printf("path: %s\n", RTDB.dataPath(i).c_str()); - Firebase.printf("data: %s\n", RTDB.to(i)); - Firebase.printf("type: %d\n", RTDB.type(i)); - Serial.println(); - - // The stream event from RealtimeDatabaseResult can be converted to the values as following. - bool v1 = RTDB.to(i); - int v2 = RTDB.to(i); - float v3 = RTDB.to(i); - double v4 = RTDB.to(i); - String v5 = RTDB.to(i); - } + Firebase.printf("event: %s\n", RTDB.event().c_str()); + Firebase.printf("path: %s\n", RTDB.dataPath().c_str()); + Firebase.printf("data: %s\n", RTDB.to()); + Firebase.printf("type: %d\n", RTDB.type()); + + // The stream event from RealtimeDatabaseResult can be converted to the values as following. + bool v1 = RTDB.to(); + int v2 = RTDB.to(); + float v3 = RTDB.to(); + double v4 = RTDB.to(); + String v5 = RTDB.to(); } else { diff --git a/examples/RealtimeDatabase/Simple/Wrapper/MyFirebase.h b/examples/RealtimeDatabase/Simple/Wrapper/MyFirebase.h index 64fc4dd6..b3fbf40a 100644 --- a/examples/RealtimeDatabase/Simple/Wrapper/MyFirebase.h +++ b/examples/RealtimeDatabase/Simple/Wrapper/MyFirebase.h @@ -5,8 +5,8 @@ #include /** - * The simple, reliable and efficient Firebase wrapper class example. - * + * The simple, reliable and efficient Firebase wrapper class example. + * * Powered by FirebaseClient library. */ class MyFirebase @@ -94,13 +94,10 @@ class MyFirebase int errorCode() { return err_code; } String payload() const { return payload_str; } - // The Stream payload might contain many events data due to - // the events are constantly changing. - uint32_t StreamEventCount() { return stream_payload.size(); } - String StreamData(uint32_t index = 0) const { return stream_payload[index < stream_payload.size() ? index : 0]; } - String StreamDataPath(uint32_t index = 0) const { return stream_data_path[index < stream_data_path.size() ? index : 0]; } - String StreamEvent(uint32_t index = 0) const { return stream_event[index < stream_event.size() ? index : 0]; } - int StreamDataType(uint32_t index = 0) const { return stream_data_type[index < stream_data_type.size() ? index : 0]; } + String StreamData() const { return stream_payload; } + String StreamDataPath() const { return stream_data_path; } + String StreamEvent() const { return stream_event; } + int StreamDataType() const { return stream_data_type; } String getString(const String &path) { return Database.get(aClient, path); } int getInt(const String &path) { return Database.get(aClient, path); } @@ -135,7 +132,7 @@ class MyFirebase streamClient[current_stream_index].setNetwork(stream_client, getNetwork(net)); Database.setSSEFilters(filter); - + // All results will store in one streamResult, the data of one Stream can be replaced by another Stream. // To avoid this issue, use StreamCallback or define the AsyncResults for each Stream. Database.get(streamClient[current_stream_index], path, streamResult, true); @@ -179,10 +176,8 @@ class MyFirebase AsyncResult authResult, streamResult; bool is_event = false, is_debug = false, is_error = false, is_payload = false, is_stream = false; - String task_id, payload_str, debug_str, event_str, err_str; - std::vector stream_payload, stream_event, stream_data_path; - std::vector stream_data_type; - int event_code = 0, err_code = 0, current_stream_index = 0; + String task_id, payload_str, stream_payload, stream_event, stream_data_path, debug_str, event_str, err_str; + int event_code = 0, err_code = 0, stream_data_type = 0, current_stream_index = 0; void beginInternal(Client &client, network_config_data &net, user_auth_data &auth, const String &databaseUrl) { @@ -233,13 +228,10 @@ class MyFirebase if (is_stream) { - for (uint32_t i = 0; i < RTDB.eventCount(); i++) - { - stream_payload.push_back(RTDB.to(i)); - stream_data_type.push_back(RTDB.type(i)); - stream_data_path.push_back(RTDB.dataPath(i)); - stream_event.push_back(RTDB.event(i)); - } + stream_payload = RTDB.to(); + stream_data_type = RTDB.type(); + stream_data_path = RTDB.dataPath(); + stream_event = RTDB.event(); } } @@ -256,14 +248,14 @@ class MyFirebase is_event = false; is_error = false; is_payload = false; + stream_data_type = false; debug_str.remove(0, debug_str.length()); payload_str.remove(0, payload_str.length()); event_str.remove(0, event_str.length()); err_str.remove(0, err_str.length()); - stream_payload.clear(); - stream_data_type.clear(); - stream_data_path.clear(); - stream_event.clear(); + stream_payload.remove(0, stream_payload.length()); + stream_event.remove(0, stream_event.length()); + stream_data_path.remove(0, stream_data_path.length()); task_id.remove(0, task_id.length()); } }; diff --git a/examples/RealtimeDatabase/Simple/Wrapper/Wrapper.ino b/examples/RealtimeDatabase/Simple/Wrapper/Wrapper.ino index 0945c226..893272e6 100644 --- a/examples/RealtimeDatabase/Simple/Wrapper/Wrapper.ino +++ b/examples/RealtimeDatabase/Simple/Wrapper/Wrapper.ino @@ -1,8 +1,8 @@ /** * ABOUT: - * + * * The example show how to create a wrapper class for Firebase Realtime Database that is easier to use. - */ +*/ #include "MyFirebase.h" #include @@ -81,18 +81,10 @@ void loop() Serial.println("---------------------------"); Serial.println("Stream data..."); Serial.printf("task: %s\n", firebase.taskId().c_str()); - - // The Stream payload might contain many events data due to - // the events are constantly changing. - Serial.printf("event count: %d\n", firebase.StreamEventCount()); - for (uint32_t i = 0; i < firebase.StreamEventCount(); i++) - { - Serial.printf("event: %s\n", firebase.StreamEvent(i).c_str()); - Serial.printf("path: %s\n", firebase.StreamDataPath(i).c_str()); - Serial.printf("data: %s\n", firebase.StreamData(i).c_str()); - Serial.printf("type: %d\n", firebase.StreamDataType(i)); - Serial.println(); - } + Serial.printf("event: %s\n", firebase.StreamEvent().c_str()); + Serial.printf("path: %s\n", firebase.StreamDataPath().c_str()); + Serial.printf("data: %s\n", firebase.StreamData().c_str()); + Serial.printf("type: %d\n", firebase.StreamDataType()); } else Serial.printf("task: %s, payload: %s\n", firebase.taskId().c_str(), firebase.payload().c_str()); diff --git a/examples/RealtimeDatabase/StreamPerformanceTest/StreamPerformanceTest.ino b/examples/RealtimeDatabase/StreamPerformanceTest/StreamPerformanceTest.ino new file mode 100644 index 00000000..b487a9ef --- /dev/null +++ b/examples/RealtimeDatabase/StreamPerformanceTest/StreamPerformanceTest.ino @@ -0,0 +1,144 @@ +/** + * ABOUT: + * + * The Realtime Database Stream performance test example. + * + * This example will show how fast your device gets the Stream event. + * + * You will get all continouse data changes events from your Realtime Database without data lost. + * + * Open the index.html file with web browser and follow the instructions on that page to test. + * + * The complete usage guidelines, please read README.md or visit https://github.com/mobizt/FirebaseClient + * + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) || defined(ARDUINO_GIGA) || defined(ARDUINO_OPTA) +#include +#elif defined(ESP8266) +#include +#elif __has_include() || defined(ARDUINO_NANO_RP2040_CONNECT) +#include +#elif __has_include() +#include +#elif __has_include() || defined(ARDUINO_UNOWIFIR4) +#include +#elif __has_include() || defined(ARDUINO_PORTENTA_C33) +#include +#elif __has_include() +#include +#endif + +#include + +#define WIFI_SSID "WIFI_AP" +#define WIFI_PASSWORD "WIFI_PASSWORD" + +#define API_KEY "Web_API_KEY" +#define USER_EMAIL "USER_EMAIL" +#define USER_PASSWORD "USER_PASSWORD" +#define DATABASE_URL "URL" + +void asyncCB(AsyncResult &aResult); + +void printResult(AsyncResult &aResult); + +DefaultNetwork network; + +UserAuth user_auth(API_KEY, USER_EMAIL, USER_PASSWORD); + +FirebaseApp app; + +#if defined(ESP32) || defined(ESP8266) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +WiFiClientSecure ssl_client; +#elif defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_UNOWIFIR4) || defined(ARDUINO_GIGA) || defined(ARDUINO_OPTA) || defined(ARDUINO_PORTENTA_C33) || defined(ARDUINO_NANO_RP2040_CONNECT) +#include +WiFiSSLClient ssl_client; +#endif + +using AsyncClient = AsyncClientClass; + +AsyncClient aClient(ssl_client, getNetwork(network)); + +RealtimeDatabase Database; + +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(); + + Firebase.printf("Firebase Client v%s\n", FIREBASE_CLIENT_VERSION); + +#if defined(ESP32) || defined(ESP8266) || defined(PICO_RP2040) + ssl_client.setInsecure(); +#if defined(ESP8266) + ssl_client.setBufferSizes(4096, 1024); +#endif +#endif + + Serial.println("Initializing the app..."); + initializeApp(aClient, app, getAuth(user_auth), asyncCB, "authTask"); + + app.getApp(Database); + + Database.url(DATABASE_URL); + + Database.setSSEFilters("get,put,patch,keep-alive,cancel,auth_revoked"); + + Database.get(aClient, "/test/performance", asyncCB, true, "streamTask"); +} + +void loop() +{ + app.loop(); + Database.loop(); +} + +void asyncCB(AsyncResult &aResult) { printResult(aResult); } + +int counter = 0; + +void printResult(AsyncResult &aResult) +{ + if (aResult.isEvent()) + { + Firebase.printf("Event task: %s, msg: %s, code: %d\n", aResult.uid().c_str(), aResult.appEvent().message().c_str(), aResult.appEvent().code()); + } + + if (aResult.isDebug()) + { + Firebase.printf("Debug task: %s, msg: %s\n", aResult.uid().c_str(), aResult.debug().c_str()); + } + + if (aResult.isError()) + { + Firebase.printf("Error task: %s, msg: %s, code: %d\n", aResult.uid().c_str(), aResult.error().message().c_str(), aResult.error().code()); + } + + if (aResult.available()) + { + RealtimeDatabaseResult &RTDB = aResult.to(); + if (RTDB.isStream() && RTDB.type() == 0) + counter = 0; + + if (RTDB.isStream() && RTDB.type() == 1) + { + Firebase.printf("counter: %d\n", counter); + Firebase.printf("data: %d\n", RTDB.to()); + counter++; + } + } +} \ No newline at end of file diff --git a/examples/RealtimeDatabase/StreamPerformanceTest/index.html b/examples/RealtimeDatabase/StreamPerformanceTest/index.html new file mode 100644 index 00000000..6046ce4f --- /dev/null +++ b/examples/RealtimeDatabase/StreamPerformanceTest/index.html @@ -0,0 +1,119 @@ + + + + Stream Performance Test + + + + +
This html test page will set the continuous 10,000 integer values to the path /test/performance.
+ In the Arduino sketch, set the stream path in the function Database.get to /test/performance.

+ And in the Stream printResult callback function, write the following code.

+
+ int counter = 0;

+ void printResult(AsyncResult &aResult)
+ {
+
+ if (aResult.isEvent())
+ {
+
Firebase.printf("Event task: %s, msg: %s, code: %d\n", aResult.uid().c_str(), aResult.appEvent().message().c_str(), aResult.appEvent().code());
+ }

+ + if (aResult.isDebug())
+ {
+
Firebase.printf("Debug task: %s, msg: %s\n", aResult.uid().c_str(), aResult.debug().c_str());
+ }

+ + if (aResult.isError())
+ {
+
Firebase.printf("Error task: %s, msg: %s, code: %d\n", aResult.uid().c_str(), aResult.error().message().c_str(), aResult.error().code());
+ }

+ + if (aResult.available())
+ {
+
RealtimeDatabaseResult &RTDB = aResult.to<RealtimeDatabaseResult>();
+ if (RTDB.isStream() && RTDB.type() == 0)
+
counter = 0;
+
+ if (RTDB.isStream() && RTDB.type() == 1)
+ {
+
Firebase.printf("counter: %d\n", counter);
+ Firebase.printf("data: %d\n", RTDB.to<int>());
+ counter++; +
+ }
+
+ }
+
+ } +
+

+ + 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 Realtime Database.
+ Press the Delete button to delete the previous set data from the Firebase Realtime Database and the counter value in the Arduino sketch will be reset to 0
+ Don't forget to change projectID, Web API Key and databaseURL in the source of this html file. +

+ After press the Set button, the output in Arduino IDE console will look like

+
+ counter: 0
+ data: 0
+ counter: 1
+ data: 1
+ counter: 2
+
+ ...
+ ...
+
+ counter: 9998
+ data: 9998
+ counter: 9999
+ data: 9999
+
+
+
+
+ + +
+ + + + + + + + + \ No newline at end of file diff --git a/keywords.txt b/keywords.txt index 1a40ef87..948a3cf1 100644 --- a/keywords.txt +++ b/keywords.txt @@ -306,7 +306,6 @@ setBlob KEYWORD2 setFile KEYWORD2 autoAuthenticate KEYWORD2 authenticate KEYWORD2 -eventCount KEYWORD2 ################### # Struct (KEYWORD3) diff --git a/library.json b/library.json index ecebdcc0..80412299 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "FirebaseClient", - "version": "1.5.3", + "version": "1.5.4", "keywords": "communication, REST, esp32, esp8266, arduino", "description": "Async Firebase Client library for Arduino.", "repository": { diff --git a/library.properties b/library.properties index b56e53aa..c1fd3fe2 100644 --- a/library.properties +++ b/library.properties @@ -1,6 +1,6 @@ name=FirebaseClient -version=1.5.3 +version=1.5.4 author=Mobizt diff --git a/resources/docs/realtime_database_result.md b/resources/docs/realtime_database_result.md index 5345e4d0..1d8e20cd 100644 --- a/resources/docs/realtime_database_result.md +++ b/resources/docs/realtime_database_result.md @@ -8,18 +8,14 @@ The Realtime database result class. class RealtimeDatabaseResult ``` -1. ## 🔹 T to(uint32_t index = 0) +1. ## 🔹 T to() Convert the RealtimeDatabaseResult to any type of values. ```cpp -T to(uint32_t index = 0) +T to() ``` -**Params:** - -- `index` - The index of Stream event to convert the data or 0 for non-Stream data. - **Returns:** - `T` - The T type value e.g. boolean, integer, float, double and string. @@ -63,51 +59,39 @@ String ETag() const - `String` - The ETag string. -5. ## 🔹 String dataPath(uint32_t index = 0) const +5. ## 🔹 String dataPath() const -Get the SSE mode (HTTP Streaming) event data path (at the specific index) which is the relative path of the data that has been changed in the database. +Get the SSE mode (HTTP Streaming) event data path which is the relative path of the data that has been changed in the database. ```cpp -String dataPath(uint32_t index = 0) const +String dataPath() const ``` -**Params:** - -- `index` - The Stream event index to get the data path. - **Returns:** - `String` - The relative path of data that has been changed. -6. ## 🔹 String event(uint32_t index = 0) +6. ## 🔹 String event() -Get the `SSE mode (HTTP Streaming)` event type string (at the specific index). +Get the `SSE mode (HTTP Streaming)` event type string. ```cpp -String event(uint32_t index = 0) +String event() ``` -**Params:** - -- `index` - The Stream event index to get the data path. - **Returns:** - `String` - The event type string e.g. `put`, `patch`, `keep-alive`, `cancel` and `auth_revoked`. -7. ## 🔹 String data(uint32_t index = 0) +7. ## 🔹 String data() -Get the SSE mode (HTTP Streaming) event data (at the specific index) that has been changed. +Get the SSE mode (HTTP Streaming) event data that has been changed. ```cpp -String data(uint32_t index = 0) +String data() ``` -**Params:** - -- `index` - The Stream event index to get the data path. - **Returns:** - `String` - The data that has been changed. @@ -125,9 +109,9 @@ bool eventTimeout() - `bool` - The SSE mode (HTTP Streaming) event timed out status. -9. ## 🔹 realtime_database_data_type type(uint32_t index = 0) +9. ## 🔹 realtime_database_data_type type() -Get the type of Realtime Database payload and SSE mode (HTTP Streaming) event data. +Get the type of Realtime database data. The realtime_database_data_type enums are included the following. @@ -150,13 +134,9 @@ The realtime_database_data_type enums are included the following. `realtime_database_data_type_array` or 7. ```cpp -realtime_database_data_type type(uint32_t index = 0) +realtime_database_data_type type() ``` -**Params:** - -- `index` - The index of Stream event to convert the data or 0 for non-Stream data. - **Returns:** - `realtime_database_data_type` - The realtime_database_data_type enum represents the type of Realtime database data. diff --git a/src/core/AsyncClient/AsyncClient.h b/src/core/AsyncClient/AsyncClient.h index b53e45ce..68568774 100644 --- a/src/core/AsyncClient/AsyncClient.h +++ b/src/core/AsyncClient/AsyncClient.h @@ -1,5 +1,5 @@ /** - * 2025-01-26 + * 2025-01-29 * * For MCU build target (CORE_ARDUINO_XXXX), see Options.h. * @@ -804,7 +804,10 @@ class AsyncClientClass : public ResultBase, RTDBResultBase // Prevent sse timeout due to large sse Stream playload feedSSETimer(&sData->aResult.rtdbResult); - if ((*payload)[payload->length() - 1] == '\n' && sData->response.tcpAvailable() == 0) + uint32_t len = payload->length(); + bool partial = (*payload)[len - 1] == '\n' && ((len > 2 && (*payload)[len - 2] == '}') || (len > 3 && (*payload)[len - 3] == '}')); + + if (((*payload)[len - 1] == '\n' && sData->response.tcpAvailable() == 0) || partial) { setRefPayload(&sData->aResult.rtdbResult, payload); parseSSE(&sData->aResult.rtdbResult); diff --git a/src/core/AsyncResult/ResultBase.h b/src/core/AsyncResult/ResultBase.h index 49c65459..485a8b74 100644 --- a/src/core/AsyncResult/ResultBase.h +++ b/src/core/AsyncResult/ResultBase.h @@ -1,5 +1,5 @@ /** - * 2025-01-29 + * 2025-01-25 * * The MIT License (MIT) * Copyright (c) 2025 K. Suwatchai (Mobizt) @@ -29,7 +29,7 @@ #define FIREBASE_CHUNK_SIZE 2048 // Base64 encoded string chunk size for TCP's read and write operations. -// This used in Realtime Database with File implementation. +// This used in Realtime database with File implementation. #define FIREBASE_BASE64_CHUNK_SIZE 1026 // SSE mode time out in milliseconds. @@ -59,23 +59,24 @@ namespace firebase_ns friend class RTDBResultBase; private: - struct event_info_t - { - uint32_t data_path_p1 = 0, data_path_p2 = 0, event_p1 = 0, event_p2 = 0, data_p1 = 0, data_p2 = 0; - }; ValueConverter vcon; StringUtil sut; Timer sse_timer; bool sse = false; event_resume_status_t event_resume_status = event_resume_status_undefined; String node_name, etag; - std::vector events; + uint32_t data_path_p1 = 0, data_path_p2 = 0, event_p1 = 0, event_p2 = 0, data_p1 = 0, data_p2 = 0; bool null_etag = false; String *ref_payload = nullptr; void clearSSE() { - events.clear(); + data_path_p1 = 0; + data_path_p2 = 0; + event_p1 = 0; + event_p2 = 0; + data_p1 = 0; + data_p2 = 0; sse = false; event_resume_status = event_resume_status_undefined; } @@ -92,70 +93,55 @@ namespace firebase_ns void parseSSE() { clearSSE(); + int p1 = 0, p2 = 0; + sut.parse(*ref_payload, "event", "\n", p1, p2); + if (p1 > -1 && p2 > -1) + { + event_p1 = p1; + event_p2 = p2; + p1 = p2; + setEventResumeStatus(event_resume_status_undefined); + sse_timer.feed(String(event()).indexOf("cancel") > -1 || String(event()).indexOf("auth_revoked") > -1 ? 0 : FIREBASE_SSE_TIMEOUT_MS / 1000); + sse = true; + } - uint32_t stream_event_begin_pos = 0, stream_event_end_pos = 0; - events.clear(); - while (stream_event_end_pos < ref_payload->length() - 3) + sut.parse(*ref_payload, "data", "\n", p1, p2); + if (p1 > -1 && p2 > -1) { - int p1 = stream_event_begin_pos, p2 = stream_event_end_pos; - event_info_t info; + int p3 = p1, p4 = p2; + if (ref_payload->substring(p1, p2) == "null") + { + data_p1 = p1; + data_p2 = p2; + return; + } - sut.parse(*ref_payload, "event", "\n", p1, p2); + sut.parse(*ref_payload, "\"path\"", ",", p1, p2); if (p1 > -1 && p2 > -1) { - info.event_p1 = p1; - info.event_p2 = p2; + data_path_p1 = p1 + 1; + data_path_p2 = p2 - 1; p1 = p2; - setEventResumeStatus(event_resume_status_undefined); - sse_timer.feed(String(event()).indexOf("cancel") > -1 || String(event()).indexOf("auth_revoked") > -1 ? 0 : FIREBASE_SSE_TIMEOUT_MS / 1000); - sse = true; } - sut.parse(*ref_payload, "data", "\n", p1, p2); + sut.parse(*ref_payload, "\"data\"", "\n", p1, p2); if (p1 > -1 && p2 > -1) { - int p3 = p1, p4 = p2; - if (ref_payload->substring(p1, p2) == "null") - { - info.data_p1 = p1; - info.data_p2 = p2; - return; - } - - sut.parse(*ref_payload, "\"path\"", ",", p1, p2); - if (p1 > -1 && p2 > -1) - { - info.data_path_p1 = p1 + 1; - info.data_path_p2 = p2 - 1; - p1 = p2; - } - - sut.parse(*ref_payload, "\"data\"", "\n", p1, p2); - if (p1 > -1 && p2 > -1) - { - if ((*ref_payload)[p2 - 1] == '}') - p2--; - info.data_p1 = p1; - info.data_p2 = p2; - } - - if (info.data_p1 == 0) - { - info.data_p1 = p3; - info.data_p2 = p4; - } + if ((*ref_payload)[p2 - 1] == '}') + p2--; + data_p1 = p1; + data_p2 = p2; } - if (info.data_p2 > 0) - events.push_back(info); - - stream_event_end_pos = info.data_p2; - stream_event_begin_pos = stream_event_end_pos + 1; + if (data_p1 == 0) + { + data_p1 = p3; + data_p2 = p4; + } } } void setEventResumeStatus(event_resume_status_t status) { event_resume_status = status; } event_resume_status_t eventResumeStatus() const { return event_resume_status; } - protected: void setRefPayload(RealtimeDatabaseResult *rtdbResult, String *payload) { rtdbResult->ref_payload = payload; } void clearSSE(RealtimeDatabaseResult *rtdbResult) { rtdbResult->clearSSE(); } @@ -170,13 +156,11 @@ namespace firebase_ns /** * Convert the RealtimeDatabaseResult to any type of values. - * - * @param index The index of Stream event to convert the data or 0 for non-Stream data. - * + * * @return T The T type value e.g. boolean, integer, float, double and string. */ template - T to(uint32_t index = 0) { return vcon.to(data(index < eventCount() ? index : 0).c_str()); } + T to() { return vcon.to(data().c_str()); } /** * Check if the async task is SSE mode (HTTP Streaming) task. @@ -193,48 +177,35 @@ namespace firebase_ns String name() const { return node_name.c_str(); } /** - * Get the ETag from Realtime Database get function. + * Get the ETag from Realtime database get function. * * @return String The ETag string. */ String ETag() const { return etag.c_str(); } /** - * Get the SSE mode (HTTP Streaming) event count in current Stream payload. + * Get the SSE mode (HTTP Streaming) event data path which is the relative path of the data that has been changed in the database. * - * @return numbers of events in current Stream payload. - */ - uint32_t eventCount() const { return events.size(); } - - /** - * Get the SSE mode (HTTP Streaming) event data path (at the specific index) which is the relative path of the data that has been changed in the database. - * - * @param index The Stream event index to get the data path. - * * @return String The relative path of data that has been changed. */ - String dataPath(uint32_t index = 0) const { return ref_payload && eventCount() ? ref_payload->substring(events[index < eventCount() ? index : 0].data_path_p1, events[index < eventCount() ? index : 0].data_path_p2).c_str() : String(); } + String dataPath() const { return ref_payload ? ref_payload->substring(data_path_p1, data_path_p2).c_str() : String(); } /** - * Get the `SSE mode (HTTP Streaming)` event type string (at the specific index). - * - * @param index The Stream event index to get the event name. - * + * Get the `SSE mode (HTTP Streaming)` event type string. + * * @return String The event type string e.g. `put`, `patch`, `keep-alive`, `cancel` and `auth_revoked`. */ - String event(uint32_t index = 0) { return ref_payload && eventCount() ? ref_payload->substring(events[index < eventCount() ? index : 0].event_p1, events[index < eventCount() ? index : 0].event_p2).c_str() : String(); } + String event() { return ref_payload ? ref_payload->substring(event_p1, event_p2).c_str() : String(); } /** - * Get the SSE mode (HTTP Streaming) event data (at the specific index) that has been changed. - * - * @param index The Stream event index to get the data. - * + * Get the SSE mode (HTTP Streaming) event data that has been changed. + * * @return String The data that has been changed. */ - String data(uint32_t index = 0) + String data() { - if (eventCount() && events[index < eventCount() ? index : 0].data_p1 > 0) - return ref_payload->substring(events[index < eventCount() ? index : 0].data_p1, events[index < eventCount() ? index : 0].data_p2); + if (data_p1 > 0) + return ref_payload->substring(data_p1, data_p2); return ref_payload ? ref_payload->c_str() : String(); } @@ -246,11 +217,9 @@ namespace firebase_ns bool eventTimeout() { return sse && sse_timer.remaining() == 0; } /** - * Get the type of Realtime Database payload and SSE mode (HTTP Streaming) event data. - * - * @param index The index of Stream event to convert the data or 0 for non-Stream data. + * Get the type of Realtime database data. * - * @return realtime_database_data_type The realtime_database_data_type enum represents the type of Realtime Database and SSE mode (HTTP Streaming) event data. + * @return realtime_database_data_type The realtime_database_data_type enum represents the type of Realtime database data. * * The realtime_database_data_type enums are included the following. * @@ -264,7 +233,7 @@ namespace firebase_ns * realtime_database_data_type_json or 6. * realtime_database_data_type_array or 7. */ - realtime_database_data_type type(uint32_t index = 0) { return vcon.getType(data(index).c_str()); } + realtime_database_data_type type() { return vcon.getType(data().c_str()); } }; #endif diff --git a/src/core/Core.h b/src/core/Core.h index a0a7a62b..88451d7b 100644 --- a/src/core/Core.h +++ b/src/core/Core.h @@ -7,7 +7,7 @@ #undef FIREBASE_CLIENT_VERSION #endif -#define FIREBASE_CLIENT_VERSION "1.5.3" +#define FIREBASE_CLIENT_VERSION "1.5.4" static void sys_idle() {