ESP32-CAM: Display Pictures in Firebase Web App

In this guide, you’ll create a Firebase Web App to display the last picture taken with an ESP32-CAM saved in the Firebase Storage. The Web App also shows the date and time that the last photo was taken. The web app is freely hosted on Firebase servers, and you can access it from anywhere.

ESP32-CAM Display Pictures in Firebase Web App

This article is Part 2 of this previous tutorial: ESP32-CAM Save Picture in Firebase Storage. Follow that tutorial first before proceeding.

Project Overview

In this tutorial (Part 2), you’ll create a web app to display the last picture taken with the ESP32-CAM and saved on the Firebase Storage (see this previous tutorial).

The following diagram shows a high-level overview of the project we’ll build—programming the ESP32-CAM and setting up the Firebase Project with Storage was done in Part 1.

ESP32-CAM Firebase Storage Project Overview
  • 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.
  • The web application displays the last picture saved on Firebase Storage on the data/photo.jpg path.
  • It also displays info about when the picture was taken (date and time).
  • If the web page is open, and meanwhile, there’s a new picture, you need to press the Refresh button, so that it gets the new picture from the storage path.
  • Later, you can update the web app to do this automatically. For example, you can save the time the last picture was taken to Firebase Realtime Database (RTDB). You can then, detect changes on the database, and refresh the web page as needed to display the last picture (we may cover this in a future more advanced tutorial).

Prerequisites

Before you 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-CAM must be running the code provided in that tutorial so that there’s a picture saved on Firebase Storage. The Firebase Storage must be set up also as shown in the tutorial.

Enabling Anonymous User

To make the web app as simple as possible, we won’t add an authentication form to the web app. We’ll use the anonymous user method—any user can see the ESP32-CAM pictures. To do that, you need to enable an Anonymous user in your Firebase project console.

Go to your project in the Firebase console. Then, go to Authentication > Sign-In method. Click on Add new provider.

Firebase Project Add Sign In Provider

Select the Anonymous sign-in provider.

Enable anonymous sign-in Firebase

Finally, enable the Anonymous sign-in.

Enable Anonymous User Firebase

If you want to add an authentication form to your web app, you can take inspiration from this project: ESP32/ESP8266: Firebase Web App to Display Sensor Readings (with Authentication).

Installing 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 the project you created in the previous tutorial 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

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

Firebase Add Web App to Project

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 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:

  • Hosting: Configure files for Firebase Hosting and (optionally) set up GitHub Action deploys
  • Storage: Configure a security rules file for Cloud Storage

The selected options will show up with a green asterisk. Then, hit Enter.

Login Firebase Account allow Firebase CLI firebase init

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.

Login Firebase Account allow Firebase CLI firebase init

14) 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

15) Then, press Enter on the following question to select the default file for storage rules.

  • What file should be used for Storage Rules?(storage.rules). Hit Enter.
Login Firebase Account allow Firebase CLI firebase init

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 create 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 Account

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 picture saved on Firebase Storage.

index.html

Copy the following to your index.html file. This HTML file creates a simple web page that displays the last picture saved on the Firebase Storage and the time it was taken (created on this previous project).

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ESP Firebase App</title>

    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
    <link rel="stylesheet" type="text/css" href="style.css">

    <!-- The core Firebase JS SDK is always required and must be listed first -->
    <script src="https://www.gstatic.com/firebasejs/8.10.0/firebase-app.js"></script>

    <!-- TODO: Add SDKs for Firebase products that you want to use
        https://firebase.google.com/docs/web/setup#available-libraries -->
    <script src="https://www.gstatic.com/firebasejs/8.8.1/firebase-auth.js"></script>
    <script src="https://www.gstatic.com/firebasejs/8.10.0/firebase-storage.js"></script>


    <script>
    // REPLACE WITH YOUR web app's Firebase configuration
    const firebaseConfig = {
      apiKey: "",
      authDomain: "",
      databaseURL: "",
      projectId: "",
      storageBucket: "",
      messagingSenderId: "",
      appId: ""
    };
    // Initialize Firebase
    firebase.initializeApp(firebaseConfig);
    
    // Get a reference to the storage service, which is used to create references in your storage bucket
    var storage = firebase.storage();

    // Create a storage reference from our storage service
    var storageRef = storage.ref();

</script>
<script src="app.js" defer></script>

</head>
<body>
  <div class="topnav">
    <h1>ESP32-CAM Web App <i class="fas fa-camera"></i></h1>
  </div>
    <p><img id="img" width="500px"></p> 
    <p>Last picture taken: <span id="date-time"></span></p>
    <button onclick="window.location.reload();">Refresh</button>
  </body>
</html>

View raw code

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 web page’s title is ESP Firebase App, but you can change it in the following line.

<title>ESP Firebase App</title>

The following line allows us to use fontawesome icons:

<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">

Reference an external style.css file to format the HTML page.

<link rel="stylesheet" type="text/css" href="style.css">

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 Storage and Authentication.

<script src="https://www.gstatic.com/firebasejs/8.8.1/firebase-auth.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.10.0/firebase-storage.js"></script>

Then, replace the firebaseConfig object with the one you’ve gotten from this step.

const firebaseConfig = {
  apiKey: "AIzaSyA2sJiXEcOWVZqdrh348eUO3aHothDz7sE",
  authDomain: "esp-firebase-demo.firebaseapp.com",
  databaseURL: "https://esp-firebase-demo-default-rtdb.europe-west1.firebasedatabase.app",
  projectId: "esp-firebase-demo",
  storageBucket: "esp-firebase-demo.appspot.com",
  messagingSenderId: "1086300631316",
  appId: "1:1086300631316:web:316410846aaeb0bb8c9201"
};

Finally, Firebase is initialized, and we create two global variables—storage, and storageRef, that refer to Firebase Storage and a reference to the storage service.

// Initialize Firebase
firebase.initializeApp(firebaseConfig);
    
// Get a reference to the storage service, which is used to create references in your storage bucket
var storage = firebase.storage();

// Create a storage reference from our storage service
var storageRef = storage.ref();

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>ESP32-CAM Web App <i class="fas fa-camera"></i></h1>
</div>

The following line creates a paragraph with an image tag where we’ll display the picture later on. The image tag has a specific id (“img“) so that we can refer to that element in the JavaScript file by its id.

<p><img id="img" width="500px"></p>

Next, we create a paragraph to display the date and time that the picture was taken. There is a <span> tag with the date-time id where we’ll display that information later on.

<p>Last picture taken: <span id="date-time"></span></p>

Finally, there’s a button to refresh the web page (to display a new picture, if that’s the case).

<button onclick="window.location.reload();">Refresh</button>

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.

Create CSS File VS Code

Then, copy the following to the style.css file.

html {
    font-family: Arial, Helvetica, sans-serif; 
    display: inline-block; 
    text-align: center;
  }
  h1 {
    font-size: 1.8rem; 
    color: white;
  }
  p { 
    font-size: 1.2rem;
  }
  .topnav { 
    overflow: hidden; 
    background-color: #0A1128;
  }
  body {  
    margin: 0;
  }
  button{
    background-color: #034078;
    border: none;
    padding: 14px 20px;
    text-align: center;
    font-size: 20px;
    border-radius: 4px;
    transition-duration: 0.4s;
    width: 150px;
    color: white;
    cursor: pointer;
  }

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 File

Create a new file inside the public folder called app.js.

The following image show how your web app project folder structure should look like.

Firebase Project VS Code Folder File Structure

app.js

Copy the following to the app.js file you created previously.

// Reference to Picture Storage Path
var imgRef = storageRef.child('data/photo.jpg');

firebase.auth().signInAnonymously().then(function() {

  imgRef.getDownloadURL().then(function(url){
    // `url` is the download URL for 'data/photo.jpg'
    document.querySelector('img').src = url;
    
  }).catch(function(error) {
    console.error(error);
  });
});

imgRef.getMetadata()
  .then((metadata) => {
    console.log(metadata);
    date = new Date(metadata.timeCreated);
    console.log(date.getFullYear()+'-' + (date.getMonth()+1) + '-'+date.getDate());
    console.log(date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds());
    var time = (date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds());
    var writtenDate = (date.getFullYear()+'-' + (date.getMonth()+1) + '-'+date.getDate());
    document.getElementById("date-time").innerHTML = time + " at " + writtenDate;
  })
  .catch((error)=> {
    console.error(error);
  });

View raw code

This file gets the picture saved on the Firebase Storage and the time it was taken and displays that on the HTML page.

First, create a reference to a location on Firebase Storage where the picture is located. In our case, it is data/photo.jpg.

var imgRef = storageRef.child('data/photo.jpg');

To access Firebase storage, you must be signed in. For simplicity, we sign in as an anonymous user, but you can add login with email and password like in this tutorial.

firebase.auth().signInAnonymously().then(function() {

After successfully signing in, you can get the download URL for a file by calling the getDownloadURL() method on a Cloud Storage reference (imgRef).

imgRef.getDownloadURL().then(function(url){

The url is the download URL for ‘data/photo.jpg’. So, now, we can display the picture on the web page by selecting the img element.

document.querySelector('img').src = url;

Display any errors if something goes wrong in the process.

}).catch(function(error) {
  console.error(error);
});

You can find the date and time the picture was taken in its metadata. You can get the picture metadata by using the getMetadata() method on a storage reference:

imgRef.getMetadata()

We display all available metadata on the JavaScript console.

.then((metadata) => {
  console.log(metadata);

Then, we can get the date and time the picture was taken with metadata.timeCreated. So, we create a new JavaScript date object with the date and time saved on the metadata.

date = new Date(metadata.timeCreated);

To learn more about the JavaScript date object, check this.

Then, we create a variable called time that contains the time in the HH:MM:SS format:

var time = (date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds());

We create a variable called writtenDate with the YYYY/MM/DD format.

var writtenDate = (date.getFullYear()+'-' + (date.getMonth()+1) + '-'+date.getDate());

Finally, display the date and time on the HTML element with the date-time id.

document.getElementById("date-time").innerHTML = time + " at " + writtenDate;

Catch any errors if something goes wrong in the process of getting the metadata.

.catch((error)=> {
  console.error(error);
});

Deploy your App

After saving the HTML and JavaScript files, deploy your app on VS Code by running the following command.

firebase deploy

Firebase offers a free hosting service to serve your assets and web apps. Then, you can access your web app from anywhere.

The Terminal should display something as follows:

ESP32 ESP8266 Deploy Firebase Web App

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.

ESP32-CAM Firebase Web App Display Picture Smartphone

Reset your ESP32-CAM board, and it should take a new picture when it first starts. Then, click on the web app Refresh button so that it retrieves the latest picture taken.

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.

Firebase Web App Deploy History and Domains

Wrapping Up

In this tutorial, you learned how to create a Firebase Web App that interacts with Firebase Storage to display the last image taken with the ESP32-CAM.

You can apply what you learned here to display any other type of files (not just jpeg), and you can change the files in the public folder to add different functionalities and features to your project. For example, add authentication, display multiple pictures, etc.

If you want to learn more about Firebase, we recommend taking a look at our new eBook:

We have other resources related to ESP32 and ESP8266 that you may like:

Thanks for reading.



Build Web Server projects with the ESP32 and ESP8266 boards to control outputs and monitor sensors remotely. Learn HTML, CSS, JavaScript and client-server communication protocols DOWNLOAD »

Build Web Server projects with the ESP32 and ESP8266 boards to control outputs and monitor sensors remotely. Learn HTML, CSS, JavaScript and client-server communication protocols DOWNLOAD »

Recommended Resources

Build a Home Automation System from Scratch » With Raspberry Pi, ESP8266, Arduino, and Node-RED.

Home Automation using ESP8266 eBook and video course » Build IoT and home automation projects.

Arduino Step-by-Step Projects » Build 25 Arduino projects with our course, even with no prior experience!

What to Read Next…


Enjoyed this project? Stay updated by subscribing our newsletter!

31 thoughts on “ESP32-CAM: Display Pictures in Firebase Web App”

  1. Hello, in this RNT project content, the editorial content is really good, very careful, I like it very much, (you are the best) I will find a time to study the firebase account by myself, and the code department. thank you for posting this item

    Reply
  2. Very interesting project.
    But it does not upload the photo and the time / date when accessing the hosting address.
    It is possible to see the body of the html/css.

    It’s like it doesn’t access the app.js
    Any ideas or if anyone has experienced the same?
    Thank you.

    Reply
    • Hi.
      Make sure that you’ve created all the necessary files in the right places and that you’ve copied the code correctly.
      Additionally, you might need to hard refresh your web browser for the javascript changes to take effect.
      Regards,
      Sara

      Reply
    • Hi,

      Did you solve it? I just had the same issue and am actually working around it.
      In app.j, I replaced:
      “firebase.auth().signInAnonymously().then(function() {”
      with:
      “const email = “[email protected]”;
      const password = “mypassword”
      firebase.auth().signInWithEmailAndPassword(email, password).then(function() {“

      Reply
      • Hi.
        I need to fix the tutorial.
        If you use the firebase.auth().signInAnonymously().then(function() {
        You need to set up anonymous user in the authentication methods.
        Otherwise, you should log in with email and password.
        Regards,
        Sara

        Reply
  3. I have the same problems as Svein.
    The 404.html, index.html, and app.js files are in the public directory.
    Is this because I’m using the Google Console’s Spark plan and not the Blaze plan?

    Reply
    • Hi.
      It should work perfectly with the free plan.
      Do you get any errors on the JavaScript console on the web browser?
      What web browser are you using?
      Did you insert your firebaseConfig object on the HTML file?
      Regards,
      Sara

      Reply
      • Hallo.
        My browser reports the following:
        11:51:52.136 FirebaseError: Firebase Storage: User does not have permission to access ‘data/photo.jpg’. (storage/unauthorized)
        {
        “error”: {
        “code”: 403,
        “message”: “Permission denied.”
        }
        }
        app.js:16
        app.js:27:13
        https://xxxx-xxxx.web.app/app.js:27
        (Async: promise callback)
        https://xxxx-xxxx.web.app/app.js:26
        11:51:52.383 Uncaught
        Object { code: “auth/admin-restricted-operation”, message: “This operation is restricted to administrators only.”, a: null, stack: “” }
        nexttick.js:33:38

        Reply
        • Hi.
          Check that your rules in Storage are as shown below:
          rules_version = ‘2’;
          service firebase.storage {
          match /b/{bucket}/o {
          match /{allPaths=**} {
          allow read, write: if request.auth != null;
          }
          }
          }
          REgards,
          Sara

          Reply
  4. Sara,
    it is not working. The picture is not loaded on the web.
    This is web console error ….

    FirebaseError: Firebase Storage: User does not have permission to access ‘data/photo.jpg’. (storage/unauthorized)
    {
    “error”: {
    “code”: 403,
    “message”: “Permission denied.”
    }
    }
    (anonymous) @ app.js:26
    Promise.catch (async)
    (anonymous) @ app.js:25

    Reply
    • Hi.
      Check that your rules in Storage are as shown below:
      rules_version = ‘2’;
      service firebase.storage {
      match /b/{bucket}/o {
      match /{allPaths=**} {
      allow read, write: if request.auth != null;
      }
      }
      }
      REgards,
      Sara

      Reply
  5. Hallo.
    It works perfectly if you log in to the project using the anonymous sign-in method.
    It is due to app.js file in the line:
    firebase.auth().signInAnonymously().then(function()

    Reply
  6. Hallo.
    If you have logged into the project with email, then you have to change the App.js file as follows:
    firebase.auth().signInWithEmailAndPassword(email, password)
    .then((userCredential)
    It works perfectly.
    Thank you .

    Reply
    • Toni,
      Where to change the code in App.js to implement this line …

      firebase.auth().signInWithEmailAndPassword(email, password)
      .then((userCredential)

      Reply
      • Hi,
        Simply replace this line in the App.js file
        firebase.auth().signInAnonymously().then(function()
        with
        firebase.auth().signInWithEmailAndPassword(email, password)
        .then((userCredential)

        Reply
  7. Tried all the above incl signinwithemail and does’nt work
    where can I see the console (I assume its the node.js web host)
    last try , I haven’t found the console anywhere on firebase console
    ..
    }).catch(function(error) {
    console.error(error);

    Reply
  8. Hi,
    I want to get and post data to Firebase by using AT commands ESP01 via TCP/IP.
    I connected to Firebase but I can’t get or post.
    AT+CIPSTART=”TCP”,”XXXX.firebaseio.com”,80
    –> CONNECT
    OK
    AT+CIPSEND=length
    curl ‘https://xxxx.firebaseio.com/users/test.json’

    –> 404 bad request…
    Thanks for helping!

    Reply
    • Hi.
      Can you provide more details?
      If you open the JavaScript console on the web browser, do you get any errors?
      Does the image show up in the Firebase Storage Files?
      Regards,
      Sara

      Reply
      • I do not get any errors
        The image shows in the storage folder
        It just does not show in the browser… I deleted everything and started again but the image and time do not show
        Thanks

        Reply

Leave a Reply to Svein Cancel reply

Download our Free eBooks and Resources

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