From d48bc42080e980eeb2eed448d43397fc1f3e25fd Mon Sep 17 00:00:00 2001 From: Johan Euphrosine Date: Wed, 13 Jan 2016 03:39:02 -0800 Subject: [PATCH 1/4] Firebase: initial json support --- Firebase.cpp | 50 +++++++++++++++++++++++++++++++------------------- Firebase.h | 22 +++++++++++++--------- 2 files changed, 44 insertions(+), 28 deletions(-) diff --git a/Firebase.cpp b/Firebase.cpp index 6f41b2f2..416ed35e 100644 --- a/Firebase.cpp +++ b/Firebase.cpp @@ -27,14 +27,21 @@ Firebase& Firebase::auth(const String& auth) { return *this; } -String Firebase::get(const String& path) { - return sendRequest("GET", path); +Firebase& Firebase::get(const String& path) { + sendRequest("GET", path); + return *this; } -String Firebase::push(const String& path, const String& value) { - return sendRequest("POST", path, value); +Firebase& Firebase::push(const String& path, const String& value) { + sendRequest("POST", path, value); + return *this; } +//Firebase& Firebase::push(const String& path, const JsonObject& value) { +// sendRequest("POST", path, value); +// return *this; +//} + Firebase& Firebase::stream(const String& path) { _error.reset(); String url = makeURL(path); @@ -74,7 +81,7 @@ String Firebase::makeURL(const String& path) { return url; } -String Firebase::sendRequest(const char* method, const String& path, const String& value) { +void Firebase::sendRequest(const char* method, const String& path, const String& value) { _error.reset(); String url = makeURL(path); _http.begin(_host.c_str(), firebasePort, url.c_str(), true, firebaseFingerprint); @@ -83,10 +90,11 @@ String Firebase::sendRequest(const char* method, const String& path, const Strin _error.set(statusCode, String(method) + " " + url + ": " + HTTPClient::errorToString(statusCode)); - return ""; + return; } // no _http.end() because of connection reuse. - return _http.getString(); + _data = _http.getString(); + return; } bool Firebase::connected() { @@ -97,18 +105,22 @@ bool Firebase::available() { return _http.getStreamPtr()->available(); } -Firebase::Event Firebase::read(String& event) { +Firebase& Firebase::read() { auto client = _http.getStreamPtr(); - Event type;; - String typeStr = client->readStringUntil('\n').substring(7); - if (typeStr == "put") { - type = Firebase::Event::PUT; - } else if (typeStr == "patch") { - type = Firebase::Event::PATCH; - } else { - type = Firebase::Event::UNKNOWN; - } - event = client->readStringUntil('\n').substring(6); + _event = client->readStringUntil('\n').substring(7); + _data = client->readStringUntil('\n').substring(6); client->readStringUntil('\n'); // consume separator - return type; + Serial.println(_event); + Serial.println(_data); + return *this; +} + +JsonObject& Firebase::create() { + return _json.createObject(); +} + +JsonObject& Firebase::json() { + _json = StaticJsonBuffer<200>(); + JsonObject& obj = _json.parseObject((char*)_data.c_str()); + return obj; } diff --git a/Firebase.h b/Firebase.h index b4104b56..087eec37 100644 --- a/Firebase.h +++ b/Firebase.h @@ -24,6 +24,7 @@ #include #include #include +#include // FirebaseError represents a Firebase API error with a code and a // message. @@ -50,24 +51,27 @@ class Firebase { const FirebaseError& error() const { return _error; } - String get(const String& path); - String push(const String& path, const String& value); + Firebase& get(const String& path); + Firebase& push(const String& path, const String& value); + // Firebase& push(const String& path, const JsonObject& value); bool connected(); Firebase& stream(const String& path); bool available(); - enum Event { - UNKNOWN, - PUT, - PATCH - }; - Event read(String& event); + Firebase& read(); + JsonObject& create(); + const String& event() const { return _event; }; + const String& data() const { return _data; } + JsonObject& json(); private: String makeURL(const String& path); - String sendRequest(const char* method, const String& path, const String& value = ""); + void sendRequest(const char* method, const String& path, const String& value = ""); HTTPClient _http; String _host; String _auth; FirebaseError _error; + String _event; + String _data; + StaticJsonBuffer<200> _json; }; #endif // firebase_h From bb8fe2aa3f23ed7fd27099fc2af79ced999838e2 Mon Sep 17 00:00:00 2001 From: Johan Euphrosine Date: Wed, 13 Jan 2016 03:43:33 -0800 Subject: [PATCH 2/4] update examples --- .../FirebasePush_ESP8266.ino | 6 ++-- .../FirebaseStream_ESP8266.ino | 32 +++++++++++-------- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/examples/FirebasePush_ESP8266/FirebasePush_ESP8266.ino b/examples/FirebasePush_ESP8266/FirebasePush_ESP8266.ino index d04b6fed..ebd75ee1 100644 --- a/examples/FirebasePush_ESP8266/FirebasePush_ESP8266.ino +++ b/examples/FirebasePush_ESP8266/FirebasePush_ESP8266.ino @@ -38,7 +38,7 @@ void setup() { Serial.println(WiFi.localIP()); // add a new entry. - String l = fbase.push("/logs", "{\".sv\": \"timestamp\"}"); + fbase.push("/logs", "{\".sv\": \"timestamp\"}"); // handle error. if (fbase.error()) { Serial.println("Firebase request failed"); @@ -46,9 +46,9 @@ void setup() { return; } // print response. - Serial.println(l); + Serial.println(fbase.data()); // print all entries. - Serial.println(fbase.get("/logs")); + Serial.println(fbase.get("/logs").data()); } void loop() { diff --git a/examples/FirebaseStream_ESP8266/FirebaseStream_ESP8266.ino b/examples/FirebaseStream_ESP8266/FirebaseStream_ESP8266.ino index 13bb2174..f1a96163 100644 --- a/examples/FirebaseStream_ESP8266/FirebaseStream_ESP8266.ino +++ b/examples/FirebaseStream_ESP8266/FirebaseStream_ESP8266.ino @@ -53,21 +53,25 @@ void loop() { Serial.println(fbase.error().message()); } if (fbase.available()) { - String event; - auto type = fbase.read(event); - Serial.print("event: "); - Serial.println(type); - if (type != Firebase::Event::UNKNOWN) { + if (fbase.read().event() == "put" { + const JsonObject& json = fbase.json(); + if (!json.success()) { + Serial.println("streaming error"); + return; + } + Serial.print("path: "); + Serial.println((const char*)json["path"]); Serial.print("data: "); - Serial.println(event); - - // TODO(proppy): parse JSON object. - display.clearDisplay(); - display.setTextSize(1); - display.setTextColor(WHITE); - display.setCursor(0,0); - display.println(event); - display.display(); + Serial.println((const char*)json["data"]); + if (String((const char*)json["path"]) != "/_updated") { + display.clearDisplay(); + display.setTextSize(2); + display.setTextColor(WHITE); + display.setCursor(0,0); + display.println((const char*)json["path"]+1); + display.println((const char*)json["data"]); + display.display(); + } } } } \ No newline at end of file From 0037b01601c1efe308c51b69aaa163c99be80593 Mon Sep 17 00:00:00 2001 From: Johan Euphrosine Date: Mon, 25 Jan 2016 16:44:51 -0800 Subject: [PATCH 3/4] add firebaseobject --- Firebase.cpp | 65 +++++++------------ Firebase.h | 65 ++++++++++--------- .../FirebasePush_ESP8266.ino | 20 +++--- .../FirebaseStream_ESP8266.ino | 31 +++++---- 4 files changed, 86 insertions(+), 95 deletions(-) diff --git a/Firebase.cpp b/Firebase.cpp index 416ed35e..860620fa 100644 --- a/Firebase.cpp +++ b/Firebase.cpp @@ -27,23 +27,21 @@ Firebase& Firebase::auth(const String& auth) { return *this; } -Firebase& Firebase::get(const String& path) { - sendRequest("GET", path); - return *this; +FirebaseObject Firebase::create() { + return FirebaseObject{}; } -Firebase& Firebase::push(const String& path, const String& value) { - sendRequest("POST", path, value); - return *this; +FirebaseObject Firebase::get(const String& path) { + return sendRequest("GET", path); } -//Firebase& Firebase::push(const String& path, const JsonObject& value) { -// sendRequest("POST", path, value); -// return *this; -//} +FirebaseObject Firebase::push(const String& path, const FirebaseObject& value) { + char buffer[256]; + value.json.printTo(buffer, sizeof(buffer)); + return sendRequest("POST", path, buffer); +} -Firebase& Firebase::stream(const String& path) { - _error.reset(); +FirebaseObject Firebase::stream(const String& path) { String url = makeURL(path); const char* headers[] = {"Location"}; _http.setReuse(true); @@ -62,11 +60,11 @@ Firebase& Firebase::stream(const String& path) { statusCode = _http.sendRequest("GET", (uint8_t*)NULL, 0); } if (statusCode != 200) { - _error.set(statusCode, - "stream " + location + ": " - + HTTPClient::errorToString(statusCode)); + return FirebaseObject(FirebaseError(statusCode, + "stream " + location + ": " + + HTTPClient::errorToString(statusCode))); } - return *this; + return FirebaseObject{}; } String Firebase::makeURL(const String& path) { @@ -81,20 +79,17 @@ String Firebase::makeURL(const String& path) { return url; } -void Firebase::sendRequest(const char* method, const String& path, const String& value) { - _error.reset(); +FirebaseObject Firebase::sendRequest(const char* method, const String& path, const String& value) { String url = makeURL(path); _http.begin(_host.c_str(), firebasePort, url.c_str(), true, firebaseFingerprint); int statusCode = _http.sendRequest(method, (uint8_t*)value.c_str(), value.length()); if (statusCode < 0) { - _error.set(statusCode, - String(method) + " " + url + ": " - + HTTPClient::errorToString(statusCode)); - return; + return FirebaseObject(FirebaseError(statusCode, + String(method) + " " + url + ": " + + HTTPClient::errorToString(statusCode))); } // no _http.end() because of connection reuse. - _data = _http.getString(); - return; + return FirebaseObject(_http.getString()); } bool Firebase::connected() { @@ -105,22 +100,12 @@ bool Firebase::available() { return _http.getStreamPtr()->available(); } -Firebase& Firebase::read() { +FirebaseObject Firebase::read() { auto client = _http.getStreamPtr(); - _event = client->readStringUntil('\n').substring(7); - _data = client->readStringUntil('\n').substring(6); + String event = client->readStringUntil('\n').substring(7); + String data = client->readStringUntil('\n').substring(6); client->readStringUntil('\n'); // consume separator - Serial.println(_event); - Serial.println(_data); - return *this; -} - -JsonObject& Firebase::create() { - return _json.createObject(); -} - -JsonObject& Firebase::json() { - _json = StaticJsonBuffer<200>(); - JsonObject& obj = _json.parseObject((char*)_data.c_str()); - return obj; + FirebaseObject result(data); + result.json["event"] = event; + return result; } diff --git a/Firebase.h b/Firebase.h index 087eec37..7154d339 100644 --- a/Firebase.h +++ b/Firebase.h @@ -26,52 +26,57 @@ #include #include -// FirebaseError represents a Firebase API error with a code and a -// message. -class FirebaseError { +// FirebaseError is an error for a given firebase API call. +struct FirebaseError { + FirebaseError() {} + FirebaseError(int c, const String& m) : code(c), message(m) {} + FirebaseError(int c, const char* m) : code(c), message(m) {} + int code = 0; + String message = ""; + operator bool() const { + return code < 0; + } +}; + +// FirebaseObject is a payload or a result for a given firebase API call. +class FirebaseObject { public: - operator bool() const { return _code < 0; } - int code() const { return _code; } - const String& message() const { return _message; } - void reset() { set(0, ""); } - void set(int code, const String& message) { - _code = code; - _message = message; + FirebaseObject() : json(_buf.createObject()) { + } + FirebaseObject(const String& data) : _data(data), json(_buf.parseObject((char*)_data.c_str())) { + if (!json.success()) { + error = FirebaseError{-1, "error parsing json"}; + } + } + FirebaseObject(const FirebaseError& err) : error{err}, json(_buf.createObject()) { } private: - int _code = 0; - String _message = ""; + StaticJsonBuffer<200> _buf; + String _data; + public: + FirebaseError error; + JsonObject& json; }; -// Firebase is the connection to firebase. +// Firebase is a client for a given firebase host. class Firebase { public: Firebase(const String& host); Firebase& auth(const String& auth); - const FirebaseError& error() const { - return _error; - } - Firebase& get(const String& path); - Firebase& push(const String& path, const String& value); - // Firebase& push(const String& path, const JsonObject& value); + FirebaseObject get(const String& path); + FirebaseObject push(const String& path, const FirebaseObject& value); bool connected(); - Firebase& stream(const String& path); + FirebaseObject stream(const String& path); bool available(); - Firebase& read(); - JsonObject& create(); - const String& event() const { return _event; }; - const String& data() const { return _data; } - JsonObject& json(); + FirebaseObject read(); + FirebaseObject create(); private: String makeURL(const String& path); - void sendRequest(const char* method, const String& path, const String& value = ""); + FirebaseObject sendRequest(const char* method, const String& path, const String& value = ""); HTTPClient _http; String _host; String _auth; - FirebaseError _error; - String _event; - String _data; - StaticJsonBuffer<200> _json; }; + #endif // firebase_h diff --git a/examples/FirebasePush_ESP8266/FirebasePush_ESP8266.ino b/examples/FirebasePush_ESP8266/FirebasePush_ESP8266.ino index ebd75ee1..0e7bb878 100644 --- a/examples/FirebasePush_ESP8266/FirebasePush_ESP8266.ino +++ b/examples/FirebasePush_ESP8266/FirebasePush_ESP8266.ino @@ -20,7 +20,7 @@ #include // create firebase client. -Firebase fbase = Firebase("example.firebaseio.com") +Firebase fbase = Firebase("firebase-arduino-example.firebaseio-demo.com") .auth("secret_or_token"); void setup() { @@ -38,17 +38,19 @@ void setup() { Serial.println(WiFi.localIP()); // add a new entry. - fbase.push("/logs", "{\".sv\": \"timestamp\"}"); + FirebaseObject obj = fbase.create(); + obj.json[".sv"] = "timestamp"; + FirebaseObject result = fbase.push("/logs", obj); + // handle error. - if (fbase.error()) { - Serial.println("Firebase request failed"); - Serial.println(fbase.error().message()); + if (result.error) { + Serial.print("firebase request failed: "); + Serial.println(result.error); return; } - // print response. - Serial.println(fbase.data()); - // print all entries. - Serial.println(fbase.get("/logs").data()); + + // print result. + Serial.println(result.json["name"]); } void loop() { diff --git a/examples/FirebaseStream_ESP8266/FirebaseStream_ESP8266.ino b/examples/FirebaseStream_ESP8266/FirebaseStream_ESP8266.ino index f1a96163..8cd0d7af 100644 --- a/examples/FirebaseStream_ESP8266/FirebaseStream_ESP8266.ino +++ b/examples/FirebaseStream_ESP8266/FirebaseStream_ESP8266.ino @@ -48,30 +48,29 @@ void setup() { void loop() { - if (fbase.error()) { - Serial.println("streaming error"); - Serial.println(fbase.error().message()); - } if (fbase.available()) { - if (fbase.read().event() == "put" { - const JsonObject& json = fbase.json(); - if (!json.success()) { - Serial.println("streaming error"); - return; - } + FirebaseObject result = fbase.read(); + if (result.error) { + Serial.println("firebase streaming error"); + Serial.println(result.error); + return; + } + if (result.json["event"] == "put") { + String path = result.json["path"]; + float data = result.json["data"]; Serial.print("path: "); - Serial.println((const char*)json["path"]); + Serial.println(path); Serial.print("data: "); - Serial.println((const char*)json["data"]); - if (String((const char*)json["path"]) != "/_updated") { + Serial.println(data); + if (path != "/_updated") { display.clearDisplay(); display.setTextSize(2); display.setTextColor(WHITE); display.setCursor(0,0); - display.println((const char*)json["path"]+1); - display.println((const char*)json["data"]); + display.println(path.c_str()+1); + display.println(data); display.display(); } } } -} \ No newline at end of file +} From 492014e4967f00026ce9860099a9705b3cfa3001 Mon Sep 17 00:00:00 2001 From: Johan Euphrosine Date: Tue, 26 Jan 2016 17:20:15 -0800 Subject: [PATCH 4/4] json: opaque FirebaseObject type --- Firebase.cpp | 4 +-- Firebase.h | 26 ++++++++++++------- .../FirebasePush_ESP8266.ino | 8 +++--- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/Firebase.cpp b/Firebase.cpp index 860620fa..df5009e9 100644 --- a/Firebase.cpp +++ b/Firebase.cpp @@ -37,7 +37,7 @@ FirebaseObject Firebase::get(const String& path) { FirebaseObject Firebase::push(const String& path, const FirebaseObject& value) { char buffer[256]; - value.json.printTo(buffer, sizeof(buffer)); + value.printTo(buffer, sizeof(buffer)); return sendRequest("POST", path, buffer); } @@ -106,6 +106,6 @@ FirebaseObject Firebase::read() { String data = client->readStringUntil('\n').substring(6); client->readStringUntil('\n'); // consume separator FirebaseObject result(data); - result.json["event"] = event; + result["event"] = event; return result; } diff --git a/Firebase.h b/Firebase.h index 7154d339..f7a95430 100644 --- a/Firebase.h +++ b/Firebase.h @@ -41,21 +41,29 @@ struct FirebaseError { // FirebaseObject is a payload or a result for a given firebase API call. class FirebaseObject { public: - FirebaseObject() : json(_buf.createObject()) { + FirebaseObject() : _json(_buf.createObject()) { } - FirebaseObject(const String& data) : _data(data), json(_buf.parseObject((char*)_data.c_str())) { - if (!json.success()) { - error = FirebaseError{-1, "error parsing json"}; + FirebaseObject(const FirebaseObject& obj) : FirebaseObject(obj._data) { + } + FirebaseObject(const String& data) : _data(data), _json(_buf.parseObject((char*)_data.c_str())) { + if (!_json.success()) { + _error = FirebaseError{-1, "error parsing json"}; } } - FirebaseObject(const FirebaseError& err) : error{err}, json(_buf.createObject()) { + FirebaseObject(const FirebaseError& err) : _error{err}, _json(_buf.createObject()) { + } + const FirebaseError& error() { return _error; } + JsonObjectSubscript operator[](const char* key) { + return _json[key]; + } + size_t printTo(char *buffer, size_t bufferSize) const { + return _json.printTo(buffer, bufferSize); } private: - StaticJsonBuffer<200> _buf; + FirebaseError _error; String _data; - public: - FirebaseError error; - JsonObject& json; + StaticJsonBuffer<200> _buf; + JsonObject& _json; }; // Firebase is a client for a given firebase host. diff --git a/examples/FirebasePush_ESP8266/FirebasePush_ESP8266.ino b/examples/FirebasePush_ESP8266/FirebasePush_ESP8266.ino index 0e7bb878..6ef7a5fe 100644 --- a/examples/FirebasePush_ESP8266/FirebasePush_ESP8266.ino +++ b/examples/FirebasePush_ESP8266/FirebasePush_ESP8266.ino @@ -39,18 +39,18 @@ void setup() { // add a new entry. FirebaseObject obj = fbase.create(); - obj.json[".sv"] = "timestamp"; + obj[".sv"] = "timestamp"; FirebaseObject result = fbase.push("/logs", obj); // handle error. - if (result.error) { + if (result.error()) { Serial.print("firebase request failed: "); - Serial.println(result.error); + Serial.println(result.error()); return; } // print result. - Serial.println(result.json["name"]); + Serial.println(result["name"]); } void loop() {