ESP32/ESP8266: Веб-приложение Firebase для отображения показаний датчиков (с аутентификацией)

В этом руководстве вы создадите веб-приложение Firebase для отображения показаний датчиков, сохранённых в Firebase Realtime Database. Веб-страница с показаниями датчиков защищена аутентификацией с использованием email и пароля. Вы узнаете, как отображать данные из базы данных и как добавить аутентификацию в ваше веб-приложение.

ESP32 ESP8266 NodeMCU Firebase Web App to Display Sensor Readings with Authentication

Обновлено 30 апреля 2025 года

Эта статья является Частью 2 предыдущего руководства: ESP32/ESP8266 Firebase: отправка показаний датчика BME280 в Realtime Database. Сначала выполните это руководство, прежде чем продолжить.

Обзор проекта

В этом руководстве (Часть 2) вы создадите веб-приложение для отображения показаний датчиков, сохранённых в Firebase Realtime Database (прочитайте предыдущее руководство).

Следующая диаграмма показывает общий обзор проекта, который мы будем создавать — программирование ESP32/ESP8266 и настройка проекта Firebase были выполнены в Части 1.

ESP32 ESP8266 Firebase Web App Sensor Readings Authentication Project Overview
  • Firebase размещает ваше веб-приложение на глобальном CDN с помощью Firebase Hosting и предоставляет SSL-сертификат. Вы можете получить доступ к вашему веб-приложению из любой точки мира, используя доменное имя, сгенерированное Firebase.

  • При первом доступе к веб-приложению вам необходимо пройти аутентификацию с авторизованным адресом электронной почты и паролем. Вы уже настроили этого пользователя и метод аутентификации в Части 1.

  • После аутентификации вы можете получить доступ к веб-странице, которая показывает показания датчиков, сохранённые в базе данных реального времени. База данных реального времени была настроена в Части 1.

  • После входа в систему вы можете выйти в любое время. При следующем доступе к приложению вам нужно будет снова войти в систему.

Предварительные требования

Перед тем как начать создание веб-приложения Firebase, необходимо проверить следующие предварительные требования.

Создание проекта Firebase

Вы должны были выполнить следующее руководство:

ESP32/ESP8266 должен выполнять код, предоставленный в этом руководстве. База данных реального времени и аутентификация также должны быть настроены, как показано в руководстве.

Установка необходимого программного обеспечения

Перед началом работы необходимо установить необходимое программное обеспечение для создания веб-приложения Firebase. Вот список программного обеспечения, которое необходимо установить (нажмите на ссылки для получения инструкций):


1) Добавление приложения в ваш проект Firebase

1) Перейдите в консоль вашего проекта Firebase и добавьте приложение в проект, нажав кнопку +Add app.

Add App to Firebase Project

2) Выберите значок веб-приложения.

3) Дайте вашему приложению имя. Затем установите флажок рядом с Also set up Firebase Hosting for this App. Нажмите Register app.

Firebase Add Web App to Project Hosting

4) Затем скопируйте объект firebaseConfig и сохраните его, потому что он понадобится вам позже.

firebaseConfig object configuration copy save

После этого вы также можете получить доступ к объекту firebaseConfig, если перейдёте в настройки проекта в консоли Firebase.

5) Нажмите Next на последующих шагах и, наконец, Continue to console.


2) Настройка проекта веб-приложения Firebase (VS Code)

Следуйте следующим шагам для создания проекта веб-приложения Firebase с использованием VS Code.

1) Создание папки проекта

1) Создайте папку на вашем компьютере, где вы хотите сохранить проект Firebase — например, Firebase-Project на рабочем столе.

2) Откройте VS Code. Перейдите в File > Open Folder… и выберите папку, которую вы только что создали.

3) Перейдите в Terminal > New Terminal. Должно открыться новое окно терминала с путём к вашему проекту.

Install Firebase Tools 2

2) Вход в Firebase

4) В предыдущем окне терминала введите следующее:

firebase login

5) Вас спросят, хотите ли вы собирать информацию об использовании CLI и отчёты об ошибках. Введите «n» и нажмите Enter, чтобы отказать.

Login Firebase VS Code Terminal Window

Примечание: Если вы уже вошли в систему, будет показано сообщение: «Already logged in as user@gmail.com».

6) После этого откроется новое окно в вашем браузере для входа в вашу учётную запись Firebase.

Login Firebase Account

7) Разрешите Firebase CLI доступ к вашей учётной записи Google.

Login Firebase Account allow Firebase CLI

8) После этого вход через Firebase CLI должен быть успешным. Вы можете закрыть окно браузера.

Login Firebase Account allow Firebase CLI Login Successful

3) Инициализация проекта Firebase для веб-приложения

9) После успешного входа выполните следующую команду для запуска каталога проекта Firebase в текущей папке.

firebase init

10) Вас спросят, хотите ли вы инициализировать проект Firebase в текущем каталоге. Введите Y и нажмите Enter.

Login Firebase Account allow Firebase CLI firebase init

11) Затем используйте стрелки вверх и вниз и клавишу пробела для выбора опций. Выберите следующие опции:

  • Realtime Database: Configure security rules file for Realtime Database and (optionally) provision default instance.

  • Hosting: Configure files for Firebase Hosting and (optionally) set up GitHub Action deploys

Выбранные опции будут отмечены зелёной звёздочкой. Затем нажмите Enter.

Login Firebase Account allow Firebase CLI configure directory

12) Выберите опцию «Use an existing project» — она должна быть выделена синим цветом — затем нажмите Enter.

Firebase Project Setup VS Code

13) После этого выберите проект Firebase для этого каталога — это должен быть проект, созданный в предыдущем руководстве. В моём случае он называется esp-project. Затем нажмите Enter.

Select Firebase Project on VS Code

14) Затем выберите опции хостинга, как показано ниже:

  • What do you want to use as your public directory? Нажмите Enter, чтобы выбрать 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) Нажмите Enter на следующем вопросе, чтобы выбрать файл правил безопасности базы данных по умолчанию: «What file should be used for Realtime Database Security Rules?»

16) Проект Firebase теперь должен быть успешно инициализирован. Обратите внимание, что VS Code создал несколько важных файлов в папке вашего проекта.

Firebase Project Files Created successfully

Файл index.html содержит некоторый HTML-текст для создания веб-страницы. Пока оставьте HTML-текст по умолчанию. Идея состоит в том, чтобы заменить его своим собственным HTML-текстом для создания пользовательской веб-страницы для ваших нужд. Мы сделаем это позже в этом руководстве.

17) Чтобы проверить, всё ли прошло как ожидалось, выполните следующую команду в окне терминала VS Code.

firebase deploy
Firebase App First Deploy Testing

Вы должны получить сообщение Deploy complete! и URL-адрес консоли проекта и URL-адрес хостинга.

18) Скопируйте URL-адрес хостинга и вставьте его в окно веб-браузера. Вы должны увидеть следующую веб-страницу. Вы можете получить доступ к этой веб-странице из любой точки мира.

Firebase test page hosting setup complete

Веб-страница, которую вы видели ранее, создана с помощью HTML-файла, размещённого в папке public вашего проекта Firebase. Изменяя содержимое этого файла, вы можете создать своё собственное веб-приложение. Это то, что мы собираемся сделать в следующем разделе.


3) Создание веб-приложения Firebase

Теперь, когда вы создали проект приложения Firebase в VS Code, следуйте следующим шагам для настройки приложения для отображения показаний датчиков на защищённой входом веб-странице.

index.html

Скопируйте следующее в ваш файл index.html. Этот HTML-файл создаёт простую веб-страницу, которая отображает показания, сохранённые в Realtime Database, созданной в предыдущем проекте.

Если вы не аутентифицированы, отображается форма входа. Когда вы аутентифицируетесь с авторизованным email пользователя и соответствующим паролем, отображается пользовательский интерфейс с показаниями датчиков.

<!-- Complete Project Details at: https://RandomNerdTutorials.com/esp32-esp8266-firebase-web-app-sensor/ -->
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>ESP IoT 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="icon" type="image/png" href="favicon.png">
    <link rel="stylesheet" type="text/css" href="style.css">
  </head>
  <body>
    <!--TOP BAR-->
    <div class="topnav">
      <h1>Sensor Readings App <i class="fas fa-clipboard-list"></i></h1>
    </div>

    <!--AUTHENTICATION BAR (USER DETAILS/LOGOUT BUTTON)-->
    <div id="authentication-bar" style="display: none;">
      <p><span id="authentication-status">User logged in</span>
         <span id="user-details">USEREMAIL</span>
         <a href="#" id="logout-link">(logout)</a>
      </p>
    </div>

    <!--LOGIN FORM-->
    <form id="login-form" style="display: none;">
      <div class="form-elements-container">
        <label for="input-email"><b>Email</b></label>
        <input type="text" placeholder="Enter Username" id="input-email" required>
        <label for="input-password"><b>Password</b></label>
        <input type="password" placeholder="Enter Password" id="input-password" required>
        <button type="submit" id="login-button">Login</button>
        <p id="error-message" style="color:red;"></p>
      </div>
    </form>

    <!--CONTENT (SENSOR READINGS)-->
    <div class="content-sign-in" id="content-sign-in" style="display: none;">
      <div class="cards">
        <!--TEMPERATURE-->
        <div class="card">
          <p><i class="fas fa-thermometer-half" style="color:#059e8a;"></i> TEMPERATURE</p>
          <p><span class="reading"><span id="temp"></span> &deg;C</span></p>
        </div>
        <!--HUMIDITY-->
        <div class="card">
          <p><i class="fas fa-tint" style="color:#00add6;"></i> HUMIDITY</p>
          <p><span class="reading"><span id="hum"></span> &percnt;</span></p>
        </div>
        <!--PRESSURE-->
        <div class="card">
          <p><i class="fas fa-angle-double-down" style="color:#e1e437;"></i> PRESSURE</p>
          <p><span class="reading"><span id="pres"></span> hPa</span></p>
        </div>
      </div>
    </div>
    <script type="module" src="scripts/auth.js"></script>
    <script type="module" src="scripts/index.js"></script>
  </body>
</html>

Посмотреть исходный код

Как это работает

Давайте кратко рассмотрим HTML-файл, или перейдите к следующему разделу.

В <head> HTML-файла мы должны добавить все необходимые метаданные.

Заголовок веб-страницы — ESP Firebase App, но вы можете изменить его в следующей строке.

<title>ESP Firebase App</title>

Следующая строка позволяет нам использовать иконки fontawesome:

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

Следующая строка включает favicon на нашу веб-страницу.

<link rel="icon" type="image/png" href="favicon.png">

Наконец, ссылка на внешний файл style.css для форматирования HTML-страницы.

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

Мы закончили с метаданными. Теперь давайте перейдём к частям HTML, которые видны пользователю — перейдите между тегами <body> и </body>.

Мы создаём верхнюю панель «навигации» с названием нашего приложения и маленькой иконкой из fontawesome.

<div class="topnav">
  <h1>Sensor Readings App <i class="fas fa-clipboard-list"></i></h1>
</div>

Следующие строки создают панель с данными аутентифицированного пользователя (email). Также отображается ссылка для выхода из системы.

<div id="authentication-bar" style="display: none;">
  <p><span id="authentication-status">User logged in</span>
     <span id="user-details">USEREMAIL</span>
     <a href="/" id="logout-link">(logout)</a>
  </p>
</div>

Сначала мы устанавливаем стиль отображения всех элементов в none. Мы будем скрывать и показывать контент в зависимости от того, аутентифицирован пользователь или нет — мы будем обрабатывать это с помощью JavaScript.

Далее, следующие строки создают форму входа с полем ввода для email и полем ввода для пароля:

<form id="login-form" style="display: none;">
  <div class="form-elements-container">
    <label for="input-email"><b>Email</b></label>
    <input type="text" placeholder="Enter Username" id="input-email" required>

    <label for="input-password"><b>Password</b></label>
    <input type="password" placeholder="Enter Password" id="input-password" required>

    <button type="submit" id="login-button">Login</button>
    <p id="error-message" style="color:red;"></p>
  </div>
</form>

Внутри формы также есть параграф для отображения сообщения об ошибке, если вход не удастся.

<p id="error-message" style="color:red;"></p>

Наконец, мы создаём сетку для отображения показаний датчиков.

<!--CONTENT (SENSOR READINGS)-->
<div class="content-sign-in" id="content-sign-in" style="display: none;">
  <div class="cards">
    <!--TEMPERATURE-->
    <div class="card">
      <p><i class="fas fa-thermometer-half" style="color:#059e8a;"></i> TEMPERATURE</p>
      <p><span class="reading"><span id="temp"></span> &deg;C</span></p>
    </div>
    <!--HUMIDITY-->
    <div class="card">
      <p><i class="fas fa-tint" style="color:#00add6;"></i> HUMIDITY</p>
      <p><span class="reading"><span id="hum"></span> &percnt;</span></p>
    </div>
    <!--PRESSURE-->
    <div class="card">
      <p><i class="fas fa-angle-double-down" style="color:#e1e437;"></i> PRESSURE</p>
      <p><span class="reading"><span id="pres"></span> hPa</span></p>
    </div>
  </div>
</div>

Места, где мы будем вставлять показания датчиков, имеют теги <span> с определёнными идентификаторами, чтобы мы могли обращаться к этим HTML-элементам с помощью JavaScript и вставлять показания датчиков, сохранённые в базе данных.

  • температура: id = «temp»

  • влажность: id = «hum»

  • давление: id = «pres»

Наконец, нам нужно добавить ссылки на внешние файлы JavaScript. Для нашего приложения мы создадим два файла JavaScript: auth.js (который обрабатывает всё, связанное с аутентификацией) и index.js, который обрабатывает всё, связанное с пользовательским интерфейсом. Мы создадим эти файлы внутри папки scripts внутри папки public нашего приложения.

<script src="scripts/auth.js"></script>
<script src="scripts/index.js"></script>

Сохраните HTML-файл.

style.css

Внутри папки public создайте файл с именем style.css. Чтобы создать файл, выберите папку public, а затем нажмите на значок +file в верхней части проводника файлов. Назовите его style.css.

Create CSS File VS Code

Затем скопируйте следующее в файл style.css.

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

p {
    font-size: 1.2rem;
}

body {
    margin: 0;
}

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

#authentication-bar{
    background-color:mintcream;
    padding-top: 10px;
    padding-bottom: 10px;
}

#user-details{
    color: cadetblue;
}

.content {
    padding: 20px;
}

.card {
    background-color: white;
    box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);
    padding: 5%;
}

.cards {
    max-width: 800px;
    margin: 0 auto;
    display: grid;
    grid-gap: 2rem;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}

.reading {
    font-size: 1.4rem;
}

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

.form-elements-container{
    padding: 16px;
    width: 250px;
    margin: 0 auto;
}

input[type=text], input[type=password] {
    width: 100%;
    padding: 12px 20px;
    margin: 8px 0;
    display: inline-block;
    border: 1px solid #ccc;
    box-sizing: border-box;
}

Посмотреть исходный код

CSS-файл включает несколько простых стилей, чтобы наша веб-страница выглядела лучше. Мы не будем обсуждать, как работает CSS, в этом руководстве.

Файлы JavaScript

Мы создадим два файла JavaScript (auth.js и index.js) внутри папки scripts внутри папки public.

  • Выберите папку public, затем нажмите на значок +folder, чтобы создать новую папку. Назовите новую папку scripts.

  • Затем выберите папку scripts и нажмите на значок +file. Создайте файл с именем auth.js. Затем повторите предыдущие шаги, чтобы создать index.js.

Следующее изображение показывает, как должна выглядеть структура папок вашего проекта веб-приложения.

Firebase Project VS Code Folder File Structure

auth.js

Теперь давайте реализуем вход пользователя с использованием аутентификации Firebase. Мы реализуем вход с помощью email и пароля.

Скопируйте следующее в файл auth.js, который вы создали ранее.

import { auth } from "./index.js";
import { signInWithEmailAndPassword, signOut, onAuthStateChanged } from "https://www.gstatic.com/firebasejs/11.6.0/firebase-auth.js";

document.addEventListener("DOMContentLoaded", () => {
  // Listen for auth status changes
  onAuthStateChanged(auth, (user) => {
    if (user) {
      console.log("User logged in:", user.email);
      setupUI(user);
    } else {
      console.log("User logged out");
      setupUI(null);
    }
  });

  // Login
  const loginForm = document.querySelector('#login-form');
  loginForm.addEventListener('submit', async (e) => {
    e.preventDefault();
    const email = loginForm['input-email'].value;
    const password = loginForm['input-password'].value;
    try {
      await signInWithEmailAndPassword(auth, email, password);
      loginForm.reset();
      console.log("Logged in:", email);
    } catch (error) {
      document.getElementById("error-message").innerHTML = error.message;
      console.error("Login error:", error.message);
    }
  });

  // Logout
  const logoutLink = document.querySelector('#logout-link');
  logoutLink.addEventListener('click', async (e) => {
    e.preventDefault();
    try {
      await signOut(auth);
      console.log("User signed out");
    } catch (error) {
      console.error("Logout error:", error.message);
    }
  });
});

Посмотреть исходный код

Затем сохраните файл. Этот файл заботится обо всём, что связано с входом и выходом пользователя. Продолжайте чтение, чтобы узнать, как работает код, или перейдите к следующему разделу.

Импорт модулей

Мы начинаем с импорта необходимых модулей. Мы импортируем переменную аутентификации auth из файла index.js (мы рассмотрим его далее), которая необходима для проверки, вошёл ли пользователь в систему или нет.

import { auth } from "./index.js";

Мы также импортируем все необходимые модули Firebase.

import { signInWithEmailAndPassword, signOut, onAuthStateChanged } from "https://www.gstatic.com/firebasejs/11.6.0/firebase-auth.js";

Вход (Login)

Следующие строки отвечают за вход пользователя в систему.

// Login
const loginForm = document.querySelector('#login-form');
loginForm.addEventListener('submit', async (e) => {
  e.preventDefault();
  const email = loginForm['input-email'].value;
  const password = loginForm['input-password'].value;
  try {
    await signInWithEmailAndPassword(auth, email, password);
    loginForm.reset();
    console.log("Logged in:", email);
  } catch (error) {
    document.getElementById("error-message").innerHTML = error.message;
    console.error("Login error:", error.message);
  }
});

Мы создаём переменную, которая ссылается на HTML-элемент формы входа, называемую loginForm.

const loginForm = document.querySelector('#login-form');

Если вы вернётесь к файлу index.html, вы увидите, что форма имеет id login-form.

Мы добавляем обработчик событий типа submit к форме. Это означает, что последующие инструкции будут выполняться всякий раз, когда форма отправляется.

loginForm.addEventListener('submit', (e) => {

Вы можете получить отправленные данные следующим образом.

const email = loginForm['input-email'].value;
const password = loginForm['input-password'].value;

Если вы вернётесь к HTML-файлу, вы увидите, что поля ввода содержат следующие идентификаторы: input-email и input-password для email и пароля соответственно.

Теперь, когда у нас есть введённые email и пароль, мы можем попытаться войти в Firebase. Для этого передайте адрес электронной почты и пароль пользователя в следующий метод: signInWithEmailAndPassword:

try {
  await signInWithEmailAndPassword(auth, email, password);

После входа мы сбрасываем форму и выводим email пользователя в консоль.

loginForm.reset();
console.log("Logged in:", email);

В случае ошибки при входе мы перехватываем сообщение об ошибке и отображаем его в HTML-элементе error-message (параграф под формой).

} catch (error) {
  document.getElementById("error-message").innerHTML = error.message;
  console.error("Login error:", error.message);
}

Выход (Logout)

Следующий фрагмент отвечает за выход пользователя из системы.

// Logout
const logoutLink = document.querySelector('#logout-link');
logoutLink.addEventListener('click', async (e) => {
  e.preventDefault();
  try {
    await signOut(auth);
    console.log("User signed out");
  } catch (error) {
    console.error("Logout error:", error.message);
  }
});

Когда пользователь вошёл в систему, ссылка для выхода видна на панели аутентификации. Эта ссылка имеет id logout-link (см. HTML-файл). Итак, сначала мы создаём переменную с именем logout, которая ссылается на ссылку выхода.

const logout = document.querySelector('#logout-link');

Затем мы добавляем обработчик событий типа click. Это означает, что последующие инструкции будут выполняться всякий раз, когда вы нажимаете на ссылку выхода.

logout.addEventListener('click', (e) => {

Когда кнопка нажата, мы выводим пользователя из системы с помощью метода signOut.

try {
  await signOut(auth);
  console.log("User signed out");
} catch (error) {
  console.error("Logout error:", error.message);
}

Изменения состояния аутентификации (Auth State Changes)

Для отслеживания состояния аутентификации пользователя — чтобы знать, вошёл ли пользователь в систему или вышел, существует метод onAuthStateChanged, который позволяет получать событие всякий раз, когда состояние аутентификации изменяется.

document.addEventListener("DOMContentLoaded", () => {
  // Listen for auth status changes
  onAuthStateChanged(auth, (user) => {
    if (user) {
      console.log("User logged in:", user.email);
      setupUI(user);
    } else {
      console.log("User logged out");
      setupUI(null);
    }
  });

Если возвращённый пользователь равен null, пользователь в данный момент вышел из системы. В противном случае он в данный момент вошёл в систему.

В обоих сценариях мы выводим текущее состояние пользователя в консоль и вызываем функцию setupUI(). Мы ещё не создали эту функцию (мы создадим её в следующем разделе), но она будет отвечать за обработку пользовательского интерфейса в соответствии с состоянием аутентификации.

Когда пользователь вошёл в систему, мы передаём пользователя в качестве аргумента функции setupUI(). В этом случае мы отобразим полный пользовательский интерфейс для показа показаний датчиков, как вы увидите позже.

if (user) {
  console.log("User logged in:", user.email);
  setupUI(user);

Если пользователь вышел из системы, мы вызываем функцию setupUI() с аргументом null. В этом сценарии мы просто отобразим сообщение о том, что пользователь вышел из системы и не имеет доступа к интерфейсу (как мы увидим позже).

} else {
  console.log("User logged out");
  setupUI(null);
}

index.js

Файл index.js обрабатывает пользовательский интерфейс — он показывает правильный контент в зависимости от статуса аутентификации пользователя. Когда пользователь вошёл в систему, этот файл получает новые показания из базы данных всякий раз, когда происходит изменение.

Скопируйте следующее в файл index.js.

import { initializeApp } from "https://www.gstatic.com/firebasejs/11.6.0/firebase-app.js";
import { getAuth } from "https://www.gstatic.com/firebasejs/11.6.0/firebase-auth.js";
import { getDatabase, ref, onValue } from "https://www.gstatic.com/firebasejs/11.6.0/firebase-database.js";

// Firebase configuration
const firebaseConfig = {
    apiKey: "REPLACE_WITH_YOUR_Firebase_CONFIGURATION",
    authDomain: "REPLACE_WITH_YOUR_Firebase_CONFIGURATION",
    databaseURL: "REPLACE_WITH_YOUR_Firebase_CONFIGURATION",
    projectId: "REPLACE_WITH_YOUR_Firebase_CONFIGURATION",
    storageBucket: "REPLACE_WITH_YOUR_Firebase_CONFIGURATION",
    messagingSenderId: "REPLACE_WITH_YOUR_Firebase_CONFIGURATION",
    appId: "REPLACE_WITH_YOUR_Firebase_CONFIGURATION"
};

// Initialize Firebase
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
const database = getDatabase(app);

// Export auth for use in auth.js
export { auth };

// UI Elements
const loginElement = document.querySelector('#login-form');
const contentElement = document.querySelector("#content-sign-in");
const userDetailsElement = document.querySelector('#user-details');
const authBarElement = document.querySelector("#authentication-bar");
const tempElement = document.getElementById("temp");
const humElement = document.getElementById("hum");
const presElement = document.getElementById("pres");

// Manage Login/Logout UI
const setupUI = (user) => {
  if (user) {
    // Toggle UI elements
    loginElement.style.display = 'none';
    contentElement.style.display = 'block';
    authBarElement.style.display = 'block';
    userDetailsElement.style.display = 'block';
    userDetailsElement.innerHTML = user.email;

    // Database paths
    const uid = user.uid;
    const dbPathTemp = `UsersData/${uid}/temperature`;
    const dbPathHum = `UsersData/${uid}/humidity`;
    const dbPathPres = `UsersData/${uid}/pressure`;

    // Database references
    const dbRefTemp = ref(database, dbPathTemp);
    const dbRefHum = ref(database, dbPathHum);
    const dbRefPres = ref(database, dbPathPres);

    // Update page with new readings
    onValue(dbRefTemp, (snap) => {
      tempElement.innerText = snap.val()?.toFixed(2) ?? "N/A";
    });

    onValue(dbRefHum, (snap) => {
      humElement.innerText = snap.val()?.toFixed(2) ?? "N/A";
    });

    onValue(dbRefPres, (snap) => {
      presElement.innerText = snap.val()?.toFixed(2) ?? "N/A";
    });
  } else {
    // Toggle UI elements
    loginElement.style.display = 'block';
    authBarElement.style.display = 'none';
    userDetailsElement.style.display = 'none';
    contentElement.style.display = 'none';
  }
};

// Expose setupUI to global scope for auth.js
window.setupUI = setupUI;

Посмотреть исходный код

Продолжайте чтение, чтобы узнать, как работает код, или перейдите к следующему разделу.

Импорт модулей Firebase

Мы начинаем с импорта необходимых модулей Firebase.

import { initializeApp } from "https://www.gstatic.com/firebasejs/11.6.0/firebase-app.js";
import { getAuth } from "https://www.gstatic.com/firebasejs/11.6.0/firebase-auth.js";
import { getDatabase, ref, onValue } from "https://www.gstatic.com/firebasejs/11.6.0/firebase-database.js";
Объект конфигурации Firebase

Измените следующие строки, вставив ваш объект конфигурации Firebase, который вы получили на предыдущих шагах.

const firebaseConfig = {
  apiKey: "REPLACE_WITH_YOUR_Firebase_CONFIGURATION",
  authDomain: "REPLACE_WITH_YOUR_Firebase_CONFIGURATION",
  databaseURL: "REPLACE_WITH_YOUR_Firebase_CONFIGURATION",
  projectId: "REPLACE_WITH_YOUR_Firebase_CONFIGURATION",
  storageBucket: "REPLACE_WITH_YOUR_Firebase_CONFIGURATION",
  messagingSenderId: "REPLACE_WITH_YOUR_Firebase_CONFIGURATION",
  appId: "REPLACE_WITH_YOUR_Firebase_CONFIGURATION"
};
Инициализация приложения Firebase

Следующая строка инициализирует приложение Firebase с использованием предоставленного объекта firebaseConfig.

const app = initializeApp(firebaseConfig);

Затем создайте экземпляр аутентификации (auth), привязанный к инициализированному приложению Firebase (app). Функция getAuth из модуля Firebase Auth настраивает службу аутентификации для управления пользователями (вход, выход и т.д.).

const auth = getAuth(app);

Создайте экземпляр Firebase Realtime Database с именем database, привязанный к вашему приложению Firebase (app).

const database = getDatabase(app);

Затем мы экспортируем экземпляр auth, чтобы его можно было импортировать и использовать в других файлах JavaScript (в auth.js, как мы видели ранее).

export { auth };

Получение HTML-элементов

Создайте переменные для ссылки на несколько элементов пользовательского интерфейса по их идентификаторам. Для идентификации этих элементов мы рекомендуем вам посмотреть предоставленный HTML-файл и найти элементы с указанными идентификаторами.

// UI Elements
const loginElement = document.querySelector('#login-form');
const contentElement = document.querySelector("#content-sign-in");
const userDetailsElement = document.querySelector('#user-details');
const authBarElement = document.querySelector("#authentication-bar");
const tempElement = document.getElementById("temp");
const humElement = document.getElementById("hum");
const presElement = document.getElementById("pres");

loginElement соответствует форме входа. contentElement соответствует разделу веб-страницы, который виден, когда пользователь вошёл в систему (показывает показания датчиков). userDetailsElement соответствует разделу, который будет отображать email вошедшего пользователя. authBarElement соответствует панели аутентификации, которая показывает текущий статус пользователя, email аутентифицированного пользователя и ссылку для выхода.

Функция setupUI()

Затем мы создаём функцию setupUI(), которая будет обрабатывать пользовательский интерфейс в соответствии с состоянием аутентификации пользователя.

В файле auth.js мы вызывали функцию setupUI() с аргументом user setupUI(user), если пользователь вошёл в систему; или функцию с аргументом null, когда пользователь вышел из системы.

Итак, давайте проверим, что происходит, когда пользователь вошёл в систему.

if (user) {

Мы определяем, какие части пользовательского интерфейса должны быть видимыми или невидимыми. Когда пользователь вошёл в систему, мы хотим скрыть форму входа. Чтобы скрыть элемент, мы можем установить стиль отображения в none.

loginElement.style.display = 'none';

Мы показываем панель аутентификации (которая показывает данные пользователя и ссылку для выхода). Для этого мы можем установить стиль отображения в block. Мы также хотим, чтобы основной контент веб-страницы с показаниями датчиков был видимым.

contentElement.style.display = 'block';
authBarElement.style.display ='block';

Наконец, мы можем получить email вошедшего пользователя с помощью user.email и отобразить его в разделе userDetailsElement следующим образом:

userDetailsElement.innerHTML = user.email;

UID пользователя и пути базы данных

После того как у нас есть вошедший пользователь, мы можем получить его UID с помощью user.uid.

const uid = user.uid;

После получения UID пользователя мы создаём переменные для ссылки на пути базы данных, где мы сохраняем данные.

const dbPathTemp = `UsersData/${uid}/temperature`;
const dbPathHum = `UsersData/${uid}/humidity`;
const dbPathPres = `UsersData/${uid}/pressure`;

Затем мы создаём ссылки на базу данных по этим путям.

// Database references
const dbRefTemp = ref(database, dbPathTemp);
const dbRefHum = ref(database, dbPathHum);
const dbRefPres = ref(database, dbPathPres);

Отображение показаний датчиков

Следующие строки получают новые показания датчиков всякий раз, когда в базе данных происходит изменение, и обновляют соответствующие HTML-элементы новыми значениями. Также выполняется форматирование значений до двух десятичных знаков или возвращается N/A, если значение отсутствует.

// Update page with new readings
onValue(dbRefTemp, (snap) => {
  tempElement.innerText = snap.val()?.toFixed(2) ?? "N/A";
 });

onValue(dbRefHum, (snap) => {
  humElement.innerText = snap.val()?.toFixed(2) ?? "N/A";
});

onValue(dbRefPres, (snap) => {
  presElement.innerText = snap.val()?.toFixed(2) ?? "N/A";
});

Интерфейс при выходе из системы

Следующий фрагмент обрабатывает пользовательский интерфейс, когда пользователь выходит из системы. Мы хотим скрыть панель аутентификации и основной контент веб-страницы (показания датчиков) и показать форму входа.

} else {
  // Toggle UI elements
  loginElement.style.display = 'block';
  authBarElement.style.display = 'none';
  userDetailsElement.style.display = 'none';
  contentElement.style.display = 'none';
}
Глобальный доступ к функции setupUI

Наконец, следующая строка делает функцию setupUI глобально доступной, присваивая её объекту window (объект window — это глобальный объект в браузере, доступный из любого файла JavaScript). По сути, это гарантирует, что другой файл JavaScript (auth.js) может использовать функцию setupUI для обновления пользовательского интерфейса при входе или выходе пользователя из системы.

window.setupUI = setupUI;

Файл favicon

Для отображения favicon в вашем веб-приложении вам нужно переместить изображение, которое вы хотите использовать в качестве favicon, в папку public. Изображение должно называться favicon.png. Вы можете просто перетащить файл favicon с вашего компьютера в папку public в VS Code.

Мы используем следующий значок в качестве favicon для нашего веб-приложения:

Развёртывание вашего приложения

После сохранения файлов HTML, CSS и JavaScript разверните приложение в VS Code, выполнив следующую команду в окне терминала.

firebase deploy

Терминал должен отобразить что-то подобное:

ESP32 ESP8266 Deploy Firebase Web App

Firebase предлагает бесплатную услугу хостинга для обслуживания ваших ресурсов и веб-приложений. Затем вы можете получить доступ к вашему веб-приложению из любой точки мира.

Вы можете использовать URL-адрес хостинга для доступа к вашему веб-приложению из любой точки мира.

Демонстрация

Поздравляем! Вы успешно развернули ваше приложение. Теперь оно размещено на глобальном CDN с помощью Firebase Hosting. Вы можете получить доступ к вашему веб-приложению из любой точки мира по URL-адресу хостинга. В моём случае это https://esp-firebase-demo.web.app.

ESP32 ESP8266 Sensor Readings Firebase Web App

Веб-приложение является адаптивным, и вы можете получить к нему доступ с помощью смартфона, компьютера или планшета.

Устранение неполадок: если вы не видите веб-страницу веб-приложения, вам может потребоваться выполнить жёсткое обновление веб-браузера для очистки кэша.

Введите email и пароль авторизованного пользователя, которого вы добавили в методы аутентификации Firebase. После этого вы сможете получить доступ к последним показаниям датчиков.

Перейдите на вкладку Hosting в консоли Firebase вашего проекта. Вы можете увидеть домены вашего приложения, историю развёртывания и даже откатить приложение к предыдущим версиям.

Firebase Web App Deploy History and Domains

Заключение

В этом руководстве вы узнали, как создать веб-приложение Firebase с аутентификацией входа/выхода, которое отображает показания датчиков. Показания датчиков сохраняются в базе данных реального времени. База данных защищена с помощью правил базы данных (которые вы уже настроили в предыдущем руководстве).

Вы можете применить полученные здесь знания для отображения любого другого типа данных, и вы можете изменять файлы в папке public, чтобы добавлять различные функции и возможности в ваш проект.

Если вы хотите узнать больше о Firebase, мы рекомендуем ознакомиться с нашей электронной книгой, посвящённой исключительно этой теме:

У нас есть другие ресурсы, связанные с ESP32 и ESP8266, которые могут вам понравиться:


Источник: :doc:`ESP32/ESP8266: Firebase Web App to Display Sensor Readings (with Authentication) <../esp32-esp8266-firebase-web-app-sensor/index>` (Random Nerd Tutorials)