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

In this project, you’ll create a Firebase Web App that displays all the sensor readings saved on the Firebase Realtime Database. We’ll create a web interface with gauges, charts, and a table to display all your data records. We’ll also add a button that allows you to delete all data from the database and checkboxes to customize the user interface. This web application will be protected with authentication (using email and password) and all the data is restricted to the user using database rules.

ESP32 ESP8266 NodeMCU Firebase Data Logging Web App with Gauges Charts and Table

This project is Part 2 of the following tutorial (there is a version for ESP32 and a version for ESP8266):

You must follow one of those tutorials first, before proceeding

Here’s a summary of the web app features:

  • login with email and password
  • displays time of the last update
  • cards to display the last sensor readings
  • gauges to display the last sensor readings
  • charts that display data history with timestamps
  • select how many readings to display on charts
  • checkboxes to enable/disable the different display options
  • table that displays all readings saved on the database
  • button to delete database data

Project Overview

In this tutorial (Part 2), you’ll create a web app to display the sensor readings logged with timestamps on the Firebase Realtime Database (read this previous tutorial – ESP32 version / ESP8266 version).

The following video shows the web app project we’ll build—programming the ESP32/ESP8266 and setting up the Firebase Project was done in Part 1 (ESP32 Part 1; ESP8266 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. The sensor readings are displayed in cards, gauges, charts and table. You can select how many readings you want to show on the charts and you can also choose how you can view your data.
  • There is a button to show/hide all readings saved on the database on a table with timestamps.
  • There’s also a Delete button that allows you to delete all data from the database.
  • All the data is restricted using database rules.

Prerequisites

Before start creating the Firebase Web App, you need to check the following prerequisites:

Creating a Firebase Project

You should have followed one of the next tutorials 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.

Firebase Add App to Project

2) Select the web app icon.

Firebase Add Web App to Project

3) Give your app a name. Then, check the box next to √ Also set up Firebase Hosting for this App. Click Register app.

Firebase Add Web App to Project Hosting

4) Then, copy the firebaseConfig object and save it because you’ll need it later.

firebaseConfig object configuration copy save

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.

Install Firebase Tools 2

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.

Login Firebase VS Code Terminal Window

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.

Login Firebase Account

7) Allow Firebase CLI to access your google account.

Login Firebase Account allow Firebase CLI

8) After this, Firebase CLI login should be successful. You can close the browser window.

Login Firebase Account allow Firebase CLI Login Successful

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.

Login Firebase Account allow Firebase CLI firebase init

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.

Login Firebase Account allow Firebase CLI configure directory

12) Select the option “Use an existing project”—it should be highlighted in blue—then, hit Enter.

Firebase Project Setup VS Code

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.

Firebase Project VS Code create project

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
Firebase initialization complete

16) The Firebase project should now be initialized successfully. Notice that VS code created some essential files under your project folder.

Firebase Project Files Created successfully

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
Firebase App First Deploy Testing

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.

Firebase test page hosting setup complete

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 (it is inside the public folder).

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>ESP Datalogging Firebase App</title>

    <!-- include Firebase SDK -->
    <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 app config object
      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>

    <!-- include highchartsjs to build the charts-->
    <script src="https://code.highcharts.com/highcharts.js"></script>
    <!-- include to use jquery-->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <!--include icons from fontawesome-->
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
    <!-- include Gauges Javascript library-->
    <script src="https://cdn.rawgit.com/Mikhus/canvas-gauges/gh-pages/download/2.1.7/all/gauge.min.js"></script>
    <!--reference for favicon-->
    <link rel="icon" type="image/png" href="favicon.png">
    <!--reference a stylesheet-->
    <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;">

      <!--LAST UPDATE-->
      <p><span class ="date-time">Last update: <span id="lastUpdate"></span></span></p>
      <p>
        Cards: <input type="checkbox" id="cards-checkbox" name="cards-checkbox" checked>
        Gauges: <input type="checkbox" id="gauges-checkbox" name="gauges-checkbox" checked>
        Charts: <input type="checkbox" id="charts-checkbox" name="charts-checkbox" unchecked>
      </p>
      <div id="cards-div">
        <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> &deg;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> &percnt;</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>
      <!--GAUGES-->
      <div id ="gauges-div">
        <div class="cards">
          <!--TEMPERATURE-->
          <div class="card">
            <canvas id="gauge-temperature"></canvas>
          </div>
          <!--HUMIDITY-->
          <div class="card">
            <canvas id="gauge-humidity"></canvas>
          </div>
        </div>
      </div>

      <!--CHARTS-->
      <div id="charts-div" style="display:none">
        <!--SET NUMBER OF READINGS INPUT FIELD-->
        <div>
          <p> Number of readings: <input type="number" id="charts-range"></p>
        </div>
        <!--TEMPERATURE-CHART-->
        <div class="cards">
          <div class="card">
            <p><i class="fas fa-thermometer-half" style="color:#059e8a;"></i> TEMPERATURE CHART</p>
            <div id="chart-temperature" class="chart-container"></div>
          </div>
        </div>
        <!--HUMIDITY-CHART-->
        <div class="cards">
          <div class="card">
            <p><i class="fas fa-tint" style="color:#00add6;"></i> HUMIDITY CHART</p>
            <div id="chart-humidity" class="chart-container"></div>
          </div>
        </div>
        <!--PRESSURE-CHART-->
        <div class="cards">
          <div class="card">
            <p><i class="fas fa-angle-double-down" style="color:#e1e437;"></i> PRESSURE CHART</p>
            <div id="chart-pressure" class="chart-container"></div>
          </div>
        </div>
      </div>

    <!--BUTTONS TO HANDLE DATA-->
    <p>
      <!--View data button-->
      <button id="view-data-button">View all data</button>
      <!--Hide data button-->
      <button id="hide-data-button" style= "display:none;">Hide data</button>
      <!--Delete data button-->
      <button id="delete-button" class="deletebtn">Delete data</button>
    </p>
    <!--Modal to delete data-->
    <div id="delete-modal" class="modal" sytle="display:none">
      <span onclick = "document.getElementById('delete-modal').style.display='none'" class="close" title="Close Modal">×</span>
      <form id= "delete-data-form" class="modal-content" action="/">
        <div class="container">
          <h1>Delete Data</h1>
          <p>Are you sure you want to delete all data from database?</p>
          <div class="clearfix">
            <button type="button" onclick="document.getElementById('delete-modal').style.display='none'" class="cancelbtn">Cancel</button>
            <button type="submit" onclick="document.getElementById('delete-modal').style.display='none'" class="deletebtn">Delete</button>
          </div>
        </div>
      </form>
    </div>

    <!--TABLE WITH ALL DATA-->
    <div class ="cards">
      <div class="card" id="table-container" style= "display:none;">
        <table id="readings-table">
            <tr id="theader">
              <th>Timestamp</th>
              <th>Temp (ºC)</th>
              <th>Hum (%)</th>
              <th>Pres (hPa)</th>
            </tr>
            <tbody id="tbody">
            </tbody>
        </table>
        <p><button id="load-data" style= "display:none;">More results...</button></p>
      </div>
    </div>

  </div>

    <!--INCLUDE JS FILES-->
    <script src="scripts/auth.js"></script>
    <script src="scripts/charts-definition.js"></script>
    <script src="scripts/gauges-definition.js"></script>
    <script src="scripts/index.js"></script>

  </body>

</html>

View raw code

Important: you need to modify the code with your own firebaseConfig object—the one you’ve got in 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"
};

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.

Create CSS File VS Code

Then, copy the following to the style.css file

html {
    font-family: Verdana, Geneva, Tahoma, sans-serif;
    display: inline-block;
    text-align: center;
}

body {
    margin: 0;
    width: 100%;
}

.topnav {
    overflow: hidden;
    background-color: #049faa;
    color: white;
    font-size: 1rem;
    padding: 5px;
}

#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;
    margin-bottom: 10px;
    display: grid;
    grid-gap: 2rem;
    grid-template-columns: repeat(auto-fit, minmax(200px, 2fr));
}

.reading {
    color: #193036;
}

.date-time{
    font-size: 0.8rem;
    color: #1282A2;
}

button {
    background-color: #049faa;
    color: white;
    padding: 14px 20px;
    margin: 8px 0;
    border: none;
    cursor: pointer;
    border-radius: 4px;
}
button:hover {
   opacity: 0.8;
}
.deletebtn{
    background-color: #c52c2c;
}

.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;
}

table {
    width: 100%;
    text-align: center;
    font-size: 0.8rem;
}   
tr, td {
    padding: 0.25rem;
}
tr:nth-child(even) {
    background-color: #f2f2f2
}
tr:hover {
    background-color: #ddd;
}
th {
    position: sticky;
    top: 0;
    background-color: #50b8b4;
    color: white;
}

/* The Modal (background) */
.modal {
    display: none; /* Hidden by default */
    position: fixed; /* Stay in place */
    z-index: 1; /* Sit on top */
    left: 0;
    top: 0;
    width: 100%; /* Full width */
    height: 100%; /* Full height */
    overflow: auto; /* Enable scroll if needed */
    background-color: #474e5d;
    padding-top: 50px;
}
  
/* Modal Content/Box */
.modal-content {
    background-color: #fefefe;
    margin: 5% auto 15% auto; /* 5% from the top, 15% from the bottom and centered */
    border: 1px solid #888;
    width: 80%; /* Could be more or less, depending on screen size */
}
  
/* Style the horizontal ruler */
hr {
    border: 1px solid #f1f1f1;
    margin-bottom: 25px;
}

/* The Modal Close Button (x) */
.close {
    position: absolute;
    right: 35px;
    top: 15px;
    font-size: 40px;
    font-weight: bold;
    color: #f1f1f1;
}

.close:hover,
.close:focus {
    color: #f44336;
    cursor: pointer;
}

/* Clear floats */
.clearfix::after {
    content: "";
    clear: both;
    display: table;
}

/* Change styles for cancel button and delete button on extra small screens */
@media screen and (max-width: 300px) {
    .cancelbtn, .deletebtn {
        width: 100%;
    }
}

View raw code

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 four JavaScript files (auth.js, index.js, charts-definition.js, and gauges-definition.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 the index.js, charts-definition.js, and gauges-definition.js files.

The following image shows what your web app project folder structure should look like.

Firebase Project VS Code Folder File Structure

auth.js

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();
    });
});  

View raw code

Then, save the file. This file takes care of everything related to the login and logout of the user.

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 and displays them in the right places.

Copy the following to the index.js file.

// convert epochtime to JavaScripte Date object
function epochToJsDate(epochTime){
  return new Date(epochTime*1000);
}

// convert time to human-readable format YYYY/MM/DD HH:MM:SS
function epochToDateTime(epochTime){
  var epochDate = new Date(epochToJsDate(epochTime));
  var dateTime = epochDate.getFullYear() + "/" +
    ("00" + (epochDate.getMonth() + 1)).slice(-2) + "/" +
    ("00" + epochDate.getDate()).slice(-2) + " " +
    ("00" + epochDate.getHours()).slice(-2) + ":" +
    ("00" + epochDate.getMinutes()).slice(-2) + ":" +
    ("00" + epochDate.getSeconds()).slice(-2);

  return dateTime;
}

// function to plot values on charts
function plotValues(chart, timestamp, value){
  var x = epochToJsDate(timestamp).getTime();
  var y = Number (value);
  if(chart.series[0].data.length > 40) {
    chart.series[0].addPoint([x, y], true, true, true);
  } else {
    chart.series[0].addPoint([x, y], true, false, true);
  }
}

// DOM elements
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');
const deleteButtonElement = document.getElementById('delete-button');
const deleteModalElement = document.getElementById('delete-modal');
const deleteDataFormElement = document.querySelector('#delete-data-form');
const viewDataButtonElement = document.getElementById('view-data-button');
const hideDataButtonElement = document.getElementById('hide-data-button');
const tableContainerElement = document.querySelector('#table-container');
const chartsRangeInputElement = document.getElementById('charts-range');
const loadDataButtonElement = document.getElementById('load-data');
const cardsCheckboxElement = document.querySelector('input[name=cards-checkbox]');
const gaugesCheckboxElement = document.querySelector('input[name=gauges-checkbox]');
const chartsCheckboxElement = document.querySelector('input[name=charts-checkbox]');

// DOM elements for sensor readings
const cardsReadingsElement = document.querySelector("#cards-div");
const gaugesReadingsElement = document.querySelector("#gauges-div");
const chartsDivElement = document.querySelector('#charts-div');
const tempElement = document.getElementById("temp");
const humElement = document.getElementById("hum");
const presElement = document.getElementById("pres");
const updateElement = document.getElementById("lastUpdate")

// 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 dbPath = 'UsersData/' + uid.toString() + '/readings';
    var chartPath = 'UsersData/' + uid.toString() + '/charts/range';

    // Database references
    var dbRef = firebase.database().ref(dbPath);
    var chartRef = firebase.database().ref(chartPath);

    // CHARTS
    // Number of readings to plot on charts
    var chartRange = 0;
    // Get number of readings to plot saved on database (runs when the page first loads and whenever there's a change in the database)
    chartRef.on('value', snapshot =>{
      chartRange = Number(snapshot.val());
      console.log(chartRange);
      // Delete all data from charts to update with new values when a new range is selected
      chartT.destroy();
      chartH.destroy();
      chartP.destroy();
      // Render new charts to display new range of data
      chartT = createTemperatureChart();
      chartH = createHumidityChart();
      chartP = createPressureChart();
      // Update the charts with the new range
      // Get the latest readings and plot them on charts (the number of plotted readings corresponds to the chartRange value)
      dbRef.orderByKey().limitToLast(chartRange).on('child_added', snapshot =>{
        var jsonData = snapshot.toJSON(); // example: {temperature: 25.02, humidity: 50.20, pressure: 1008.48, timestamp:1641317355}
        // Save values on variables
        var temperature = jsonData.temperature;
        var humidity = jsonData.humidity;
        var pressure = jsonData.pressure;
        var timestamp = jsonData.timestamp;
        // Plot the values on the charts
        plotValues(chartT, timestamp, temperature);
        plotValues(chartH, timestamp, humidity);
        plotValues(chartP, timestamp, pressure);
      });
    });

    // Update database with new range (input field)
    chartsRangeInputElement.onchange = () =>{
      chartRef.set(chartsRangeInputElement.value);
    };

    //CHECKBOXES
    // Checbox (cards for sensor readings)
    cardsCheckboxElement.addEventListener('change', (e) =>{
      if (cardsCheckboxElement.checked) {
        cardsReadingsElement.style.display = 'block';
      }
      else{
        cardsReadingsElement.style.display = 'none';
      }
    });
    // Checbox (gauges for sensor readings)
    gaugesCheckboxElement.addEventListener('change', (e) =>{
      if (gaugesCheckboxElement.checked) {
        gaugesReadingsElement.style.display = 'block';
      }
      else{
        gaugesReadingsElement.style.display = 'none';
      }
    });
    // Checbox (charta for sensor readings)
    chartsCheckboxElement.addEventListener('change', (e) =>{
      if (chartsCheckboxElement.checked) {
        chartsDivElement.style.display = 'block';
      }
      else{
        chartsDivElement.style.display = 'none';
      }
    });

    // CARDS
    // Get the latest readings and display on cards
    dbRef.orderByKey().limitToLast(1).on('child_added', snapshot =>{
      var jsonData = snapshot.toJSON(); // example: {temperature: 25.02, humidity: 50.20, pressure: 1008.48, timestamp:1641317355}
      var temperature = jsonData.temperature;
      var humidity = jsonData.humidity;
      var pressure = jsonData.pressure;
      var timestamp = jsonData.timestamp;
      // Update DOM elements
      tempElement.innerHTML = temperature;
      humElement.innerHTML = humidity;
      presElement.innerHTML = pressure;
      updateElement.innerHTML = epochToDateTime(timestamp);
    });

    // GAUGES
    // Get the latest readings and display on gauges
    dbRef.orderByKey().limitToLast(1).on('child_added', snapshot =>{
      var jsonData = snapshot.toJSON(); // example: {temperature: 25.02, humidity: 50.20, pressure: 1008.48, timestamp:1641317355}
      var temperature = jsonData.temperature;
      var humidity = jsonData.humidity;
      var pressure = jsonData.pressure;
      var timestamp = jsonData.timestamp;
      // Update DOM elements
      var gaugeT = createTemperatureGauge();
      var gaugeH = createHumidityGauge();
      gaugeT.draw();
      gaugeH.draw();
      gaugeT.value = temperature;
      gaugeH.value = humidity;
      updateElement.innerHTML = epochToDateTime(timestamp);
    });

    // DELETE DATA
    // Add event listener to open modal when click on "Delete Data" button
    deleteButtonElement.addEventListener('click', e =>{
      console.log("Remove data");
      e.preventDefault;
      deleteModalElement.style.display="block";
    });

    // Add event listener when delete form is submited
    deleteDataFormElement.addEventListener('submit', (e) => {
      // delete data (readings)
      dbRef.remove();
    });

    // TABLE
    var lastReadingTimestamp; //saves last timestamp displayed on the table
    // Function that creates the table with the first 100 readings
    function createTable(){
      // append all data to the table
      var firstRun = true;
      dbRef.orderByKey().limitToLast(100).on('child_added', function(snapshot) {
        if (snapshot.exists()) {
          var jsonData = snapshot.toJSON();
          console.log(jsonData);
          var temperature = jsonData.temperature;
          var humidity = jsonData.humidity;
          var pressure = jsonData.pressure;
          var timestamp = jsonData.timestamp;
          var content = '';
          content += '<tr>';
          content += '<td>' + epochToDateTime(timestamp) + '</td>';
          content += '<td>' + temperature + '</td>';
          content += '<td>' + humidity + '</td>';
          content += '<td>' + pressure + '</td>';
          content += '</tr>';
          $('#tbody').prepend(content);
          // Save lastReadingTimestamp --> corresponds to the first timestamp on the returned snapshot data
          if (firstRun){
            lastReadingTimestamp = timestamp;
            firstRun=false;
            console.log(lastReadingTimestamp);
          }
        }
      });
    };

    // append readings to table (after pressing More results... button)
    function appendToTable(){
      var dataList = []; // saves list of readings returned by the snapshot (oldest-->newest)
      var reversedList = []; // the same as previous, but reversed (newest--> oldest)
      console.log("APEND");
      dbRef.orderByKey().limitToLast(100).endAt(lastReadingTimestamp).once('value', function(snapshot) {
        // convert the snapshot to JSON
        if (snapshot.exists()) {
          snapshot.forEach(element => {
            var jsonData = element.toJSON();
            dataList.push(jsonData); // create a list with all data
          });
          lastReadingTimestamp = dataList[0].timestamp; //oldest timestamp corresponds to the first on the list (oldest --> newest)
          reversedList = dataList.reverse(); // reverse the order of the list (newest data --> oldest data)

          var firstTime = true;
          // loop through all elements of the list and append to table (newest elements first)
          reversedList.forEach(element =>{
            if (firstTime){ // ignore first reading (it's already on the table from the previous query)
              firstTime = false;
            }
            else{
              var temperature = element.temperature;
              var humidity = element.humidity;
              var pressure = element.pressure;
              var timestamp = element.timestamp;
              var content = '';
              content += '<tr>';
              content += '<td>' + epochToDateTime(timestamp) + '</td>';
              content += '<td>' + temperature + '</td>';
              content += '<td>' + humidity + '</td>';
              content += '<td>' + pressure + '</td>';
              content += '</tr>';
              $('#tbody').append(content);
            }
          });
        }
      });
    }

    viewDataButtonElement.addEventListener('click', (e) =>{
      // Toggle DOM elements
      tableContainerElement.style.display = 'block';
      viewDataButtonElement.style.display ='none';
      hideDataButtonElement.style.display ='inline-block';
      loadDataButtonElement.style.display = 'inline-block'
      createTable();
    });

    loadDataButtonElement.addEventListener('click', (e) => {
      appendToTable();
    });

    hideDataButtonElement.addEventListener('click', (e) => {
      tableContainerElement.style.display = 'none';
      viewDataButtonElement.style.display = 'inline-block';
      hideDataButtonElement.style.display = 'none';
    });

  // 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';
  }
}

View raw code

charts-definition.js

Copy the following to the charts-definition.js file. This file creates the different charts using the highcharts javascript library.

// Create the charts when the web page loads
window.addEventListener('load', onload);

function onload(event){
  chartT = createTemperatureChart();
  chartH = createHumidityChart();
  chartP = createPressureChart();
}

// Create Temperature Chart
function createTemperatureChart() {
  var chart = new Highcharts.Chart({
    chart:{ 
      renderTo:'chart-temperature',
      type: 'spline' 
    },
    series: [
      {
        name: 'BME280'
      }
    ],
    title: { 
      text: undefined
    },
    plotOptions: {
      line: { 
        animation: false,
        dataLabels: { 
          enabled: true 
        }
      }
    },
    xAxis: {
      type: 'datetime',
      dateTimeLabelFormats: { second: '%H:%M:%S' }
    },
    yAxis: {
      title: { 
        text: 'Temperature Celsius Degrees' 
      }
    },
    credits: { 
      enabled: false 
    }
  });
  return chart;
}

// Create Humidity Chart
function createHumidityChart(){
  var chart = new Highcharts.Chart({
    chart:{ 
      renderTo:'chart-humidity',
      type: 'spline'  
    },
    series: [{
      name: 'BME280'
    }],
    title: { 
      text: undefined
    },    
    plotOptions: {
      line: { 
        animation: false,
        dataLabels: { 
          enabled: true 
        }
      },
      series: { 
        color: '#50b8b4' 
      }
    },
    xAxis: {
      type: 'datetime',
      dateTimeLabelFormats: { second: '%H:%M:%S' }
    },
    yAxis: {
      title: { 
        text: 'Humidity (%)' 
      }
    },
    credits: { 
      enabled: false 
    }
  });
  return chart;
}

// Create Pressure Chart
function createPressureChart() {
  var chart = new Highcharts.Chart({
    chart:{ 
      renderTo:'chart-pressure',
      type: 'spline'  
    },
    series: [{
      name: 'BME280'
    }],
    title: { 
      text: undefined
    },    
    plotOptions: {
      line: { 
        animation: false,
        dataLabels: { 
          enabled: true 
        }
      },
      series: { 
        color: '#A62639' 
      }
    },
    xAxis: {
      type: 'datetime',
      dateTimeLabelFormats: { second: '%H:%M:%S' }
    },
    yAxis: {
      title: { 
        text: 'Pressure (hPa)' 
      }
    },
    credits: { 
      enabled: false 
    }
  });
  return chart;
}

View raw code

gauges-definition.js

In our web app, we’ll display a gauge for the temperature and another for the humidity. The gauges-definition.js file contains functions to create the gauges.

// Create Temperature Gauge
function createTemperatureGauge() {
    var gauge = new LinearGauge({
        renderTo: 'gauge-temperature',
        width: 120,
        height: 400,
        units: "Temperature C",
        minValue: 0,
        startAngle: 90,
        ticksAngle: 180,
        maxValue: 40,
        colorValueBoxRect: "#049faa",
        colorValueBoxRectEnd: "#049faa",
        colorValueBoxBackground: "#f1fbfc",
        valueDec: 2,
        valueInt: 2,
        majorTicks: [
            "0",
            "5",
            "10",
            "15",
            "20",
            "25",
            "30",
            "35",
            "40"
        ],
        minorTicks: 4,
        strokeTicks: true,
        highlights: [
            {
                "from": 30,
                "to": 40,
                "color": "rgba(200, 50, 50, .75)"
            }
        ],
        colorPlate: "#fff",
        colorBarProgress: "#CC2936",
        colorBarProgressEnd: "#049faa",
        borderShadowWidth: 0,
        borders: false,
        needleType: "arrow",
        needleWidth: 2,
        needleCircleSize: 7,
        needleCircleOuter: true,
        needleCircleInner: false,
        animationDuration: 1500,
        animationRule: "linear",
        barWidth: 10,
    });
    return gauge;
}

// Create Humidity Gauge
function createHumidityGauge(){
    var gauge = new RadialGauge({
        renderTo: 'gauge-humidity',
        width: 300,
        height: 300,
        units: "Humidity (%)",
        minValue: 0,
        maxValue: 100,
        colorValueBoxRect: "#049faa",
        colorValueBoxRectEnd: "#049faa",
        colorValueBoxBackground: "#f1fbfc",
        valueInt: 2,
        majorTicks: [
            "0",
            "20",
            "40",
            "60",
            "80",
            "100"
    
        ],
        minorTicks: 4,
        strokeTicks: true,
        highlights: [
            {
                "from": 80,
                "to": 100,
                "color": "#03C0C1"
            }
        ],
        colorPlate: "#fff",
        borderShadowWidth: 0,
        borders: false,
        needleType: "line",
        colorNeedle: "#007F80",
        colorNeedleEnd: "#007F80",
        needleWidth: 2,
        needleCircleSize: 3,
        colorNeedleCircleOuter: "#007F80",
        needleCircleOuter: true,
        needleCircleInner: false,
        animationDuration: 1500,
        animationRule: "linear"
    });
    return gauge;
}

View raw code

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 Deploy web app

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.

When you first access the web app, you’ll see a form to insert the email username and password.

Firebase Web App Login Page

Insert the email and password of the authorized user you added in the Firebase Authentication methods. If the form doesn’t show up at first, refresh the web page. After that, you can access the web page with the readings.

Firebase Web app Sensor readings cards and gauges

The readings are displayed in cards, gauges, charts, and a table. You can also select which interfaces you want to see by checking/unchecking the checkboxes.

You can also check the readings displayed on charts. You can select the charts range, but keep in mind that selecting more than 30 readings will take some time.

Firebase Web app Sensor readings table with all data

Finally, if you want to see all the readings. You can open the readings table. At the end of the table, there’s a button to load more readings until all readings are displayed.

Firebase Web app Sensor readings table with all data

There is also a button to delete all data if you want to remove all readings from the database.

Firebase Web app Sensor readings table with all data delete data

Here’s a video showing how the web app works.


Wrapping Up

In this tutorial, you created a Firebase Web App with login/logout authentication that displays sensor readings in many different ways. The sensor readings are saved on the realtime database. The database is protected using database rules (that you’ve already set up in a 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.

We didn’t explain how the javascript files work because the project is quite long. However, if there is enough interest in this subject, we can split this application into smaller projects so that you understand how to handle data using queries and how to display it in different ways. Let us know what you think in the comments below.

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.



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!

187 thoughts on “ESP32/ESP8266: Firebase Data Logging Web App (Gauges, Charts, and Table)”

  1. Do you have maybe an example of Modbus RTU communication? For example: communication with HMI – reading of digital outputs, temperature measurement…

    Reply
    • Hi.
      Refresh the web page and see if the login screen shows up.
      Open the Javascript console and check if there are any error messages.
      Regards,
      Sara

      Reply
      • Hi,
        Having the same problem as Michael Walton I refreshed the web page.
        Helas no difference.
        How do I open the Javascript console in Google Chrome ?

        Thank you in advance.

        P.s. where can I find documentation if I want to alter the scripts in case I only want to upload less data to firebase and display them ?

        Greetings,

        René.

        Reply
          • Thank you Sara for your quick reply.

            The information from the console:

            auth.js:1 Failed to load resource: the server responded with a status of 404 ()
            test-1-30f43.firebaseapp.com/:1 [DOM] Input elements should have autocomplete attributes (suggested: “current-password”): (More info: https://goo.gl/9p2vKq) ​
            highcharts.src.js:226 Highcharts warning: Consider including the “accessibility.js” module to make your chart more usable for people with disabilities. Set the “accessibility.enabled” option to false to remove this warning. See https://www.highcharts.com/docs/accessibility/accessibility-module.
            (anoniem) @ highcharts.src.js:226

            I checkt the login settings in firebase -> Authentication -> sign-in method.
            It is set to Email/password.

            What do I have to change and where ?

            Greetings,

            René.

          • Hi Sara,

            I found it, there was a typo in the name of the auth-file.
            “auith.js”
            Ordered new contact lenses.
            Sorry to have bordered you with such a stupid mistake.

            Eveyithing works fine, nice project, thank you.

            Regards,

            René.

  2. Good Afternoon,
    thank you for your new project.
    I was able to show with almost no problems.
    But I have a problem with the time between the read sensor time (e.g. 17:30:54) and the time in the chart display (15:30:54), i.e. a time difference of two hours.
    In which file can I set my time zone?

    Kind Regards
    Juergen

    Reply
    • Hi.
      Yes, you just need to make sure that those devices login as an authorized user.
      Then, you can organize your database in a different way to organize the data by device.
      Regards,
      Sara

      Reply
  3. Very good project. I have almost no knowledge about Firebase and java scripts, so I had to copy everything from this web. Now I try to learn what is doing what.
    I see the first part that is collecting data and writhing to the database is the easy part and the part I know about. To be able to store the data and see it form the rest of the world has been my dream for several years. Thank you. Now I feel it is within reach to make data collection from my boat, cottage and house. The next will be to turn on heat on the cottage from my phone.

    Reply
      • Hello Svein,

        I have the same problem. Using the shift+ctl+J function in the browser I found out, that the var chartRange contains 0. This is not accepted by the function limitToLast. Something seems to be wrong around the databasepath

        var chartRef = firebase.database().ref(chartPath);

        I keep on searching. Please let me know, if or how You solved the problem.

        regards Ulli

        Reply
      • Hi Svein,

        for me the problem was solved, when I entered a number in the “number of readings” field. I simply had forgotten to do this. Now everything works fine!

        Regards Ulli

        Reply
  4. Hello
    I like your tutorials and have usually no problem with them because they are well detailed.
    But this time, I have no success with the latest tutorial.
    Following the first part of the Firebase tutorial (ESP32 Data Logging to Firebase Realtime Database), I can read the values given by the sensor on the browser page, but the second part (ESP32/ESP8266: Firebase Data Logging Web App (Gauges, Charts, and Table)) does not show any values for the sensor nor time stamps or something in the “Last update” field on the browser page.
    I must have missed something but was not able to find what it is . . . .
    Any ideas?

    Reply
  5. Uncaught ReferenceError: chartT is not defined
    at index.js:86:9
    at o (Reference.ts:253:16)
    at za.onValue (EventRegistration.ts:56:27)
    at Reference_impl.ts:850:30
    at Be (util.ts:546:5)
    at EventQueue.ts:160:7
    at ha (EventQueue.ts:128:9)
    at la (EventQueue.ts:108:3)
    at ga (Repo.ts:406:3)
    at tn.a.server_ [as onDataUpdate_] (Repo.ts:256:9)
    util.ts:556 Uncaught ReferenceError: chartT is not defined
    at index.js:86:9
    at o (Reference.ts:253:16)
    at za.onValue (EventRegistration.ts:56:27)
    at Reference_impl.ts:850:30
    at Be (util.ts:546:5)
    at EventQueue.ts:160:7
    at ha (EventQueue.ts:128:9)
    at la (EventQueue.ts:108:3)
    at ba (Repo.ts:541:3)
    at as (Reference_impl.ts:677:3)

    Reply
    • Hi.
      Make sure you’ve created all the necessary Javascript files and in the right place.
      Hard refresh your web browser after deploying your app.
      Regards,
      Sara

      Reply
  6. My problem is solved now. I followed the tutorial “ESP32 Data Logging to Firebase Realtime Database” a couple of days after it was published on the Random Nerd web site. But I found that the main.ccp file has been modified in the mean time by addition of #include “time.h”, several tempPath, time stamp, etc. . . . When using this modified main.ccp file, everything is now working.

    Reply
  7. As with Juergen above, when looking at the readings, the time stamp in the readings is correct, but the time shown on the charts is one hour less (= GMT, I live in a GMT+1 zone). Could it be that the firebase server (the one assigned to me is Europe-west1) is using GMT as basis, not taking account of the timestamp sent to it? How can I modify this to have the correct time on the charts?

    Reply
  8. Is there an easy way to show more than one value on a chart? I have adjusted the programme to read three DS18B20 sensors and would like to display all three temperatures on one graph. I am guessing it is something to do with the plotValues function in index.js?

    Reply
  9. Great project – I’m new to VS and Firebase. It’s all working for me except gauges. I realized that my gauges-definition.js file is missing from Firebase, but running “Firebase deploy” again in VS doesn’t seem to upload the missing file. Any suggestions or hints? Thanks.

    Reply
    • Hi.
      Make sure your charts-definition.js file is located in the scripts folder.
      Hard refresh your web browser after deploying.
      Regards,
      Sara

      Reply
      • When you say “Hard refresh” – is this simply closing the tab in the browser and re-opening? Do I need to close the browser and all the tabs? reboot the PC?

        I am also trying to find why the temperature is showing “76.9 C” – where should I change to show Fahrenheit?

        Reply
        • Hi.
          A hard refresh clears your browser cache for a specific page, which forces it to load the most recent version of that page. This could include new scripts, styles or features.
          If you’re using google chrome:
          Windows users: hold down Ctrl and then press F5 on your keyboard
          Mac users: hold down Cmd and Shift and then press R on your keyboard

          To show in Fahrenheit, you need to do the conversion on the code before sending the data to the database.
          Regards,
          Sara

          Reply
  10. Is there an easy way to show multiple lines on one chart. I have modified the programme to sense 3 x DS18B20 and want to show them on one graph? I am guessing the plotValues function in index.js will need modifying.

    Reply
        • In charts-definition.js

          // Create Temperature Chart
          function createTemperatureChart() {
          var chart = new Highcharts.Chart({
          chart:{
          renderTo:’chart-temperature’,
          type: ‘spline’
          },
          series: [
          {
          name: ‘DS18B20 2’,
          marker: {
          symbol: ‘square’
          }
          },
          {
          name: ‘DS18B20 3’,
          marker: {
          symbol: ‘diamond’
          }
          },
          {name: ‘DS18B20 1’,
          marker: {
          symbol: ‘triangle’
          }
          }
          ],
          title: {
          text: undefined
          },
          plotOptions: {
          line: {
          animation: false,
          dataLabels: {
          enabled: true
          }
          }
          },
          xAxis: {
          type: ‘datetime’,
          dateTimeLabelFormats: { second: ‘%H:%M:%S’ }
          },
          yAxis: {
          title: {
          text: ‘Temperature (°C)’
          }
          },
          credits: {
          enabled: false
          }

          });
          return chart;

          In index.js I have added a function to plot multiple values.

          / function to plot multiple values on charts

          function plotValuesMulti(chart, timestamp, value1, value2, value3){
          var x = epochToJsDate(timestamp).getTime();
          var y = Number (value1);
          var y2 = Number (value2);
          var y3 = Number (value3);
          if(chart.series[0].data.length > 40) {
          chart.series[0].addPoint([x, y], true, true, true);
          chart.series[1].addPoint ([x, y2], true, true, true);
          chart.series[2].addPoint ([x, y3], true, true, true);
          } else {
          chart.series[0].addPoint([x, y], true, false, true);
          chart.series[1].addPoint ([x, y2], true, false, true);
          chart.series[2].addPoint ([x, y3], true, false, true);
          }
          }

          Call the function with

          plotValuesMulti(chartT, timestamp, temperature, humidity, pressure);

          Although the variables are called temperature, humidity and pressure, they are in fact all temperature readings as I haven’t got round to changing the actual database yet.

          Reply
  11. Hi Sara
    Another great article, however there is no explanation of the code, I can see that would have made for a much longer article however.

    I am also not able to get the charts to work, I see a problem with index.js line 72
    var chartPath = ‘UsersData/’ + uid.toString() + ‘/charts/range’; as this isn’t my path, I changed it to …+’/readings’; but still no go. The error is
    util.ts:556 Uncaught Error: limitToLast: First argument must be a positive integer.
    Ie it is not getting a valid chartRange, probably coz it is not seeing any data.

    What am I doing wrong?

    I am really pleased to get the data into the cards and gauges, I have been trying for some time with no success until you published this article!
    Regards
    Bruce

    Reply
    • Hi.
      Insert a number in the “Number of readings” field, like 30 for example.
      After that, the chart should load.

      As I explained in the Wrapping Up section, the project is quite long. I’m able to write explanations about each section of the code in different tutorials if there is enough interest in these subjects.
      Regards,
      Sara

      Reply
      • Hello Sara,

        nice project, many thanks for your effort. I am not proficient at Java at all.

        I am seeing an issue with large data points. When “Number of readings” is 50 or more, the entire things fails. Any idea why?

        Reply
  12. Werry nice, is it possible for you to ad the funktion to set alarms wen reading sensors?
    Like, if a battery is charging and getting to hot.. a alarm goes off with sound and perhaps red flaching display?
    Many thanks, best regards
    /fredde

    Reply
  13. Nice write up. My first time with Firebase and it all worked as it should (almost)

    When I have run the code, I dont get any gauges. I note that in you instructions you create a gauges.definition.js file. But in the code its referenced as scripts/gauges-definition.js NOTE the hyphen- vs the dot. This causes “createTemperatureGauge is not defined” exception. I fixed the mistake, but Im still unable to see the gauges. EDIT – a hard refresh after deploy fixed the issue (ctrl + shift + R)

    Reply
    • Hi.
      The file should be called gauges-definition.js. There was a typo in the tutorial. It is fixed now.
      After changing javascript files always hard refresh your web browser.
      Regards.
      Sara

      Reply
  14. Buenas tardes
    Desde España
    Felicitaros, por vuestro inmenso trabajo.
    Acabo de realizar este proyecto muy ilusionado, pero la parte de web no me funciona, no me muestra los datos en la app. Lo he realizado 4 veces siempre con el mismo resultado.
    Me podeis ayudar
    GRACIA
    Jesús Cuesta

    Reply
      • Hola Sara
        Este proyecto es lo primero que realice y funciona correctamente esta enviando los datos y generando la tabla de los mismos.
        El problema es que cuando realice el 2º proyecto tal y como te he comentado, no me muestra ningún dato de los que estan almacenados.
        No encuentro el problema, me puede ayudar?
        Saludos cordiales

        Reply
        • Hola.

          Open your javascript console on your web browser and tell me if there are any errors.
          Additionally, double-check that you’re saving all the required javascript files on the scripts folder.

          Regards.
          Sara

          P.S. I can read and understand Spanish, but I can only write the basics.

          Reply
          • 341 / 5.000
            Resultados de traducción
            Hi Sara
            There was an error on my part in the code that entered it wrong and now it shows me the temperature and the values in the table.
            But I get 4 errors in the javascript console and it doesn’t show me the graphics, nor the widgets.
            I am attaching the errors.

            
            esp-cascosta-termico.web.app/:198
            GET https://esp-cascosta-termico.web.app/scripts/gauges-definition.js net::ERR_ABORTED 404
            esp-cascosta-termico.web.app/:198
            GET https://esp-cascosta-termico.web.app/scripts/gauges-definition.js net::ERR_ABORTED 404
            Reference_impl.ts:2020 Uncaught Error: limitToLast: First argument must be a positive integer.
            at Reference_impl.ts:2020:11
            at Cu.limitToLast (Reference.ts:400:59)
            at index.js:95:28
            at o (Reference.ts:253:16)
            at za.onValue (EventRegistration.ts:56:27)
            at Reference_impl.ts:850:30
            at Be (util.ts:546:5)
            at EventQueue.ts:160:7
            at ha (EventQueue.ts:128:9)
            at la (EventQueue.ts:108:3)
            2
            util.ts:556 Uncaught ReferenceError: createTemperatureGauge is not defined
            at index.js:167:22
            at o (Reference.ts:253:16)
            at za.onValue (EventRegistration.ts:56:27)
            at Reference_impl.ts:924:30
            at Be (util.ts:546:5)
            at EventQueue.ts:160:7
            at ha (EventQueue.ts:128:9)
            at la (EventQueue.ts:108:3)
            at ga (Repo.ts:406:3)
            at tn.a.server_ [as onDataUpdate_] (Repo.ts:256:9)

            I await your news.

            P.S. I’m glad you understand Spanish

            Hola Sara
            Ha habido un error por mi parte en el código que lo introducido mal y ahora me muestra la temperatura y los valores en la tabla.
            Pero me salen 2 errores en la consola de javascript y no me muestra los gráficos, tampoco los widgets.
            Te adjunto los errores.
            Quedo a la espera de tus noticias.

            PD. Me alegra que entiendas el español

  15. Good project — a very complex one (6 different files to create and understand, in 4 different languages, and dealing with where everything goes). There are 2 parts to this immense project: creating the code, and knowing the procedures for getting that code where it needs to live (ESP32 and the cloud). The code part is understandable at a high level, assuming one has gone through other eBooks like the webservers one, and the firebase one. The procedure is strung out over many pages and I found it hard to create a similar but different project “from scratch” – i.e. not so much the code writing part, but the procedural part. I wrote up a 3 page procedure that I’d like to share (but can’t figure out how to get a pdf into a gist; maybe there’s another way)

    Reply
    • Hi Joe.
      I already answered your question in the forum.
      To share a PDF, you can upload it to google drive and then share a link to the file, for example.
      Regards,
      Sara

      Reply
  16. Hi Sara
    Many thanks, I got the charts going, my error.

    I would for one be interested in more on the code for these examples and maybe more on different charting etc.
    Thanks
    Bruce

    Reply
  17. hai Sara
    thanks for great tutorials….

    why my ESP8266 can’t conect to firebase,
    i was make correct setup with my credential :

    // Insert Firebase project API Key
    #define API_KEY “******”
    // Insert Authorized Email and Corresponding Password
    #define USER_EMAIL “
    #define USER_PASSWORD “

    // Insert RTDB URLefine the RTDB URL
    #define DATABASE_URL “***”

    but this is error from serial print after conected to wifi, like this :
    06:56:40.573 -> Token info: type = id token, status = on request
    06:56:47.799 -> Token info: type = id token, status = error
    06:56:47.799 -> Token error: code: -1, message: connection refused
    06:56:47.799 -> Getting User UID
    06:56:47.799 -> ……………………………………….

    Reply
    • Hi.
      Wow. Your document looks great. It contains a great summary of all the important steps to create a Firebase project with the ESP32 and ESP8266.
      Thank you so much for sharing this.
      I’m sure this will be helpful for many of our readers.
      Regards,
      Sra

      Reply
      • I too cannot access the file, “Sorry, the file you have requested does not exist.” Is the link dead? I’d love to see it

        Reply
  18. 15-03-2022

    Hello dear Mr Randomnerst,
    I want to show you courtesy and decency and I am grateful that I have come to understand the Web App development around the esp8266 and esp32.

    I’ve known you for quite some time, and ran into you again on the side of my mobile phone.

    I will join the Randomnerst community from now on and next week I will buy a book and then take a course with you.

    I am proud of you…

    My thanks is great
    Mr: A.Olieberg from the Netherlands

    Reply
  19. Hi Sara, I am able to upload my sensor readings to FireBase and get them displayed on the cards. But I couldnt get the Gauges update in realtime. Is there a way that I can share you the code and get it fixed?

    Reply
    • Hi.
      What is the error that you’re getting?
      Open the JavaScript console and check if you’re getting any specific errors.
      Regards,
      Sara

      Reply
  20. Solid tutorial. Works like a champ on a laptop but no joy on an Android device, all devices are quite new (S-21 phone). All I get is the top line banner “Sensor Readings App”. Tried refreshing, then reloading the page but again no joy. Tried resizing the screen as well. Might something be missing from the Android device? As I said works great from my laptop.

    Reply
    • Hi.

      I found the issue.
      Basically, you need to make sure that index.js is fully loaded before auth.js.
      So, auth.js will only run after everything has been loaded. I wrapped all auth.js content inside:

      document.addEventListener(“DOMContentLoaded”, function(){
      });

      The auth.js file will be fixed in a few minutes.

      Let me know if this fixes the issue.

      Regards,
      Sara

      Reply
      • Hi Sara,

        I have the same issue but the modification of auth.js does not work for me. Any ideas?

        Regards,

        Stephan

        Reply
        • Hi.
          Make sure you saved the file and deployed the app again.
          Then, add refresh your web browser so that it starts using the newest js file.
          Regards,
          Sara

          Reply
  21. Hi Sara,

    I have integrated an BH1750 into Your project; if interested, I can send You the modified files all together.
    Just one problem: I am living in a GMT+2h Zone, but the Website shows (correct) GMT time which ist transferred from the ESP 32. Can You give me a hint how to change the ESP Code to send the correct timestamp for my City (GMT +2h)

    Regards, Stephan

    Reply
    • Hi. Are you referring to the time on the charts?
      To adjust the time, add the following when defining a chart:
      var chart = new Highcharts.Chart({
      time:{
      useUTC: false
      },

      chart:{ (…)
      Regards,
      Sara

      Reply
  22. How would one have multiple device send data to the firebase database? There is a lot of information going the other way, database push to many devices, but none for this scenario.

    Reply
    • Found the answer to this question in the Firebase Project Docs. They call this multi-tenancy and strongly discourage it as it can lead to serious configuration, privacy and authentication issues.

      Reply
  23. Gracias Sara por ese aporte tan maravilloso. Todo se encuentra perfectamente bien explicado y siguiendo los pasos pude hacer funcionar la aplicación.

    Sólo dos detalles se me presentaron, uno con la zona horaria en el gráfico. El cual logré corregir según menciono en uno de mis comentarios realizados.

    Por otro lado, un segundo detalle que tengo días tratando y no he podido resolver. Se trata que cuando se muestra la tabla de las lecturas, haciendo clic en el botón respectivo, el último valor se duplica cuando se hace una actualización de una nueva lectura.

    Sabes algo de ese error y como se podría resolver ?

    Reply
      • Gracias por responder…

        En el siguiente enlace puedes ver un video del error que se presenta en la carga de datos desde Firebase. Ocurre cuando se muestra y se oculta la tabla con los registros de las lecturas.

        https://youtu.be/xm_GJfEerqc

        Reply
        • Eureka !!! … Problema resuelto !!!

          var tableChildAddedListener = null;

          // Function that creates the table with the first 100 readings
          function createTable() {
          // append all data to the table
          var firstRun = true;

          $('#tbody').empty();

          if (tableChildAddedListener != null) {
          dbRef.off('child_added', tableChildAddedListener);
          }

          tableChildAddedListener = dbRef.orderByKey().limitToLast(10).on('child_added', (snapshot) =>

          Cada vez que se presiona el botón de “View all data” se agrega con el “.on” nuevamente el Listener al evento “child_added”. Eso hace que se repita el registro nuevo. Por lo tanto, lo que hago es eliminar con el “.off” el Listener antes de agregarlo.

          Me ayudó mucho el siguiente enlace:

          https://stackoverflow.com/questions/51902759/remove-off-for-firebase-listeners

          Reply
  24. Hi Sara,

    I’ve just completed installing the Sensor Readings App, you guys and gal’s did a great job putting it together.
    I had the advantage of having completed the project in the Firebase Web App book some time ago which gave me an understanding of Firebase.
    Ever since completing the Web App I took an interest in html and css and I would love to get an understanding of how the js files work in the sensor app and hopefully enough people are showing an interest to make it worthwhile putting out a “how it works tutorial” on the subject using this project.

    Thanks again for your excellent work that gives me so much enjoyment.

    Reply
    • That’s great!
      I’m glad you enjoyed the tutorial and the eBook.
      Thank you so much for your feedback.
      Regards,
      Sara

      Reply
  25. Hi Sarah, no doubt it was a great project, which required you to do lots of hard work. appreciated!

    I need one help, can you please tell me how to increase the speed of data uploading?
    I need 2 data points on chart in one second.

    Thanks

    Reply
  26. Hi Sara,
    I’ve just got back to this great app after some time and noticed that my chart time is showing actual GMT. I live in a GMT+12 zone it was probably like this when I originally got it going and I didn’t notice but who knows I played around with it after I originally installed it.
    I see your reply from 22nd April to a similar issue as follows:
    var chart = new Highcharts.Chart({
    time:{
    useUTC: false
    },
    chart:{ (…)
    Would I replace the above with useGMT:false ?
    Regards

    Mike

    Reply
  27. Hi Sara
    Thanks for another great tutorial
    Could you maybe look into how to integrate this with Google assistant so that it all can be voice controlled Would be great if I can voice request some room temperature and then switch on heater or aircon based on the answer
    Thanks

    Reply
  28. Sarah,
    Thanks for your meticulous work, this is fabulous. Modified to track on/off times of my water heater. I am a huge fan of randomnerd.

    Reply
  29. Any hint on how to change the temperature gauge from Celsius to Fahrenheit?
    I did change the scale bar values, but display still displaying as Celsius.

    Reply
    • Hi.
      Are you logging your temperature in F or C?
      If you want to display the temperature in F, it is better to save the temperature in F on the database.
      Convert the temperature in the Arduino code.
      Regards,
      Sara

      Reply
      • Hi Sara,
        I have the all the temperature converted to F and saved to Firebase. Webpage displays all temperature in F. My problem is that the temperature gauge. I am trying to display the value corresponding to the scale gauge, but i am a little off. Do you know that variable need to change, so the gauge will display properly?
        r/
        -leon

        Reply
        • Hi.
          In the gauges-definition.js file, check the settings of the temperature gauge.
          You’ll need to change the minValue and maxValue to redefine the gauge range.

          I hope this helps.

          regards,
          Sara

          Reply
          • Thanks it worked. Changes on gauges-definition.js were:
            minValue: 32
            maxValue: 100
            majorTicks: [“32″,”40″,”50″,”60″,”70″,”80″,”90″,”100”, ]
            and highlights: [ “from”: 85, “to”: 100, …

  30. This is absolutely great work. Thanks a lot for sharing – I now understand a lot better about how everything is connected and should be advancing my projects way faster now.
    Cheers!

    Reply
  31. This worked without any problems. Definitely an opus major from you. It also helped me to expand my view on Firebase. Definitely a lot more versatile than I initially thought.
    I made slight additions to your work: Added a checkbox to show/hide the password. Added Fahrenheit and mmHg to the Celsius and hPa scales (calculated in JS, did not want to mess with your JSON yet) added a tad more color to the gauges, added a pressure gauge, all small stuff actually coz your design is pretty near perfect. I may try another gauge library as i am looking for a slightly different appearance, but again. that is just dabbling in the margin. Anyway, great work, saves me a lot of time. If I had done it all myself, it would have taken me much longer and I would probably have chosen a slightly different way to persist the data for the graphs, but the way you do it is in fact more flexible and as said, expanded my view on Firebase.

    Reply
    • That’s great!
      Thanks. I’m really glad you found this tutorial helpful and that you learned a lot from it. That’s our goal with all our tutorials.
      Regards,
      Sara

      Reply
  32. Though initially I experienced no problems with this project, last 2 days, I do have a problem. I do not expect you to have the answer, but I am sharing it here, wondering if other users had this as well.
    Suddenly the page with the web-app has become incredibly slow. It loads the sensor values correctly, it loads the gauges, but then does take a loooong time to set the needles right and if I click the ‘charts’ tick-box, the page basically freezes. Happens on various browsers, on tablest, PC and phone and even on another network, and then occasionally, it works like it should again

    As i made some additions to the app, this morning i started from scratch again, new app, using your exact files….same problem.
    in another firebase webapp that does not load gauges or charts, I have no problems at all.
    If the problem was only in loading the charts, I’d suspect the highcharts link maybe being overburdened, but the delay seems to start with the sensor values needing to be put in the gauges. Odd, very odd.
    Initially I got the impression that maybe it had to do with the number of datetime records stored, but that doesn’t seem to be it.
    I will look into it a bit further, but was wondering if other people experienced similar issues.

    Still a great project though

    Reply
    • Interesting, the problem seems to be the highcharts link. If I temporarily comment that out, everything works again, no unresponsive app, and clicking the charts tickbox gives immediate response in loading the placeholders (not the graphs itself ofcourse).
      What exactly is causing this is a bit of a mystery still. Might still be a Firebase hick-up as I can also see that regularly it cannot find my favicon.
      OK, well, more sleuth work to do this weekend. When they said computers would give us more free time, it was a lie 🙂

      Reply
      • OK, think, I found it: It is definitely Highcharts and probably it can’t handle many datapoints. When I delete all points it immediately seems to work properly again. I gather points every 10 minutes, so after a day that should be 168 datapoints. That is not humungus and one would expect that the problem only arises once one wants to draw the graphics itself, but apparently something happens before that already. I will have to go to the code a bit deeper (as if i haven’t yet :-)) to see if there is anyway to solve it such that at least the delay only happens once you actually wants to show the graphs, not during loading of the of the app itself. Oh well….a challenge

        Reply
          • Yes, i think I did find it and it is kinda dumb. The amount of points to be shown in the graphs is stored in the RTDB (in the range or readings field I think it was). What i think happened is that at one time or another i entered a ‘big’ number (say 200), so that was stored. When i later reloaded the page that number caused the loading problems, but because on reload the webapp doesnt show that number, nor the graphs, the few times i did manage to reload, I did not notice that high number and immediately got stuck again when ticking the ‘charts’ tickbox. Only when i finally took a look at the RTDB did I think, perhaps that number should be a bit lower.
            No problems since.
            One could consider putting a limit on the inputbox, but that is a limitation. And the charts will load say 150 points without too much complaining…..but if you then reload the webpage that’s when the problems start.
            Well, i just see it as having learned again.

          • Hi again.
            Yes, I think it’s probably because of that.
            You need to add a small number.
            I think it worked fine whenever I tested with 50 data points.
            Regards,
            Sara

        • Hi Ed, Sara, All,

          Seems I have the same issue. my web app page works fine when I create new fresh one. When I get readings of day or two worth, the web app page loads up for ever, doesn’t even let me to choose the charts. This is with clearing cache, brows data, etc

          I suspect it has something with amount of reading/ logs. Could you please guide me how to fix the issue.

          Very nice project, I learned a lot, but it works responsive only for a day or two.

          I am dealing with Firebase IT crowd atm, in case its something slows the web app on their side.

          May Thanks
          Stef

          Reply
          • Hi.
            I think it has to do with the way we load the data on the JavaScript side.
            It goes through a loop through all the data to display it on the web page.
            Probably there are other methods to do display the data via JavaScript, but at the moment I don’t think I know how to fix the issue.
            A quick “fix” is to increase the delay time between readings and delete the data periodically, but that’s not ideal.

            Regards,
            Sara

  33. Hi Sara.
    Thanks for the code.
    Just wanted to know if I can connect more than one esp32/esp8266 to the same database. For example, temperature and vibration readings using separate esp32/esp8266, sending the sensor readings to firebase database.

    Reply
    • Hi.
      Yes, you can have multiple board interacting with the same database.
      Just make sure you use a different path for each board so that the readings don’t overwrite each other.
      Regards,
      Sara

      Reply
      • Hi. I have a ml model to detect changes in temperature, humidity and pressure. Is it possible to integrate this beautiful web app and firebase RTDB with an ml model to detect changes. If it’s possible how can its be done.
        Thank you.

        Reply
  34. Not sure if I have words enough to credit all these excellent tutorials and code samples that I’ve gone through on this website. And everything is so well described and code samples actually just works!
    I’m so thankful! You guys have save me hundred of hours. I will buy some of your E-books or just donate something to at least give something back.
    P.s.
    Got this little awesome beauty the other day, “FireBeetle Esp32-E”. Have you ever tested that one? It’s supposed to be supercheap on amps in deep sleep.

    Yet again,
    Thank you!
    /Anders

    Reply
    • Hi Anders.
      Thanks for your nice words.
      I haven’t tested that board.
      Usually, all boards advertise super low power consumption in deep sleep. But the reality usually is very different. But I haven’t experimented with that board.
      Then let me know your findings.
      Regards,
      Sara

      Reply
    • I have used the Firebeetle ESP32 – E for ESPNOW projects and it does have very low power consumption in sleep mode. There is a track to cut to enable very low power mode.

      Reply
  35. A bit disappointed on Firebase itself. If you track like 500 records it just hangs. So what’s the point? Excellent sample code here to make it work, but is it really usable in RL?
    It’s just a (very slow) mongodb more or less.

    Reply
  36. Is it possible to export the data into csv format? which part of the program do i need to add? where can I learn this?

    Reply
    • Hi.
      On your web app, open the Javascript console and check if there are any errors that might point out where the issue is.
      Regards,
      Sara

      Reply
  37. Hola Sara, excelente proyecto, me parece bárbaro la integración del desarrollo web con el mundo iot, quiero hacer una pregunta, hay posibilidad de hacerlo más automático al proyecto. Osea desde la app crear un user y password y que el esp32 tome esos datos y recién ahí empezar a enviar la data, osea, que el user y pass no sea hardcodeado por nosotros sino por medio de la app. Y la otra siguiendo con firebase, con que frecuencia es recomendable el envío y actualización de los datos en la database realtime para que Google no empieze a cobrar por el uso. Ya que en la parte 1 hablas de aumentar el tiempo de escritura, creo que es por eso. Pero de cuánto sería ese tiempo para un proyecto online 24 hours. Gracias de antemano por responder y ojalá puedas ahondar más en este proyecto ya que es súper escalable.

    Reply
  38. Hello Rui and Sara.

    This is probably one of the best internet pages on electronics projects that I have been able to see in the entire internet, I congratulate you for your excellent work.

    I already did all the steps and configurations and everything is working in an extraordinary way, your tutorials were a perfect guide to set up my project. However, there is only one thing that did not go well. On the main page the time of the readings appear fine, with my local time, even in the tables they also displayed with my local time, however in the graphs the hours appear with GMT time, which with my country, Colombia, gives a difference of + 5 hours. How could I fix that little detail?

    Thanks in advance for your help.

    Reply
  39. Nice project!

    One minor issue is that each time we have an update of data, the values of the gauges (arrows of gauges) go first to 0 and after to the updated value. For example if the temperature was 23 and the new reading (update) is 25, the arrow goes from 23 to 0 and then goes to 25, instead of going from 23 to 25 immediately. Could we do something about that?

    Also, although the “Last update: 2023/05/14 11:38:33” shows the right time, instead the time in the charts is 2 hours behind (it shows: 09:38:33) I tried to change the js file and the parameters of ntp server, but still having this issue. Any solution?

    Thank you in advance.

    Reply
  40. Saludos, excelente proyecto y muy educativo. Tengo dos consultas:

    Si he realizado ya un proyecto con Arduino UNO, al querer implementar el ESP32, para realizar las mismas funciones que con el Arduino UNO, lectura de sensores y demás. Podrían trabajar juntos, o tendría que utilizar uno y dejar el otro de lado.
    Estos valores que aparecen en las tablas, ¿también pueden ser visualizados dentro de Firebase (todos)?.

    Reply
    • Hi.
      You can use both boards, but it will be easier to just use the ESP32.
      Otherwise, you’ll need to implement a communication between both boards.

      You can access all readings on the Firebase console, on the database tab.
      Regards,
      Sara

      Reply
  41. i do all the steps exactly same as you shown but still i can only see just the heading. no login form or any other data.
    here are the error showing me on console:
    (index):34 Uncaught ReferenceError: firebase is not defined
    at (index):34:1
    (anonymous) @ (index):34
    auth.js:3 Uncaught ReferenceError: auth is not defined
    at HTMLDocument. (auth.js:3:5)

    Reply
  42. THANK YOU for such a great website/tutorials.
    I have the web page working but now am trying to understand where I need to modify to apply to my use case.
    My temperatures need to show in Fahrenheit ?
    I want to use a different ESP8266 sensor and thus change all references to HUMIDITY to pH. I have the data in the firebase database but am trying to figure out how to make the changes.
    I also would like to add additional data points.

    Reply
    • Hi.
      If you would like to show temperature in Fahrenheit, you can do it on the Arduino sketch before sending the data to the database or on the Javascript.
      In my opnion, it’s better to do that in the Arduino IDE so that all your database shows temperatures in Fahrenheit.

      If you’re using a BME280 like us, you just need to do the conversion:

      tempF = temperature *9/5 + 32;

      Regards
      Sara

      Reply
  43. Saludos,
    He realizado todos los pasos, pero no me muestran los valores en la Web, pero en Firebase. Haciéndo la primera parte, sin graficos ni cartas, todo correcto. Pero al implementarle los graficos y demas, ya no me manda los valores. ¿Que podría ser?, tal vez haya algún correo donde pueda comunicarme.

    Reply
  44. This was an awesome tutorial Sara, very well explained and the html/js code is very detailed. Reasonably quickly, I was able to adapt this and include a page navigation footer (as used on many apps) that help navigate the different screens.

    The Highcharts graph lag is where I am at at the moment. If we are to use this foundation as Blynk alternative, which I think it very well good be, we need to find a solution to reduce the time it takes to display many data points.

    Thank you
    Andrew

    Reply
  45. Hello,
    thanks a lot for this very nice tutorial. I was able to reproduce your example and make it to work, then I tried to adapt it to my project.
    Now I have the bad feeling that Firebase is really full of bugs, might be it is my mistake:
    – Especially if you put too much delay during firebase RTDB writes (like 1 minute), it stop working after a while, with a timeout error message, obviously the link to Firebase is closed
    – if you try to execute firebaseInit() without a proper Web connection, your ESP32 is stuck forever with ‘token…’ error messages.
    – when you deploy your web app (through VS code), it might take a very long time to have the app updated on the web browser. Worse, I got strange behavior like ‘index.html’ was up to date but ‘index.js’ was several releases late….. weird, I had to place a version number, visible in a displayed field, in each file, to understand which versions I was using.
    At some point, I had 3 browsers (Chrome, Firefox & Edge) looking at the app web page and they could display 3 different versions (a refresh doesn’t fix that, sometimes closing and opening the browser forces an update)
    – overall, I do not understand how you can efficiently debug all this firebase development, for me, it has been very painful.
    – I do not understand how you can rely on such a system for an important application.
    Thanks anyway for your excellent work,
    Jef

    Reply
    • Hi.
      To make sure your web browser is displaying the latest app version, you need to hard refresh your web browser for it to display the latest version.
      Learn more here: contractsafe.com/support/how-to-clear-your-browser-cache-and-hard-refresh
      Regards,
      Sara

      Reply
  46. Additional point:
    I am using the “Firebase Arduino Client For Arduino Devices” by Mobizt at rev 4.4.8 (latest)

    The readme suggest to rather use AsyncFirebaseClient ?
    I might give it a try

    Reply
  47. Dear sara, i have followed all the way this project step by step and i can see the esp32 logging info on my real time database console. but my web app isnt showing me any data on the page. on temperature humidity and pressure everything is blank. even the last update: as well.
    i dont know what i did wrong and what can i do to fix it.

    Reply
    • Hi.
      When you open your web app on the browser, open the javascript console and check if you have any error that might help you figure out what is wrong.
      Regards,
      Sara

      Reply
      • Hello, I have a similar problem. The readings in the realtime database are good but in the web app all the values appear has “undefined” except for the timestamp, that is the only value that is showing. I checked the javascript console and there is no error. I need your help please.

        Reply
  48. Hi sir,
    Great tutorial. Can I use multiple esp32/esp8266 devices to log data to this web app at the same time, and if yes what I need to do for that? How many number of readings (or how many days reading) history are stored in this setup?
    Please reply.

    Reply
  49. Hello, I am based on your code to make mine. Could you help me with some questions? It’s for my electronic engineering thesis.

    Reply
  50. Is there a way for several ESP32’s to connect to this one app and display readings on separate tabs? For example: a multi-zone heating/cooling in a home where the home would be the main page and each zone would be displayed/controlled from a separate tab.

    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.