{"id":110568,"date":"2025-06-12T09:39:00","date_gmt":"2025-06-12T09:39:00","guid":{"rendered":"https:\/\/randomnerdtutorials.com\/?p=110568"},"modified":"2025-06-12T15:39:45","modified_gmt":"2025-06-12T15:39:45","slug":"control-esp-gpios-firebase-web-app","status":"publish","type":"post","link":"https:\/\/randomnerdtutorials.com\/control-esp-gpios-firebase-web-app\/","title":{"rendered":"Control ESP32\/ESP8266 GPIOs from Anywhere (Firebase Web App)"},"content":{"rendered":"\n<p>In this guide, you&#8217;ll create a Firebase Web App to control the ESP32 or ESP8266 GPIOs from anywhere. The access to the web app is protected with authentication using email and password. The GPIO states are saved on the Firebase Realtime Database. The web app writes to the database to change the GPIO states and the ESP boards are listening for database changes to update the GPIO states accordingly.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" fetchpriority=\"high\" decoding=\"async\" width=\"1200\" height=\"675\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2022\/07\/ESP-Control-GPIOs-from-Anywhere-web-app.jpg?resize=1200%2C675&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Control ESP32 or ESP8266 NodeMCU GPIOs from Anywhere Firebase Web App\" class=\"wp-image-171206\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2022\/07\/ESP-Control-GPIOs-from-Anywhere-web-app.jpg?w=1280&amp;quality=100&amp;strip=all&amp;ssl=1 1280w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2022\/07\/ESP-Control-GPIOs-from-Anywhere-web-app.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2022\/07\/ESP-Control-GPIOs-from-Anywhere-web-app.jpg?resize=1024%2C576&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2022\/07\/ESP-Control-GPIOs-from-Anywhere-web-app.jpg?resize=768%2C432&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/><\/figure><\/div>\n\n\n<p class=\"rntbox rntclgray\"><em>Updated 12 June 2025<\/em><\/p>\n\n\n\n<p>This article is Part 2 of a previous tutorial. You need to complete one of the following tutorials before proceeding:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/firebase-control-esp32-gpios\/\">Control ESP32 GPIOs from Anywhere using Firebase<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/firebase-control-esp8266-nodemcu-gpios\/\">Control ESP8266 NodeMCU GPIOs from Anywhere using Firebase<\/a><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Project Overview<\/h2>\n\n\n\n<p>In this tutorial (Part 2), you&#8217;ll create a web app to control the ESP32 or ESP8266 GPIOs from anywhere. In a previous tutorial, you learned how to set the ESP32 or ESP8266 to listen to database changes and update its GPIOs accordingly. You changed the GPIO states manually on the Realtime Database using the Firebase console. Now, you&#8217;ll create your own web app, hosted on Firebase, to control your boards from anywhere.<\/p>\n\n\n\n<p>The following diagram shows a high-level overview of the project we&#8217;ll build\u2014programming the ESP32\/ESP8266 and setting up the Firebase Project was done in Part 1:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/firebase-control-esp32-gpios\/\">Part 1\u2014ESP32<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/firebase-control-esp8266-nodemcu-gpios\/\">Part 1\u2014ESP8266<\/a><\/li>\n<\/ul>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"750\" height=\"1052\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2022\/07\/Firebase-Control-Outputs-from-anywhere-web-app-project-overview-f.jpg?resize=750%2C1052&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Firebase Web App control ESP32 ESP8266 Outputs from Anywhere\" class=\"wp-image-171202\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2022\/07\/Firebase-Control-Outputs-from-anywhere-web-app-project-overview-f.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2022\/07\/Firebase-Control-Outputs-from-anywhere-web-app-project-overview-f.jpg?resize=214%2C300&amp;quality=100&amp;strip=all&amp;ssl=1 214w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2022\/07\/Firebase-Control-Outputs-from-anywhere-web-app-project-overview-f.jpg?resize=730%2C1024&amp;quality=100&amp;strip=all&amp;ssl=1 730w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<ul class=\"wp-block-list\">\n<li>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.<\/li>\n\n\n\n<li>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.<\/li>\n\n\n\n<li>After authentication, you can access a web app page that shows several buttons to change the GPIO states on the database.<\/li>\n\n\n\n<li>The ESP32 or ESP8266 is listening to database changes. When you click on the buttons, the GPIO states change on the database, and the ESP updates the states accordingly.<\/li>\n\n\n\n<li>The web app also shows what&#8217;s the current state of the GPIOs.<\/li>\n\n\n\n<li>As an example, we&#8217;ll control three GPIOs (12, 13, and 14). As mentioned in the previous tutorial, you can add\/remove more GPIOs and boards or control other GPIOs.<\/li>\n\n\n\n<li>Once you&#8217;re logged in, you can logout any time. The next time you&#8217;ll access the app you&#8217;ll need to login again.<\/li>\n<\/ul>\n\n\n\n<p>The following screenshot shows what the web page looks like on a computer web browser.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"687\" height=\"473\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2022\/04\/Control-from-Anywhere-Firebase-App-small.png?resize=687%2C473&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Control ESP GPIOs from Anywhere Web App\" class=\"wp-image-110586\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2022\/04\/Control-from-Anywhere-Firebase-App-small.png?w=687&amp;quality=100&amp;strip=all&amp;ssl=1 687w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2022\/04\/Control-from-Anywhere-Firebase-App-small.png?resize=300%2C207&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 687px) 100vw, 687px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\">Prerequisites<\/h2>\n\n\n\n<p>Before start creating the Firebase Web App, you need to check the following prerequisites.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Creating a Firebase Project<\/h3>\n\n\n\n<p>You should have followed the one the following tutorials first:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/firebase-control-esp32-gpios\/\">Control ESP32 GPIOs from Anywhere using Firebase<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/firebase-control-esp8266-nodemcu-gpios\/\">Control ESP8266 NodeMCU GPIOs from Anywhere using Firebase<\/a><\/li>\n<\/ul>\n\n\n\n<p>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.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Install Required Software<\/h3>\n\n\n\n<p>Before getting started you need to install the required software to create the Firebase Web App. Here&#8217;s a list of the software you need to install (click on the links for instructions):<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-firebase-web-app\/#install-vs-code\">Visual Studio Code<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-firebase-web-app\/#install-nodejs\">Node.JS LTS version<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-firebase-web-app\/#install-firebase-tools\">Install Firebase Tools<\/a><\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity is-style-wide\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">1) Add an App to Your Firebase Project<\/h2>\n\n\n\n<p><strong>1)<\/strong> Go to your Firebase project Console and add an app to your project by clicking on the <strong>+Add app <\/strong>button.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"740\" height=\"198\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/12\/Add-App-to-Firebase-Project.png?resize=740%2C198&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Add App to Firebase Project\" class=\"wp-image-169592\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/12\/Add-App-to-Firebase-Project.png?w=740&amp;quality=100&amp;strip=all&amp;ssl=1 740w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/12\/Add-App-to-Firebase-Project.png?resize=300%2C80&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 740px) 100vw, 740px\" \/><\/figure><\/div>\n\n\n<p><strong>2)<\/strong> Select the web app icon.<\/p>\n\n\n\n<p><strong>3)<\/strong> Give your app a name. Then, check the box next to&nbsp;<strong>\u221a Also set up Firebase Hosting for this App<\/strong>. Click <strong>Register app<\/strong>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"552\" height=\"601\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/10\/add-firebase-to-web-app-example.png?resize=552%2C601&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Firebase Add Web App to Project Hosting\" class=\"wp-image-107458\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/10\/add-firebase-to-web-app-example.png?w=552&amp;quality=100&amp;strip=all&amp;ssl=1 552w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/10\/add-firebase-to-web-app-example.png?resize=276%2C300&amp;quality=100&amp;strip=all&amp;ssl=1 276w\" sizes=\"(max-width: 552px) 100vw, 552px\" \/><\/figure><\/div>\n\n\n<p id=\"firebaseconfig-object\"><strong>4)<\/strong>&nbsp;Then, copy the&nbsp;<span class=\"rnthl rntliteral\">firebaseConfig<\/span>&nbsp;object and save it because you&#8217;ll need it later.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"666\" height=\"210\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/10\/app-firebase-config-object.png?resize=666%2C210&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"firebaseConfig\u00a0object configuration copy save\" class=\"wp-image-107462\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/10\/app-firebase-config-object.png?w=666&amp;quality=100&amp;strip=all&amp;ssl=1 666w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/10\/app-firebase-config-object.png?resize=300%2C95&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 666px) 100vw, 666px\" \/><\/figure><\/div>\n\n\n<p>After this, you can also access the&nbsp;<span class=\"rnthl rntliteral\">firebaseConfig<\/span>&nbsp;object if you go to your Project settings in your Firebase console.<\/p>\n\n\n\n<p><strong>5)<\/strong> Click&nbsp;<strong>Next<\/strong>&nbsp;on the proceeding steps, and finally on <strong>Continue to console<\/strong>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity is-style-wide\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">2) Setting Up a Firebase Web App Project (VS Code)<\/h2>\n\n\n\n<p>Follow the next steps to create a Firebase Web App Project using VS Code.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"create-project-folder\">1) Creating a Project Folder<\/h3>\n\n\n\n<p id=\"create-project-folder\"><strong>1)<\/strong> Create a folder on your computer where you want to save your Firebase project\u2014for example, <span class=\"rnthl rntliteral\"><em>Firebase-Project<\/em><\/span> on the Desktop.<\/p>\n\n\n\n<p><strong>2)<\/strong> Open VS Code. Go to <strong>File<\/strong> &gt; <strong>Open Folder&#8230;<\/strong> and select the folder you&#8217;ve just created.<\/p>\n\n\n\n<p><strong>3)<\/strong> Go to <strong>Terminal <\/strong>&gt; <strong>New Terminal<\/strong>. A new Terminal window should open on your project path.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"746\" height=\"163\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/Terminal-Window-Firebase-Folder-Project.png?resize=746%2C163&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Install Firebase Tools 2\" class=\"wp-image-106193\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/Terminal-Window-Firebase-Folder-Project.png?w=746&amp;quality=100&amp;strip=all&amp;ssl=1 746w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/Terminal-Window-Firebase-Folder-Project.png?resize=300%2C66&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 746px) 100vw, 746px\" \/><\/figure><\/div>\n\n\n<h3 class=\"wp-block-heading\" id=\"firebase-login\">2) Firebase Login<\/h3>\n\n\n\n<p><strong>4)<\/strong> On the previous Terminal window, type the following:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>firebase <\/strong>login<\/code><\/pre>\n\n\n\n<p><strong>5)<\/strong> You&#8217;ll be asked to collect CLI usage and error reporting information. Enter &#8220;<strong>n<\/strong>&#8221; and press <strong>Enter<\/strong> to deny.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"397\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/Terminal-Window-Login-Firebase-VS-Code.png?resize=750%2C397&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Login Firebase VS Code Terminal Window\" class=\"wp-image-106194\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/Terminal-Window-Login-Firebase-VS-Code.png?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/Terminal-Window-Login-Firebase-VS-Code.png?resize=300%2C159&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<p><strong>Note:<\/strong> If you are already logged in, it will show a message saying: &#8220;Already logged in as user@gmail.com&#8221;.<\/p>\n\n\n\n<p><strong>6)<\/strong> After this, it will pop up a new window on your browser to login into your firebase account.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"648\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/Login-Firebase-Account.png?resize=750%2C648&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Login Firebase Account\" class=\"wp-image-106195\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/Login-Firebase-Account.png?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/Login-Firebase-Account.png?resize=300%2C259&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<p><strong>7)<\/strong> Allow Firebase CLI to access your google account.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"875\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/Login-Firebase-Account-2.png?resize=750%2C875&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Login Firebase Account allow Firebase CLI\" class=\"wp-image-106196\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/Login-Firebase-Account-2.png?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/Login-Firebase-Account-2.png?resize=257%2C300&amp;quality=100&amp;strip=all&amp;ssl=1 257w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<p><strong>8)<\/strong> After this, Firebase CLI login should be successful. You can close the browser window.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"689\" height=\"454\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/Firebase-CLI-Login-Successful.png?resize=689%2C454&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Login Firebase Account allow Firebase CLI Login Successful\" class=\"wp-image-106197\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/Firebase-CLI-Login-Successful.png?w=689&amp;quality=100&amp;strip=all&amp;ssl=1 689w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/Firebase-CLI-Login-Successful.png?resize=300%2C198&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 689px) 100vw, 689px\" \/><\/figure><\/div>\n\n\n<h3 class=\"wp-block-heading\" id=\"init-project\">3) Initializing Web App Firebase Project<\/h3>\n\n\n\n<p><strong>9)<\/strong> After successfully login in, run the following command to start a Firebase project directory in the current folder.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>firebase <\/strong>init<\/code><\/pre>\n\n\n\n<p><strong>10)<\/strong> You&#8217;ll be asked if you want to initialize a Firebase project in the current directory. Enter <strong>Y<\/strong> and hit <strong>Enter<\/strong>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"684\" height=\"187\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/Firebase-Start-Project-VS-Code.png?resize=684%2C187&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Login Firebase Account allow Firebase CLI firebase init\" class=\"wp-image-106199\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/Firebase-Start-Project-VS-Code.png?w=684&amp;quality=100&amp;strip=all&amp;ssl=1 684w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/Firebase-Start-Project-VS-Code.png?resize=300%2C82&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 684px) 100vw, 684px\" \/><\/figure><\/div>\n\n\n<p><strong>11)<\/strong> Then, use up and down arrows and the Space key to select the options. Select the following options:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Realtime Database<\/strong>: Configure security rules file for Realtime Database and (optionally) provision default instance.  <\/li>\n\n\n\n<li><strong>Hosting<\/strong>: Configure files for Firebase Hosting and (optionally) set up GitHub Action deploys<\/li>\n<\/ul>\n\n\n\n<p>The selected options will show up with a green asterisk. Then, hit <strong>Enter<\/strong>. <\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"186\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/realtime-database-hosting-options.png?resize=750%2C186&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Login Firebase Account allow Firebase CLI configure directory\" class=\"wp-image-106239\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/realtime-database-hosting-options.png?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/realtime-database-hosting-options.png?resize=300%2C74&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<p><strong>12)<\/strong> Select the option &#8220;Use an existing project&#8221;\u2014it should be highlighted in blue\u2014then, hit Enter.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"658\" height=\"228\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/Firebase-Project-Setup-VS-Code.png?resize=658%2C228&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Firebase Project Setup VS Code\" class=\"wp-image-106201\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/Firebase-Project-Setup-VS-Code.png?w=658&amp;quality=100&amp;strip=all&amp;ssl=1 658w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/Firebase-Project-Setup-VS-Code.png?resize=300%2C104&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 658px) 100vw, 658px\" \/><\/figure><\/div>\n\n\n<p><strong>13)<\/strong> After that, select the Firebase project for this directory\u2014it should be <strong>the<a href=\"https:\/\/randomnerdtutorials.com\/firebase-control-esp32-gpios\/\" title=\"\"> project created in Part 1<\/a><\/strong>. Then hit <strong>Enter<\/strong>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"662\" height=\"174\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/select-firebase-project-VS-Code.png?resize=662%2C174&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Select Firebase Project on VS Code\" class=\"wp-image-170134\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/select-firebase-project-VS-Code.png?w=662&amp;quality=100&amp;strip=all&amp;ssl=1 662w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/select-firebase-project-VS-Code.png?resize=300%2C79&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 662px) 100vw, 662px\" \/><\/figure><\/div>\n\n\n<p><strong>14)<\/strong> Then, select the hosting options as shown below:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>What do you want to use as your public directory? Hit <strong>Enter <\/strong>to select <strong>public<\/strong>.<\/li>\n\n\n\n<li>Configure as a single-page app (rewrite urls to \/index.html)? <strong>No<\/strong><\/li>\n\n\n\n<li>Set up automatic builds and deploys with GitHub? <strong>No<\/strong><\/li>\n<\/ul>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"657\" height=\"277\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/firebase-hosting-setup-all-options.png?resize=657%2C277&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Firebase initialization complete\" class=\"wp-image-106240\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/firebase-hosting-setup-all-options.png?w=657&amp;quality=100&amp;strip=all&amp;ssl=1 657w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/firebase-hosting-setup-all-options.png?resize=300%2C126&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 657px) 100vw, 657px\" \/><\/figure><\/div>\n\n\n<p><strong>15)<\/strong> Press <strong>Enter <\/strong>on the following question to select the default database security rules file: &#8220;<strong>What file should be used for Realtime Database Security Rules?<\/strong>&#8220;<\/p>\n\n\n\n<p><strong>16)<\/strong> The Firebase project should now be initialized successfully. Notice that VS Code created some essential files under your project folder.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"382\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/firebase-project-app-created-successfully.png?resize=750%2C382&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Firebase Project Files Created successfully\" class=\"wp-image-106297\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/firebase-project-app-created-successfully.png?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/firebase-project-app-created-successfully.png?resize=300%2C153&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<p>The <span class=\"rnthl rntliteral\">index.html<\/span> 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&#8217;ll do that later in this tutorial.<\/p>\n\n\n\n<p><strong>17)<\/strong> To check if everything went as expected, run the following command on the VS Code Terminal window.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>firebase <\/strong>deploy<\/code><\/pre>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"713\" height=\"384\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2022\/02\/deploy-firebase-project.png?resize=713%2C384&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Firebase App First Deploy Testing\" class=\"wp-image-170137\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2022\/02\/deploy-firebase-project.png?w=713&amp;quality=100&amp;strip=all&amp;ssl=1 713w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2022\/02\/deploy-firebase-project.png?resize=300%2C162&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 713px) 100vw, 713px\" \/><\/figure><\/div>\n\n\n<p>You should get a <strong>Deploy complete!<\/strong> message and a URL to the Project Console and the Hosting URL.<\/p>\n\n\n\n<p><strong>18)<\/strong> 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.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"740\" height=\"534\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2022\/02\/Firebase-Hosting-Setup-Complete.png?resize=740%2C534&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Firebase Hosting Setup Complete\" class=\"wp-image-170138\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2022\/02\/Firebase-Hosting-Setup-Complete.png?w=740&amp;quality=100&amp;strip=all&amp;ssl=1 740w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2022\/02\/Firebase-Hosting-Setup-Complete.png?resize=300%2C216&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 740px) 100vw, 740px\" \/><\/figure><\/div>\n\n\n<p>The web page you&#8217;ve seen previously is built with the HTML file placed in the <span class=\"rnthl rntliteral\">public<\/span> folder of your Firebase project. By changing the content of that file, you can create your own web app. That&#8217;s what we&#8217;re going to do in the next section.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity is-style-wide\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">3) Creating the Firebase Web App<\/h2>\n\n\n\n<p>Now that you&#8217;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.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">index.html<\/h3>\n\n\n\n<p>Copy the following to your <span class=\"rnthl rntliteral\">index.html<\/span> file. This HTML file creates a simple web page with ON and OFF buttons to control GPIOs 12, 13, and 14.<\/p>\n\n\n\n<p>If you aren&#8217;t authenticated, it shows a login form. When you authenticate with an authorized user email and corresponding password, it shows the user interface with the buttons.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-html\">&lt;!DOCTYPE html&gt;\n&lt;!-- Complete Project Details at: https:\/\/RandomNerdTutorials.com\/ --&gt;\n&lt;html&gt;\n  &lt;head&gt;\n    &lt;meta charset=&quot;utf-8&quot;&gt;\n    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&gt;\n    &lt;title&gt;ESP IoT Firebase App&lt;\/title&gt;\n    &lt;link rel=&quot;stylesheet&quot; href=&quot;https:\/\/use.fontawesome.com\/releases\/v5.7.2\/css\/all.css&quot; integrity=&quot;sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr&quot; crossorigin=&quot;anonymous&quot;&gt;\n    &lt;link rel=&quot;icon&quot; type=&quot;image\/png&quot; href=&quot;favicon.png&quot;&gt;\n    &lt;link rel=&quot;stylesheet&quot; type=&quot;text\/css&quot; href=&quot;style.css&quot;&gt;\n  &lt;\/head&gt;\n  &lt;body&gt;\n    &lt;div class=&quot;topnav&quot;&gt;\n      &lt;h1&gt;ESP GPIO Control &lt;i class=&quot;fas fa-lightbulb&quot;&gt;&lt;\/i&gt;&lt;\/h1&gt;\n    &lt;\/div&gt;\n    &lt;div id=&quot;authentication-bar&quot; style=&quot;display: none;&quot;&gt;\n      &lt;p&gt;&lt;span id=&quot;authentication-status&quot;&gt;User logged in&lt;\/span&gt;\n         &lt;span id=&quot;user-details&quot;&gt;USEREMAIL&lt;\/span&gt;\n         &lt;a href=&quot;\/&quot; id=&quot;logout-link&quot;&gt;(logout)&lt;\/a&gt;\n      &lt;\/p&gt;\n    &lt;\/div&gt;\n    &lt;form id=&quot;login-form&quot; style=&quot;display: none;&quot;&gt;\n      &lt;div class=&quot;form-elements-container&quot;&gt;\n        &lt;label for=&quot;input-email&quot;&gt;&lt;b&gt;Email&lt;\/b&gt;&lt;\/label&gt;\n        &lt;input type=&quot;text&quot; placeholder=&quot;Enter Username&quot; id=&quot;input-email&quot; required&gt;\n        &lt;label for=&quot;input-password&quot;&gt;&lt;b&gt;Password&lt;\/b&gt;&lt;\/label&gt;\n        &lt;input type=&quot;password&quot; placeholder=&quot;Enter Password&quot; id=&quot;input-password&quot; required&gt;\n        &lt;button type=&quot;submit&quot; id=&quot;login-button&quot;&gt;Login&lt;\/button&gt;\n        &lt;p id=&quot;error-message&quot; style=&quot;color:red;&quot;&gt;&lt;\/p&gt;\n      &lt;\/div&gt;\n    &lt;\/form&gt;\n    &lt;div class=&quot;content-sign-in&quot; id=&quot;content-sign-in&quot; style=&quot;display: none;&quot;&gt;\n      &lt;div class=&quot;card-grid&quot;&gt;\n        &lt;div class=&quot;card&quot;&gt;\n          &lt;p class=&quot;card-title&quot;&gt;&lt;i class=&quot;fas fa-lightbulb&quot;&gt;&lt;\/i&gt; GPIO 12&lt;\/p&gt;\n          &lt;p&gt;\n            &lt;button class=&quot;button-on&quot; id=&quot;btn1On&quot;&gt;ON&lt;\/button&gt;\n            &lt;button class=&quot;button-off&quot; id=&quot;btn1Off&quot;&gt;OFF&lt;\/button&gt;\n          &lt;\/p&gt;\n          &lt;p class=&quot;state&quot;&gt;State:&lt;span id=&quot;state1&quot;&gt;&lt;\/span&gt;&lt;\/p&gt;\n        &lt;\/div&gt;\n        &lt;div class=&quot;card&quot;&gt;\n          &lt;p class=&quot;card-title&quot;&gt;&lt;i class=&quot;fas fa-lightbulb&quot;&gt;&lt;\/i&gt; GPIO 13&lt;\/p&gt;\n          &lt;p&gt;\n            &lt;button class=&quot;button-on&quot; id=&quot;btn2On&quot;&gt;ON&lt;\/button&gt;\n            &lt;button class=&quot;button-off&quot; id=&quot;btn2Off&quot;&gt;OFF&lt;\/button&gt;\n          &lt;\/p&gt;\n          &lt;p class=&quot;state&quot;&gt;State:&lt;span id=&quot;state2&quot;&gt;&lt;\/span&gt;&lt;\/p&gt;\n        &lt;\/div&gt;\n        &lt;div class=&quot;card&quot;&gt;\n          &lt;p class=&quot;card-title&quot;&gt;&lt;i class=&quot;fas fa-lightbulb&quot;&gt;&lt;\/i&gt; GPIO 14&lt;\/p&gt;\n          &lt;p&gt;\n            &lt;button class=&quot;button-on&quot; id=&quot;btn3On&quot;&gt;ON&lt;\/button&gt;\n            &lt;button class=&quot;button-off&quot; id=&quot;btn3Off&quot;&gt;OFF&lt;\/button&gt;\n          &lt;\/p&gt;\n          &lt;p class=&quot;state&quot;&gt;State:&lt;span id=&quot;state3&quot;&gt;&lt;\/span&gt;&lt;\/p&gt;\n        &lt;\/div&gt;\n      &lt;\/div&gt;\n    &lt;\/div&gt;\n    &lt;script type=&quot;module&quot; src=&quot;scripts\/index.js&quot;&gt;&lt;\/script&gt;\n    &lt;script type=&quot;module&quot; src=&quot;scripts\/auth.js&quot;&gt;&lt;\/script&gt;\n  &lt;\/body&gt;\n&lt;\/html&gt;\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Firebase-ESP\/raw\/main\/ESP-Firebase-Control-GPIOs-Anywhere\/Web-App\/index.html\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<h4 class=\"wp-block-heading\">How it Works<\/h4>\n\n\n\n<p>Let&#8217;s take a quick look at the HTML file, or skip to the next section.<\/p>\n\n\n\n<p>In the <span class=\"rnthl rntliteral\"><span style=\"color: #333399;\">&lt;head&gt;<\/span><\/span> of the HTML file, we must add all the required metadata.<\/p>\n\n\n\n<p>The title of the web page is <strong>ESP Firebase App<\/strong>, but you can change it in the following line.<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;title&gt;ESP Firebase App&lt;\/title&gt;<\/code><\/pre>\n\n\n\n<p>The following line allows us to use <a href=\"https:\/\/fontawesome.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">fontawesome icons<\/a>:<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;link rel=\"stylesheet\" href=\"https:\/\/use.fontawesome.com\/releases\/v5.7.2\/css\/all.css\" integrity=\"sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr\" crossorigin=\"anonymous\"&gt;<\/code><\/pre>\n\n\n\n<p>The next includes a <a href=\"https:\/\/github.com\/RuiSantosdotme\/build-web-servers-dl\/raw\/main\/favicon.zip\" target=\"_blank\" rel=\"noreferrer noopener\">favicon<\/a> on our web page.<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;link rel=\"icon\" type=\"image\/png\" href=\"favicon.png\"&gt;<\/code><\/pre>\n\n\n\n<p>Finally, reference an external <span class=\"rnthl rntliteral\">style.css<\/span> file to format the HTML page.<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;link rel=\"stylesheet\" type=\"text\/css\" href=\"style.css\"&gt;<\/code><\/pre>\n\n\n\n<p>We&#8217;re done with the metadata. Now, let&#8217;s go to the HTML parts that are visible to the user\u2014go between the <span class=\"rnthl rntliteral\"><span style=\"color: #333399;\">&lt;body&gt;<\/span><\/span> and <span class=\"rnthl rntliteral\"><span style=\"color: #333399;\">&lt;\/body&gt;<\/span><\/span> tags.<\/p>\n\n\n\n<p>We create a top &#8220;navigation&#8221; bar with the name of our app and a small icon from fontawesome.<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;!--TOP BAR--&gt;\n&lt;div class=\"topnav\"&gt;\n  &lt;h1&gt;ESP GPIO Control &lt;i class=\"fas fa-lightbulb\"&gt;&lt;\/i&gt;&lt;\/h1&gt;\n&lt;\/div&gt;<\/code><\/pre>\n\n\n\n<p>The following lines create a bar with the details of the authenticated user (email). It also shows a logout link to log out the user. <\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;div id=\"authentication-bar\" style=\"display: none;\"&gt;\n  &lt;p&gt;&lt;span id=\"authentication-status\"&gt;User logged in&lt;\/span&gt;\n     &lt;span id=\"user-details\"&gt;USEREMAIL&lt;\/span&gt;\n     &lt;a href=\"\/\" id=\"logout-link\"&gt;(logout)&lt;\/a&gt;\n  &lt;\/p&gt;\n&lt;\/div&gt;<\/code><\/pre>\n\n\n\n<p>First, we set the display style of all elements to <span class=\"rnthl rntliteral\">none<\/span>. We&#8217;ll hide and show content depending if the user is authenticated or not\u2014we&#8217;ll handle that using JavaScript.<\/p>\n\n\n\n<p>Next, the following lines create the login form with an input field for the email and an input field for the password:<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;form id=\"login-form\" style=\"display: none;\"&gt;  \n  &lt;div class=\"form-elements-container\"&gt;\n    &lt;label for=\"input-email\"&gt;&lt;b&gt;Email&lt;\/b&gt;&lt;\/label&gt;\n    &lt;input type=\"text\" placeholder=\"Enter Username\" id=\"input-email\" required&gt;\n  \n    &lt;label for=\"input-password\"&gt;&lt;b&gt;Password&lt;\/b&gt;&lt;\/label&gt;\n    &lt;input type=\"password\" placeholder=\"Enter Password\" id=\"input-password\" required&gt;\n          \n    &lt;button type=\"submit\" id=\"login-button\"&gt;Login&lt;\/button&gt;\n    &lt;p id=\"error-message\" style=\"color:red;\"&gt;&lt;\/p&gt;\n  &lt;\/div&gt;\n&lt;\/form&gt;<\/code><\/pre>\n\n\n\n<p>Inside the form, there&#8217;s also a paragraph to display an error message if the login fails.<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;p id=\"error-message\" style=\"color:red;\"&gt;&lt;\/p&gt;<\/code><\/pre>\n\n\n\n<p>Finally, we create a grid to display different cards for the GPIOs.<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;div class=\"content-sign-in\" id=\"content-sign-in\" style=\"display: none;\"&gt;\n  &lt;div class=\"card-grid\"&gt;<\/code><\/pre>\n\n\n\n<p>For example, the following lines create a card for GPIO 12:<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;div class=\"card\"&gt;\n  &lt;p class=\"card-title\"&gt;&lt;i class=\"fas fa-lightbulb\"&gt;&lt;\/i&gt; GPIO 12&lt;\/p&gt;\n  &lt;p&gt;\n    &lt;button class=\"button-on\" id=\"btn1On\"&gt;ON&lt;\/button&gt;\n    &lt;button class=\"button-off\" id=\"btn1Off\"&gt;OFF&lt;\/button&gt;\n  &lt;\/p&gt;\n  &lt;p class=\"state\"&gt;State:&lt;span id=\"state1\"&gt;&lt;\/span&gt;&lt;\/p&gt;\n&lt;\/div&gt;<\/code><\/pre>\n\n\n\n<p>The buttons have specific ids so that we can refer to them later on in the Javascript files. There&#8217;s also a span tag with a specific id to insert the GPIO state.<\/p>\n\n\n\n<p>Creating the cards for the other GPIOs is similar:<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;div class=\"card\"&gt;\n  &lt;p class=\"card-title\"&gt;&lt;i class=\"fas fa-lightbulb\"&gt;&lt;\/i&gt; GPIO 13&lt;\/p&gt;\n  &lt;p&gt;\n    &lt;button class=\"button-on\" id=\"btn2On\"&gt;ON&lt;\/button&gt;\n    &lt;button class=\"button-off\" id=\"btn2Off\"&gt;OFF&lt;\/button&gt;\n  &lt;\/p&gt;\n  &lt;p class=\"state\"&gt;State:&lt;span id=\"state2\"&gt;&lt;\/span&gt;&lt;\/p&gt;\n&lt;\/div&gt;\n&lt;div class=\"card\"&gt;\n  &lt;p class=\"card-title\"&gt;&lt;i class=\"fas fa-lightbulb\"&gt;&lt;\/i&gt; GPIO 14&lt;\/p&gt;\n  &lt;p&gt;\n    &lt;button class=\"button-on\" id=\"btn3On\"&gt;ON&lt;\/button&gt;\n    &lt;button class=\"button-off\" id=\"btn3Off\"&gt;OFF&lt;\/button&gt;\n  &lt;\/p&gt;\n  &lt;p class=\"state\"&gt;State:&lt;span id=\"state3\"&gt;&lt;\/span&gt;&lt;\/p&gt;\n&lt;\/div&gt;<\/code><\/pre>\n\n\n\n<p>It&#8217;s important to keep in mind the ids of each of those elements, so that&#8217;s its easier to identify them on the JavaScript file. You can use any other ids that make sense for your project.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td><\/td><td><strong>GPIO 12<\/strong><\/td><td><strong>GPIO 13<\/strong><\/td><td><strong>GPIO 14<\/strong><\/td><\/tr><tr><td><strong>ON Button<\/strong><\/td><td><span class=\"rnthl rntliteral\">btn1On<\/span><\/td><td><span class=\"rnthl rntliteral\">btn2On<\/span><\/td><td><span class=\"rnthl rntliteral\">btn3On<\/span><\/td><\/tr><tr><td><strong>OFF Button<\/strong><\/td><td><span class=\"rnthl rntliteral\">btn1Off<\/span><\/td><td><span class=\"rnthl rntliteral\">btn2Off<\/span><\/td><td><span class=\"rnthl rntliteral\">btn3Off<\/span><\/td><\/tr><tr><td><strong>State<\/strong><\/td><td><span class=\"rnthl rntliteral\">state1<\/span><\/td><td><span class=\"rnthl rntliteral\">state2<\/span><\/td><td><span class=\"rnthl rntliteral\">state3<\/span><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Finally, we need to add references to the external JavaScript files. For our application, we&#8217;ll create two JavaScript files: <span class=\"rnthl rntliteral\">auth.js<\/span> (that handles everything related to the authentication) and <span class=\"rnthl rntliteral\">index.js<\/span> that handles everything related to the UI. We&#8217;ll create those files inside a folder called <span class=\"rnthl rntliteral\">scripts<\/span> inside the <span class=\"rnthl rntliteral\">public<\/span> folder of our application.<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;script type=\"module\" src=\"scripts\/index.js\"&gt;&lt;\/script&gt;\n&lt;script type=\"module\" src=\"scripts\/auth.js\"&gt;&lt;\/script&gt;<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">style.css<\/h3>\n\n\n\n<p>Inside the <span class=\"rnthl rntliteral\">public<\/span> folder create a file called <span class=\"rnthl rntliteral\">style.css<\/span>. To create the file, select the <span class=\"rnthl rntliteral\">public<\/span> folder, and then click on the <strong>+file<\/strong> icon at the top of the File Explorer. Call it <span class=\"rnthl rntliteral\">style.css<\/span>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"578\" height=\"277\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/10\/Firebase-Project-VS-Code-CSS-File.png?resize=578%2C277&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Create CSS File VS Code\" class=\"wp-image-107545\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/10\/Firebase-Project-VS-Code-CSS-File.png?w=578&amp;quality=100&amp;strip=all&amp;ssl=1 578w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/10\/Firebase-Project-VS-Code-CSS-File.png?resize=300%2C144&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 578px) 100vw, 578px\" \/><\/figure><\/div>\n\n\n<p>Then, copy the following to the <span class=\"rnthl rntliteral\">style.css<\/span> file<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-css\">html {\r\n    font-family: Verdana, Geneva, Tahoma, sans-serif;\r\n    display: inline-block;\r\n    text-align: center;\r\n}\r\nh1 {\r\n    font-size: 1.8rem;\r\n    color: white;\r\n}\r\n.topnav {\r\n    overflow: hidden;\r\n    background-color: #049faa;\r\n    color: white;\r\n    font-size: 1rem;\r\n    padding: 10px;\r\n}\r\n#authentication-bar{\r\n    background-color:mintcream;\r\n    padding-top: 10px;\r\n    padding-bottom: 10px;\r\n}\r\n\r\n#user-details{\r\n    color: cadetblue;\r\n}\r\n\r\n.content {\r\n    padding: 20px;\r\n}\r\n\r\nbody {\r\n    margin: 0;\r\n}\r\n\r\n.card-grid {\r\n    max-width: 800px;\r\n    margin: 0 auto;\r\n    display: grid;\r\n    grid-gap: 2rem;\r\n    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\r\n}\r\n.card {\r\n    background-color: white;\r\n    box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);\r\n}\r\n\r\n.card-title {\r\n    font-size: 1.2rem;\r\n    color: #034078\r\n}\r\n.state {\r\n    color:#1282A2;\r\n}\r\nbutton {\r\n    background-color: #049faa;\r\n    color: white;\r\n    padding: 14px 20px;\r\n    margin: 8px 0;\r\n    border: none;\r\n    cursor: pointer;\r\n    border-radius: 4px;\r\n}\r\n.button-on {\r\n    background-color:#034078;\r\n}\r\n.button-on:hover {\r\n    background-color: #1282A2;\r\n}\r\n.button-off {\r\n    background-color:#858585;\r\n}\r\n.button-off:hover {\r\n    background-color: #252524;\r\n}\r\n\r\n.form-elements-container{\r\n    padding: 16px;\r\n    width: 250px;\r\n    margin: 0 auto;\r\n}\r\n\r\ninput[type=text], input[type=password] {\r\n    width: 100%;\r\n    padding: 12px 20px;\r\n    margin: 8px 0;\r\n    display: inline-block;\r\n    border: 1px solid #ccc;\r\n    box-sizing: border-box;\r\n}<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Firebase-ESP\/raw\/main\/ESP-Firebase-Control-GPIOs-Anywhere\/Web-App\/style.css\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<p>The CSS file includes some simple styles to make our webpage look better. We won&#8217;t discuss how CSS works in this tutorial. You can easily modify the CSS file to change the colors and font size, for example.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">JavaScript Files<\/h3>\n\n\n\n<p>We&#8217;ll create two JavaScript files (<span class=\"rnthl rntliteral\">auth.js<\/span> and <span class=\"rnthl rntliteral\">index.js<\/span>) inside a <span class=\"rnthl rntliteral\">scripts<\/span> folder inside the <span class=\"rnthl rntliteral\">public<\/span> folder.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Select the <span class=\"rnthl rntliteral\">public<\/span> folder, then click on the <strong>+folder<\/strong> icon to create a new folder. Call <span class=\"rnthl rntliteral\">scripts<\/span> to that new folder.<\/li>\n\n\n\n<li>Then, select the <span class=\"rnthl rntliteral\">scripts<\/span> folder and click on the <strong>+file<\/strong> icon. Create a file called <span class=\"rnthl rntliteral\">auth.js<\/span>. Then, repeat the previous steps to create an <span class=\"rnthl rntliteral\">index.js<\/span>.<\/li>\n<\/ul>\n\n\n\n<p>The following image shows how your web app project folder structure should look like.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"586\" height=\"288\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/10\/Firebase-Project-VS-Code-Folder-File-Structure.png?resize=586%2C288&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Firebase Project VS Code Folder File Structure\" class=\"wp-image-107546\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/10\/Firebase-Project-VS-Code-Folder-File-Structure.png?w=586&amp;quality=100&amp;strip=all&amp;ssl=1 586w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/10\/Firebase-Project-VS-Code-Folder-File-Structure.png?resize=300%2C147&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 586px) 100vw, 586px\" \/><\/figure><\/div>\n\n\n<h4 class=\"wp-block-heading\">auth.js<\/h4>\n\n\n\n<p>Now let&#8217;s implement user sign-in using Firebase authentication. We&#8217;ll implement sign-in using email and password.<\/p>\n\n\n\n<p>Copy the following to the <span class=\"rnthl rntliteral\">auth.js<\/span> file you created previously. <\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-javascript\">import { auth, setupUI } from &quot;.\/index.js&quot;;\r\nimport { signInWithEmailAndPassword, signOut, onAuthStateChanged } from &quot;https:\/\/www.gstatic.com\/firebasejs\/11.6.0\/firebase-auth.js&quot;;\r\n\r\ndocument.addEventListener(&quot;DOMContentLoaded&quot;, () =&gt; {\r\n  \/\/ Listen for auth status changes\r\n  onAuthStateChanged(auth, (user) =&gt; {\r\n    if (user) {\r\n      console.log(&quot;User logged in:&quot;, user.email);\r\n      setupUI(user);\r\n    } else {\r\n      console.log(&quot;User logged out&quot;);\r\n      setupUI(null);\r\n    }\r\n  });\r\n\r\n  \/\/ Login\r\n  const loginForm = document.querySelector('#login-form');\r\n  loginForm.addEventListener('submit', async (e) =&gt; {\r\n    e.preventDefault();\r\n    const email = loginForm['input-email'].value;\r\n    const password = loginForm['input-password'].value;\r\n    try {\r\n      await signInWithEmailAndPassword(auth, email, password);\r\n      loginForm.reset();\r\n      console.log(&quot;Logged in:&quot;, email);\r\n    } catch (error) {\r\n      document.getElementById(&quot;error-message&quot;).textContent = error.message;\r\n      console.error(&quot;Login error:&quot;, error.message);\r\n    }\r\n  });\r\n\r\n  \/\/ Logout\r\n  const logoutLink = document.querySelector('#logout-link');\r\n  logoutLink.addEventListener('click', async (e) =&gt; {\r\n    e.preventDefault();\r\n    try {\r\n      await signOut(auth);\r\n      console.log(&quot;User signed out&quot;);\r\n    } catch (error) {\r\n      console.error(&quot;Logout error:&quot;, error.message);\r\n    }\r\n  });\r\n});\r\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Firebase-ESP\/raw\/main\/ESP-Firebase-Control-GPIOs-Anywhere\/Web-App\/scripts\/auth.js\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<p>Then, save the file. This file takes care of everything related to the login and logout of the user. Continue reading to learn how the code works, or skip to the next section.<\/p>\n\n\n\n<p>First, we import the required functions and modules from the index.js file (that we&#8217;ll create later) and from the Firebase JavaScript Library.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>import { auth, setupUI } from \".\/index.js\";\nimport { signInWithEmailAndPassword, signOut, onAuthStateChanged } from \"https:\/\/www.gstatic.com\/firebasejs\/11.6.0\/firebase-auth.js\";<\/code><\/pre>\n\n\n\n<p><strong>Login<\/strong><\/p>\n\n\n\n<p>The following lines are responsible for logging in the user.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code> \/\/ Login\nconst loginForm = document.querySelector('#login-form');\nloginForm.addEventListener('submit', async (e) =&gt; {\n  e.preventDefault();\n  const email = loginForm&#091;'input-email'].value;\n  const password = loginForm&#091;'input-password'].value;\n  try {\n    await signInWithEmailAndPassword(auth, email, password);\n    loginForm.reset();\n    console.log(\"Logged in:\", email);\n  } catch (error) {\n    document.getElementById(\"error-message\").textContent = error.message;\n    console.error(\"Login error:\", error.message);\n  }\n});<\/code><\/pre>\n\n\n\n<p>We create a variable that refers to the login form HTML element called <span class=\"rnthl rntliteral\">loginForm<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>const loginForm = document.querySelector('#login-form');<\/code><\/pre>\n\n\n\n<p>If you go back to the <span class=\"rnthl rntliteral\">index.html<\/span> file, you can see that the form has the <span class=\"rnthl rntliteral\">login-form<\/span> id.<\/p>\n\n\n\n<p>We add an event listener of type <span class=\"rnthl rntliteral\">submit<\/span> to the form. This means that the subsequent instructions will run whenever the form is submitted.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>loginForm.addEventListener('submit', (e) =&gt; {<\/code><\/pre>\n\n\n\n<p>You can get the submitted data as follows.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>const email = loginForm&#091;'input-email'].value;\nconst password = loginForm&#091;'input-password'].value;<\/code><\/pre>\n\n\n\n<p>If you go back to the HTML file, you&#8217;ll see that the input fields contain the following ids: <span class=\"rnthl rntliteral\">input-email<\/span> and <span class=\"rnthl rntliteral\">input-password<\/span> for the email and password, respectively.<\/p>\n\n\n\n<p>Now that we have the inserted email and password, we can try to log in to Firebase. To do that, pass the user&#8217;s email address and password to the following method: <span class=\"rnthl rntliteral\">signInWithEmailAndPassword<\/span>:<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>await signInWithEmailAndPassword(auth, email, password);<\/code><\/pre>\n\n\n\n<p>After logging in, we reset the form and print the user email in the console.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>try {\n  await signInWithEmailAndPassword(auth, email, password);\n  loginForm.reset();\n  console.log(\"Logged in:\", email);\n}<\/code><\/pre>\n\n\n\n<p>In case there is an error signing in, we catch the error message, and display it on the <span class=\"rnthl rntliteral\">error-message<\/span> HTML element (a paragraph below the form).<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>} catch (error) {\n  document.getElementById(\"error-message\").textContent = error.message;\n  console.error(\"Login error:\", error.message)<\/code><\/pre>\n\n\n\n<p><strong>Logout<\/strong><\/p>\n\n\n\n<p>The following snippet is responsible for logging out the user.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>\/\/ Logout\nconst logoutLink = document.querySelector('#logout-link');\nlogoutLink.addEventListener('click', async (e) =&gt; {\n  e.preventDefault();\n  try {\n    await signOut(auth);\n    console.log(\"User signed out\");\n  } catch (error) {\n    console.error(\"Logout error:\", error.message);\n  }\n});<\/code><\/pre>\n\n\n\n<p>When the user is logged in, a logout link is visible in the authentication bar. That link has the <span class=\"rnthl rntliteral\">logout-link<\/span> id (see on the HTML file). So, first, we create a variable called <span class=\"rnthl rntliteral\">logoutLink<\/span> that refers to the logout link.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>const logoutLink = document.querySelector('#logout-link');<\/code><\/pre>\n\n\n\n<p>Then, we add an event listener of type <span class=\"rnthl rntliteral\">click<\/span>. This means the subsequent instructions will run whenever you click on the logout link.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>logoutLink.addEventListener('click', async (e) =&gt; {<\/code><\/pre>\n\n\n\n<p>When the button is clicked, we sign out the user using the <span class=\"rnthl rntliteral\">signOut<\/span> method.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>await signOut(auth);<\/code><\/pre>\n\n\n\n<p><strong>Auth State Changes<\/strong><\/p>\n\n\n\n<p>To keep track of the user authentication state\u2014to know if the user is logged in or logged out, there is a method called <span class=\"rnthl rntliteral\">onAuthSateChanged<\/span> that allows you to receive an event whenever the authentication state changes.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>document.addEventListener(\"DOMContentLoaded\", () =&gt; {\n  \/\/ Listen for auth status changes\n  onAuthStateChanged(auth, (user) =&gt; {\n    if (user) {\n      console.log(\"User logged in:\", user.email);\n      setupUI(user);\n    } else {\n      console.log(\"User logged out\");\n      setupUI(null);\n    }\n  })<\/code><\/pre>\n\n\n\n<p>If the user returned is <span class=\"rnthl rntliteral\">null<\/span>, the user is currently signed out. Otherwise, it is currently signed in.<\/p>\n\n\n\n<p>In both scenarios, we print the current user state to the console and call the <span class=\"rnthl rntliteral\">setupUI()<\/span> function. We haven&#8217;t created that function yet (we&#8217;ll create it in the next section), but it will be responsible for handling the user interface according to the authentication state.<\/p>\n\n\n\n<p>When the user is logged in, we pass the <span class=\"rnthl rntliteral\">user<\/span> as an argument to the <span class=\"rnthl rntliteral\">setupUI()<\/span> function. In this case, we&#8217;ll display the complete user interface to show the buttons to control the GPIOs, as you&#8217;ll see later.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>if (user) {\n  console.log(\"User logged in:\", user.email);\n  setupUI(user);<\/code><\/pre>\n\n\n\n<p>If the user is logged out, we call the <span class=\"rnthl rntliteral\">setupUI()<\/span> function with the <span class=\"rnthl rntliteral\">null<\/span> argument. In that scenario, we&#8217;ll simply display a message informing that the user is logged out and doesn&#8217;t have access to the interface (as we&#8217;ll see later).<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>} else {\n  console.log(\"User logged out\");\n  setupUI(null);<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">index.js<\/h4>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">index.js<\/span> file handles the UI &#8211; it shows the right content depending on the user authentication status. When the user is logged in, it gets the GPIO states from the database and updates the GPIO states on the interface. Then, it changes the states whenever you press the buttons.<\/p>\n\n\n\n<p>Copy the following to the <span class=\"rnthl rntliteral\">index.js<\/span> file. <\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-javascript\">import { initializeApp } from &quot;https:\/\/www.gstatic.com\/firebasejs\/11.6.0\/firebase-app.js&quot;;\r\nimport { getAuth } from &quot;https:\/\/www.gstatic.com\/firebasejs\/11.6.0\/firebase-auth.js&quot;;\r\nimport { getDatabase, ref, onValue, set } from &quot;https:\/\/www.gstatic.com\/firebasejs\/11.6.0\/firebase-database.js&quot;;\r\n\r\n\/\/ Firebase configuration\r\nconst firebaseConfig = {\r\n    apiKey: &quot;REPLACE_WITH_YOUR_Firebase_CONFIGURATION&quot;,\r\n    authDomain: &quot;REPLACE_WITH_YOUR_Firebase_CONFIGURATION&quot;,\r\n    databaseURL: &quot;REPLACE_WITH_YOUR_Firebase_CONFIGURATION&quot;,\r\n    projectId: &quot;REPLACE_WITH_YOUR_Firebase_CONFIGURATION&quot;,\r\n    storageBucket: &quot;REPLACE_WITH_YOUR_Firebase_CONFIGURATION&quot;,\r\n    messagingSenderId: &quot;REPLACE_WITH_YOUR_Firebase_CONFIGURATION&quot;,\r\n    appId: &quot;REPLACE_WITH_YOUR_Firebase_CONFIGURATION&quot;\r\n};\r\n\r\n\/\/ Initialize Firebase\r\nconst app = initializeApp(firebaseConfig);\r\nconst auth = getAuth(app);\r\nconst database = getDatabase(app);\r\n\r\n\/\/ Export auth for use in auth.js\r\nexport { auth };\r\n\r\n\/\/ DOM elements\r\nconst loginElement = document.querySelector('#login-form');\r\nconst contentElement = document.querySelector(&quot;#content-sign-in&quot;);\r\nconst userDetailsElement = document.querySelector('#user-details');\r\nconst authBarElement = document.querySelector(&quot;#authentication-bar&quot;);\r\n\r\n\/\/ Elements for GPIO states\r\nconst stateElement1 = document.getElementById(&quot;state1&quot;);\r\nconst stateElement2 = document.getElementById(&quot;state2&quot;);\r\nconst stateElement3 = document.getElementById(&quot;state3&quot;);\r\n\r\n\/\/ Button Elements\r\nconst btn1On = document.getElementById('btn1On');\r\nconst btn1Off = document.getElementById('btn1Off');\r\nconst btn2On = document.getElementById('btn2On');\r\nconst btn2Off = document.getElementById('btn2Off');\r\nconst btn3On = document.getElementById('btn3On');\r\nconst btn3Off = document.getElementById('btn3Off');\r\n\r\n\/\/ Database paths for GPIO states\r\nconst dbPathOutput1 = 'board1\/outputs\/digital\/12';\r\nconst dbPathOutput2 = 'board1\/outputs\/digital\/13';\r\nconst dbPathOutput3 = 'board1\/outputs\/digital\/14';\r\n\r\n\/\/ Database references using modular API\r\nconst dbRefOutput1 = ref(database, dbPathOutput1);\r\nconst dbRefOutput2 = ref(database, dbPathOutput2);\r\nconst dbRefOutput3 = ref(database, dbPathOutput3);\r\n\r\n\/\/ Manage Login\/Logout UI\r\nconst setupUI = (user) =&gt; {\r\n  console.log('setupUI called with user:', user ? user.email : null);\r\n  if (user) {\r\n    \/\/ Toggle UI elements for logged-in state\r\n    loginElement.style.display = 'none';\r\n    contentElement.style.display = 'block';\r\n    authBarElement.style.display = 'block';\r\n    userDetailsElement.style.display = 'block';\r\n    userDetailsElement.innerHTML = user.email;\r\n\r\n    \/\/ Update states depending on database value\r\n    onValue(dbRefOutput1, (snap) =&gt; {\r\n      stateElement1.textContent = snap.val() === 1 ? &quot;ON&quot; : &quot;OFF&quot;;\r\n    });\r\n\r\n    onValue(dbRefOutput2, (snap) =&gt; {\r\n      stateElement2.textContent = snap.val() === 1 ? &quot;ON&quot; : &quot;OFF&quot;;\r\n    });\r\n\r\n    onValue(dbRefOutput3, (snap) =&gt; {\r\n      stateElement3.textContent = snap.val() === 1 ? &quot;ON&quot; : &quot;OFF&quot;;\r\n    });\r\n\r\n    \/\/ Update database upon button click\r\n    btn1On.addEventListener('click', () =&gt; set(dbRefOutput1, 1));\r\n    btn1Off.addEventListener('click', () =&gt; set(dbRefOutput1, 0));\r\n    btn2On.addEventListener('click', () =&gt; set(dbRefOutput2, 1));\r\n    btn2Off.addEventListener('click', () =&gt; set(dbRefOutput2, 0));\r\n    btn3On.addEventListener('click', () =&gt; set(dbRefOutput3, 1));\r\n    btn3Off.addEventListener('click', () =&gt; set(dbRefOutput3, 0));\r\n  } else {\r\n    \/\/ Toggle UI elements for logged-out state\r\n    loginElement.style.display = 'block';\r\n    authBarElement.style.display = 'none';\r\n    userDetailsElement.style.display = 'none';\r\n    contentElement.style.display = 'none';\r\n  }\r\n};\r\n\r\n\/\/ Export setupUI for use in other modules\r\nexport { setupUI };\r\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Firebase-ESP\/raw\/main\/ESP-Firebase-Control-GPIOs-Anywhere\/Web-App\/scripts\/index.js\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<p><strong>Important<\/strong>: you need to modify the code with your own&nbsp;<span class=\"rnthl rntliteral\">firebaseConfig<\/span>&nbsp;object\u2014the one you\u2019ve got&nbsp;in the previous steps.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>const firebaseConfig = {\n  apiKey: \"REPLACE_WITH_YOUR_Firebase_CONFIGURATION\",\n  authDomain: \"REPLACE_WITH_YOUR_Firebase_CONFIGURATION\",\n  databaseURL: \"REPLACE_WITH_YOUR_Firebase_CONFIGURATION\",\n  projectId: \"REPLACE_WITH_YOUR_Firebase_CONFIGURATION\",\n  storageBucket: \"REPLACE_WITH_YOUR_Firebase_CONFIGURATION\",\n  messagingSenderId: \"REPLACE_WITH_YOUR_Firebase_CONFIGURATION\",\n  appId: \"REPLACE_WITH_YOUR_Firebase_CONFIGURATION\"\n};<\/code><\/pre>\n\n\n\n<p>Continue reading to learn how the code works or skip to the next section.<\/p>\n\n\n\n<p><strong>Importing JavaScript Modules<\/strong><\/p>\n\n\n\n<p>First, we import all the required JavaScript modules.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>import { initializeApp } from \"https:\/\/www.gstatic.com\/firebasejs\/11.6.0\/firebase-app.js\";\nimport { getAuth } from \"https:\/\/www.gstatic.com\/firebasejs\/11.6.0\/firebase-auth.js\";\nimport { getDatabase, ref, onValue, set } from \"https:\/\/www.gstatic.com\/firebasejs\/11.6.0\/firebase-database.js\";<\/code><\/pre>\n\n\n\n<p><strong>Firebase Configuration Object<\/strong><\/p>\n\n\n\n<p>Then, insert your Firebase Project Configurations.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>\/\/ Firebase configuration\nconst firebaseConfig = {\n    apiKey: \"REPLACE_WITH_YOUR_Firebase_CONFIGURATION\",\n    authDomain: \"REPLACE_WITH_YOUR_Firebase_CONFIGURATION\",\n    databaseURL: \"REPLACE_WITH_YOUR_Firebase_CONFIGURATION\",\n    projectId: \"REPLACE_WITH_YOUR_Firebase_CONFIGURATION\",\n    storageBucket: \"REPLACE_WITH_YOUR_Firebase_CONFIGURATION\",\n    messagingSenderId: \"REPLACE_WITH_YOUR_Firebase_CONFIGURATION\",\n    appId: \"REPLACE_WITH_YOUR_Firebase_CONFIGURATION\"\n};<\/code><\/pre>\n\n\n\n<p><strong>Initialize the Firebase App<\/strong><\/p>\n\n\n\n<p>The following lines initialize the Firebase App and export the <span class=\"rnthl rntliteral\">auth<\/span> object to be used in the <span class=\"rnthl rntliteral\">auth.js<\/span> file.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>\/\/ Initialize Firebase\nconst app = initializeApp(firebaseConfig);\nconst auth = getAuth(app);\nconst database = getDatabase(app);\n\n\/\/ Export auth for use in auth.js\nexport { auth };<\/code><\/pre>\n\n\n\n<p><strong>Getting HTML Elements<\/strong><\/p>\n\n\n\n<p>We create variables to refer to several elements on the UI interface by referring to their ids. To identify these elements, we recommend that you take a look at the HTML file provided and find the elements with the referred ids.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>const loginElement = document.querySelector('#login-form');\nconst contentElement = document.querySelector(\"#content-sign-in\");\nconst userDetailsElement = document.querySelector('#user-details');\nconst authBarElement = document.querySelector(\"#authentication-bar\");<\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">loginElement<\/span> corresponds to the login form. The <span class=\"rnthl rntliteral\">contentElement<\/span> corresponds to the section of the web page that is visible when the user is logged in (that shows the sensor readings). The <span class=\"rnthl rntliteral\">userDetailsElement<\/span> corresponds to a section that will display the email of the logged in user. The <span class=\"rnthl rntliteral\">auhtBarElement<\/span> corresponds to the authentication bar that shows the current user status, the email of the authenticated user and the logout link.<\/p>\n\n\n\n<p>The following creates variables to refer to the buttons as GPIOs states on the interface:<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>\/\/ Elements for GPIO states\nconst stateElement1 = document.getElementById(\"state1\");\nconst stateElement2 = document.getElementById(\"state2\");\nconst stateElement3 = document.getElementById(\"state3\");\n\n\/\/ Button Elements\nconst btn1On = document.getElementById('btn1On');\nconst btn1Off = document.getElementById('btn1Off');\nconst btn2On = document.getElementById('btn2On');\nconst btn2Off = document.getElementById('btn2Off');\nconst btn3On = document.getElementById('btn3On');\nconst btn3Off = document.getElementById('btn3Off');<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Database Paths and References<\/h4>\n\n\n\n<p>Then, we need to create database paths to where the GPIOs states are saved:<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>\/\/ Database path for GPIO states\nvar dbPathOutput1 = 'board1\/outputs\/digital\/12';\nvar dbPathOutput2 = 'board1\/outputs\/digital\/13';\nvar dbPathOutput3 = 'board1\/outputs\/digital\/14';<\/code><\/pre>\n\n\n\n<p>To be able to interact with the database on those paths, we need to create database references using those paths:<\/p>\n\n\n\n<pre id=\"language-javascript\" class=\"wp-block-code language-javascript\"><code>const dbRefOutput1 = ref(database, dbPathOutput1);\nconst dbRefOutput2 = ref(database, dbPathOutput2);\nconst dbRefOutput3 = ref(database, dbPathOutput3);<\/code><\/pre>\n\n\n\n<p><strong>sertupUI() Function<\/strong><\/p>\n\n\n\n<p>Then, we create the <span class=\"rnthl rntliteral\">setupUI()<\/span> function that will handle the UI accordingly to the state of the user authentication.<\/p>\n\n\n\n<p>In the <span class=\"rnthl rntliteral\">auth.js<\/span> file, we called the <span class=\"rnthl rntliteral\">setupUI()<\/span> function with the <span class=\"rnthl rntliteral\">user<\/span> argument <span class=\"rnthl rntliteral\">setupUI(user)<\/span> if the user is logged in; or the function with the null argument, <span class=\"rnthl rntliteral\">setupUI(null)<\/span>, when the user is logged out.<\/p>\n\n\n\n<p>So, let&#8217;s check what happens when the user is logged in.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>if (user) {<\/code><\/pre>\n\n\n\n<p>We show the authentication bar (that shows the user details and the logout link). To do that, we can set its display style to <span class=\"rnthl rntliteral\">block<\/span>. We also want the web page&#8217;s main content with the sensor readings to be visible.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>contentElement.style.display = 'block';\nauthBarElement.style.display ='block';<\/code><\/pre>\n\n\n\n<p>Finally, we can get the logged in user email with <span class=\"rnthl rntliteral\">user.email<\/span> and display it in the <span class=\"rnthl rntliteral\">userDetailsElement<\/span> section as follows:<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>userDetailsElement.innerHTML = user.email;<\/code><\/pre>\n\n\n\n<p><strong>Get GPIO States<\/strong><\/p>\n\n\n\n<p>The following lines get the GPIO states whenever there&#8217;s a change in the database and update the corresponding HTML elements with the new values. For that, we use the <span class=\"rnthl rntliteral\">onValue()<\/span> function.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>\/\/ Update states depending on database value\nonValue(dbRefOutput1, (snap) =&gt; {\n  stateElement1.textContent = snap.val() === 1 ? \"ON\" : \"OFF\";\n});\n\nonValue(dbRefOutput2, (snap) =&gt; {\n  stateElement2.textContent = snap.val() === 1 ? \"ON\" : \"OFF\";\n});\n\nonValue(dbRefOutput3, (snap) =&gt; {\n  stateElement3.textContent = snap.val() === 1 ? \"ON\" : \"OFF\";\n});<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Button Events<\/h4>\n\n\n\n<p>Then, we add events to the buttons to write 1 or 0 to the corresponding database path accordingly to the button that was pressed.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>btn1On.addEventListener('click', () =&gt; set(dbRefOutput1, 1));\nbtn1Off.addEventListener('click', () =&gt; set(dbRefOutput1, 0));\nbtn2On.addEventListener('click', () =&gt; set(dbRefOutput2, 1));\nbtn2Off.addEventListener('click', () =&gt; set(dbRefOutput2, 0));\nbtn3On.addEventListener('click', () =&gt; set(dbRefOutput3, 1));\nbtn3Off.addEventListener('click', () =&gt; set(dbRefOutput3, 0));<\/code><\/pre>\n\n\n\n<p><strong>Logged Out UI<\/strong><\/p>\n\n\n\n<p>The following snippet handles the UI when the user logs out. We want to hide the authentication bar and the main webpage content (GPIO states and corresponding buttons) and show the login form.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>} else {\n  \/\/ Toggle UI elements for logged-out state\n  loginElement.style.display = 'block';\n  authBarElement.style.display = 'none';\n  userDetailsElement.style.display = 'none';\n  contentElement.style.display = 'none';\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Favicon File<\/h3>\n\n\n\n<p>To display a favicon in your web app, you need to move the picture you want to use as favicon to the <span class=\"rnthl rntliteral\">public<\/span> folder. The picture should be called favicon.png. You can simply drag the favicon file from your computer into the <span class=\"rnthl rntliteral\">public<\/span> folder in VS Code.<\/p>\n\n\n\n<p>We&#8217;re using the following icon as a favicon for our web app:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/github.com\/RuiSantosdotme\/build-web-servers-dl\/raw\/main\/favicon.zip\" target=\"_blank\" rel=\"noreferrer noopener\">favicon.png<\/a><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Deploy your App<\/h3>\n\n\n\n<p>After saving the HTML, CSS, and JavaScript files, deploy your app on VS Code by running the following command on the Terminal window.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>firebase<\/strong> deploy<\/code><\/pre>\n\n\n\n<p>The Terminal should display something as follows:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"724\" height=\"312\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/10\/ESP32-ESP8266-Deploy-Firebase-App-VS-Code-1.png?resize=724%2C312&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 ESP8266 Deploy Firebase Web App\" class=\"wp-image-107548\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/10\/ESP32-ESP8266-Deploy-Firebase-App-VS-Code-1.png?w=724&amp;quality=100&amp;strip=all&amp;ssl=1 724w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/10\/ESP32-ESP8266-Deploy-Firebase-App-VS-Code-1.png?resize=300%2C129&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 724px) 100vw, 724px\" \/><\/figure><\/div>\n\n\n<p>Firebase offers a free hosting service to serve your assets and web apps. Then, you can access your web app from anywhere.<\/p>\n\n\n\n<p>You can use the Hosting URL provided to access your web app from anywhere.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Demonstration<\/h2>\n\n\n\n<p>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 <span class=\"rnthl rntliteral\">https:\/\/esp-firebase-demo.web.app<\/span>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"431\" height=\"436\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2022\/04\/Firebase-Web-App-Control-GPIOs-from-Anywhere-with-Authentication.png?resize=431%2C436&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Firebase Web App Control ESP32 ESP8266 GPIOs from Anywhere with Authentication\" class=\"wp-image-110582\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2022\/04\/Firebase-Web-App-Control-GPIOs-from-Anywhere-with-Authentication.png?w=431&amp;quality=100&amp;strip=all&amp;ssl=1 431w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2022\/04\/Firebase-Web-App-Control-GPIOs-from-Anywhere-with-Authentication.png?resize=297%2C300&amp;quality=100&amp;strip=all&amp;ssl=1 297w\" sizes=\"(max-width: 431px) 100vw, 431px\" \/><\/figure><\/div>\n\n\n<p>The web app is responsive, and you can access it using your smartphone, computer, or tablet.<\/p>\n\n\n\n<p>Insert the email and password of the authorized user you added in the Firebase Authentication methods. After that, you can access the dashboard to control the ESP32 or ESP8266 GPIOs.<\/p>\n\n\n\n<p>Go to your project&#8217;s Firebase console&nbsp;<strong>Hosting<\/strong>&nbsp;tab. You can see your app domains, deploy history, and you can even roll back to previous versions of your app.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"804\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/10\/ESP32-ESP8266-Firebase-Web-App-Deploy-History.png?resize=750%2C804&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Firebase Web App Deploy History and Domains\" class=\"wp-image-107552\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/10\/ESP32-ESP8266-Firebase-Web-App-Deploy-History.png?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/10\/ESP32-ESP8266-Firebase-Web-App-Deploy-History.png?resize=280%2C300&amp;quality=100&amp;strip=all&amp;ssl=1 280w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\">Wrapping Up<\/h2>\n\n\n\n<p>In this tutorial, you learned how to create a Firebase Web App with login\/logout authentication to control the ESP32 or ESP8266 GPIOs from anywhere. The GPIO states are saved to the realtime database, and the ESP is listening to any changes that occur in the database to update the GPIOs right away. You can easily add more GPIOs or more boards to this project.<\/p>\n\n\n\n<p>The database is protected using database rules. Only authorized authenticated users can access the web app to control the GPIOs.<\/p>\n\n\n\n<p>You can combine this project with other <a href=\"https:\/\/randomnerdtutorials.com\/?s=firebase\">ESP32\/ESP8266 Firebase projects we have published<\/a> and add more functionalities to your app.<\/p>\n\n\n\n<p>If you want to learn more about Firebase, we recommend taking a look at our eBook, exclusively dedicated to this subject:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><a href=\"https:\/\/randomnerdtutorials.com\/firebase-esp32-esp8266-ebook\/\">Firebase Web App with ESP32 and ESP8266<\/a><\/strong><\/li>\n<\/ul>\n\n\n\n<p>We have other resources related to ESP32 and ESP8266 that you may like:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/learn-esp32-with-arduino-ide\/\">Learn ESP32 with Arduino IDE<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/home-automation-using-esp8266\/\">Home Automation using ESP8266<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/build-web-servers-esp32-esp8266-ebook\/\">Build Web Servers with ESP32 and ESP8266<\/a><\/li>\n<\/ul>\n\n\n\n<p>Thanks for reading.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this guide, you&#8217;ll create a Firebase Web App to control the ESP32 or ESP8266 GPIOs from anywhere. The access to the web app is protected with authentication using email &#8230; <\/p>\n<p class=\"read-more-container\"><a title=\"Control ESP32\/ESP8266 GPIOs from Anywhere (Firebase Web App)\" class=\"read-more button\" href=\"https:\/\/randomnerdtutorials.com\/control-esp-gpios-firebase-web-app\/#more-110568\" aria-label=\"Read more about Control ESP32\/ESP8266 GPIOs from Anywhere (Firebase Web App)\">CONTINUE READING \u00bb<\/a><\/p>\n","protected":false},"author":5,"featured_media":110573,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[281,276,277,299,264],"tags":[],"class_list":["post-110568","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-esp32-project","category-esp32","category-esp32-arduino-ide","category-0-esp32","category-project"],"aioseo_notices":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2022\/04\/ESP-Control-GPIOs-from-Anywhere-Firebase.jpg?fit=1280%2C720&quality=100&strip=all&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/110568","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/comments?post=110568"}],"version-history":[{"count":16,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/110568\/revisions"}],"predecessor-version":[{"id":171211,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/110568\/revisions\/171211"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media\/110573"}],"wp:attachment":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media?parent=110568"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/categories?post=110568"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/tags?post=110568"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}