diff --git a/Firebase.cpp b/Firebase.cpp index 7006ad3e..42bb2f38 100644 --- a/Firebase.cpp +++ b/Firebase.cpp @@ -15,7 +15,7 @@ // #include "Firebase.h" -const char* firebaseFingerprint = "C1 56 CD D8 49 A3 7D D2 1D 49 60 7E 0D 59 A7 7C C1 0E 58 D2"; +const char* firebaseFingerprint = "7A 54 06 9B DC 7A 25 B3 86 8D 66 53 48 2C 0B 96 42 C7 B3 0A"; const uint16_t firebasePort = 443; FirebaseRoot Firebase; @@ -27,12 +27,12 @@ FirebaseRef& FirebaseRef::root() { return _root; } -String FirebaseRef::set(const String& value) { - return _root.buildRequest("PUT", _path, value); +String FirebaseRef::val() { + return _root.sendRequest("GET", _path); } String FirebaseRef::push(const String& value) { - return _root.buildRequest("POST", _path, value); + return _root.sendRequest("POST", _path, (uint8_t*)value.c_str(), value.length()); } FirebaseRef FirebaseRef::child(const String& key) { @@ -40,47 +40,37 @@ FirebaseRef FirebaseRef::child(const String& key) { } FirebaseRoot::FirebaseRoot() : FirebaseRef(*this, "") { + _http.setReuse(true); } -void FirebaseRoot::begin(const String& host) { +FirebaseRoot& FirebaseRoot::begin(const String& host) { _host = host; + return *this; } -void FirebaseRoot::auth(const String& token) { - _token = token; +FirebaseRoot& FirebaseRoot::auth(const String& auth) { + _auth = auth; + return *this; } FirebaseRef FirebaseRoot::child(const String& key) { return FirebaseRef(*this, key); } -String FirebaseRoot::buildRequest(const String& method, const String& path, const String& data) { - String req; - req += method + " /" + path + ".json"; - if (_token.length() > 0) { - req += "?auth=" + _token; +String FirebaseRoot::sendRequest(const char* method, const String& path, uint8_t* value, size_t size) { + _error.reset(); + String url = "/" + path + ".json"; + if (_auth.length() > 0) { + url += "?auth=" + _auth; } - req += " HTTP/1.1\r\n"; - req += "Host: " + _host + "\r\n"; - req += "User-Agent: Arduino\r\n"; - req += "Connection: close\r\n"; - if (data.length()) { - req += "Content-Length: "; - req += data.length(); - req += "\r\n\r\n"; - req += data; + _http.begin(_host.c_str(), firebasePort, url.c_str(), true, firebaseFingerprint); + int statusCode = _http.sendRequest(method, value, size); + if (statusCode < 0) { + _error.set(statusCode, + String(method) + " " + url + ": " + + HTTPClient::errorToString(statusCode)); + return ""; } - return req; -} - -const char* FirebaseRoot::host() const { - return _host.c_str(); -} - -uint16_t FirebaseRoot::port() const { - return firebasePort; -} - -const char* FirebaseRoot::fingerprint() const { - return firebaseFingerprint; + return _http.getString(); + // NOTE: no end() because reuse. } diff --git a/Firebase.h b/Firebase.h index 51ee0268..58a1be45 100644 --- a/Firebase.h +++ b/Firebase.h @@ -14,29 +14,33 @@ // limitations under the License. // -// Firebase is an helper library for building Firebase request. -// TODO(proppy): add value() method for GET. +// firebase-arduino is an Arduino client for Firebase. +// It is currently limited to the ESP8266 board family. + +// TODO(proppy): add set() method for PUT. // TODO(proppy): add update() method for PATCH. // TODO(proppy): add remove() method for DELETE. -// TODO(proppy): add helper for decoding response. +// TODO(proppy): add connect() + non blocking #ifndef firebase_h #define firebase_h -#include "Arduino.h" +#include +#include +#include +#include -class Client; class FirebaseRoot; -// FirebaseRef is a reference in the firebase hierarchy. +// FirebaseRef is a node in the firebase hierarchy. // -// Methods `set()` and `push()` returns the HTTP request as a raw -// `String`, the requests then need be sent using an Arduino Wifi, -// Ethernet or GSM `Client`. +// Methods val() and push() performs respectivly HTTP GET and POST +// requests on the corresponding child reference and return the +// response body. class FirebaseRef { public: FirebaseRef(FirebaseRoot& root, const String& path); FirebaseRef& root(); - String set(const String& value); + String val(); String push(const String& value); FirebaseRef child(const String& key); private: @@ -44,7 +48,25 @@ class FirebaseRef { String _path; }; -// FirebaseRoot is a root of firebase hierarchy. + +// FirebaseError is a string representation of a firebase HTTP error. +class FirebaseError { + 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; + } + private: + int _code = 0; + String _message = ""; +}; + + +// FirebaseRoot is the root node of firebase hierarchy. // // A global `Firebase` instance is available for convenience, and need // to be initialized with the `begin()` and `auth()` methods. @@ -52,16 +74,16 @@ class FirebaseRoot : public FirebaseRef { friend FirebaseRef; public: FirebaseRoot(); - void begin(const String& host); - void auth(const String& token); - const char* host() const; - uint16_t port() const; - const char* fingerprint() const; - FirebaseRef child(const String& key); + FirebaseRoot& begin(const String& host); + FirebaseRoot& auth(const String& auth); + FirebaseRef child(const String& key); + const FirebaseError& error() { return _error; } private: - String buildRequest(const String& method, const String& path, const String& data); + String sendRequest(const char* method, const String& path, uint8_t* value = NULL, size_t size = 0); + HTTPClient _http; String _host; - String _token; + String _auth; + FirebaseError _error; }; extern FirebaseRoot Firebase; diff --git a/README.md b/README.md index 1095387b..956bc20a 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,23 @@ # firebase-arduino -This sample show how to call firebase from an arduino sketch. - -*This is not an official Google product*. +This sample shows how to call [Firebase](https://www.firebase.com/) from the [ESP8266 Arduino core](https://github.com/esp8266/Arduino). ## Requirements -- 1 Arduino compatible esp8266 board. -- Arduino 1.6.x +- 1 [ESP8266 Arduino board](https://www.adafruit.com/products/2821). +- [Arduino 1.6.x](https://www.arduino.cc/en/Main/Software) +- ESP8266 Arduino board definition [(master branch)](https://github.com/esp8266/Arduino#using-git-version-) ## Setup - Clone the repo in your Arduino libraries directory. - open the `FirebasePush_ESP8266` example. -- Update `WIFI_SSID` `WIFI_PASSWORD` `FIREBASE_HOST` `FIREBASE_TOKEN` constant. +- Replace `SSID` `PASSWORD` `example.firebaseio.com` `secret_or_token` `node` placeholders. ## Run -- Open firebase dashboard on `/logs.json`. + +- Open firebase dashboard. - Power up the arduino board. - Notice the new entry. + +*This is not an official Google product*. diff --git a/examples/FirebasePush_ESP8266/FirebasePush_ESP8266.ino b/examples/FirebasePush_ESP8266/FirebasePush_ESP8266.ino index 0a3c4e74..f4164706 100644 --- a/examples/FirebasePush_ESP8266/FirebasePush_ESP8266.ino +++ b/examples/FirebasePush_ESP8266/FirebasePush_ESP8266.ino @@ -1,48 +1,55 @@ -// FirebasePush_ESP8266 is a sample that write a timestamp to a firebase -// everytime it is powered on. - -#include -#include +// +// Copyright 2015 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// FirebasePush_ESP8266 is a sample that push a new timestamp to firebase +// on each reset. #include -#define WIFI_SSID "..." -#define WIFI_PASSWORD "..." -#define FIREBASE_HOST "..." -#define FIREBASE_TOKEN "..." - void setup() { Serial.begin(9600); - - WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + + // connect to wifi. + WiFi.begin("SSID", "PASSWORD"); + Serial.print("connecting"); while (WiFi.status() != WL_CONNECTED) { + Serial.print("."); delay(500); } + Serial.println(); + Serial.print("connected: "); Serial.println(WiFi.localIP()); - Firebase.begin(FIREBASE_HOST); - Firebase.auth(FIREBASE_TOKEN); - - WiFiClientSecure wifiClient; - if (!wifiClient.connect(Firebase.host(), Firebase.port())) { - Serial.print("connected failed"); + // get firebase child reference. + FirebaseRef logsRef = Firebase.begin("example.firebaseio.com") + .auth("secret_or_token") + .child("node"); + + // add a new entry. + String logEntry = logsRef.push("{\".sv\": \"timestamp\"}"); + // handle error. + if (Firebase.error()) { + Serial.println("Firebase request failed"); + Serial.println(Firebase.error().message()); + return; } - if (!wifiClient.verify(Firebase.fingerprint(), Firebase.host())) { - Serial.println("certificate verification failed"); - return; - } - - String req = Firebase.child("logs").push("{\".sv\": \"timestamp\"}"); - Serial.println("request:"); - Serial.println(req); - wifiClient.print(req); - - Serial.println("response:"); - while(wifiClient.connected() || wifiClient.available() > 0) { - String data = wifiClient.readStringUntil('\n'); - Serial.println(data); - } + Serial.println(logEntry); + // print all entries. + Serial.println(logsRef.val()); } void loop() { -} +} \ No newline at end of file