Skip to content
This repository was archived by the owner on Mar 17, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/FirebaseDemo_ESP8266/FirebaseDemo_ESP8266.ino
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ void loop() {

// get value
Serial.print("number: ");
Serial.println((float)Firebase.get("number"));
Serial.println(Firebase.getFloat("number"));
delay(1000);

// remove value
Expand Down
36 changes: 18 additions & 18 deletions examples/FirebaseRoom_ESP8266/FirebaseRoom_ESP8266.ino
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,24 @@
#include <ESP8266WiFi.h>
#include <FirebaseArduino.h>

const int pinGrove = 15;
const int pinVibrator = 5;
const int pinLightSensor = A0;
const int pinLed = 12;
const int pinButton = 14;
const int pinFan = 13;
const int grovePowerPin = 15;
const int vibratorPin = 5;
const int lightSensorPin = A0;
const int ledPin = 12;
const int buttonPin = 14;
const int fanPin = 13;

void setup() {
Serial.begin(9600);

pinMode(pinGrove, OUTPUT);
digitalWrite(pinGrove, HIGH);
pinMode(grovePowerPin, OUTPUT);
digitalWrite(grovePowerPin, HIGH);

pinMode(pinVibrator, OUTPUT);
pinMode(pinLightSensor, INPUT);
pinMode(pinLed, OUTPUT);
pinMode(pinButton, INPUT);
pinMode(pinFan, OUTPUT);
pinMode(vibratorPin, OUTPUT);
pinMode(lightSensorPin, INPUT);
pinMode(ledPin, OUTPUT);
pinMode(buttonPin, INPUT);
pinMode(fanPin, OUTPUT);

// connect to wifi.
WiFi.begin("SSID", "PASSWORD");
Expand All @@ -62,15 +62,15 @@ int button = 0;
float light = 0.0;

void loop() {
digitalWrite(pinLed, (int)Firebase.get("redlight"));
digitalWrite(pinFan, (int)Firebase.get("cooldown"));
digitalWrite(pinVibrator, (int)Firebase.get("brrr"));
int newButton = digitalRead(pinButton);
digitalWrite(ledPin, Firebase.getInt("redlight"));
digitalWrite(fanPin, Firebase.getInt("cooldown"));
digitalWrite(vibratorPin, Firebase.getInt("brrr"));
int newButton = digitalRead(buttonPin);
if (newButton != button) {
button = newButton;
Firebase.set("pushbutton", button);
}
float newLight = analogRead(pinLightSensor);
float newLight = analogRead(lightSensorPin);
if (abs(newLight - light) > 100) {
light = newLight;
Firebase.set("sunlight", light);
Expand Down
14 changes: 7 additions & 7 deletions examples/FirebaseStream_ESP8266/FirebaseStream_ESP8266.ino
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,16 @@ void loop() {

if (Firebase.available()) {
FirebaseObject event = Firebase.readEvent();
String event_type = event["type"];
event_type.toLowerCase();
String eventType = event.getString("type");
eventType.toLowerCase();

Serial.print("event: ");
Serial.println(event_type);
if (event_type == "put") {
Serial.println(eventType);
if (eventType == "put") {
Serial.print("data: ");
Serial.println(event["data"].asString());
String path = event["path"];
float data = event["data"];
Serial.println(event.getString("data"));
String path = event.getString("path");
float data = event.getFloat("data");

display.clearDisplay();
display.setTextSize(2);
Expand Down
39 changes: 38 additions & 1 deletion src/FirebaseArduino.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,43 @@ FirebaseObject FirebaseArduino::get(const char* path) {
return FirebaseObject(get.response());
}

int FirebaseArduino::getInt(const char* path) {
auto get = FirebaseGet(host_, auth_, path, http_.get());
error_ = get.error();
if (failed()) {
return 0;
}
return FirebaseObject(get.response()).getInt();
}


Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extra line here too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

float FirebaseArduino::getFloat(const char* path) {
auto get = FirebaseGet(host_, auth_, path, http_.get());
error_ = get.error();
if (failed()) {
return 0.0f;
}
return FirebaseObject(get.response()).getFloat();
}

String FirebaseArduino::getString(const char* path) {
auto get = FirebaseGet(host_, auth_, path, http_.get());
error_ = get.error();
if (failed()) {
return "";
}
return FirebaseObject(get.response()).getString();
}

bool FirebaseArduino::getBool(const char* path) {
auto get = FirebaseGet(host_, auth_, path, http_.get());
error_ = get.error();
if (failed()) {
return "";
}
return FirebaseObject(get.response()).getBool();
}

void FirebaseArduino::remove(const char* path) {
auto remove = FirebaseRemove(host_, auth_, path, http_.get());
error_ = remove.error();
Expand All @@ -67,7 +104,7 @@ FirebaseObject FirebaseArduino::readEvent() {
String event = client->readStringUntil('\n').substring(6);
client->readStringUntil('\n'); // consume separator
FirebaseObject obj = FirebaseObject(event);
obj["type"] = type;
obj.getJsonVariant().asObject()["type"] = type;
return obj;
}

Expand Down
39 changes: 35 additions & 4 deletions src/FirebaseArduino.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,42 @@ class FirebaseArduino {


/**
* Gets the value located at path.
* Gets the integer value located at path.
* You should check success() after calling.
* \param path The path to the node you wish to retrieve.
* \return The data located at that path. This may either be a single element
* or it may be a json structure. Will only be populated if success() is true.
* \return The integer value located at that path. Will only be populated if success() is true.
*/
int getInt(const char* path);

/**
* Gets the float value located at path.
* You should check success() after calling.
* \param path The path to the node you wish to retrieve.
* \return The float value located at that path. Will only be populated if success() is true.
*/
float getFloat(const char* path);

/**
* Gets the string value located at path.
* You should check success() after calling.
* \param path The path to the node you wish to retrieve.
* \return The string value located at that path. Will only be populated if success() is true.
*/
String getString(const char* path);

/**
* Gets the boolean value located at path.
* You should check success() after calling.
* \param path The path to the node you wish to retrieve.
* \return The boolean value located at that path. Will only be populated if success() is true.
*/
bool getBool(const char* path);

/**
* Gets the json object value located at path.
* You should check success() after calling.
* \param path The path to the node you wish to retrieve.
* \return a FirebaseObject value located at that path. Will only be populated if success() is true.
*/
FirebaseObject get(const char* path);

Expand Down Expand Up @@ -94,7 +125,7 @@ class FirebaseArduino {
/**
* Reads the next event in a stream. This is only meaningful once stream() has
* been called.
* \return Object will have ["type"] that describes the event type, ["path"]
* \return FirebaseObject will have ["type"] that describes the event type, ["path"]
* that describes the effected path and ["data"] that was updated.
*/
FirebaseObject readEvent();
Expand Down
96 changes: 60 additions & 36 deletions src/FirebaseObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,57 +16,81 @@

#include "FirebaseObject.h"

namespace {
template<typename T>
T decodeJsonLiteral(const String& json) {
return JsonVariant{ArduinoJson::RawJson{json.c_str()}};
}

// ugly workaround to https://github.com/bblanchon/ArduinoJson/issues/265
template<>
String decodeJsonLiteral<String>(const String& json) {
StaticJsonBuffer<JSON_ARRAY_SIZE(1)> buf;
String array = "[" + json + "]";
return buf.parseArray(&array[0])[0];
}
} // namespace

FirebaseObject::FirebaseObject(const String& data) : data_{data} {
if (data_[0] == '{') {
json_ = &buffer_.parseObject(&data_[0]);
} else if (data_[0] == '"') {
data_ = decodeJsonLiteral<String>(data_);
}
json_ = buffer_.parse(&data_[0]);
// TODO(proppy): find a way to check decoding error, tricky because
// ArduinoJson doesn't surface error for variant parsing.
// See: https://github.com/bblanchon/ArduinoJson/issues/279
}

FirebaseObject::operator bool() {
return decodeJsonLiteral<bool>(data_);
bool FirebaseObject::getBool(const String& path) {
JsonVariant variant = getJsonVariant(path);
if (!variant.is<bool>()) {
error_ = "failed to convert to bool";
return 0;
}
return static_cast<bool>(variant);
}

FirebaseObject::operator int() {
return decodeJsonLiteral<int>(data_);
int FirebaseObject::getInt(const String& path) {
JsonVariant variant = getJsonVariant(path);
if (!variant.is<int>()) {
error_ = "failed to convert to int";
return 0;
}
return static_cast<int>(variant);
}

FirebaseObject::operator float() {
return decodeJsonLiteral<float>(data_);
float FirebaseObject::getFloat(const String& path) {
JsonVariant variant = getJsonVariant(path);
if (!variant.is<float>()) {
error_ = "failed to convert to float";
return 0;
}
return static_cast<float>(variant);
}

FirebaseObject::operator const String&() {
return data_;
String FirebaseObject::getString(const String& path) {
JsonVariant variant = getJsonVariant(path);
if (!variant.is<const char *>()) {
error_ = "failed to convert to string";
return "";
}
return static_cast<const char*>(variant);
}

FirebaseObject::operator const JsonObject&() {
return *json_;
JsonVariant FirebaseObject::getJsonVariant(const String& path) {
String key(path);
char* start = &key[0];
char* end = start + key.length();
// skip first `/`.
if (*start == '/') {
start++;
}
JsonVariant json = json_;
while (start < end) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While this block of code seems valid it is pretty tricky and could probably be made clearer, at the least it could use some comments.
If I follow correctly you start with a pointer to the start of the path, you then search for the next / and replace it with a \0 you then read a c string from start that should then terminate on the recently added \0 to be the current token. You then start the next iteration immediately after the old / which is now a \0.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

// TODO(proppy) split in a separate function.
char* p = start;
// advance to next `/`.
while (*p && (*p != '/')) p++;
// make `start` a C string.
*p = 0;
// return json variant at `start`.
json = json.asObject().get(start);
// advance to next path element.
start = p + 1;
}
return json;
}

JsonObjectSubscript<const char*> FirebaseObject::operator[](const char* key) {
return json_->operator[](key);
bool FirebaseObject::failed() const {
return error_.length() > 0;
}

JsonObjectSubscript<const String&> FirebaseObject::operator[](const String& key) {
return json_->operator[](key);
bool FirebaseObject::success() const {
return error_.length() == 0;
}

JsonVariant FirebaseObject::operator[](JsonObjectKey key) const {
return json_->operator[](key);
const String& FirebaseObject::error() const {
return error_;
}
Loading