In this guide, you’ll create a Firebase Web App to display sensor readings saved on the Firebase Realtime Database. The sensor readings web page is protected with authentication with email and password. You’ll learn how to display data from the database and how to add authentication to your web app.
This article is Part 2 of this previous tutorial: ESP32/ESP8266 Firebase: Send BME280 Sensor Readings to the Realtime Database. Follow that tutorial first, before proceeding.
Project Overview
In this tutorial (Part 2), you’ll create a web app to display the sensor readings saved on the Firebase Realtime Database (read this previous tutorial).
The following diagram shows a high-level overview of the project we’ll build—programming the ESP32/ESP8266 and setting up the Firebase Project was done in Part 1.
- Firebase hosts your web app over a global CDN using Firebase Hosting and provides an SSL certificate. You can access your web app from anywhere using the Firebase-generated domain name.
- When you first access the web app, you need to authenticate with an authorized email address and password. You already set up that user and the authentication method in Part 1.
- After authentication, you can access a web app page that shows the sensor readings saved on the realtime database. The realtime database was set up on Part 1.
- Once you’re logged in, you can logout any time. The next time you’ll acces the app you’ll need to login again.
Prerequisites
Before start creating the Firebase Web App, you need to check the following prerequisites.
Creating a Firebase Project
You should have followed the following tutorial first:
The ESP32/ESP8266 must be running the code provided in that tutorial. The realtime database and authentication must be set up also as shown in the tutorial.
Install Required Software
Before getting started you need to install the required software to create the Firebase Web App. Here’s a list of the software you need to install (click on the links for instructions):
1) Add an App to Your Firebase Project
1) Go to your Firebase project Console and add an app to your project by clicking on the +Add app button.
2) Select the web app icon.
3) Give your app a name. Then, check the box next to √ Also set up Firebase Hosting for this App. Click Register app.
4) Then, copy the firebaseConfig object and save it because you’ll need it later.
After this, you can also access the firebaseConfig object if you go to your Project settings in your Firebase console.
5) Click Next on the proceeding steps, and finally on Continue to console.
2) Setting Up a Firebase Web App Project (VS Code)
Follow the next steps to create a Firebase Web App Project using VS Code.
1) Creating a Project Folder
1) Create a folder on your computer where you want to save your Firebase project—for example, Firebase-Project on the Desktop.
2) Open VS Code. Go to File > Open Folder… and select the folder you’ve just created.
3) Go to Terminal > New Terminal. A new Terminal window should open on your project path.
2) Firebase Login
4) On the previous Terminal window, type the following:
firebase login
5) You’ll be asked to collect CLI usage and error reporting information. Enter “n” and press Enter to deny.
Note: If you are already logged in, it will show a message saying: “Already logged in as [email protected]”.
6) After this, it will pop up a new window on your browser to login into your firebase account.
7) Allow Firebase CLI to access your google account.
8) After this, Firebase CLI login should be successful. You can close the browser window.
3) Initializing Web App Firebase Project
9) After successfully login in, run the following command to start a Firebase project directory in the current folder.
firebase init
10) You’ll be asked if you want to initialize a Firebase project in the current directory. Enter Y and hit Enter.
11) Then, use up and down arrows and the Space key to select the options. Select the following options:
- Realtime Database: Configure security rules file for Realtime Database and (optionally) provision default instance.
- Hosting: Configure files for Firebase Hosting and (optionally) set up GitHub Action deploys
The selected options will show up with a green asterisk. Then, hit Enter.
12) Select the option “Use an existing project”—it should be highlighted in blue—then, hit Enter.
13) After that, select the Firebase project for this directory—it should be the project created in this previous tutorial. In my case, it is called esp-firebase-demo. Then hit Enter.
14) Press Enter on the following question to select the default database security rules file: “What file should be used for Realtime Database Security Rules?“
15) Then, select the hosting options as shown below:
- What do you want to use as your public directory? Hit Enter to select public.
- Configure as a single-page app (rewrite urls to /index.html)? No
- Set up automatic builds and deploys with GitHub? No
16) The Firebase project should now be initialized successfully. Notice that VS code created some essential files under your project folder.
The index.html file contains some HTML text to build a web page. For now, leave the default HTML text. The idea is to replace that with your own HTML text to build a custom web page for your needs. We’ll do that later in this tutorial.
17) To check if everything went as expected, run the following command on the VS Code Terminal window.
firebase deploy
You should get a Deploy complete! message and an URL to the Project Console and the Hosting URL.
18) Copy the hosting URL and paste it into a web browser window. You should see the following web page. You can access that web page from anywhere in the world.
The web page you’ve seen previously is built with the HTML file placed in the public folder of your Firebase project. By changing the content of that file, you can create your own web app. That’s what we’re going to do in the next section.
3) Creating Firebase Web App
Now that you’ve created a Firebase project app successfully on VS Code, follow the next steps to customize the app to display the sensor readings on a login-protected web page.
index.html
Copy the following to your index.html file. This HTML file creates a simple web page that displays the readings saved on the Realtime Database created on this previous project.
If you aren’t authenticated, it shows a login form. When you authenticate with an authorized user email and corresponding password, it shows the user interface with the sensor readings.
<!-- Complete Project Details at: https://RandomNerdTutorials.com/ -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>ESP IoT Firebase App</title>
<!-- update the version number as needed -->
<script src="https://www.gstatic.com/firebasejs/8.8.1/firebase-app.js"></script>
<!-- include only the Firebase features as you need -->
<script src="https://www.gstatic.com/firebasejs/8.8.1/firebase-auth.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.8.1/firebase-database.js"></script>
<script>
// REPLACE WITH YOUR web app's Firebase configuration
const firebaseConfig = {
apiKey: "REPLACE_WITH_YOUR_Firebase_CONFIGURATION",
authDomain: "REPLACE_WITH_YOUR_Firebase_CONFIGURATION",
databaseURL: "REPLACE_WITH_YOUR_Firebase_CONFIGURATION",
projectId: "REPLACE_WITH_YOUR_Firebase_CONFIGURATION",
storageBucket: "REPLACE_WITH_YOUR_Firebase_CONFIGURATION",
messagingSenderId: "REPLACE_WITH_YOUR_Firebase_CONFIGURATION",
appId: "REPLACE_WITH_YOUR_Firebase_CONFIGURATION"
};
// Initialize firebase
firebase.initializeApp(firebaseConfig);
// Make auth and database references
const auth = firebase.auth();
const db = firebase.database();
</script>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
<link rel="icon" type="image/png" href="favicon.png">
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<!--TOP BAR-->
<div class="topnav">
<h1>Sensor Readings App <i class="fas fa-clipboard-list"></i></h1>
</div>
<!--AUTHENTICATION BAR (USER DETAILS/LOGOUT BUTTON)-->
<div id="authentication-bar" style="display: none;">
<p><span id="authentication-status">User logged in</span>
<span id="user-details">USEREMAIL</span>
<a href="/" id="logout-link">(logout)</a>
</p>
</div>
<!--LOGIN FORM-->
<form id="login-form" style="display: none;">
<div class="form-elements-container">
<label for="input-email"><b>Email</b></label>
<input type="text" placeholder="Enter Username" id="input-email" required>
<label for="input-password"><b>Password</b></label>
<input type="password" placeholder="Enter Password" id="input-password" required>
<button type="submit" id="login-button">Login</button>
<p id="error-message" style="color:red;"></p>
</div>
</form>
<!--CONTENT (SENSOR READINGS)-->
<div class="content-sign-in" id="content-sign-in" style="display: none;">
<div class="cards">
<!--TEMPERATURE-->
<div class="card">
<p><i class="fas fa-thermometer-half" style="color:#059e8a;"></i> TEMPERATURE</p>
<p><span class="reading"><span id="temp"></span> °C</span></p>
</div>
<!--HUMIDITY-->
<div class="card">
<p><i class="fas fa-tint" style="color:#00add6;"></i> HUMIDITY</p>
<p><span class="reading"><span id="hum"></span> %</span></p>
</div>
<!--PRESSURE-->
<div class="card">
<p><i class="fas fa-angle-double-down" style="color:#e1e437;"></i> PRESSURE</p>
<p><span class="reading"><span id="pres"></span> hPa</span></p>
</div>
</div>
</div>
<script src="scripts/auth.js"></script>
<script src="scripts/index.js"></script>
</body>
</html>
You need to modify the code with your own firebaseConfig object—the one you’ve got in this step.
How it Works
Let’s take a quick look at the HTML file, or skip to the next section.
In the <head> of the HTML file, we must add all the required metadata.
The title of the web page is ESP Firebase App, but you can change it in the following line.
<title>ESP Firebase App</title>
You must add the following line to be able to use Firebase with your app.
<script src="https://www.gstatic.com/firebasejs/8.10.0/firebase-app.js"></script>
You must also add any Firebase products you want to use. In this example, we’re using the Realtime Database and Authentication.
<script src="https://www.gstatic.com/firebasejs/8.8.1/firebase-auth.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.8.1/firebase-database.js"></script>
Then, replace the firebaseConfig object with the one you’ve gotten from this step.
const firebaseConfig = {
apiKey: "REPLACE_WITH_YOUR_Firebase_CONFIGURATION",
authDomain: "REPLACE_WITH_YOUR_Firebase_CONFIGURATION",
databaseURL: "REPLACE_WITH_YOUR_Firebase_CONFIGURATION",
projectId: "REPLACE_WITH_YOUR_Firebase_CONFIGURATION",
storageBucket: "REPLACE_WITH_YOUR_Firebase_CONFIGURATION",
messagingSenderId: "REPLACE_WITH_YOUR_Firebase_CONFIGURATION",
appId: "REPLACE_WITH_YOUR_Firebase_CONFIGURATION"
};
Finally, Firebase is initialized, and we create two global variables db and auth that refer to Firebase authentication and to Firebase realtime database.
// Initialize firebase
firebase.initializeApp(firebaseConfig);
// Make auth and database references
const auth = firebase.auth();
const db = firebase.database();
The following line allows us to use fontawesome icons:
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
The next includes a favicon on our web page.
<link rel="icon" type="image/png" href="favicon.png">
Finally, reference an external style.css file to format the HTML page.
<link rel="stylesheet" type="text/css" href="style.css">
We’re done with the metadata. Now, let’s go to the HTML parts that are visible to the user—go between the <body> and </body> tags.
We create a top “navigation” bar with the name of our app and a small icon from fontawesome.
<div class="topnav">
<h1>Sensor Readings App <i class="fas fa-clipboard-list"></i></h1>
</div>
The following lines create a bar with the details of the authenticated user (email). It also shows a logout link to log out the user.
<div id="authentication-bar" style="display: none;">
<p><span id="authentication-status">User logged in</span>
<span id="user-details">USEREMAIL</span>
<a href="/" id="logout-link">(logout)</a>
</p>
</div>
First, we set the display style of all elements to none. We’ll hide and show content depending if the user is authenticated or not—we’ll handle that using JavaScript.
Next, the following lines create the login form with an input field for the email and an input field for the password:
<form id="login-form" style="display: none;">
<div class="form-elements-container">
<label for="input-email"><b>Email</b></label>
<input type="text" placeholder="Enter Username" id="input-email" required>
<label for="input-password"><b>Password</b></label>
<input type="password" placeholder="Enter Password" id="input-password" required>
<button type="submit" id="login-button">Login</button>
<p id="error-message" style="color:red;"></p>
</div>
</form>
Inside the form, there’s also a paragraph to display an error message if the login fails.
<p id="error-message" style="color:red;"></p>
Finally, we create a grid to display the sensor readings.
<!--CONTENT (SENSOR READINGS)-->
<div class="content-sign-in" id="content-sign-in" style="display: none;">
<div class="cards">
<!--TEMPERATURE-->
<div class="card">
<p><i class="fas fa-thermometer-half" style="color:#059e8a;"></i> TEMPERATURE</p>
<p><span class="reading"><span id="temp"></span> °C</span></p>
</div>
<!--HUMIDITY-->
<div class="card">
<p><i class="fas fa-tint" style="color:#00add6;"></i> HUMIDITY</p>
<p><span class="reading"><span id="hum"></span> %</span></p>
</div>
<!--PRESSURE-->
<div class="card">
<p><i class="fas fa-angle-double-down" style="color:#e1e437;"></i> PRESSURE</p>
<p><span class="reading"><span id="pres"></span> hPa</span></p>
</div>
</div>
</div>
The places where we’ll insert the sensor readings have <span> tags with specific ids so that we can refer to those HTML elements using JavaScript and insert sensor readings saved on the database.
- temperature: id = “temp”
- humidity: id = “hum”
- pressure: id = “pres”
Finally, we need to add references to the external JavaScript files. For our application, we’ll create two JavaScript files: auth.js (that handles everything related to the authentication) and index.js that handles everything related to the UI. We’ll create those files inside a folder called scripts inside the public folder of our application.
<script src="scripts/auth.js"></script>
<script src="scripts/index.js"></script>
After making the necessary changes (inserting your firebaseConfig object), you can save the HTML file.
style.css
Inside the public folder create a file called style.css. To create the file, select the public folder, and then click on the +file icon at the top of the File Explorer. Call it style.css.
Then, copy the following to the style.css file
html {
font-family: Verdana, Geneva, Tahoma, sans-serif;
display: inline-block;
text-align: center;
}
p {
font-size: 1.2rem;
}
body {
margin: 0;
}
.topnav {
overflow: hidden;
background-color: #049faa;
color: white;
font-size: 1rem;
padding: 10px;
}
#authentication-bar{
background-color:mintcream;
padding-top: 10px;
padding-bottom: 10px;
}
#user-details{
color: cadetblue;
}
.content {
padding: 20px;
}
.card {
background-color: white;
box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);
padding: 5%;
}
.cards {
max-width: 800px;
margin: 0 auto;
display: grid;
grid-gap: 2rem;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
.reading {
font-size: 1.4rem;
}
button {
background-color: #049faa;
color: white;
padding: 14px 20px;
margin: 8px 0;
border: none;
cursor: pointer;
border-radius: 4px;
}
button:hover {
opacity: 0.8;
}
.form-elements-container{
padding: 16px;
width: 250px;
margin: 0 auto;
}
input[type=text], input[type=password] {
width: 100%;
padding: 12px 20px;
margin: 8px 0;
display: inline-block;
border: 1px solid #ccc;
box-sizing: border-box;
}
The CSS file includes some simple styles to make our webpage look better. We won’t discuss how CSS works in this tutorial.
JavaScript Files
We’ll create two JavaScript files (auth.js and index.js) inside a scripts folder inside the public folder.
- Select the public folder, then click on the +folder icon to create a new folder. Call scripts to that new folder.
- Then, select the scripts folder and click on the +file icon. Create a file called auth.js. Then, repeat the previous steps to create an index.js.
The following image show how your web app project folder structure should look like.
auth.js
Now let’s implement user sign-in using Firebase authentication. We’ll implement sign-in using email and password.
Copy the following to the auth.js file you created previously.
document.addEventListener("DOMContentLoaded", function(){
// listen for auth status changes
auth.onAuthStateChanged(user => {
if (user) {
console.log("user logged in");
console.log(user);
setupUI(user);
var uid = user.uid;
console.log(uid);
} else {
console.log("user logged out");
setupUI();
}
});
// login
const loginForm = document.querySelector('#login-form');
loginForm.addEventListener('submit', (e) => {
e.preventDefault();
// get user info
const email = loginForm['input-email'].value;
const password = loginForm['input-password'].value;
// log the user in
auth.signInWithEmailAndPassword(email, password).then((cred) => {
// close the login modal & reset form
loginForm.reset();
console.log(email);
})
.catch((error) =>{
const errorCode = error.code;
const errorMessage = error.message;
document.getElementById("error-message").innerHTML = errorMessage;
console.log(errorMessage);
});
});
// logout
const logout = document.querySelector('#logout-link');
logout.addEventListener('click', (e) => {
e.preventDefault();
auth.signOut();
});
});
Then, save the file. This file takes care of everything related to the login and logout of the user. Continue reading to learn how the code works or skip to the next section.
Login
The following lines are responsible for logging in the user.
const loginForm = document.querySelector('#login-form');
loginForm.addEventListener('submit', (e) => {
e.preventDefault();
// get user info
const email = loginForm['input-email'].value;
const password = loginForm['input-password'].value;
// log the user in
auth.signInWithEmailAndPassword(email, password).then((cred) => {
// close the login modal & reset form
loginForm.reset();
console.log(email);
})
.catch((error) =>{
const errorCode = error.code;
const errorMessage = error.message;
document.getElementById("error-message").innerHTML = errorMessage;
console.log(errorMessage);
});
});
We create a variable that refers to the login form HTML element called loginForm.
const loginForm = document.querySelector('#login-form');
If you go back to the index.html file, you can see that the form has the login-form id.
We add an event listener of type submit to the form. This means that the subsequent instructions will run whenever the form is submitted.
loginForm.addEventListener('submit', (e) => {
You can get the submitted data as follows.
const email = loginForm['input-email'].value;
const password = loginForm['input-password'].value;
If you go back to the HTML file, you’ll see that the input fields contain the following ids: input-email and input-password for the email and password, respectively.
Now that we have the inserted email and password, we can try to log in to Firebase. To do that, pass the user’s email address and password to the following method: signInWithEmailAndPassword:
auth.signInWithEmailAndPassword(email, password).then((cred) => {
After logging in, we reset the form and print the user email in the console.
auth.signInWithEmailAndPassword(email, password).then((cred) => {
// close the login modal & reset form
loginForm.reset();
console.log(email);
})
In case there is an error signing in, we catch the error message, and display it on the error-message HTML element (a paragraph below the form).
.catch((error) =>{
const errorCode = error.code;
const errorMessage = error.message;
document.getElementById("error-message").innerHTML = errorMessage;
console.log(errorMessage);
});
Logout
The following snippet is responsible for logging out the user.
const logout = document.querySelector('#logout-link');
logout.addEventListener('click', (e) => {
e.preventDefault();
auth.signOut();
});
When the user is logged in, a logout link is visible in the authentication bar. That link has the logout-link id (see on the HTML file). So, first, we create a variable called logout that refers to the logout link.
const logout = document.querySelector('#logout-link');
Then, we add an event listener of type click. This means the subsequent instructions will run whenever you click on the logout link.
logout.addEventListener('click', (e) => {
When the button is clicked, we sign out the user using the signOut method.
auth.signOut();
Auth State Changes
To keep track of the user authentication state—to know if the user is logged in or logged out, there is a method called onAuthSateChanged that allows you to receive an event whenever the authentication state changes.
auth.onAuthStateChanged(user => {
if (user) {
console.log("user logged in");
console.log(user);
setupUI(user);
var uid = user.uid;
console.log(uid);
} else {
console.log("user logged out");
setupUI();
}
});
If the user returned is null, the user is currently signed out. Otherwise, it is currently signed in.
In both scenarios, we print the current user state to the console and call the setupUI() function. We haven’t created that function yet (we’ll create it in the next section), but it will be responsible for handling the user interface accordingly to the authentication state.
When the user is logged in, we pass the user as an argument to the setupUI() function. In this case, we’ll display the complete user interface to show the sensor readings, as you’ll see later.
if (user) {
console.log("user logged in");
console.log(user);
setupUI(user);
We also get the user UID that we’ll need later to insert and read data from the database.
var uid = user.uid;
console.log(uid);
If the user is logged out, we call the setupUI() function without any argument. In that scenario, we’ll simply display a message informing that the user is logged out and doesn’t have access to the interface (as we’ll see later).
} else {
console.log("user logged out");
setupUI();
}
index.js
The index.js file handles the UI – it shows the right content depending on the user authentication status. When the user is logged in, this file gets new readings from the database whenever there’s a change.
Copy the following to the index.js file.
const loginElement = document.querySelector('#login-form');
const contentElement = document.querySelector("#content-sign-in");
const userDetailsElement = document.querySelector('#user-details');
const authBarElement = document.querySelector("#authentication-bar");
// Elements for sensor readings
const tempElement = document.getElementById("temp");
const humElement = document.getElementById("hum");
const presElement = document.getElementById("pres");
// MANAGE LOGIN/LOGOUT UI
const setupUI = (user) => {
if (user) {
//toggle UI elements
loginElement.style.display = 'none';
contentElement.style.display = 'block';
authBarElement.style.display ='block';
userDetailsElement.style.display ='block';
userDetailsElement.innerHTML = user.email;
// get user UID to get data from database
var uid = user.uid;
console.log(uid);
// Database paths (with user UID)
var dbPathTemp = 'UsersData/' + uid.toString() + '/temperature';
var dbPathHum = 'UsersData/' + uid.toString() + '/humidity';
var dbPathPres = 'UsersData/' + uid.toString() + '/pressure';
// Database references
var dbRefTemp = firebase.database().ref().child(dbPathTemp);
var dbRefHum = firebase.database().ref().child(dbPathHum);
var dbRefPres = firebase.database().ref().child(dbPathPres);
// Update page with new readings
dbRefTemp.on('value', snap => {
tempElement.innerText = snap.val().toFixed(2);
});
dbRefHum.on('value', snap => {
humElement.innerText = snap.val().toFixed(2);
});
dbRefPres.on('value', snap => {
presElement.innerText = snap.val().toFixed(2);
});
// if user is logged out
} else{
// toggle UI elements
loginElement.style.display = 'block';
authBarElement.style.display ='none';
userDetailsElement.style.display ='none';
contentElement.style.display = 'none';
}
}
Continue reading to learn how the code works or skip to the next section.
Getting HTML Elements
First, we create variables to refer to several elements on the UI interface by referring to their ids. To identify these elements, we recommend that you take a look at the HTML file provided and find the elements with the referred ids.
const loginElement = document.querySelector('#login-form');
const contentElement = document.querySelector("#content-sign-in");
const userDetailsElement = document.querySelector('#user-details');
const authBarElement = document.querySelector("#authentication-bar");
// Elements for sensor readings
const tempElement = document.getElementById("temp");
const humElement = document.getElementById("hum");
const presElement = document.getElementById("pres");
The loginElement corresponds to the login form. The contentElement corresponds to the section of the web page that is visible when the user is logged in (that shows the sensor readings). The userDetailsElement corresponds to a section that will display the email of the logged in user. The auhtBarElement corresponds to the authentication bar that shows the current user status, the email of the authenticated user and the logout link.
sertupUI() Function
Then, we create the setupUI() function that will handle the UI accordingly to the state of the user authentication.
In the auth.js file, we called the setupUI() function with the user argument setupUI(user) if the user is logged in; or the function without argument setupUI() when the user is logged out.
So, let’s check what happens when the user is logged in.
if (user) {
We define which parts of the UI should be visible or invisible. When the user is logged in, we want to hide the login form. To hide an element, we can set the display style to none.
loginElement.style.display = 'none';
We show the authentication bar (that shows the user details and the logout link). To do that, we can set its display style to block. We also want the web page’s main content with the sensor readings to be visible.
contentElement.style.display = 'block';
authBarElement.style.display ='block';
Finally, we can get the logged in user email with user.email and display it in the userDetailsElement section as follows:
userDetailsElement.innerHTML = user.email;
User UID and Database Paths
After we have a logged-in user, we can get its UID with user.uid.
var uid = user.uid;
console.log(uid);
After getting the user UID, we create variables to refer to the database paths where we save the data.
// Database paths (with user UID)
var dbPathTemp = 'UsersData/' + uid.toString() + '/temperature';
var dbPathHum = 'UsersData/' + uid.toString() + '/humidity';
var dbPathPres = 'UsersData/' + uid.toString() + '/pressure';
Then, we create database references to those paths.
var dbRefTemp = firebase.database().ref().child(dbPathTemp);
var dbRefHum = firebase.database().ref().child(dbPathHum);
var dbRefPres = firebase.database().ref().child(dbPathPres);
Display Sensor Readings
The following lines get the new sensor readings whenever there’s a change and update the corresponding HTML elements with the new values.
// Update page with new readings
dbRefTemp.on('value', snap => {
tempElement.innerText = snap.val().toFixed(2);
});
dbRefHum.on('value', snap => {
humElement.innerText = snap.val().toFixed(2);
});
dbRefPres.on('value', snap => {
presElement.innerText = snap.val().toFixed(2);
});
Logged Out UI
The following snippet handles the UI when the user logs out. We want to hide the authentication bar and the main webpage content (sensor readings) and show the login form.
} else{
// toggle UI elements
loginElement.style.display = 'block';
authBarElement.style.display ='none';
contentElement.style.display = 'none';
}
Favicon File
To display a favicon in your web app, you need to move the picture you want to use as favicon to the public folder. The picture should be called favicon.png. You can simply drag the favicon file from your computer into the public folder in VS Code.
We’re using the following icon as a favicon for our web app:
Deploy your App
After saving the HTML, CSS, and JavaScript files, deploy your app on VS Code by running the following command on the Terminal window.
firebase deploy
The Terminal should display something as follows:
Firebase offers a free hosting service to serve your assets and web apps. Then, you can access your web app from anywhere.
You can use the Hosting URL provided to access your web app from anywhere.
Demonstration
Congratulations! You successfully deployed your app. It is now hosted on a global CDN using Firebase hosting. You can access your web app from anywhere on the Hosting URL provided. In my case, it is https://esp-firebase-demo.web.app.
The web app is responsive, and you can access it using your smartphone, computer, or tablet.
Insert the email and password of the authorized user you added in the Firebase Authentication methods. After that, you can access the latest sensor readings.
Go to your project’s Firebase console Hosting tab. You can see your app domains, deploy history, and you can even roll back to previous versions of your app.
Wrapping Up
In this tutorial, you learned how to create a Firebase Web App with login/logout authentication that displays sensor readings. The sensor readings are saved on the realtime database. The database is protected using database rules (that you’ve already set up in the previous tutorial).
You can apply what you learned here to display any other type of data, and you can change the files in the public folder to add different functionalities and features to your project.
If you want to learn more about Firebase, we recommend taking a look at our new eBook, exclusively dedicated to this subject:
We have other resources related to ESP32 and ESP8266 that you may like:
Thanks for reading.
Being struck down with covid and bored, i was looking forward to your new article. Thanks
Hi, great authentication and data logging example thanks a lot for the article, would recommend to use module bundlers, so that the firebase configuration won’t be visible to the end-user or publicly on the website
https://firebase.google.com/docs/web/module-bundling
https://webpack.js.org/
here’s a practice been working on recently where i’ve used some of your codes to render the web page https://github.com/ramymagdy-rm/home_automation
the bundling approach is way safer than the conventional index.js method, the user eventually gets to see the nods.js compiled pack which is an encoded static asset
Hi.
Thanks for sharing.
I will take a look into that.
Regards,
Sara
Hi
Works fine with the ESP32-WROOM board.
With an 8266 NodeMCU board it works OK for an hour or so, then I get a token error code 400 that is repeated “forever”, varying intervals from a few seconds to a minute and varying numbers of errors (same 3 lines repeated). The only way to stop is to reset the board after which it returns to normal for a while.
13:04:29.627 -> Writing value: 994.19 on the following path: /UsersData/xxxxxxx/pressure
13:04:29.627 -> PASSED
13:04:29.627 -> PATH: /UsersData/xxxxxxx/pressure
13:04:29.627 -> TYPE: double
13:16:55.479 -> Token info: type = id token, status = error
13:16:55.479 -> Token error: code: 400, message: MISSING_REFRESH_TOKEN
13:16:55.479 -> Token info: type = id token, status = on refreshing
13:16:55.479 -> Token info: type = id token, status = error
13:16:55.479 -> Token error: code: 400, message: MISSING_REFRESH_TOKEN
13:16:55.479 -> Token info: type = id token, status = on refreshing
Hi.
I never faced that error.
Did you change anything on the code?
I have no idea what that error means?
Did you enable the right authentication methods?
Regards,
Sara
Hi Sara
First of all thanks for this series of projects: I accidentally cut that from the first comment. It is a very interesting way to get information accessible from anywhere.
The error code is due to a missing refresh token if I understand correctly. What is strange is that everything works fine for an hour or so, then breaks. I thought it might be due to a wdt, as there is a comment in the TokenHelper.h file regarding the 8266, but after reading up a bit I cannot see how that could be relevant as the hardware wdt is always active.
I’ll see if I can find another 8266 to try it out on.
BR
Phi
Ok.
Then, let us know the results.
Regards,
Sara
bro you write invalid token
Hello all.
I cant compile this project.
i receive the error
“fatal error: Firebase_ESP_Client.h: No such file or directory
compilation terminated.
Compilation error: exit status 1}”
I use Arduino IDE 2.0.0-rc3, but before i have try also with 1.8.19
I have install also the boards. I use ESP32 Wrover Module
The file Firebase_ESP_Client.h exist inside the correct folder of this library
Some help please
Thanks
Hi.
The error says it cannot find the library.
Make sure you’ve installed the correct library and that it is installed properly as shown in the tutorial.
Regards,
Sara
Theodoros, I had a similar error, turned out I had installed the wrong library, must be “Firebase Arduino Client Library for Expressif…” not “Firebase ESP32 Client….” or similar. Also go into “Sketch”, “Include library” and click on the installed library. Check the library is in the sketch path as set in “preferences”, file must be in sketchpath\libraries\Fire_Base….\src\file.h , any other director path probably won’t work. Hope that helps.
Sara thanks for very clear detailed project instructions, this makes it so easy! However I have found that when I “deploy” a project it doesn’t alway upload the edited saved files, even though it says “found 4 files in public” (correct number), “file upload complete”, changes made don’t appear on web page even though I have refreshed it or loaded from a different browser with no history. Or I have added a new file it is not found. Is there any way to forcefully upload all files, changed or unchanged? Any way to check what files are on the firebase server? The firebase “Hosting page” doesn’t seem to list the files.
Thanks Bruce
Thanks a lot Bruse. I will consider that you write to me because in addition I had a second problem with the appearance with “one drive”. It shows me that I have dual libraries. I disconnected the “one drive”
I uninstalled Arduino ide2, cleaned the C: \ Users \ …. . ArduinoIDE folder and did the installation from the beginning and the compilation was done normally.
Thanks
Hi All, previous problem now solved, the problem was VS Code was not always saving changes when I hit Ctl S, nothing to do with firebase deploy.
I can read the data logged from the rtdb if I hard code in a timestamp example, but how can I iterate through timestamps? I have a little experience with simple sql but this is completely different!
Thanks
Hello, I’m stuck with a command error, when I write: “firebase login” I have this error: “firebase: The term ‘firebase’ is not recognozed as the name of a cmdlet, function, script file, pr operable program …’
Good day
Hola Adrien, respondo 1 año después porque me encontré con el mismo problema. Aprovecho para dejar la solución a futuros programadores.
Debes instalar todos los complementos que indica éste tutorial:
https://randomnerdtutorials.com/esp32-firebase-web-app/
ya que esos pasos no se vuelven a explicar en éste tutorial.
Saludos!
Problem fixed ^^
how did you fix it?
Hello, I have another problem, when I press enter to the question “What file should be used for Realtime Database Security Rules?“ as said in the tutorial, an error is returned: “Error: An unexpected error has occured ”
Good day
Hi.
Can you provide more details about the error?
Regards,
Sara
I managed to solve the problem, just restart and everything works. I would like to know if it is possible to link several ESP 32 on the same account to have several statements and have them on the same account
Hi.
Yes, you can do that.
You just have to make sure that each ESP publishes on a different path, otherwise, the readings will be overwritten.
Regards,
Sara
Hello,
Actually everything is fine.
You do great tutorials.
I allow myself to ask a few more questions: how can we make the user create his own account?
Hi.
We don’t have any tutorials about that.
But there are great youtube videos about that.
Also, search on the firebase documentation
I might cover that subject in the future, but at the moment, we don’t have any resources about that.
Regards,
Sara
Hello,
Can you publish an example about firestore?
At the moment, we don’t have any firestore examples.
But, you can check the library. There are several examples: https://github.com/mobizt/Firebase-ESP-Client/tree/main/examples
Regards,
Sara
Hello Sara,
I am trying to control my ESP from Fdtb but I cannot manage usage of setString/getString function on this library. Yes, you said, stay tuned until next moth, but it is much appreciate you to explain this.
Here are my functions:
// writing OFF on the path
Firebase.RTDB.setString(&fbdo, led, “OFF”);
//getting the string on the path
void receiveString(String path, String value){
if (Firebase.RTDB.getString(&fbdo, value)){
Serial.print(“Writing value: “);
Serial.print (value);
Serial.print(” on the following path: “);
Serial.println(path);
Serial.println(“PASSED”);
Serial.println(“PATH: ” + fbdo.dataPath());
Serial.println(“TYPE: ” + fbdo.dataType());
}
else {
Serial.println(“FAILED”);
Serial.println(“REASON: ” + fbdo.errorReason());
}
}
I followed the tutorial, and at the end, after login, the sensor data is not displayed, it is blank. Any idea what could have happened?
Hi.
Double-check your database paths.
Open the JavaScrtip console on the web browser and check if you get any issues.
Regards,
Sara
Please what the another method for deleting firebase.ps1 security . Am unable to install vs code extension because of it
Hello Sara,
thank you for excelent tutorial.
I would like to ask how can I set filter for retrieving data from database.
What I need – I save data from two sensors (I add “sensorID” to both of sensors) and than I want to display on web page data from sensor1 or sensor2. Could you help me set filter for sensor1 (or sensor2).
Thank you
Marek
Hi.
For that, you need to know how to make queries.
Here’s the documentation: https://firebase.google.com/docs/reference/js/v8/firebase.database.Query
Regards,
Sara
Hi Sara Santos,
I’m grateful about your detailed tutorial. So, l’m the beginner could understand the project well.
Somehow, l found a problem that after deploying the website just showing the title without any contents inside. Could you please let me know what’s happening? I put the link of website there
Hi.
Open the javascript console on the web browser and check if you get any errors.
regards,
Sara
Hello i am also getting same error, i tried to copy paste the js code agian and again but still same error.
Hi, I had the same problem, for me it was the script tags at the end of the index.html tags, if you have your auth.js and index.js files in the same folder you only need to have “auth.js” and “index.js” as your path in there.
Hi Sara. I also have problem loading the auth.js and index.js files (example from that book I bought). It works fine in the local network. It acts as if the files are empty. You can see it on my project.
Thank you for your response.
Hi.
Please open an issue in our forum or send an email to our support so that we can give you proper guidance.
Forum: https://rntlab.com/forum/
Support: https://randomnerdtutorials.com/support/
Regards,
Sara