ESP32-CAM: Отображение фотографий в веб-приложении Firebase
В этом руководстве вы создадите веб-приложение Firebase для отображения последней фотографии, сделанной ESP32-CAM и сохранённой в Firebase Storage. Веб-приложение также показывает дату и время, когда была сделана последняя фотография. Веб-приложение бесплатно размещено на серверах Firebase, и вы можете получить к нему доступ из любого места.
Эта статья является Частью 2 предыдущего руководства: ESP32-CAM: Сохранение фотографий в Firebase Storage. Сначала выполните это руководство, прежде чем продолжить.
Обзор проекта
В этом руководстве (Часть 2) вы создадите веб-приложение для отображения последней фотографии, сделанной ESP32-CAM и сохранённой в Firebase Storage (см. предыдущее руководство).
На следующей диаграмме показан общий обзор проекта, который мы будем создавать — программирование ESP32-CAM и настройка проекта Firebase со Storage были выполнены в Части 1.
Firebase размещает ваше веб-приложение через глобальную CDN с помощью Firebase Hosting и предоставляет SSL-сертификат. Вы можете получить доступ к вашему веб-приложению из любого места, используя доменное имя, сгенерированное Firebase.
Веб-приложение отображает последнюю фотографию, сохранённую в Firebase Storage по пути data/photo.jpg.
Оно также отображает информацию о том, когда была сделана фотография (дата и время).
Если веб-страница открыта и тем временем появилась новая фотография, вам нужно нажать кнопку Refresh, чтобы получить новую фотографию из хранилища.
Позже вы можете обновить веб-приложение, чтобы это происходило автоматически. Например, вы можете сохранять время последней сделанной фотографии в Firebase Realtime Database (RTDB). Затем вы можете отслеживать изменения в базе данных и обновлять веб-страницу по мере необходимости для отображения последней фотографии (мы можем рассмотреть это в будущем, более продвинутом руководстве).
Предварительные требования
Прежде чем приступить к созданию веб-приложения Firebase, необходимо проверить следующие предварительные условия.
Создание проекта Firebase
Вы должны были выполнить следующее руководство:
ESP32-CAM должен работать с кодом, предоставленным в этом руководстве, чтобы в Firebase Storage была сохранена фотография. Firebase Storage должен быть настроен, как показано в руководстве.
Установка необходимого программного обеспечения
Прежде чем начать, необходимо установить необходимое программное обеспечение для создания веб-приложения Firebase. Вот список программного обеспечения, которое необходимо установить (перейдите по ссылкам для получения инструкций):
1) Добавление приложения в ваш проект Firebase
1) Перейдите в консоль вашего проекта Firebase и добавьте приложение в проект, созданный в предыдущем руководстве, нажав кнопку +Add app.
2) Выберите значок веб-приложения.
3) Дайте вашему приложению имя. Затем установите флажок рядом с Also set up Firebase Hosting for this App. Нажмите Register app.
4) Затем скопируйте объект firebaseConfig и сохраните его, потому что он понадобится позже.
После этого вы также можете получить доступ к объекту 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. Новое окно терминала должно открыться по пути вашего проекта.
2) Вход в Firebase
4) В предыдущем окне терминала введите следующее:
firebase login
5) Вам будет предложено собирать информацию об использовании CLI и отчёты об ошибках. Введите «n» и нажмите Enter, чтобы отказать.
Примечание: Если вы уже вошли, появится сообщение: «Already logged in as user@gmail.com».
6) После этого в вашем браузере откроется новое окно для входа в учётную запись Firebase.
7) Разрешите Firebase CLI доступ к вашей учётной записи Google.
8) После этого вход в Firebase CLI должен быть успешным. Вы можете закрыть окно браузера.
3) Инициализация проекта веб-приложения Firebase
9) После успешного входа выполните следующую команду, чтобы начать каталог проекта Firebase в текущей папке.
firebase init
10) Вам будет предложено инициализировать проект Firebase в текущем каталоге. Введите Y и нажмите Enter.
11) Затем используйте стрелки вверх и вниз и клавишу пробела для выбора параметров. Выберите следующие параметры:
Hosting: Configure files for Firebase Hosting and (optionally) set up GitHub Action deploys
Storage: Configure a security rules file for Cloud Storage
Выбранные параметры будут отмечены зелёной звёздочкой. Затем нажмите Enter.
12) Выберите опцию «Use an existing project» — это должен быть проект, созданный в Части 1 этого руководства — затем нажмите Enter.
13) Затем выберите параметры хостинга, как показано ниже:
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
14) Затем нажмите Enter на следующем вопросе, чтобы выбрать файл по умолчанию для правил хранилища.
What file should be used for Storage Rules? (storage.rules). Нажмите Enter.
15) Проект Firebase теперь должен быть успешно инициализирован. Обратите внимание, что VS Code создал некоторые необходимые файлы в папке вашего проекта.
Файл index.html содержит некоторый HTML-текст для создания веб-страницы. Пока оставьте HTML-текст по умолчанию. Идея состоит в том, чтобы заменить его своим собственным HTML-текстом для создания пользовательской веб-страницы для ваших нужд. Мы сделаем это позже в этом руководстве.
16) Чтобы проверить, всё ли прошло, как ожидалось, выполните следующую команду в окне терминала VS Code.
firebase deploy
Вам будет предложено установить новую роль. Нажмите Enter для подтверждения.
Вы должны получить сообщение Deploy complete! и URL-адрес консоли проекта и URL-адрес хостинга.
17) Скопируйте URL хостинга и вставьте его в окно веб-браузера. Вы должны увидеть следующую веб-страницу. Вы можете получить доступ к этой веб-странице из любой точки мира.
Веб-страница, которую вы видели ранее, создана с помощью HTML-файла, размещённого в папке public вашего проекта Firebase. Изменяя содержимое этого файла, вы можете создать своё собственное веб-приложение. Именно это мы и будем делать в следующем разделе.
3) Создание веб-приложения Firebase
Теперь, когда вы успешно создали приложение проекта Firebase в VS Code, выполните следующие шаги для настройки приложения для отображения фотографии, сохранённой в Firebase Storage.
index.html
Скопируйте следующий код в ваш файл index.html. Этот HTML-файл создаёт простую веб-страницу, которая отображает последнюю фотографию, сохранённую в Firebase Storage, и время, когда она была сделана (создано в предыдущем проекте).
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ESP Firebase App</title>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href="style.css">
<script type="module" src="app.js"></script>
</head>
<body>
<div class="topnav">
<h1>ESP32-CAM Web App <i class="fas fa-camera"></i></h1>
</div>
<p><img id="img" width="500px"></p>
<p>Last picture taken: <span id="date-time"></span></p>
<button type="button" id="refreshBtn">Refresh</button>
</body>
</html>
Вам нужно изменить код, указав свой собственный объект firebaseConfig — тот, который вы получили на этом шаге.
Как это работает
Давайте кратко рассмотрим 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">
Ссылка на внешний файл style.css для форматирования HTML-страницы.
<link rel="stylesheet" type="text/css" href="style.css">
Загрузка файла JavaScript app.js.
<script type="module" src="app.js"></script>
Эта строка указывает браузеру загрузить и выполнить файл JavaScript app.js, расположенный в том же каталоге, что и файл index.html — мы создадим этот файл далее.
Мы закончили с метаданными. Теперь давайте перейдём к HTML-частям, видимым пользователю — между тегами <body> и </body>.
Мы создаём верхнюю панель «навигации» с именем нашего приложения и маленькой иконкой из fontawesome.
<div class="topnav">
<h1>ESP32-CAM Web App <i class="fas fa-camera"></i></h1>
</div>
Следующая строка создаёт абзац с тегом изображения, где мы позже отобразим фотографию. Тег изображения имеет определённый id («img»), чтобы мы могли обращаться к этому элементу в файле JavaScript по его id.
<p><img id="img" width="500px"></p>
Далее мы создаём абзац для отображения даты и времени, когда была сделана фотография. Есть тег <span> с id date-time, где мы позже отобразим эту информацию.
<p>Last picture taken: <span id="date-time"></span></p>
Наконец, есть кнопка для обновления веб-страницы (для отображения новой фотографии, если она есть).
<button onclick="window.location.reload();">Refresh</button>
Сохраните HTML-файл.
style.css
Внутри папки public создайте файл с именем style.css. Чтобы создать файл, выберите папку public, а затем нажмите на значок +file в верхней части проводника файлов. Назовите его style.css.
Затем скопируйте следующий код в файл style.css.
html {
font-family: Arial, Helvetica, sans-serif;
display: inline-block;
text-align: center;
}
h1 {
font-size: 1.8rem;
color: white;
}
p {
font-size: 1.2rem;
}
.topnav {
overflow: hidden;
background-color: #0A1128;
}
body {
margin: 0;
}
button{
background-color: #034078;
border: none;
padding: 14px 20px;
text-align: center;
font-size: 20px;
border-radius: 4px;
transition-duration: 0.4s;
width: 150px;
color: white;
cursor: pointer;
}
CSS-файл содержит несколько простых стилей, чтобы наша веб-страница выглядела лучше. Мы не будем обсуждать работу CSS в этом руководстве.
Файл JavaScript
Создайте новый файл внутри папки public с именем app.js.
На следующем изображении показано, как должна выглядеть структура папок вашего проекта веб-приложения.
app.js
Скопируйте следующий код в файл app.js, который вы создали ранее.
import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.14.1/firebase-app.js';
import { getAuth, signInWithEmailAndPassword } from 'https://www.gstatic.com/firebasejs/10.14.1/firebase-auth.js';
import { getStorage, ref, getDownloadURL, getMetadata } from 'https://www.gstatic.com/firebasejs/10.14.1/firebase-storage.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"
};
const email = 'AUTHORIZED_USER_EMAIL'; // Replace with your user email
const password = 'PASSWORD'; // Replace with your user password
// Initialize Firebase
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
const storage = getStorage(app);
// Format date and time
const formatDateTime = (date) => {
const pad = (num) => String(num).padStart(2, '0');
return `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())} at ${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
};
// Authenticate user
const authenticate = async () => {
try {
const userCredential = await signInWithEmailAndPassword(auth, email, password);
return userCredential.user;
} catch (error) {
document.getElementById('date-time').textContent = `Authentication error: ${error.message}`;
throw error;
}
};
// Load image and metadata
const loadImageData = async (user) => {
try {
const storageRef = ref(storage, 'data/photo.jp');
const url = await getDownloadURL(storageRef);
document.querySelector('#img').src = url;
const metadata = await getMetadata(storageRef);
document.getElementById('date-time').textContent = formatDateTime(new Date(metadata.timeCreated));
} catch (error) {
document.getElementById('date-time').textContent = `Error: ${error.message}`;
}
};
// Initialize on page load
document.addEventListener('DOMContentLoaded', async () => {
const user = await authenticate();
await loadImageData(user);
document.querySelector('#refreshBtn').addEventListener('click', async () => {
const user = await authenticate();
await loadImageData(user);
});
});
Этот файл получает фотографию, сохранённую в Firebase Storage, и время, когда она была сделана, и отображает это на HTML-странице.
Модули Firebase
Сначала мы загружаем необходимые модули Firebase, которые будем использовать.
import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.14.1/firebase-app.js';
import { getAuth, signInWithEmailAndPassword } from 'https://www.gstatic.com/firebasejs/10.14.1/firebase-auth.js';
import { getStorage, ref, getDownloadURL, getMetadata } from 'https://www.gstatic.com/firebasejs/10.14.1/firebase-storage.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"
};
Email и пароль пользователя
Вставьте email и пароль авторизованного пользователя. Вы должны были настроить это в части 1 этого руководства.
const email = 'AUTHORIZED_USER_EMAIL'; // Replace with your user email
const password = 'PASSWORD'; // Replace with your user password
Инициализация приложения Firebase
Следующие строки инициализируют приложение Firebase.
// Initialize Firebase
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
const storage = getStorage(app);
Форматирование даты и времени
Следующие строки форматируют дату и время для отображения на веб-странице в определённом формате. Например: 11:05:11 at 2025-07-02.
// Format date and time
const formatDateTime = (date) => {
const pad = (num) => String(num).padStart(2, '0');
return `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())} at ${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
};
Аутентификация
Следующая функция выполнит аутентификацию с использованием email и пароля, которые мы определили ранее.
// Authenticate user
const authenticate = async () => {
try {
const userCredential = await signInWithEmailAndPassword(auth, email, password);
return userCredential.user;
} catch (error) {
document.getElementById('date-time').textContent = `Authentication error: ${error.message}`;
throw error;
}
};
Загрузка изображения и метаданных
Функция loadImageData получит изображение из Firebase Storage и разместит его в нужном месте на веб-странице.
const loadImageData = async (user) => {
try {
const storageRef = ref(storage, 'data/photo.jp');
const url = await getDownloadURL(storageRef);
document.querySelector('#img').src = url;
Это конкретная строка, которая получает ссылку на изображение:
const storageRef = ref(storage, 'data/photo.jp');
Примечание: в моём случае на данный момент есть своего рода баг, который обрезает имя фотографии до data/photo.jp вместо data/photo.jpg. Измените имя фотографии, если у вас не так.
Мы можем получить время, когда было сделано изображение, из его метаданных. Следующие строки получают дату и время, когда была сделана фотография, и размещают их в нужном месте на веб-странице.
const metadata = await getMetadata(storageRef);
document.getElementById('date-time').textContent = formatDateTime(new Date(metadata.timeCreated));
} catch (error) {
document.getElementById('date-time').textContent = `Error: ${error.message}`;
}
Инициализация приложения при загрузке страницы
Следующие строки будут выполняться каждый раз, когда вы открываете или обновляете веб-страницу.
// Initialize on page load
document.addEventListener('DOMContentLoaded', async () => {
const user = await authenticate();
await loadImageData(user);
document.querySelector('#refreshBtn').addEventListener('click', async () => {
const user = await authenticate();
await loadImageData(user);
});
});
Когда это происходит, мы аутентифицируемся с помощью email и пароля.
const user = await authenticate();
Затем мы загружаем изображение.
await loadImageData(user);
Мы также добавляем обработчик событий к кнопке Refresh. При нажатии на эту кнопку будет выполнена аутентификация с email и паролем, а также загрузка изображения.
document.querySelector('#refreshBtn').addEventListener('click', async () => {
const user = await authenticate();
await loadImageData(user);
});
Правила Storage
В левой боковой панели вашего проекта Firebase должен быть файл с именем storage.rules.
Откройте этот файл и скопируйте следующие правила. Эти правила позволяют любому аутентифицированному пользователю читать и записывать в Firebase Storage. Сохраните файл.
rules_version = '2';
// Craft rules based on data in your Firestore database
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if request.auth != null;
}
}
}
Развёртывание приложения
После сохранения HTML- и JavaScript-файлов разверните ваше приложение в VS Code, выполнив следующую команду.
firebase deploy
Firebase предлагает бесплатный хостинг для размещения ваших ресурсов и веб-приложений. После этого вы можете получить доступ к вашему веб-приложению из любого места.
Терминал должен отобразить что-то подобное:
Вы можете использовать предоставленный URL хостинга для доступа к вашему веб-приложению из любого места.
Демонстрация
Поздравляем! Вы успешно развернули ваше приложение. Теперь оно размещено на глобальной CDN с помощью Firebase Hosting. Вы можете получить доступ к вашему веб-приложению из любого места по предоставленному URL хостинга. В моём случае это https://esp-firebase-demo.web.app.
Веб-приложение адаптивное, и вы можете получить к нему доступ с помощью смартфона, компьютера или планшета.
Перезагрузите плату ESP32-CAM, и она должна сделать новую фотографию при первом запуске. Затем нажмите кнопку Refresh в веб-приложении, чтобы получить последнюю сделанную фотографию.
Заключение
В этом руководстве вы узнали, как создать веб-приложение Firebase, которое взаимодействует с Firebase Storage для отображения последнего изображения, сделанного ESP32-CAM.
Вы можете применить то, что вы узнали здесь, для отображения любого другого типа файла (не только jpeg), и вы можете изменить файлы в папке public, чтобы добавить различные функциональные возможности и функции в ваш проект. Например, добавить форму аутентификации, отобразить несколько фотографий и т.д.
Если вы хотите узнать больше о Firebase, рекомендуем ознакомиться с нашей новой электронной книгой:
У нас также есть другие ресурсы, связанные с ESP32 и ESP8266, которые могут вам понравиться: