diff --git a/Firebase.cpp b/Firebase.cpp index 6f41b2f2..df5009e9 100644 --- a/Firebase.cpp +++ b/Firebase.cpp @@ -27,16 +27,21 @@ Firebase& Firebase::auth(const String& auth) { return *this; } -String Firebase::get(const String& path) { +FirebaseObject Firebase::create() { + return FirebaseObject{}; +} + +FirebaseObject Firebase::get(const String& path) { return sendRequest("GET", path); } -String Firebase::push(const String& path, const String& value) { - return sendRequest("POST", path, value); +FirebaseObject Firebase::push(const String& path, const FirebaseObject& value) { + char buffer[256]; + value.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); @@ -55,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) { @@ -74,19 +79,17 @@ String Firebase::makeURL(const String& path) { return url; } -String 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. - return _http.getString(); + return FirebaseObject(_http.getString()); } bool Firebase::connected() { @@ -97,18 +100,12 @@ bool Firebase::available() { return _http.getStreamPtr()->available(); } -Firebase::Event Firebase::read(String& event) { +FirebaseObject 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); + String event = client->readStringUntil('\n').substring(7); + String data = client->readStringUntil('\n').substring(6); client->readStringUntil('\n'); // consume separator - return type; + FirebaseObject result(data); + result["event"] = event; + return result; } diff --git a/Firebase.h b/Firebase.h index b4104b56..f7a95430 100644 --- a/Firebase.h +++ b/Firebase.h @@ -24,50 +24,67 @@ #include #include #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 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()) { + } + 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: - int _code = 0; - String _message = ""; + FirebaseError _error; + String _data; + StaticJsonBuffer<200> _buf; + 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; - } - String get(const String& path); - String push(const String& path, const String& 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(); - enum Event { - UNKNOWN, - PUT, - PATCH - }; - Event read(String& event); + FirebaseObject read(); + FirebaseObject create(); private: String makeURL(const String& path); - String 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; }; + #endif // firebase_h diff --git a/examples/FirebasePush_ESP8266/FirebasePush_ESP8266.ino b/examples/FirebasePush_ESP8266/FirebasePush_ESP8266.ino index d04b6fed..6ef7a5fe 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. - String l = fbase.push("/logs", "{\".sv\": \"timestamp\"}"); + FirebaseObject obj = fbase.create(); + obj[".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(l); - // print all entries. - Serial.println(fbase.get("/logs")); + + // print result. + Serial.println(result["name"]); } void loop() { diff --git a/examples/FirebaseStream_ESP8266/FirebaseStream_ESP8266.ino b/examples/FirebaseStream_ESP8266/FirebaseStream_ESP8266.ino index 13bb2174..8cd0d7af 100644 --- a/examples/FirebaseStream_ESP8266/FirebaseStream_ESP8266.ino +++ b/examples/FirebaseStream_ESP8266/FirebaseStream_ESP8266.ino @@ -48,26 +48,29 @@ void setup() { void loop() { - if (fbase.error()) { - Serial.println("streaming error"); - 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) { + 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(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(data); + if (path != "/_updated") { + display.clearDisplay(); + display.setTextSize(2); + display.setTextColor(WHITE); + display.setCursor(0,0); + display.println(path.c_str()+1); + display.println(data); + display.display(); + } } } -} \ No newline at end of file +}