Question on FirebaseArduino.cpp

Hi. I’m using an ESP8266 Wi-Fi module to get data from the Firebase Realtime Database and I would like to know how this is being done in the code. Since my ESP is retrieving string from the Firebase, I’m using the getString() function in FirebaseArduino.cpp. When I was trying to understand the code, I found out that there is some function that is not within that file. For example, the reset() function that is used in the initRequest function is not found in that file. Also, the function printTo() used in set() function is also not defined in that file. May I know where are all these function being defined?

Here is the code for FirebaseArduino.cpp:

//
// Copyright 2016 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.
//

#include "FirebaseArduino.h"

// This is needed to compile std::string on esp8266.
template class std::basic_string<char>;

void FirebaseArduino::begin(const String& host, const String& auth) {
  host_ = host.c_str();
  auth_ = auth.c_str();
}

void FirebaseArduino::initStream() {
  if (stream_http_.get() == nullptr) {
    stream_http_.reset(FirebaseHttpClient::create());
    stream_http_->setReuseConnection(true);
    stream_.reset(new FirebaseStream(stream_http_));
  }
}

void FirebaseArduino::initRequest() {
  if (req_http_.get() == nullptr) {
    req_http_.reset(FirebaseHttpClient::create());
    req_http_->setReuseConnection(true);
    req_.reset(new FirebaseRequest(req_http_));
  }
}

String FirebaseArduino::pushInt(const String& path, int value) {
  return push(path, value);
}

String FirebaseArduino::pushFloat(const String& path, float value) {
  return push(path, value);
}

String FirebaseArduino::pushBool(const String& path, bool value) {
  return push(path, value);
}

String FirebaseArduino::pushString(const String& path, const String& value) {
  JsonVariant json(value.c_str());
  return push(path, json);
}

String FirebaseArduino::push(const String& path, const JsonVariant& value) {
  int size = value.measureLength()+1;
  char * buf = new char[size];
  value.printTo(buf, size);
  initRequest();
  int status = req_.get()->sendRequest(host_, auth_, "POST", path.c_str(), buf);
  error_ = req_.get()->error();
  const char* name = req_.get()->json()["name"].as<const char*>();
  delete buf;
  return name;
}

void FirebaseArduino::setInt(const String& path, int value) {
  set(path, value);
}

void FirebaseArduino::setFloat(const String& path, float value) {
  set(path, value);
}

void FirebaseArduino::setBool(const String& path, bool value) {
  set(path, value);
}

void FirebaseArduino::setString(const String& path, const String& value) {
  JsonVariant json(value.c_str());
  set(path, json);
}

void FirebaseArduino::set(const String& path, const JsonVariant& value) {
  int size = value.measureLength()+1;
  char* buf= new char[size];
  value.printTo(buf, size);
  initRequest();
  req_.get()->sendRequest(host_, auth_, "PUT", path.c_str(), buf);
  error_ = req_.get()->error();
  delete buf;
}

void FirebaseArduino::getRequest(const String& path) {
  initRequest();
  req_.get()->sendRequest(host_, auth_, "GET", path.c_str());
  error_ = req_.get()->error();
}

FirebaseObject FirebaseArduino::get(const String& path) {
  getRequest(path);
  if (failed()) {
    return FirebaseObject{""};
  }
  return FirebaseObject(req_.get()->response().c_str());
}

int FirebaseArduino::getInt(const String& path) {
  getRequest(path);
  if (failed()) {
    return 0;
  }
  return FirebaseObject(req_.get()->response().c_str()).getInt();
}


float FirebaseArduino::getFloat(const String& path) {
  getRequest(path);
  if (failed()) {
    return 0.0f;
  }
  return FirebaseObject(req_.get()->response().c_str()).getFloat();
}

String FirebaseArduino::getString(const String& path) {
  getRequest(path);
  if (failed()) {
    return "";
  }
  return FirebaseObject(req_.get()->response().c_str()).getString();
}

bool FirebaseArduino::getBool(const String& path) {
  getRequest(path);
  if (failed()) {
    return "";
  }
  return FirebaseObject(req_.get()->response().c_str()).getBool();
}
void FirebaseArduino::remove(const String& path) {
  initRequest();
  req_.get()->sendRequest(host_, auth_, "DELETE", path.c_str());
  error_ = req_.get()->error();
}

void FirebaseArduino::stream(const String& path) {
  initStream();
  stream_.get()->startStreaming(host_, auth_, path.c_str());
  error_ = stream_.get()->error();
}

bool FirebaseArduino::available() {
  if (stream_http_.get() == nullptr) {
    return 0;
  }
  auto client = stream_http_.get()->getStreamPtr();
  return (client == nullptr) ? false : client->available();
}

FirebaseObject FirebaseArduino::readEvent() {
  if (stream_http_.get() == nullptr) {
    return FirebaseObject("");
  }
  auto client = stream_http_.get()->getStreamPtr();
  if (client == nullptr) {
      return FirebaseObject("");
  }
  String type = client->readStringUntil('\n').substring(7);;
  String event = client->readStringUntil('\n').substring(6);
  client->readStringUntil('\n'); // consume separator
  FirebaseObject obj = FirebaseObject(event.c_str());
  obj.getJsonVariant().asObject()["type"] = type.c_str();
  return obj;
}

bool FirebaseArduino::success() {
  return error_.code() == 0;
}

bool FirebaseArduino::failed() {
  return error_.code() != 0;
}

const String& FirebaseArduino::error() {
  return error_.message().c_str();
}

FirebaseArduino Firebase;

Any help would be appreciated.

That would be so much more informative if you showed the .h file as well.

.reset() is a method on the stream_http_ object. The .h file will tell you what type of object that is and probably will tell you which .h file created that type.

Here’s the .h file:

//
// Copyright 2016 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.
//

#ifndef FIREBASE_ARDUINO_H
#define FIREBASE_ARDUINO_H

#include <string>

#include "Firebase.h"
#include "FirebaseObject.h"

/**
 * Main class for Arduino clients to interact with Firebase.
 * This implementation is designed to follow Arduino best practices and favor
 * simplicity over all else.
 * For more complicated usecases and more control see the Firebase class in
 * Firebase.h.
 */
class FirebaseArduino {
 public:
  /**
   * Must be called first. This initialize the client with the given
   * firebase host and credentials.
   * \param host Your firebase db host, usually X.firebaseio.com.
   * \param auth Optional credentials for the db, a secret or token.
   */
  virtual void begin(const String& host, const String& auth = "");

  /**
   * Appends the integer value to the node at path.
   * Equivalent to the REST API's POST.
   * You should check success() after calling.
   * \param path The path of the parent node.
   * \param value Integer value that you wish to append to the node.
   * \return The unique key of the new child node.
   */
  String pushInt(const String& path, int value);

  /**
   * Appends the float value to the node at path.
   * Equivalent to the REST API's POST.
   * You should check success() after calling.
   * \param path The path of the parent node.
   * \param value Float value that you wish to append to the node.
   * \return The unique key of the new child node.
   */
  String pushFloat(const String& path, float value);

  /**
   * Appends the bool value to the node at path.
   * Equivalent to the REST API's POST.
   * You should check success() after calling.
   * \param path The path of the parent node.
   * \param value Bool value that you wish to append to the node.
   * \return The unique key of the new child node.
   */
  String pushBool(const String& path, bool value);

  /**
   * Appends the String value to the node at path.
   * Equivalent to the REST API's POST.
   * You should check success() after calling.
   * \param path The path of the parent node.
   * \param value String value that you wish to append to the node.
   * \return The unique key of the new child node.
   */
  virtual String pushString(const String& path, const String& value);

  /**
   * Appends the JSON data to the node at path.
   * Equivalent to the REST API's POST.
   * You should check success() after calling.
   * \param path The path of the parent node.
   * \param value JSON data that you wish to append to the node.
   * \return The unique key of the new child node.
   */
  String push(const String& path, const JsonVariant& value);

  /**
   * Writes the integer value to the node located at path equivalent to the
   * REST API's PUT.
   * You should check success() after calling.
   * \param path The path inside of your db to the node you wish to update.
   * \param value Integer value that you wish to write.
   */
  void setInt(const String& path, int value);

  /**
   * Writes the float value to the node located at path equivalent to the
   * REST API's PUT.
   * You should check success() after calling.
   * \param path The path inside of your db to the node you wish to update.
   * \param value Float value that you wish to write.
   */
  void setFloat(const String& path, float value);

  /**
   * Writes the bool value to the node located at path equivalent to the
   * REST API's PUT.
   * You should check success() after calling.
   * \param path The path inside of your db to the node you wish to update.
   * \param value Bool value that you wish to write.
   */
  void setBool(const String& path, bool value);

  /**
   * Writes the String value to the node located at path equivalent to the
   * REST API's PUT.
   * You should check success() after calling.
   * \param path The path inside of your db to the node you wish to update.
   * \param value String value that you wish to write.
   */
  virtual void setString(const String& path, const String& value);

  /**
   * Writes the JSON data to the node located at path.
   * Equivalent to the REST API's PUT.
   * You should check success() after calling.
   * \param path The path inside of your db to the node you wish to update.
   * \param value JSON data that you wish to write.
   */
  void set(const String& path, const JsonVariant& value);


  /**
   * 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 integer value located at that path. Will only be populated if success() is true.
   */
  int getInt(const String& 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 String& 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.
   */
  virtual String getString(const String& 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 String& 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 String& path);

  /**
   * Remove the node, and possibly entire tree, located at path.
   * You should check success() after calling.
   * \param path The path to the node you wish to remove,
   * including all of its children.
   */
  virtual void remove(const String& path);

  /**
   * Starts streaming any changes made to the node located at path, including
   * any of its children.
   * You should check success() after calling.
   * This changes the state of this object. Once this is called you may start
   * monitoring available() and calling readEvent() to get new events.
   * \param path The path inside of your db to the node you wish to monitor.
   */
  virtual void stream(const String& path);

  /**
   * Checks if there are new events available. This is only meaningful once
   * stream() has been called.
   * \return If a new event is ready.
   */
  virtual bool available();

  /**
   * Reads the next event in a stream. This is only meaningful once stream() has
   * been called.
   * \return FirebaseObject will have ["type"] that describes the event type, ["path"]
   * that describes the effected path and ["data"] that was updated.
   */
  virtual FirebaseObject readEvent();

  /**
   * \return Whether the last command was successful.
   */
  bool success();

  /**
   * \return Whether the last command failed.
   */
  bool failed();

  /**
   * \return Error message from last command if failed() is true.
   */
  virtual const String& error();
 private:
  std::string host_;
  std::string auth_;
  FirebaseError error_;
  std::shared_ptr<FirebaseHttpClient> req_http_;
  std::shared_ptr<FirebaseRequest> req_;
  std::shared_ptr<FirebaseHttpClient> stream_http_;
  std::shared_ptr<FirebaseStream> stream_;

  void initStream();
  void initRequest();
  void getRequest(const String& path);
};

extern FirebaseArduino Firebase;

#endif // FIREBASE_ARDUINO_H
  std::shared_ptr<FirebaseHttpClient> stream_http_;

So it’s a FirebaseHttpClient. That’s probably defined in “FirebaseObject.h”

It looks like reset() is a method of the std::shared_ptr class of which those objects are instances.

MorganS:
That’s probably defined in “FirebaseObject.h”

Here’s the code for FirebaseObject.h, but it seems like they are not defined here.

//
// 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.
//

#ifndef FIREBASE_OBJECT_H
#define FIREBASE_OBJECT_H


#include "WString.h"
#include <memory>

#include <ArduinoJson.h>


#ifndef FIREBASE_JSONBUFFER_SIZE
#define FIREBASE_JSONBUFFER_SIZE JSON_OBJECT_SIZE(32)
#endif // FIREBASE_JSONBUFFER_SIZE



/**
 * Represents value stored in firebase, may be a singular value (leaf node) or
 * a tree structure.
 */
class FirebaseObject {
  public:
    /**
   * Construct from json.
   * \param data JSON formatted string.
    */
    FirebaseObject(const char* data);

    /**
   * Return the value as a boolean.
   * \param optional path in the JSON object.
   * \return result as a bool.
    */
    bool getBool(const String& path = "") const;

    /**
   * Returns true if specified path is NULL string.
   * Useful to detect tree deletions.
   * \param optional path in the JSON object.
   * \return result as a bool.
    */
    bool isNullString(const String& path = "") const;

    /**
   * Return the value as an int.
   * \param optional path in the JSON object.
   * \return result as an integer.
    */
    int getInt(const String& path = "") const;

    /**
   * Return the value as a float.
   * \param optional path in the JSON object.
   * \return result as a float.
    */
    float getFloat(const String& path = "") const;

    /**
   * Return the value as a String.
   * \param optional path in the JSON object.
   * \return result as a String.
    */
    String getString(const String& path = "") const;

    /**
   * Return the value as a JsonVariant.
   * \param optional path in the JSON object.
   * \return result as a JsonVariant.
    */
    JsonVariant getJsonVariant(const String& path = "") const;


    /**
   *
   * \return Whether there was an error decoding or accessing the JSON object.
    */
    bool success() const;

    /**
   *
   * \return Whether there was an error decoding or accessing the JSON object.
    */
    bool failed() const;

    /**
   *
   * \return Error message if failed() is true.
    */
    const String& error() const;

  private:
    String data_;
    std::shared_ptr<StaticJsonBuffer<FIREBASE_JSONBUFFER_SIZE>> buffer_;
    JsonVariant json_;
    mutable String error_;
};

#endif // FIREBASE_OBJECT_H

pauline95:
Here's the code for FirebaseObject.h, but it seems like they are not defined here.

Like I said:

gfvalvo:
It looks like reset() is a method of the std::shared_ptr class of which those objects are instances.

gfvalvo:
It looks like reset() is a method of the std::shared_ptr class of which those objects are instances.

Thanks. I saw that in the link that you posted.

std::shared_ptr req_http_;

For this line in the code, does it means that create a shared ptr of FirebaseHttpClient type named req_http_? What’s the difference between this syntax and the syntax that uses new keyword? I saw some syntax of shared_ptr that uses new keyword.

The new operator allocates the storage and initializes the new object dynamically. It returns a pointer to the newly created object. It is conceptually similar to the malloc() function in C, but it also initializes the object.

gfvalvo:
It returns a pointer to the newly created object.

But since there is no new operator in that statement, does it mean that the pointer req_http_ doesn't point to anything? And if that's the case, how is the pointer being used in the code if it doesn't point to anything?

No. ‘new’ and ‘malloc()’ allocate storage dynamically. ‘new’ also initializes the allocated storage as a specific object. Dynamic allocation is one way of allocating memory to store data. You can read about it in the links I provided and get others from Google.

The other method for allocating storage is the one you’re already familiar with:

int intVar;
float floatVar = 3.14159;
char name[20];
SoftwareSerial mySerial(3, 4);

This method also gets the required memory and may or may not initialize the object – depending on how and where you do it.

The code you’re questioning uses the second method to create an object of the ‘std::shared_ptr’ class named ‘req_http_’. Objects of this class are somewhat complex, you’ll need to read about them. Again, I provided one link and you can Google others.

Ok, thanks for your help.

In FirebaseArduino.cpp, there is a getRequest() function as shown below:

void FirebaseArduino::getRequest(const String& path) {
  initRequest();
  req_.get()->sendRequest(host_, auth_, "GET", path.c_str());
  error_ = req_.get()->error();
}

In the second line of the getRequest() function, there is a get() function. Is the get() function referring to the get() function in FirebaseArduino.cpp? Here's the code for get() function in FirebaseArduino.cpp:

FirebaseObject FirebaseArduino::get(const String& path) {
  getRequest(path);
  if (failed()) {
    return FirebaseObject{""};
  }
  return FirebaseObject(req_.get()->response().c_str());
}

If the get() function in getRequestion() is referring to this get() function, how does it work if the get() function is calling the getRequest() function? Wouldn't that be a problem if they are calling each other?

What type of object is req_? Look there to find the get method.

You probably need to read about the → operator too.

@pauline95,

As I’ve told you multiple times, that the objects you keep asking about are instances of the ‘std::shared_ptr<…>’ class. I’ve provided a link to a reference for that class. I’ve advised that you read that and Google search for more references. And that you should read those. I’ve advised that you should look at the methods of THAT class (which both get() and reset() are).

I don’t know if you’re ignoring my advice or if you’re trying to dissect programs that your current coding skills and knowledge aren’t yet ready for. If the former, then I’m done helping. If the latter, then take a step back and learn more of the C++ language before tackling these more advanced topics.

gfvalvo:
I don't know if you're ignoring my advice or if you're trying to dissect programs that your current coding skills and knowledge aren't yet ready for.

I'm sorry. I didn't ignore your advice, I have gone through the website yesterday and found out that the get() is actually a member function of the shared pointer. And yes, my coding skills isn't so advanced so I'm actually struggling understand the code. I'm trying to improve my coding skills. I apologize for that and thanks for you help.