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).
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:
- ESP32: Getting Started with Firebase (Realtime Database)
- ESP8266 NodeMCU: Getting Started with Firebase (Realtime Database)
- ESP32 with Firebase – Creating a Web App
- ESP8266 NodeMCU with Firebase – Creating a Web App
- ESP32/ESP8266 Firebase Authentication (Email and Password)
- ESP32/ESP8266 Firebase: Send BME280 Sensor Readings to the Realtime Database
- ESP32/ESP8266: Firebase Web App to Display Sensor Readings (with Authentication)
What is Firebase?
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.
- The ESP32 authenticates as a user with email and password (that user must be set on the Firebase authentication methods);
- After authentication, the ESP gets the user UID;
- 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;
- The ESP32 gets temperatrure, humidity and pressure from the BME280 sensor.
- It gets epoch time right after gettings the readings (timestamp).
- The ESP32 sends temperature, humidity, pressure and timestamp to the database.
- 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:
- Create Firebase Project
- Set Authentication Methods
- Get Project API Key
- Set up Realtime Database
- Set up Database Security Rules
- 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 of 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 ESP boards using VS Code with the PlatformIO extension, follow the following tutorial instead:
1) Create Firebase Project
1) Go to Firebase and sign in using a Google Account.
2) Click Get Started and then Add project to create a new project.
3) Give a name to your project, for example, ESP Firebase Demo.
4) Disable the option Enable Google Analytics for this project as it is not needed and click Create project.
5) It will take a few seconds to set up your project. Then, click Continue when it’s ready.
6) You’ll be redirected to your Project console page.
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 Authentication and then on Get started.
2) Select the Option Email/Password.
3) Enable that authentication method and click Save.
4) The authentication with email and password should now be enabled.
5) Now, you need to add a user. On the Authentication tab, select the Users tab at the top. Then, click on Add User.
6) Add an email address for the authorized user. It can be your google account email or any other email. You can also create an email for this specific project. Add a password that will allow you to sign in to your app and access the database. Don’t forget to save the password in a safe place because you’ll need it later. When you’re done, click Add user.
7) A new user was successfully created and added to the Users table.
Notice that 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 board, you need to get your project API key. Follow the next steps to get your project API key.
1) On the left sidebar, click on Project Settings.
2) Copy the Web API Key to a safe place because you’ll need it later.
4) Set up 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.
2) Select your database location. It should be the closest to your 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.
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 code.
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"
}
}
}
}
These rules grant access to a node matching the authenticated user’s UID. This grants that each authenticated user can only access its own data. This means the user can only access the nodes that are under a node with its corresponding user UID. If there are other data published on the database, not under a node with the users’ UID, that user can’t access that data.
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.
You’ll better understand how this works when you start working with the ESP32.
6) ESP32 Datalogging (Firebase Realtime Database)
In this section, we’ll program the ESP32 board to do the following tasks:
- Authenticate as a user with email and password (the user you set up in this section);
- Get BME280 readings: temperature, humidity, and pressure;
- Get epoch time (timestamp) from an NTP server;
- Send sensor readings and timestamp to the realtime database as an authorized user.
Parts Required
For this project, you need the following parts*:
- ESP32 board (read best ESP32 development boards);
- BME280 or any other sensor you’re familiar with;
- Breadboard;
- Jumper wires.
* 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.
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 extension.
Install the Firebase-ESP-Client Library
There is a library with lots of examples to use Firebase with the ESP32: the Firebase-ESP-Client library. This library is compatible with both the ESP32 and ESP8266 boards.
Click on the PIO Home icon and select the Libraries tab. Search for “Firebase ESP Client“. Select the Firebase Arduino Client Library for ESP8266 and ESP32.
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.
Then, click Add to Project and select the project you’re working on.
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.
For the Firebase Client library, select the Firebase Arduino Client Library for ESP8266 and ESP32.
Now, you’re all set to start programming the ESP32 board 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
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 <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include "time.h"
// 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 "REPLACE_WITH_YOUR_SSID"
#define WIFI_PASSWORD "REPLACE_WITH_YOUR_PASSWORD"
// Insert Firebase project API Key
#define API_KEY "REPLACE_WITH_YOUR_PROJECT_API_KEY"
// Insert Authorized Email and Corresponding Password
#define USER_EMAIL "REPLACE_WITH_THE_USER_EMAIL"
#define USER_PASSWORD "REPLACE_WITH_THE_USER_PASSWORD"
// Insert RTDB URLefine the RTDB URL
#define DATABASE_URL "REPLACE_WITH_YOUR_DATABASE_URL"
// 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 = "/pressure";
String timePath = "/timestamp";
// Parent Node (to be updated in every loop)
String parentPath;
int timestamp;
FirebaseJson json;
const char* ntpServer = "pool.ntp.org";
// BME280 sensor
Adafruit_BME280 bme; // I2C
float temperature;
float humidity;
float pressure;
// Timer variables (send new readings every three minutes)
unsigned long sendDataPrevMillis = 0;
unsigned long timerDelay = 180000;
// 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);
}
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);
}
time(&now);
return now;
}
void setup(){
Serial.begin(115200);
// Initialize BME280 sensor
initBME();
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(){
// 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);
parentPath= databasePath + "/" + String(timestamp);
json.set(tempPath.c_str(), String(bme.readTemperature()));
json.set(humPath.c_str(), String(bme.readHumidity()));
json.set(presPath.c_str(), String(bme.readPressure()/100.0F));
json.set(timePath, String(timestamp));
Serial.printf("Set json... %s\n", Firebase.RTDB.setJSON(&fbdo, parentPath.c_str(), &json) ? "ok" : fbdo.errorReason().c_str());
}
}
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. The WiFi.h library to connect the ESP32 to the internet, the Firebase_ESP_Client.h library to interface the boards with Firebase, the Wire, Adafruit_Sensor, and Adafruit_BME280 to interface with the BME280 sensor, and the time library to get the time.
#include <Arduino.h>
#include <WiFi.h>
#include <Firebase_ESP_Client.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include "time.h"
You also need to include the following for the Firebase library to work.
// Provide the token generation process info.
#include "addons/TokenHelper.h"
// Provide the RTDB payload printing info and other helper functions.
#include "addons/RTDBHelper.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 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"
Firebase Objects and Other Variables
The following line defines a FirebaseData object.
FirebaseData fbdo;
The next line defines a FirebaseAuth object needed for authentication.
FirebaseAuth auth;
Finally, the following line defines a FirebaseConfig object required for configuration data.
FirebaseConfig config;
The uid variable will be used to save the user’s UID. We can get the user’s UID after the authentication.
String uid;
The databasePath variable saves the database main path, which will be updated later with the user UID.
String databasePath;
The following variables save the database child nodes for the temperature, humidity, pressure, and timestamp.
String tempPath = "/temperature";
String humPath = "/humidity";
String presPath = "/pressure";
String timePath = "/timestamp";
The parentPath is the parent node that will be updated in every loop with the current timestamp.
// Parent Node (to be updated in every loop)
String parentPath;
To better understand how we’ll organize our data, here’s a diagram.
It might seem redundant to save the timestamp twice (in the parent node and in 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.
The timestamp variable will be used to save time (epoch time format).
int timestamp;
To learn more about getting epoch time with the ESP32 board, you can check the following tutorial:
We’ll send all the readings and corresponding timestamp to the realtime database at the same time by creating a JSON object that contains the values of those variables. The ESP Firebase Client library has its own JSON methods. We’ll use them to send data in JSON format to the database. We start by creating a variable of type FirebaseJson called json.
FirebaseJson json;
The ESP_Firebase_Client library provides some examples showing how to use FirebaseJson and how to send data in JSON format to the database: ESP_Firebase_Client library FirebaseJson examples.
We’ll request the time from pool.ntp.org, which is a cluster of time servers that anyone can use to request the time.
const char* ntpServer = "pool.ntp.org";
Then, create an Adafruit_BME280 object called bme. This automatically creates a sensor object on the ESP32 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;
Delay Time
The sendDataPrevMillis and timerDelay variables are used to check the delay time between each send. In this example, we’re setting the delay time to 3 minutes (18000 milliseconds). Once you test this project and check that everything is working as expected, we recommend increasing the delay.
// Timer variables (send new readings every three minutes)
unsigned long sendDataPrevMillis = 0;
unsigned long timerDelay = 180000;
initBME()
The initBME() function initializes the BME280 library using the bme object created previously. Then, you should call this library in the setup().
void initBME(){
if (!bme.begin(0x76)) {
Serial.println("Could not find a valid BME280 sensor, check wiring!");
while (1);
}
}
initWiFi()
The initWiFi() function connects your ESP to the internet using the network credentials provided. You must call this function later in the setup() to initialize WiFi.
// 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();
}
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;
}
setup()
In setup(), initialize the Serial Monitor for debugging purposes at a baud rate of 115200.
Serial.begin(115200);
Call the initBME() function to initialize the BME280 sensor.
initBME();
Call the initWiFi() function to initialize WiFi.
initWiFi();
Configure the time:
configTime(0, 0, ntpServer);
Assign the API key to the Firebase configuration.
config.api_key = API_KEY;
The following lines assign the email and password to the Firebase authentication object.
auth.user.email = USER_EMAIL;
auth.user.password = USER_PASSWORD;
Assign the database URL to the Firebase configuration object.
config.database_url = DATABASE_URL;
Add the following to the configuration object.
// 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 Firebase library (authenticate) with the configuration and authentication settings we defined earlier.
// Initialize the library with the Firebase authen and config
Firebase.begin(&config, &auth);
After initializing the library, we can get the user UID by calling auth.token.uid. Getting the user’s UID might take some time, so we add a while loop that waits until we get it.
// Getting the user UID might take a few seconds
Serial.println("Getting User UID");
while ((auth.token.uid) == "") {
Serial.print('.');
delay(1000);
}
Finally, we save the user’s UID in the uid variable and print it in the Serial Monitor.
uid = auth.token.uid.c_str();
Serial.print("User UID: ");
Serial.print(uid);
After getting the user UID, we can update the database path to include the user UID.
// Update database path
databasePath = "/UsersData/" + uid + "/readings";
loop()
In the loop(), check if it is time to send new readings:
if (Firebase.ready() && (millis() - sendDataPrevMillis > timerDelay || sendDataPrevMillis == 0)){
sendDataPrevMillis = millis();
If it is, get the current time and save it in the timestamp variable.
//Get current timestamp
timestamp = getTime();
Serial.print ("time: ");
Serial.println (timestamp);
Update the parentPath variable to include the timestamp.
parentPath= databasePath + "/" + String(timestamp);
Then, add data to the json object by using the set() method and passing as first argument the child node destination (key) and as second argument the value:
json.set(tempPath.c_str(), String(bme.readTemperature()));
json.set(humPath.c_str(), String(bme.readHumidity()));
json.set(presPath.c_str(), String(bme.readPressure()/100.0F));
json.set(timePath, String(timestamp));
Finally, call Firebase.RTDB.setJSON(&fbdo, parentPath.c_str(), &json) to append the data to the parent path. We can call that instruction inside a Serial.printf() command to print the results in the Serial Monitor at the same time the command runs.
Serial.printf("Set json... %s\n", Firebase.RTDB.setJSON(&fbdo, parentPath.c_str(), &json) ? "ok" : fbdo.errorReason().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.
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.
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 ESP_Firebase_Client 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.
I already tried it. Works perfectly!
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.
Can you help in saving a large amount of data say of years of data to spreadsheet.
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
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.
I Guess 1800000 should be intentionally correct; it means to get data every half hour!!
Sara, am I wrong?
Hi.
Yes. I say three minutes everywhere, but then add 30 minutes in the code. that’s my fault.
You’re right.
I’ll fix that.
Thanks.
Hello dear please help me how to interface Hx711 load cell code send
data to firebase plz
Combine this tutorial with this: https://randomnerdtutorials.com/esp32-load-cell-hx711/
Regards,
Sara
How to combine plz tell me
Thank you for this tutorial, much appriciated.
Cheers,
Rene.
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?
Hi.
You can save time as a string in a human-readable format.
Check this tutorial to learn how to get the date (day, month, year, etc) and hour, minute, second: https://randomnerdtutorials.com/esp32-date-time-ntp-client-server-arduino/
Regards
Sara
So, is it working now?
Weird that it gets messed up with PlatformIO…
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;
}
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?
Yes, cancel the BME280 stuff and name the sensors for what you want to measure.
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
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");
}
}
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.
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.
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.
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();
}
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
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
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?
Try to create another Firebase project and use the API key for that new project.
I’m not sure what might be causing the issue…
Thank you Sara. That worked. Will continue on. Appreciate the help!
Great!
… 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?
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
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.
Hi.
There is a picture in the post: https://i0.wp.com/randomnerdtutorials.com/wp-content/uploads/2021/12/ESP-Firebase-Realtime-Database-Data-Logging.png?
Regards,
Sara
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.
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.
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
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?
Same issue for me!
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
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
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!
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.
If I go into Firebase and run a simulated read or write, using the email address and User ID, it runs successfully.
Hi Robert,
Send an email to our support and I’ll try to help you via email.
https://randomnerdtutorials.com/support/
Regards,
Sara
How to send max30102 data from esp32 to firebase ?
I keep getting “set json… not found” error
Hi.
Can you tell me exactly the error you’re getting?
Regards,
Sara
I am getting the same error did you manage to fix it
I had the same problem, unfortunately the “not found” error message is very misleading. For me it was the wrong URL that I copied from firebase.
If you use right click copy link it won’t work, you have to manually select the link and copy paste it. This solved my problem, so the real problem was that the ESP couldn’t connect to the database because of the wrong URL I was using.
In my case
copy link address: https://console.firebase.google.com/u/0/project/esplogtest/database/esplogtest-default-rtdb/data/~2F
Correct link: https://esplogtest-default-rtdb.europe-west1.firebasedatabase.app
Hope it does help.
Ruben, THANKS. After hours of trying your answer helped. Exactlly the same problem.
I mange it according Ruben instructions.
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?
Hi.
Did you copy the whole code and installed all the required libraries?
What is the ESP32 boards version you have installed?
Regards,
Sara
This is a great tutorial and project! Do you have any other examples with other sensor types? Looking for an MFRC522 integration from your other tutorial: https://randomnerdtutorials.com/security-access-using-mfrc522-rfid-reader-with-arduino/ Would like to just send all read data to the cloud.
Hello, The code is not compiling on ESP-8266 (Node MCU).
error: ‘getLocalTime’ was not declared in this scope
if (!getLocalTime(&timeinfo)) {
Hi.
Follow this tutorial for the ESP8266 board: https://randomnerdtutorials.com/esp8266-data-logging-firebase-realtime-database/
Regards,
Sara
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.
its giving me an error.
Set json… Permission denied
I followed every step.
Hi.
Can you please check your database rules?
Regards,
Sara
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.
Check your database rules.
I fixed it,Is there any way of making it more effecient and not having each code for each esp32.
How you fixed json permission denied. @Sara Santos I copy paste rules still getting the error
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”
}
}
}
}
Check the Authentication tab and see if the user created is the same that you use on the ESP32 sketch.
@Sara Santos Yes the Esp32 sketch displayed UID and UID in Firebase 2 are same. Still Json Permission Denied.
I want to use this code with another sensors, but I don’t know how. please help me
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
Hi.
For high sampling rate data it is better to use InfluxDB.
Take a look at this tutorial and see if you think it is suitable for your application.https://randomnerdtutorials.com/esp32-influxdb/
Regards,
Sara
Thank you so much.. I will check it 🙂
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)
For example instead of having in the “timestamp” child node the: “16407….”, I want to have:
13:37, 14 May 2023
why doesn’t my project have an API KEY
All firebase projects have an API key.
Check all the steps carefully.
Regards,
Sara
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.
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.
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:
(…)
Hi.
Do you have more information about the error?
Regards,
Sara
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..
Hi.
Yes. You can do that.
Just make sure you initialize Firebase after deep sleep.
You can check our deep sleep tutorial here: https://randomnerdtutorials.com/esp32-deep-sleep-arduino-ide-wake-up-sources/
Regards,
Sara
Good day everything works great. What I need now is to read data from the Firebase database with the authentication added please help