ESP32 Data Logging to Firebase Realtime Database

In this guide, you’ll learn how to log data with the ESP32 to the Firebase Realtime Database with timestamps (data logging) so that you have a record of your data history. As an example, we’ll log temperature, humidity, and pressure from a BME280 sensor and we’ll get timestamps from an NTP server. Then, you can access the data using the Firebase console, or build a web app to display the results (check this tutorial).

ESP32 Data Logging to Firebase Realtime Database

Updated 12 May 2025

Part 2: ESP32/ESP8266: Firebase Data Logging Web App (Gauges, Charts, and Table)

Other Firebase Tutorials with the ESP32/ESP8266 that you might be interested in:

What is Firebase?

Firebase Logo

Firebase is Google’s mobile application development platform that helps you build, improve, and grow your app. It has many services used to manage data from any android, IOS, or web application like authentication, realtime database, hosting, etc.

Project Overview

The following diagram shows a high-level overview of the project we’ll build.

ESP32 with BME280 Firebase Datalogging
  1. The ESP32 authenticates as a user with email and password (that user must be set on the Firebase authentication methods);
  2. After authentication, the ESP gets the user UID;
  3. The database is protected with security rules. The user can only access the database nodes under the node with its user UID. After getting the user UID, the ESP can publish data to the database;
  4. The ESP32 gets temperatrure, humidity and pressure from the BME280 sensor.
  5. It gets epoch time right after gettings the readings (timestamp).
  6. The ESP32 sends temperature, humidity, pressure and timestamp to the database.
  7. New readings are added to the database periodically. You’ll have a record of all readings on the Firebase realtime database.

These are the main steps to complete this project:

  1. Create Firebase Project
  2. Set Authentication Methods
  3. Get Project API Key
  4. Set up Realtime Database
  5. Set up Database Security Rules
  6. ESP32 Datalogging (Firebase Realtime Database)

You can continue with the Firebase project from this previous tutorial or create a new project. If you use the Firebase project from that previous tutorial, you can skip to section 4) Set up Realtime Database because the authentication methods are already set up.

Preparing Arduino IDE

For this tutorial, we’ll program the ESP32 board using the Arduino core. So, make sure you have the ESP32 add-on installed in your Arduino IDE:

If you want to program the ESP32/ESP8266 boards using VS Code with the pioarduino or PlatformIO extensions, follow these tutorials instead:

1) Create a Firebase Project

Follow the next instructions to create a new project on Firebase.

  1. Go to Firebase and sign in using a Google Account.
  2. Go to the Firebase Console and create a new project.
  3. Give a name to your project, for example: ESP-Project, and click Continue.
    Set Up Firebase Project for ESP32 and ESP8266 Step 1
  4. Next, enable or disable AI assistance for your project. This is optional.
    Set Up Firebase Project for ESP32 and ESP8266 - Enable AI assistant
  5. Disable the option Enable Google Analytics for this project, as it is not needed. Then, click Create project.
    Disable Google Analytics for firebase project
  6. It will take a few seconds to set up your project. Click Continue when it’s ready.
    Firebase Project for ESP32 Ready

  7. You’ll be redirected to your Project console page.
    Firebase console project

2) Set Authentication Methods

To allow authentication with email and password, first, you need to set authentication methods for your app.

“Most apps need to know the identity of a user. In other words, it takes care of logging in and identifying the users (in this case, the ESP32). Knowing a user’s identity allows an app to securely save user data in the cloud and provide the same personalized experience across all of the user’s devices.” To learn more about the authentication methods, you can read the documentation.

  1. On the left sidebar, click on Build > Authentication and then on Get started.
    Firebase project set authentication
  2. There are several authentication methods like email and password, Google Account, Facebook account, and others.
    SFirebase authentication methods
  3. Select Email/Password and enable that authentication method. Then, click Save.
    Enable Email Password Sign in Firebase
  4. Then, at the top, click on the Users tab. Then, click on Add user.
    Firebase Create a new user
  5. Create a new user with an email and password. The email can be your personal email. Create a password for that user (you need to remember the password later). Finally, click on Add user.
    Firebase add user email and password
  6. The User will show up on the list of users. You can see information about the user, like when it was created, the last time it signed in, and its user UID.
    Firebase User Created

Firebase creates a unique UID for each registered user. The user UID allows us to identify the user and keep track of the user to provide or deny access to the project or the database. There’s also a column that registers the date of the last sign-in. At the moment, it is empty because we haven’t signed in with that user yet.

3) Get Project API Key

To interface with your Firebase project using the ESP32 or ESP8266 boards, you need to get your project API key. Follow the next steps to get your project API key.

  1. To get your project’s API key, on the left sidebar click on Project Settings.
    Firebase Realtime Database Project Settings
  2. Copy the API Key to a safe place because you’ll need it later.
    Firebase Project API Key

4) Set up the Realtime Database

Now, let’s create a realtime database and set up database rules for our project.

1) On the left sidebar, click on Realtime Database and then click on Create Database.

Firebase Project Create Database

2) Select your database location. It should be the closest to your location.

Firebase Realtime Database Set up location

3) Set up security rules for your database. You can select Start in test mode. We’ll change the database rules in just a moment.

Firebase Realtime Database Start in Test Mode

4) Your database is now created. You need to copy and save the database URL—highlighted in the following image—because you’ll need it later in your ESP32/ESP8266 code.

Firebase Real time database URL

5) Set up Database Security Rules

Now, let’s set up the database rules. On the Realtime Database tab, select the Rules tab at the top. Then, click on Edit rules, copy the following rules and then click Publish.

// These rules grant access to a node matching the authenticated
// user's ID from the Firebase auth token
{
  "rules": {
    "UsersData": {
      "$uid": {
        ".read": "$uid === auth.uid",
        ".write": "$uid === auth.uid"
      }
    }
  }
}
Firebase Realtime Database Set Up Rules

These rules allow access only to the node that matches the authenticated user’s UID. This ensures that each user can access only their own data. In other words, a user can only read or write to the parts of the database located under their specific UID. Any data stored outside of their UID node will not be accessible to them.

For example, imagine our user UID is RjO3taAzMMXBB2Xmir2LQ. With our security rules, it can read and write data to the database under the node UsersData/RjO3taAzMMXBB2Xmir2LQ.

6) ESP32 Datalogging (Firebase Realtime Database)

In this section, we’ll program the ESP32 board to do the following tasks:

  1. Authenticate as a user with email and password (the user you set up in this section);
  2. Get BME280 readings: temperature, humidity, and pressure;
  3. Get epoch time (timestamp) from an NTP server;
  4. Send sensor readings and timestamp to the realtime database as an authorized user.

Parts Required

For this project, you need the following parts*:

* you can also test the project with random values instead of sensor readings, or you can use any other sensor you’re familiar with.

You can use the preceding links or go directly to MakerAdvisor.com/tools to find all the parts for your projects at the best price!

Schematic Diagram

In this tutorial, we’ll send BME280 sensor readings to the Firebase Realtime Database. So, you need to wire the BME280 sensor to your board.

We’re going to use I2C communication with the BME280 sensor module. For that, wire the sensor to the default ESP32 SCL (GPIO 22) and SDA (GPIO 21) pins, as shown in the following schematic diagram.

Learn more about I2C with the ESP32: ESP32 I2C Communication: Set Pins, Multiple Bus Interfaces and Peripherals (Arduino IDE).

ESP32 BME280 Sensor Temperature Humidity Pressure Wiring Diagram Circuit

Not familiar with the BME280 with the ESP32? Read this tutorial: ESP32 with BME280 Sensor using Arduino IDE (Pressure, Temperature, Humidity).

Installing Libraries

For this project, you need to install the following libraries:

Installing Libraries – VS Code

Follow the next instructions if you’re using VS Code with the PlatformIO or pioarduino extension.

Install the FirebaseClient Library

Click on the PIO Home icon and select the Libraries tab. Search for “FirebaseClient“. Select the Firebase Client Library by Mobitz.

If you’re using VS Code with the PlatformIO extension, click on the PIO Home icon and then select the Libraries tab. Search for “FirebaseClient“. Select the Firebase Client Library by Mobitz.

Install FirebaseClient Library VS Code

Then, click Add to Project and select the project you’re working on.

Add FirebaseClient Library ro project in VS Code

Then, click Add to Project and select the project you’re working on.

Install the BME280 Library

In the Libraries tab, search for BME280. Select the Adafruit BME280 library.

PlatformIO VS Code Search for BME280 Library

Then, click Add to Project and select the project you’re working on.

PlatformIO with VS Code Add Library to Project

Also, change the monitor speed to 115200 by adding the following line to the platformio.ini file of your project:

monitor_speed = 115200

Installation – Arduino IDE

Follow this section if you’re using Arduino IDE.

You need to install the following libraries:

Go to Sketch > Include Library > Manage Libraries, search for the libraries’ names, and install the libraries.

Install Firebase Client Library Arduino IDE

Now, you’re all set to start programming the ESP32 and ESP8266 boards to interact with the database.

Datalogging—Firebase Realtime Database Code

Copy the following code to your Arduino IDE or to the main.cpp file if you’re using VS Code.

You need to insert your network credentials, project API key, database URL, and the authorized user email and password.

/*
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete project details at our blog: https://RandomNerdTutorials.com/esp32-data-logging-firebase-realtime-database/
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/

#include <Arduino.h>
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <FirebaseClient.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include "time.h"

// Network and Firebase credentials
#define WIFI_SSID "REPLACE_WITH_YOUR_SSID"
#define WIFI_PASSWORD "REPLACE_WITH_YOUR_PASSWORD"

#define Web_API_KEY "REPLACE_WITH_YOUR_FIREBASE_PROJECT_API_KEY"
#define DATABASE_URL "REPLACE_WITH_YOUR_FIREBASE_DATABASE_URL"
#define USER_EMAIL "REPLACE_WITH_FIREBASE_PROJECT_EMAIL_USER"
#define USER_PASS "REPLACE_WITH_FIREBASE_PROJECT_USER_PASS"

// User functions
void processData(AsyncResult &aResult);

// Authentication
UserAuth user_auth(Web_API_KEY, USER_EMAIL, USER_PASS);

// Firebase components
FirebaseApp app;
WiFiClientSecure ssl_client;
using AsyncClient = AsyncClientClass;
AsyncClient aClient(ssl_client);
RealtimeDatabase Database;

// Timer variables for sending data every 10 seconds
unsigned long lastSendTime = 0;
const unsigned long sendInterval = 10000; // 10 seconds in milliseconds

// Variable to save USER UID
String uid;

// Database main path (to be updated in setup with the user UID)
String databasePath;
// Database child nodes
String tempPath = "/temperature";
String humPath = "/humidity";
String presPath = "/pressure";
String timePath = "/timestamp";

// Parent Node (to be updated in every loop)
String parentPath;

int timestamp;

const char* ntpServer = "pool.ntp.org";

// BME280 sensor
Adafruit_BME280 bme; // I2C
float temperature;
float humidity;
float pressure;

// Create JSON objects for storing data
object_t jsonData, obj1, obj2, obj3, obj4;
JsonWriter writer;

// Initialize BME280
void initBME(){
  if (!bme.begin(0x76)) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);
  }
}

// Initialize WiFi
void initWiFi() {
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  Serial.print("Connecting to WiFi ..");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(1000);
  }
}

// Function that gets current epoch time
unsigned long getTime() {
  time_t now;
  struct tm timeinfo;
  if (!getLocalTime(&timeinfo)) {
    //Serial.println("Failed to obtain time");
    return(0);
  }
  time(&now);
  return now;
}

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

  initBME();
  initWiFi();
  configTime(0, 0, ntpServer);

  // Configure SSL client
  ssl_client.setInsecure();
  ssl_client.setConnectionTimeout(1000);
  ssl_client.setHandshakeTimeout(5);

  // Initialize Firebase
  initializeApp(aClient, app, getAuth(user_auth), processData, "🔐 authTask");
  app.getApp<RealtimeDatabase>(Database);
  Database.url(DATABASE_URL);
}

void loop(){
  // Maintain authentication and async tasks
  app.loop();

  // Check if authentication is ready
  if (app.ready()){

    // Periodic data sending every 10 seconds
    unsigned long currentTime = millis();
    if (currentTime - lastSendTime >= sendInterval){
      // Update the last send time
      lastSendTime = currentTime;

      uid = app.getUid().c_str();

      // Update database path
      databasePath = "/UsersData/" + uid ;

      //Get current timestamp
      timestamp = getTime();
      Serial.print ("time: ");
      Serial.println (timestamp);

      parentPath= databasePath + "/" + String(timestamp);

      // Get sensor readings
      temperature = bme.readTemperature();
      humidity = bme.readHumidity();
      pressure = bme.readPressure()/100.0;

      // Create a JSON object with the data
      writer.create(obj1, tempPath, temperature);
      writer.create(obj2, humPath, humidity);
      writer.create(obj3, presPath, pressure);
      writer.create(obj4, timePath, timestamp);
      writer.join(jsonData, 4, obj1, obj2, obj3, obj4);

      Database.set<object_t>(aClient, parentPath, jsonData, processData, "RTDB_Send_Data");
    }
  }
}

void processData(AsyncResult &aResult){
  if (!aResult.isResult())
    return;

  if (aResult.isEvent())
    Firebase.printf("Event task: %s, msg: %s, code: %d\n", aResult.uid().c_str(), aResult.eventLog().message().c_str(), aResult.eventLog().code());

  if (aResult.isDebug())
    Firebase.printf("Debug task: %s, msg: %s\n", aResult.uid().c_str(), aResult.debug().c_str());

  if (aResult.isError())
    Firebase.printf("Error task: %s, msg: %s, code: %d\n", aResult.uid().c_str(), aResult.error().message().c_str(), aResult.error().code());

  if (aResult.available())
    Firebase.printf("task: %s, payload: %s\n", aResult.uid().c_str(), aResult.c_str());
}

View raw code

How the Code Works

Continue reading to learn how the code works, or skip to the demonstration section.

Include Libraries

First, include the required libraries.

#include <Arduino.h>
#if defined(ESP32)
    #include <WiFi.h>
#elif defined(ESP8266)
    #include <ESP8266WiFi.h>
#endif
#include <WiFiClientSecure.h>
#include <FirebaseClient.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include "time.h"

Network Credentials

Include your network credentials in the following lines so that your boards can connect to the internet using your local network.

// Insert your network credentials
#define WIFI_SSID "REPLACE_WITH_YOUR_SSID"
#define WIFI_PASSWORD "REPLACE_WITH_YOUR_PASSWORD"

Firebase Project API Key, Firebase User, and Database URL

Insert your Firebase project API key—the one you’ve gotten in this section.

#define Web_API_KEY "REPLACE_WITH_YOUR_PROJECT_API_KEY"

Insert the authorized email and the corresponding password—these are the details of the user you’ve added in this section.

// Insert Authorized Email and Corresponding Password
#define USER_EMAIL "REPLACE_WITH_THE_USER_EMAIL"
#define USER_PASSWORD "REPLACE_WITH_THE_USER_PASSWORD"

Insert your database URL in the following line:

// Insert RTDB URLefine the RTDB URL
#define DATABASE_URL "REPLACE_WITH_YOUR_DATABASE_URL"

Declaring Firebase Authentication and Components

The following line creates an authentication object using the project API key, the project user email, and password.

UserAuth user_auth(Web_API_KEY, USER_EMAIL, USER_PASS);

This creates a FirebaseApp instance called app that refers to the Firebase application.

FirebaseApp app;

The following lines set up the asynchronous communication framework for interacting with Firebase’s Realtime Database. Basically, you create an SSL client using the WiFiClientSecure library. Then, you instantiate an Asynchronous client called aClient that enables secure HTTPS. This will allow you to handle network operations asynchronously.

WiFiClientSecure ssl_client;
using AsyncClient = AsyncClientClass;
AsyncClient aClient(ssl_client);

The following line creates a RealtimeDatabase object called Database, which represents the Firebase Realtime Database.

RealtimeDatabase Database;

Timer and Data Variables

Then create variables to track the time. We’ll send sensor readings to the database every 10 seconds.

// Timer variables for sending data every 10 seconds
unsigned long lastSendTime = 0;
const unsigned long sendInterval = 10000;

Create a variable to save the user UID. The uid variable will be used to save the user’s UID. We can get the user’s UID after the authentication.

// Variable to save USER UID
String uid;

Create variables to save the database path and specific database nodes. We’ll update these variables later in the code when we get the user UID.

// Database main path (to be updated in setup with the user UID)
String databasePath;
// Database child nodes
String tempPath = "/temperature";
String humPath = "/humidity";
String presPath = "/pressure";
String timePath = "/timestamp";

// Parent Node (to be updated in every loop)
String parentPath;

We create a variable to save the timestamp and another to save the NTP server.

int timestamp;

const char* ntpServer = "pool.ntp.org";

BME280 Variables

Then, create an Adafruit_BME280 object called bme. This automatically creates a sensor object on the ESP32 or ESP8266 default I2C pins.

Adafruit_BME280 bme; // I2C

The following variables will hold the temperature, humidity, and pressure readings from the sensor.

float temperature;
float humidity;
float pressure;

JSON Variables

We’ll send all data to the database in a JSON object. The FirebaseClient library has its own JSON methods. You should use them instead of other JSON libraries. To do that, we need to create four jsonData objects called obj1, obj2, obj3, and obj4.

object_t jsonData, obj1, obj2, obj3, obj4;

Then, we need to create an instance of the JsonWriter class, in this case called writer, that provides methods to create and combine JSON objects for Firebase.

JsonWriter writer;

To learn more, we recommend reading this section of the documentation about the JsonWriter object.

initBME()

The initBME() function will initialize the BME280 sensor. We’ll call it later in the setup().

// Initialize BME280
void initBME(){
  if (!bme.begin(0x76)) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);
  }
  Serial.print("BME280 Initialized with success");
}

initWiFi()

The initWiFi() function will connect the ESP32 to your local network using the SSID and password defined earlier.

// Initialize WiFi
void initWiFi() {
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  Serial.print("Connecting to WiFi ..");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(1000);
  }
}

getTime()

The getTime() function returns the current epoch time.

// Function that gets current epoch time
unsigned long getTime() {
  time_t now;
  struct tm timeinfo;
  if (!getLocalTime(&timeinfo)) {
    //Serial.println("Failed to obtain time");
    return(0);
  }
  time(&now);
  return now;
}

To learn more about getting epoch time with the ESP32 board, you can check the following tutorial:

setup()

In the setup(), initialize the Serial Monitor, the BME280 sensor, WiFi, and configure the NTP server.

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

    initBME();
    initWiFi();
    configTime(0, 0, ntpServer);

Configure the SSL Client.

ssl_client.setInsecure();
#if defined(ESP32)
  ssl_client.setConnectionTimeout(1000);
  ssl_client.setHandshakeTimeout(5);
#elif defined(ESP8266)
  ssl_client.setTimeout(1000); // Set connection timeout
  ssl_client.setBufferSizes(4096, 1024); // Set buffer sizes
#endif

The following line initializes the Firebase app with authentication and sets the processData() as the callback function for async results (this means that any results from the initializeApp() function will be handled on the processData() callback function).

initializeApp(aClient, app, getAuth(user_auth), processData, "🔐 authTask");

Then, tell that you want to set the Database object defined earlier as a database for our Firebase app.

app.getApp<RealtimeDatabase>(Database);

Finally, set the database URL.

Database.url(DATABASE_URL);

loop()

The Firebase library we’re using works asynchronously and with callback functions. This means that when an event happens, the corresponding assigned callback functions will run. To keep the Firebase app running, handling authentication and asynchronous tasks, we need to add app.loop() at the start of our loop() function.

void loop(){
  app.loop();

The app.ready() command checks if Firebase authentication is complete and ready, so that we can proceed with other Firebase operations (like writing to the database).

if (app.ready()){

The following lines check if 10 seconds (sendInterval) have passed. We’ll use this to send data periodically every 10 seconds.

// Periodic data sending every 10 seconds
unsigned long currentTime = millis();
if (currentTime - lastSendTime >= sendInterval){
   // Update the last send time
  lastSendTime = currentTime;

After a successful authentication, we’ll get the user UID and save it in the uid variable. Then, we’ll update the database path to UsersData/<USER_UID>.

uid = app.getUid().c_str();

The databasePath variable saves the database main path, which can now be updated with the user UID.

// Update database path
databasePath = "/UsersData/" + uid;

After this, we can get the current timestamp and update the path where the readings will be saved.

//Get current timestamp
timestamp = getTime();
Serial.print ("time: ");
Serial.println (timestamp);

parentPath= databasePath + "/" + String(timestamp);

To better understand how we’ll organize our data, here’s a diagram.

Firebase BME280 datalogging database

It might seem redundant to save the timestamp twice (in the parent node and the child node), however, having all the data at the same level of the hierarchy will make things simpler in the future, if we want to build a web app to display the data.

After getting the timestamp and updating all database nodes with the user UID and corresponding timestamp, we can get readings from the BME280 sensor.

// Get sensor readings
temperature = bme.readTemperature();
humidity = bme.readHumidity();
pressure = bme.readPressure()/100.0;

Creating the JSON Objects

We’ll send all the readings and corresponding timestamps to the realtime database at the same time by creating a JSON object that contains the values of those variables. The FirebaseClient library has its own JSON methods. We’ll use them to send data in JSON format to the database.

We use the create() method on the writer object to create a JSON object with a key (node) and corresponding value (sensor readings).

For example, the following line creates a JSON object with tempPath as the key and temperature as the value. It stores the result in obj1.

writer.create(obj1, tempPath, temperature);

An example of output would be in this case:

obj1 = {"UserData/<user_udi>/timestamp/temperature": 23.5}

We proceed similarly for the other readings and timestamp.

writer.create(obj2, humPath, humidity);
writer.create(obj3, presPath, pressure);
writer.create(obj4, timePath, timestamp);

Then, we use the join() method on the writer object to merge the four JSON objects (obj1, obj2, obj3, obj4) into a single JSON structure, stored in jsonData. The 4 indicates the number of objects to combine.

writer.join(jsonData, 4, obj1, obj2, obj3, obj4);

Sending the JSON Object

Finally, we can send the JSON object to the database using the set() method on the database object. We already explained how this works in this previous tutorial.

Database.set<object_t>(aClient, parentPath, jsonData, processData, "RTDB_Send_Data");

This uses the SSL client aClient and sends the jsonData variable to the parentPath path in the database. The results of this operation will be handled on the processData function. The last parameter RTDB_Send_Data identifies this task.

Finally, the processData() function logs the results of the asynchronous Firebase operations.

void processData(AsyncResult &aResult){
    if (!aResult.isResult())
        return;

    if (aResult.isEvent())
        Firebase.printf("Event task: %s, msg: %s, code: %d\n", aResult.uid().c_str(), aResult.eventLog().message().c_str(), aResult.eventLog().code());

    if (aResult.isDebug())
        Firebase.printf("Debug task: %s, msg: %s\n", aResult.uid().c_str(), aResult.debug().c_str());

    if (aResult.isError())
        Firebase.printf("Error task: %s, msg: %s, code: %d\n", aResult.uid().c_str(), aResult.error().message().c_str(), aResult.error().code());

    if (aResult.available())
        Firebase.printf("task: %s, payload: %s\n", aResult.uid().c_str(), aResult.c_str());
}

Demonstration

Upload the previous code to your ESP32 board. Don’t forget to insert your network credentials, project API key, database URL, user email, and the corresponding password.

After uploading the code, press the board RST button so that it starts running the code. It should authenticate to Firebase, get the user UID, and immediately send new readings to the database.

Open the Serial Monitor at a baud rate of 115200 and check that everything is working as expected.

ESP32 Send JSON Firebase Serial Monitor

Aditionally, go to the Realtime Database on your Firebase project interface and check that new readings are saved. Notice that it saves the data under a node with the own user UID—this is a way to restrict access to the database.

Firebase Realtime Database Datalogging

Wait some time until you get some readings on the database. Expand the nodes to check the data.

Wrapping Up

In this tutorial, you learned how to log your sensor readings with timestamps to the Firebase Realtime Database using the ESP32. This was just a simple example for you to understand how it works.

You can use other methods provided by the FirebaseClient library to log your data, and you can organize your database in different ways. We organized the database in a way that is convenient for another project that we’ll publish soon.

In PART 2, we’ll create a Firebase Web App to display all saved data in a table and the latest readings on charts.

We hope you’ve found this tutorial useful.

If you like Firebase projects, please take a look at our new eBook. We’re sure you’ll like it:

Learn more about the ESP32 with our resources:

Thanks for reading.



Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »
Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »

Enjoyed this project? Stay updated by subscribing our newsletter!

83 thoughts on “ESP32 Data Logging to Firebase Realtime Database”

  1. How many data writes can you get before google starts charging you for real-time database usage?

    I have similar project running but write to Google Spreadsheet via pushing box and have 6 years of data collecting every 15 mins.

    Reply
  2. Great project, works fine, looking forward to the part 2 – display the data in graphical form. As above how much data can we save? Is there a way of auto deleting data older than a set timestamp?
    Thanks again
    Bruce

    Reply
  3. Very good, this worked on first try. It was only one 0 too much in the timerDelay.

    unsigned long timerDelay = 1800000;
    In the text it was corrected till 180000.

    Reply
  4. Thanks for this. I have adapted the code to use a DS18B20 as I only wish to record temperatures, so have substituted the BME280 libraries for One Wire and Dallas. This works fine. Is there a simple way to change the Timestamp to display the actual time and date in a readable format?

    Reply
      • I suggest you should try this one

        String getTime(void) {
        time_t now;
        struct tm * timeinfo;
        char buffer [80];

        time(&now);
        timeinfo = localtime (&now);

        strftime(buffer, 80, “%Y-%m-%d_%H:%M:%S”, timeinfo);
        return buffer;
        }

        Reply
    • Hi Michael, I am using a Esp32 with ds18b20 as well. Im really hoping to see what all changes to make to use with ds18b20’s with this firebase coding. delete every part that mentions BME280?

      Reply
        • Hi Michael
          Can you send the DS18B20 code? Because I am struggling to change this code to DS18B20. If you can I am real appreciate.
          Thank You

          Reply
          • This should give you an idea.

            /*
            Rui Santos
            Complete project details at our blog: https://RandomNerdTutorials.com/esp32-data-logging-firebase-realtime-database/
            Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
            The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
            */

            #include <Arduino.h>
            #include <WiFi.h>
            #include <Firebase_ESP_Client.h>
            #include <OneWire.h>
            #include <DallasTemperature.h>
            //#include <Wire.h>
            //#include <Adafruit_Sensor.h>
            //#include <Adafruit_BME280.h>
            #include “time.h”

            OneWire oneWire(22);
            DallasTemperature tempSensor(&oneWire);
            DeviceAddress sensor1 = { 0x28, 0xa5, 0xd, 0xbd, 0x2c, 0x20, 0x1, 0xf9 };
            DeviceAddress sensor2 = { 0x28, 0x8d, 0xf4, 0x18, 0x2c, 0x20, 0x1, 0x93 };
            //DeviceAddress sensor3 = { 0x28, 0x8F, 0x88, 0xd7, 0x2c, 0x20, 0x1, 0x12 };

            // Provide the token generation process info.
            #include “addons/TokenHelper.h”
            // Provide the RTDB payload printing info and other helper functions.
            #include “addons/RTDBHelper.h”

            // Insert your network credentials
            #define WIFI_SSID “xxxxx”
            #define WIFI_PASSWORD “xxxx”

            // Insert Firebase project API Key
            #define API_KEY “xxxxxxxxxxxxxxxxxxx”

            // Insert Authorized Email and Corresponding Password
            #define USER_EMAIL “xxxxxxxxxxxxxx”
            #define USER_PASSWORD “xxxxxxxxxxxxxxxx”

            // Insert RTDB URLefine the RTDB URL
            #define DATABASE_URL “https://temperature-logging-efabb-default-rtdb.europe-west1.firebasedatabase.app/”
            // Define Firebase objects
            FirebaseData fbdo;
            FirebaseAuth auth;
            FirebaseConfig config;

            // Variable to save USER UID
            String uid;

            //Database main path (to be updated in setup with the user UID)
            String databasePath;
            // Database child nodes
            String tempPath = “/temperature”;
            String humPath = “/humidity”;
            //String presPath = “/temperature 3”;
            String presPath = “/pressure”;
            String timePath = “/timestamp”;

            // Parent Node (to be updated in every loop)
            String parentPath;
            //char current [42];

            int timestamp;
            FirebaseJson json;

            const char* ntpServer = “pool.ntp.org”;

            /* BME280 sensor
            Adafruit_BME280 bme; // I2C
            */
            float temperature1;
            float temperature2;
            float temperature3;
            //float pressure;

            // Timer variables (send new readings every three minutes)
            unsigned long sendDataPrevMillis = 0;
            unsigned long timerDelay = 60000;

            // Initialize WiFi
            void initWiFi() {
            WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
            Serial.print(“Connecting to WiFi ..”);
            while (WiFi.status() != WL_CONNECTED) {
            Serial.print(‘.’);
            delay(1000);
            }
            Serial.println(WiFi.localIP());
            Serial.println();
            }

            // Function that gets current epoch time
            unsigned long getTime() {
            time_t now;
            struct tm timeinfo;
            if (!getLocalTime(&timeinfo)) {
            //Serial.println(“Failed to obtain time”);
            return (0);
            }

            /* strftime(current, 42, “%a %b %d %Y %H:%M:%S”, &timeinfo); // Converts timestamp to readable date and time.
            Serial.println(&timeinfo, “%A, %B %d %Y %H:%M:%S”);
            Serial.println (current);

            Serial.println();*/

            time(&now);
            return now;
            }

            /*
            * void printLocalTime() {

            Serial.println (current);

            Serial.println();
            }
            */
            void setup() {
            Serial.begin(115200);
            tempSensor.begin();

            initWiFi();
            configTime(0, 0, ntpServer);

            // Assign the api key (required)
            config.api_key = API_KEY;

            // Assign the user sign in credentials
            auth.user.email = USER_EMAIL;
            auth.user.password = USER_PASSWORD;

            // Assign the RTDB URL (required)
            config.database_url = DATABASE_URL;

            Firebase.reconnectWiFi(true);
            fbdo.setResponseSize(4096);

            // Assign the callback function for the long running token generation task */
            config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h

            // Assign the maximum retry of token generation
            config.max_token_generation_retry = 5;

            // Initialize the library with the Firebase authen and config
            Firebase.begin(&config, &auth);

            // Getting the user UID might take a few seconds
            Serial.println(“Getting User UID”);
            while ((auth.token.uid) == “”) {
            Serial.print(‘.’);
            delay(1000);
            }
            // Print user UID
            uid = auth.token.uid.c_str();
            Serial.print(“User UID: “);
            Serial.println(uid);

            // Update database path
            databasePath = “/UsersData/” + uid + “/readings”;
            }

            void loop() {

            tempSensor.requestTemperatures(); // Gets temperature from sensor

            temperature1 = (tempSensor.getTempC(sensor1));
            temperature2 = (tempSensor.getTempC(sensor2));

            if(temperature1 >= temperature2)
            {

            temperature3 = temperature1 – temperature2;

            }

            else

            {
            temperature3 = temperature2-temperature1;

            }

            // Send new readings to database
            if (Firebase.ready() && (millis() – sendDataPrevMillis > timerDelay || sendDataPrevMillis == 0)) {
            sendDataPrevMillis = millis();

            //Get current timestamp
            timestamp = getTime();

            Serial.print ("time: ");
            Serial.println (timestamp);

            // String currentTime = String(current);

            parentPath= databasePath + "/" + String(timestamp);

            // parentPath = databasePath + “/” + current;
            json.set(tempPath.c_str(), String(tempSensor.getTempC(sensor1)));
            json.set(humPath.c_str(), String(tempSensor.getTempC(sensor2)));
            // json.set(presPath.c_str(), String(tempSensor.getTempC(sensor3)));
            json.set(presPath.c_str(), String (temperature3));
            json.set(timePath, String(timestamp) );
            //json.set (timePath, String(currentTime));

            Serial.printf("Set json... %s\n", Firebase.RTDB.setJSON(&fbdo, parentPath.c_str(), &json) ? "ok" : fbdo.errorReason().c_str());
            // printLocalTime();

            // Serial.println (current);

            Serial.println();

            Serial.print("Temperature 1: ");
            Serial.print(tempSensor.getTempC(sensor1));
            Serial.println(" C");

            Serial.print("Temperature 2: ");
            Serial.print(tempSensor.getTempC(sensor2));
            Serial.println(" C");

            Serial.print("Temperature 3: ");
            //Serial.print(tempSensor.getTempC(sensor3));
            Serial.print (temperature3);
            Serial.println(" C");

            }
            }

  5. This program is working fine, and I wanted to use it for logging data from the boat and cottage. My plan was to use and old phone as hotspot or shared internet. My problem is that the phone turns of hotspot after 19 hours.
    Do you know how I can keep it on?
    Sorry, this question is a bit on the side for this project.

    Reply
  6. Maybe I found a solution. On my phone I changed settings. Mobile Hotspot>configure>Advanced>Turn off when no device connected for … Never timeout.
    I will test this now and see.

    Reply
  7. OK, now I know a lot more. The logging had stopped when I got home, but when I rebooted the ESP32, the logging continued. So, the problem is not the mobile phone, but the ESP32. Now I will try to make the ESP32 reboot itself every hour, then it should be fine I hope.

    Reply
    • It has been running for more than two days now, logging every 3 min. So I think this workaround will make it work. Here is the code I used:

      In the start of the program:
      unsigned long bootDelay = 3600000; // One hour = 3600 sec
      unsigned long bootPrevMillis;

      In setup:
      bootPrevMillis = millis();

      In the loop:
      if (millis() – bootPrevMillis > bootDelay){
      ESP.restart();
      }

      Reply
      • When I boot I got two logging to close in time, but with this change, it will logg with 3 min. intervall also during boot.

        unsigned long bootDelay = 3593000; // One hour -7 sec

        Reply
        • Hi Svein I had a similar problem with a smart meter I made using a EPS32. Every 10 days or so it would lock up, but I cheated and ended up using a timer plug to switch it off for 2mins a day then reboot.

          But I will use your idea now, thankyou.

          Adam

          Reply
  8. I cannot get Firebase (Fb) to recognize my API_KEY. Get the error: ” Invalid API_KEY …” on my Serial Monitor with an error code -32.
    My API_KEY, Firebase URL (both with the location and without), UID, and my email with the Firebase USER_PASSWORD have been thoroughly checked and are correct as transmitted. My billing account is set up at Fb. I have reached out to Fb and they just confirmed that I have a valid API_KEY there and said they could not help with code (understandable). Any suggestions?

    Reply
  9. … works fine 🙂 .. I noticed that you did not use a database.json to establish the realtime database structure (like you did in the eBook “Firebase_Web_App_ESP32”), but rather established it by defining databasePath = “/UsersData/” + uid + “/readings”; … so, this could have been done in the eBook as well, but probably too many lines, and for that complex database, the .json file was preferred. … is that a correct assessment?

    Reply
    • Hi.
      Yes, you could have done that in the eBook as well.
      In the eBook, we create the database with the json file so that the readers can better understand how the database works.However, that step can be done in the Arduino code or on the Firebase Web App.
      Regards,
      Sara

      Reply
  10. Can you please post a screenshot of what your RTDB ‘Data’ tab looks like after the ESP runs for a bit?
    (Of course, blur out any id’s.)
    thank you.

    Reply
  11. sorry and nevermind – already in there!

    Can you please post a screenshot of what your RTDB ‘Data’ tab looks like after the ESP runs for a bit?
    (Of course, blur out any id’s.)
    thank you.

    Reply
  12. Hello Sara..
    Thanks for this great tutorial.

    If there is more than 1 user, do I have to enter more USER_EMAIL and USER_PASSWORD on the Arduino code?

    Sorry for my basic question.
    Thanks again.

    Reply
    • Hi.
      No.
      You need to create another user in your Firebase project.
      Then, you need to change the database rules so that the user has access to the data.
      Then, you also need to change the paths on the javascript files so that the new user can access the database path of the user that is publishing the data.
      Regards,
      Sara

      Reply
  13. Hi, I’m getting the following error after uploading the code to ESP-WROOM-32:

    Rebooting…
    ets Jun 8 2016 00:22:57

    rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
    configsip: 0, SPIWP:0xee
    clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
    mode:DIO, clock div:2
    load:0x3fff0018,len:4
    load:0x3fff001c,len:1044
    load:0x40078000,len:10124
    load:0x40080400,len:5828
    entry 0x400806a8
    Token info: type = id token, status = on request
    assertion “Invalid mbox” failed: file “/home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/lwip/lwip/src/api/tcpip.c”, line 374, function: tcpip_send_msg_wait_sem
    abort() was called at PC 0x400fd20f on core 1

    ELF file SHA256: 0000000000000000

    Backtrace: 0x40087844:0x3ffb19f0 0x40087ac1:0x3ffb1a10 0x400fd20f:0x3ffb1a30 0x4013aa5f:0x3ffb1a60 0x4014435d:0x3ffb1a90 0x40144510:0x3ffb1ab0 0x40142b84:0x3ffb1af0 0x401556db:0x3ffb1b10
    0x40155382:0x3ffb1d90 0x401554bd:0x3ffb1dc0 0x400e151e:0x3ffb1de0 0x4016ce29:0x3ffb1e00 0x400d3892:0x3ffb1e20 0x400df75d:0x3ffb1e40 0x400e0c0f:0x3ffb1ec0 0x400e136d:0x3ffb1f10 0x400d340d:0x3ffb1f30 0x400d15f2:0x3ffb1f70 0x400e399e:0x3ffb1fb0 0x40088ad2:0x3ffb1fd0

    Any ideas how to resolve?

    Reply
  14. Great tutorial! Managed to get it running with no problem!
    Why do you suggest increasing the delay? As in “Once you test this project and check that everything is working as expected, we recommend increasing the delay.”
    Would you say it overloads the database or something? For a project I’m doing it would be great if I managed to a reading every 5 seconds or so (I’m guessing it takes longer than that to actually send the data over Firebase?).

    Regards,
    Luiz

    Reply
    • Hi.
      I recommend increasing the delay time to not overload the database. But, if your project required readings every 5 seconds, there’s no problem.
      Just make sure you check your database usage once in a while.
      Regards,
      Sara

      Reply
      • Ahh perfect, I can alway clear it after extracting the data, so it shouldn’t be a problem! Thanks again, and as always, great tutorials and follow through!

        Reply
  15. Sara;
    I’m probably driving you crazy, between this demo and the previous. I am still unable to get either to work. This one seems to be progressing the furthest, but I am getting the following error when I upload the code to my device and run:

    Token info: type = id token, status = on request
    Token info: type = id token, status = ready
    Getting User UID
    User UID: S1lazRbly6VCwmyrCYJ8ZAyuDTn1
    Water Temp Fahrenheit 69.57ºF
    time: 1645729599
    [E][ssl_client.cpp:98] start_ssl_client(): Connect to Server failed!
    [E][WiFiClientSecure.cpp:133] connect(): start_ssl_client: -1
    Set json… send request failed
    The user ID it pulls from the system is consistent with what is shown in firebase, but it still fails to connect to server.

    anything you can suggest would be appreciated.

    Reply
  16. Hello, I have some issues which says ‘getLocalTime’ was not declared in this scope.
    and error: ‘auth’ does not name a type. How do I resolve it?

    Reply
    • Hi.
      Did you copy the whole code and installed all the required libraries?
      What is the ESP32 boards version you have installed?
      Regards,
      Sara

      Reply
  17. Hello, The code is not compiling on ESP-8266 (Node MCU).
    error: ‘getLocalTime’ was not declared in this scope
    if (!getLocalTime(&timeinfo)) {

    Reply
  18. Hi! I’ve been following this tutorial and changing things slightly for a project of my own, but I’ve run into a problem which I don’t know if it has to do with my ESP hardware or with the code. The data will be sent to the database for about 10 seconds, and then just stops. I check the serial monitor and it says “Set json…ok” and then the timestamp. All of a sudden after ten seconds, it says “Set json… connection lost” and still has the timestamp. The upload speeds match, and the cable I’m using seems to be working, so I’m really not sure what the problem is here.

    Reply
  19. Hi I want to send sensor data from 3 different ESP32 to the same Firebase database do you have any suggestions. I tried working on another code for the second ESP32 but it says set json..permission denied.

    Reply
          • Hi.
            What are exactly your database rules?
            Are you referring the right project on your code with the right API key?
            Regards,
            Sara

          • These are the rules I applied. I cross checked the API key it’s fine.

            // These rules grant access to a node matching the authenticated
            // user’s ID from the Firebase auth token
            {
            “rules”: {
            “UsersData”: {
            “$uid”: {
            “.read”: “$uid === auth.uid”,
            “.write”: “$uid === auth.uid”
            }
            }
            }
            }

  20. Hello, I used this code to save and display ECG data . ehich Iam collecting using 250 SPS. I noticed that when using Firebase.RTDB.setJSON function, there is a delay happen which results in losing some data.
    my question is that Is the Firebase is not suitable for acquiring high sampling rate data?
    Thank you

    Reply
  21. Does someone know how we can have the child node “timestamp” of the real database in readable format instead of having that string of integers?

    (I want having the readable time in the child node “timestamp”, NOT at serial output or on any webpage that we could build up)

    Reply
    • For example instead of having in the “timestamp” child node the: “16407….”, I want to have:
      13:37, 14 May 2023

      Reply
  22. Hello, if for example I have two different users. User1 and User2. Will user1 have different readings than user2 or will they have the same data in the “View all data” section.

    Reply
  23. Hi, every 100 hundreds write i have this message Set Json… response payload read timed out, what coud it be? I am writing every 10ms perfectly until the 101th write when this happens, and then after 1-2 seconds the program continues with the 102th write and then repeats again the problem at the 201th.

    Reply
  24. Hi! Your content its so good that i acutally bought the Firebase WEB APP ebook! But tesing my database i always run a error after 10-20minutes sending data to the Real Time Database. The code works great then all of sudden it starts reporting “connection lost” when appending the JSON file. I thought that maybe the token expired after sometime, but testing with assigning a bool variable to the function “Firebase.isTokenExpired()” it informs me that actually was never expired to begin with, increasing the time between connections also didnt solved it. Im using ESP32 1.0.4(but in newer versions the problem also persists), anyway thanks for you excellent content and heres my code:
    (…)

    Reply
  25. Hello Sara,
    I do find your content to be quite amazing as I intend to use this concept on a project I am working on but I however do have some worries.
    I wish to ask if it will be possible to set the ESP32 to sleep mode when data is not being sent to the real time database so as to minimize power consumption in a scenario where the ESP32 is being powered by an external source such a battery etc..

    Reply
  26. Good day everything works great. What I need now is to read data from the Firebase database with the authentication added please help

    Reply

Leave a Comment

Download Our Free eBooks and Resources

Get instant access to our FREE eBooks, Resources, and Exclusive Electronics Projects by entering your email address below.

OSZAR »