{"id":168608,"date":"2025-04-17T14:56:21","date_gmt":"2025-04-17T14:56:21","guid":{"rendered":"https:\/\/randomnerdtutorials.com\/?p=168608"},"modified":"2025-04-17T14:56:25","modified_gmt":"2025-04-17T14:56:25","slug":"esp32-cam-qr-code-reader-web-server","status":"publish","type":"post","link":"https:\/\/randomnerdtutorials.com\/esp32-cam-qr-code-reader-web-server\/","title":{"rendered":"ESP32-CAM QR Code Reader User Management System (Web Server)"},"content":{"rendered":"\n<p>In this project, you&#8217;ll build a QR code user management system with a web server that runs on an ESP32-CAM. The ESP32-CAM is constantly using its camera to scan for new QR codes using the <span class=\"rnthl rntliteral\">ESP32QRCodeReader<\/span> library and a modified version of the <span class=\"rnthl rntliteral\">quirc<\/span> library. When it detects a valid QR code, it stores the QR code data on the MicroSD card. You can access the web server in any browser to manage the users and view the complete log. The ESP32-CAM will be programmed using Arduino IDE.<\/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\/2025\/04\/ESP32-CAM-QR-Code-Manager-Web-Server.jpg?resize=1200%2C675&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32-CAM QR Code Reader User Management System (Web Server)\" class=\"wp-image-168957\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Manager-Web-Server.jpg?w=1920&amp;quality=100&amp;strip=all&amp;ssl=1 1920w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Manager-Web-Server.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Manager-Web-Server.jpg?resize=1024%2C576&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Manager-Web-Server.jpg?resize=768%2C432&amp;quality=100&amp;strip=all&amp;ssl=1 768w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Manager-Web-Server.jpg?resize=1536%2C864&amp;quality=100&amp;strip=all&amp;ssl=1 1536w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\">Project Overview<\/h2>\n\n\n\n<p>The following diagram shows a high-level overview of how the project works.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"1200\" height=\"829\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Management-Web-Server-01.jpg?resize=1200%2C829&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32-CAM QR Code Management Web Server\" class=\"wp-image-168952\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Management-Web-Server-01.jpg?w=1200&amp;quality=100&amp;strip=all&amp;ssl=1 1200w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Management-Web-Server-01.jpg?resize=300%2C207&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Management-Web-Server-01.jpg?resize=1024%2C707&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Management-Web-Server-01.jpg?resize=768%2C531&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/><\/figure><\/div>\n\n\n<p><strong>1) <\/strong>When the ESP32-CAM detects a valid QR code, it reads its data and the built-in LED flash will blink.<\/p>\n\n\n\n<p><strong>2)<\/strong> The ESP32-CAM records the time of that interaction and saves the time and QR code data on the microSD card on a file called <em>log.txt<\/em>.<\/p>\n\n\n\n<p><strong>3)<\/strong> The ESP32-CAM also hosts a web server to display and manage the information from the microSD card.<\/p>\n\n\n\n<p><strong>4)<\/strong> The root (<span class=\"rnthl rntliteral\">\/<\/span>) URL shows the complete log (saved on the microSD card module <em>log.txt<\/em>) with the timestamp and the QR code data.<\/p>\n\n\n\n<p><strong>5)<\/strong> There&#8217;s another page on the <span class=\"rnthl rntliteral\">\/add-user<\/span> path that allows you to add users and their roles using a form.<\/p>\n\n\n\n<p><strong>6)<\/strong> The data entered via this form will be saved on the <em>user.txt<\/em> file saved on the microSD card.<\/p>\n\n\n\n<p><strong>7)<\/strong> There is another page on the <span class=\"rnthl rntliteral\">\/manage-users<\/span> path that allows you to consult and delete users.<\/p>\n\n\n\n<p><strong>8)<\/strong> This page allows you to interact with the <em>users.txt <\/em>file.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Parts Required<\/h2>\n\n\n\n<p>We&#8217;ll be using the ESP32-CAM board labeled as AI-Thinker module, but other modules should also work by making the correct pin assignment in the code. The <a aria-label=\" (opens in a new tab)\" href=\"https:\/\/makeradvisor.com\/tools\/esp32-cam\/\" target=\"_blank\" rel=\"noreferrer noopener\">ESP32-CAM board<\/a> is a $9 device (or less) that combines an ESP32-S chip, an OV2640 camera, a microSD card slot, and several GPIO pins.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"750\" height=\"421\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2019\/03\/ESP32-CAM-camera.jpg?resize=750%2C421&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32-CAM board is a $9 device with an OV2640 camera, microSD card slot and several GPIO pins\" class=\"wp-image-82440\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2019\/03\/ESP32-CAM-camera.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2019\/03\/ESP32-CAM-camera.jpg?resize=300%2C168&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<p>To follow this tutorial you need the following components:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><a aria-label=\" (opens in a new tab)\" href=\"https:\/\/makeradvisor.com\/tools\/esp32-cam\/\" target=\"_blank\" rel=\"noreferrer noopener\">ESP32-CAM with OV2640<\/a><\/strong> &#8211; read <a aria-label=\"Best ESP32-CAM Dev Boards (opens in a new tab)\" href=\"https:\/\/makeradvisor.com\/esp32-camera-cam-boards-review-comparison\/\" target=\"_blank\" rel=\"noreferrer noopener\">Best ESP32-CAM Dev Boards<\/a> (or another ESP32-CAM with the OV2640 camera)<\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/esp32-cam-mb-usb-programmer\/\" target=\"_blank\" rel=\"noopener\" title=\"\">Recommended &#8211; ESP32-CAM-MB Micro USB Programmer<\/a> or <a aria-label=\" (opens in a new tab)\" href=\"https:\/\/makeradvisor.com\/tools\/ftdi-programmer-board\/\" target=\"_blank\" rel=\"noreferrer noopener\">FTDI programmer<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/microsd-card-raspberry-pi-16gb-class-10\/\" target=\"_blank\" rel=\"noreferrer noopener\">MicroSD Card<\/a><\/li>\n<\/ul>\n\n\n\n<p>If you&#8217;re using an ESP32 camera board without microSD card support, you also need a <a href=\"https:\/\/makeradvisor.com\/tools\/sd-card-module\/\" target=\"_blank\" rel=\"noopener\" title=\"\">microSD card module<\/a>: <\/p>\n\n\n<p>You can use the preceding links or go directly to <a href=\"https:\/\/makeradvisor.com\/tools\/?utm_source=rnt&utm_medium=post&utm_campaign=post\" target=\"_blank\">MakerAdvisor.com\/tools<\/a> to find all the parts for your projects at the best price!<\/p><p style=\"text-align:center;\"><a href=\"https:\/\/makeradvisor.com\/tools\/?utm_source=rnt&utm_medium=post&utm_campaign=post\" target=\"_blank\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2017\/10\/header-200.png?w=1200&#038;quality=100&#038;strip=all&#038;ssl=1\"><\/a><\/p>\n\n\n\n<p>For an introduction to the ESP32-CAM, you can follow the next tutorials:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-cam-video-streaming-face-recognition-arduino-ide\/\">ESP32-CAM Video Streaming with Arduino IDE<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-cam-ai-thinker-pinout\/\">ESP32-CAM AI-Thinker Pinout Guide: GPIOs Usage Explained<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-cam-troubleshooting-guide\/\">ESP32-CAM Troubleshooting Guide<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-cam-qr-code-reader-scanner-arduino\/\">ESP32-CAM QR Code Reader\/Scanner (Arduino IDE)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-cam-projects-ebook\/\">Build ESP32-CAM Projects using Arduino IDE (eBook)<\/a><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Preparing the Arduino IDE<\/h2>\n\n\n\n<p>We&#8217;ll program the ESP32 board using Arduino IDE. So you need the Arduino IDE installed as well as the ESP32 add-on. You can follow the next tutorial to install the ESP32 add-on, if you haven\u2019t already:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/installing-esp32-arduino-ide-2-0\/\" title=\"\">Installing ESP32 Board in Arduino IDE 2 (Windows, Mac OS X, Linux)<\/a><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Installing the&nbsp;ESP32QRCodeReader Library<\/h3>\n\n\n\n<p>For this tutorial, we\u2019ll use the&nbsp;<span class=\"rnthl rntliteral\">ESP32QRCodeReader<\/span> library by Alvarowolfx, which makes it easy to read QR codes with the ESP32-CAM board.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><a href=\"https:\/\/github.com\/RuiSantosdotme\/ESP32QRCodeReader\/archive\/refs\/heads\/master.zip\" target=\"_blank\" rel=\"noopener\" title=\"\">Click here to download the ESP32QRCodeReader library<\/a><\/strong><\/li>\n<\/ul>\n\n\n\n<p>Then, in the Arduino IDE, go to&nbsp;<strong>Sketch<\/strong>&nbsp;&gt; <strong>Include Library<\/strong>&nbsp;&gt;&nbsp;<strong>Add .ZIP library<\/strong> and install the library that you&#8217;ve just downloaded in the previous link.<\/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=\"560\" height=\"293\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/03\/Arduino-Install-Library-Sketch-include-library-add-zip-library.png?resize=560%2C293&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Arduino Install Library Sketch include library add zip library\" class=\"wp-image-168263\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/03\/Arduino-Install-Library-Sketch-include-library-add-zip-library.png?w=560&amp;quality=100&amp;strip=all&amp;ssl=1 560w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/03\/Arduino-Install-Library-Sketch-include-library-add-zip-library.png?resize=300%2C157&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 560px) 100vw, 560px\" \/><\/figure><\/div>\n\n\n<h3 class=\"wp-block-heading\">Installing the Async Web Server Libraries<\/h3>\n\n\n\n<p>We&#8217;ll build the web server using the following libraries:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/github.com\/ESP32Async\/ESPAsyncWebServer\" target=\"_blank\" rel=\"noopener\" title=\"\">ESPAsyncWebServer&nbsp;<\/a>by ESP32Async<\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/ESP32Async\/AsyncTCP\" target=\"_blank\" rel=\"noopener\" title=\"\">AsyncTCP<\/a> by ESP32Async<\/li>\n<\/ul>\n\n\n\n<p>You can install these libraries in the Arduino Library Manager. Open the Library Manager by clicking the Library icon at the left sidebar.<\/p>\n\n\n\n<p>Search for <span class=\"rnthl rntliteral\">ESPAsyncWebServer<\/span> and install the <strong>ESPAsyncWebServer by ESP32Async<\/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=\"666\" height=\"586\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/Install-ESPAsyncWebServer-Library-ArduinoIDE-2-f.png?resize=666%2C586&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Installing ESPAsyncWebServer ESP32 Arduino IDE\" class=\"wp-image-167890\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/Install-ESPAsyncWebServer-Library-ArduinoIDE-2-f.png?w=666&amp;quality=100&amp;strip=all&amp;ssl=1 666w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/Install-ESPAsyncWebServer-Library-ArduinoIDE-2-f.png?resize=300%2C264&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 666px) 100vw, 666px\" \/><\/figure><\/div>\n\n\n<p>Then, install the AsyncTCP library. Search for <span class=\"rnthl rntliteral\">AsyncTCP<\/span> and install the <strong>AsyncTCP by ESP32Async<\/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=\"722\" height=\"586\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/Install-AsyncTCP-Library-ArduinoIDE.png?resize=722%2C586&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Installing AsyncTCP ESP32 Arduino IDE\" class=\"wp-image-167886\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/Install-AsyncTCP-Library-ArduinoIDE.png?w=722&amp;quality=100&amp;strip=all&amp;ssl=1 722w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/Install-AsyncTCP-Library-ArduinoIDE.png?resize=300%2C243&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 722px) 100vw, 722px\" \/><\/figure><\/div>\n\n\n<h3 class=\"wp-block-heading\">LittleFS Uploader Plugin<\/h3>\n\n\n\n<p>The files used to build the web server will be saved on the ESP32 LittleFS filesystem. Make sure you have the LittleFS Uploader Plugin installed in your Arduino IDE. You can follow this tutorial:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/arduino-ide-2-install-esp32-littlefs\/\">Arduino IDE 2: Install ESP32 LittleFS Uploader (Upload Files to the Filesystem)<\/a><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Preparing the MicroSD Card<\/h2>\n\n\n\n<p>Before proceeding with the tutorial, make sure you <strong>format your microSD card as FAT32<\/strong>. Follow the next instructions to format your microSD card or use a software tool like <a href=\"https:\/\/www.sdcard.org\/downloads\/formatter\/\" target=\"_blank\" rel=\"noreferrer noopener\">SD Card Formatter<\/a> (compatible with Windows and Mac OS).<\/p>\n\n\n\n<p><strong>1.<\/strong>&nbsp;Insert the microSD card into your computer. Go to&nbsp;<strong>My Computer<\/strong>&nbsp;and right-click on the SD card. Select&nbsp;<strong>Format&nbsp;<\/strong>as shown in the figure below.<\/p>\n\n\n<div class=\"wp-block-image is-style-default\">\n<figure class=\"aligncenter\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/rntlab.com\/wp-content\/uploads\/2018\/05\/format-SD-card-1.png?w=1200&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"MicroSD Card Module format sd card\" class=\"wp-image-11805\"\/><\/figure><\/div>\n\n\n<p><strong>2.&nbsp;<\/strong>A new window pops up. Select&nbsp;<strong>FAT32<\/strong>, press&nbsp;<strong>Start<\/strong>&nbsp;to initialize the formatting process, and follow the onscreen instructions.<\/p>\n\n\n<div class=\"wp-block-image is-style-default\">\n<figure class=\"aligncenter\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/rntlab.com\/wp-content\/uploads\/2018\/05\/format-SD-card-2.png?w=1200&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"MicroSD Card Module format sd card\" class=\"wp-image-11806\"\/><\/figure><\/div>\n\n\n<p>Attach the microSD card to the ESP32-CAM:<\/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=\"422\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-connect-Micro-SD-Card-in-slot.jpg?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32-CAM connect Micro SD Card in slot\" class=\"wp-image-168774\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-connect-Micro-SD-Card-in-slot.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-connect-Micro-SD-Card-in-slot.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<p>To learn how to use the microSD card with the ESP32-CAM, you can read the next tutorial:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-cam-photo-microsd-card-timestamp\/\">ESP32-CAM Take Photo and Save to MicroSD Card with Date and Time (timestamp)<\/a><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"organizing-web-server-files\">Organizing Your Files<\/h2>\n\n\n\n<p>To keep the project organized and make it easier to understand, we\u2019ll create 6 files to build the web server:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Arduino sketch<\/strong>: to handle the web server, QR Code reader, and microSD card;<\/li>\n\n\n\n<li><strong>full-log.html<\/strong>: loads the log of every QR Code that has been successfully scanned and its user data;<\/li>\n\n\n\n<li><strong>manage-users.html<\/strong>: web page that allows you to view and delete users;<\/li>\n\n\n\n<li><strong>add-user.html<\/strong>: web page that allows you to add new users with a unique QR Code;<\/li>\n\n\n\n<li><strong>get.html<\/strong>: handles all the HTTP GET requests;<\/li>\n\n\n\n<li><strong>style.css<\/strong>: to style the web page.<\/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=\"1200\" height=\"516\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/12\/Folder-structure-RFID-Web-Server_Folder-Structure-ESP32.png?resize=1200%2C516&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Organizing your Files arduino sketch index html style css\" class=\"wp-image-164640\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/12\/Folder-structure-RFID-Web-Server_Folder-Structure-ESP32.png?w=3553&amp;quality=100&amp;strip=all&amp;ssl=1 3553w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/12\/Folder-structure-RFID-Web-Server_Folder-Structure-ESP32.png?resize=300%2C129&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/12\/Folder-structure-RFID-Web-Server_Folder-Structure-ESP32.png?resize=1024%2C441&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/12\/Folder-structure-RFID-Web-Server_Folder-Structure-ESP32.png?resize=768%2C331&amp;quality=100&amp;strip=all&amp;ssl=1 768w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/12\/Folder-structure-RFID-Web-Server_Folder-Structure-ESP32.png?resize=1536%2C661&amp;quality=100&amp;strip=all&amp;ssl=1 1536w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/12\/Folder-structure-RFID-Web-Server_Folder-Structure-ESP32.png?resize=2048%2C881&amp;quality=100&amp;strip=all&amp;ssl=1 2048w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/12\/Folder-structure-RFID-Web-Server_Folder-Structure-ESP32.png?w=2400&amp;quality=100&amp;strip=all&amp;ssl=1 2400w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/><\/figure><\/div>\n\n\n<p>You should save the HTML and CSS files inside a folder called&nbsp;<em><strong>data<\/strong>&nbsp;<\/em>inside the Arduino sketch folder, as shown in the previous diagram. We\u2019ll upload these files to the ESP32-CAM filesystem (LittleFS).<\/p>\n\n\n\n<p><strong>You can download all project files:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><a href=\"https:\/\/github.com\/RuiSantosdotme\/ESP32-CAM-Arduino-IDE\/raw\/refs\/heads\/master\/ESP32-CAM-QR-Code-User-Management-WS\/ESP32-CAM-QR-Code-User-Management-WS.zip\" target=\"_blank\" rel=\"noopener\" title=\"\">Click here to download all the project files<\/a><\/strong><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"html-file\">HTML Files<\/h2>\n\n\n\n<p>Copy the following to the <span class=\"rnthl rntliteral\">full-log.html<\/span> file.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-html\">&lt;!DOCTYPE html&gt;\r\n&lt;html lang=&quot;en&quot;&gt;\r\n&lt;head&gt;\r\n    &lt;meta charset=&quot;UTF-8&quot;&gt;\r\n    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;\r\n    &lt;title&gt;Manage Users&lt;\/title&gt;\r\n    &lt;link rel=&quot;stylesheet&quot; href=&quot;style.css&quot;&gt;\r\n&lt;\/head&gt;\r\n&lt;body&gt;\r\n    &lt;nav&gt;\r\n        &lt;div class=&quot;nav-container&quot;&gt;\r\n            &lt;a href=&quot;\/&quot; class=&quot;brand&quot;&gt;User Management&lt;\/a&gt;\r\n            &lt;ul class=&quot;nav-menu&quot;&gt;\r\n                &lt;li&gt;&lt;a href=&quot;\/&quot;&gt;\ud83d\udcc4 Full Log&lt;\/a&gt;&lt;\/li&gt;\r\n                &lt;li&gt;&lt;a href=&quot;add-user&quot;&gt;\u2795 Add User&lt;\/a&gt;&lt;\/li&gt;\r\n                &lt;li&gt;&lt;a href=&quot;manage-users&quot;&gt;\ud83d\udc64 Manage Users&lt;\/a&gt;&lt;\/li&gt;\r\n            &lt;\/ul&gt;\r\n        &lt;\/div&gt;\r\n    &lt;\/nav&gt;\r\n    &lt;div class=&quot;main-container&quot;&gt;\r\n        &lt;section class=&quot;main-section&quot;&gt;\r\n            &lt;h2&gt;\ud83d\udcc4 Full Access Log&lt;\/h2&gt;\r\n            &lt;table id=&quot;tableData&quot;&gt;\r\n                &lt;thead&gt;\r\n                    &lt;tr&gt;\r\n                        &lt;th&gt;Date&lt;\/th&gt;\r\n                        &lt;th&gt;Time&lt;\/th&gt;\r\n                        &lt;th&gt;QR Code&lt;\/th&gt;\r\n                        &lt;th&gt;Role&lt;\/th&gt;\r\n                    &lt;\/tr&gt;\r\n                &lt;\/thead&gt;\r\n                &lt;tbody&gt;\r\n                    &lt;!-- Data from log.txt will be loaded here --&gt;\r\n                &lt;\/tbody&gt;\r\n            &lt;\/table&gt;\r\n        &lt;\/section&gt;\r\n    &lt;\/div&gt;\r\n    &lt;div class=&quot;main-container&quot;&gt;\r\n        &lt;a href=&quot;get?delete=log&quot;&gt;&lt;button class=&quot;button button-delete&quot;&gt;\ud83d\uddd1\ufe0f Delete log.txt File&lt;\/button&gt;&lt;\/a&gt;\r\n    &lt;\/div&gt;\r\n    &lt;script&gt;\r\n        \/\/ JavaScript to load and parse log.txt\r\n        async function loadTableData() {\r\n            try {\r\n                const response = await fetch('view-log');\r\n                const data = await response.text();\r\n                const rows = data.trim().split('\\n').slice(1); \/\/ Skip the header line\r\n\r\n                const tableBody = document.querySelector('#tableData tbody');\r\n                rows.forEach(row =&gt; {\r\n                    const columns = row.split(',');\r\n                    const tr = document.createElement('tr');\r\n                    columns.forEach(column =&gt; {\r\n                        const td = document.createElement('td');\r\n                        td.textContent = column;\r\n                        tr.appendChild(td);\r\n                    });\r\n                    tableBody.appendChild(tr);\r\n                });\r\n            } catch (error) {\r\n                console.error('Error loading log data:', error);\r\n            }\r\n        }\r\n        \/\/ Call the function to load log data\r\n        loadTableData();\r\n    &lt;\/script&gt;\r\n&lt;\/body&gt;\r\n&lt;\/html&gt;\r\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/ESP32-CAM-Arduino-IDE\/raw\/master\/ESP32-CAM-QR-Code-User-Management-WS\/data\/full-log.html\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<p>Copy the following to the <span class=\"rnthl rntliteral\">manage-users.html<\/span> file.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-html\">&lt;!DOCTYPE html&gt;\r\n&lt;html lang=&quot;en&quot;&gt;\r\n&lt;head&gt;\r\n    &lt;meta charset=&quot;UTF-8&quot;&gt;\r\n    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;\r\n    &lt;title&gt;Manage Users&lt;\/title&gt;\r\n    &lt;link rel=&quot;stylesheet&quot; href=&quot;style.css&quot;&gt;\r\n&lt;\/head&gt;\r\n&lt;body&gt;\r\n    &lt;nav&gt;\r\n        &lt;div class=&quot;nav-container&quot;&gt;\r\n            &lt;a href=&quot;\/&quot; class=&quot;brand&quot;&gt;User Management&lt;\/a&gt;\r\n            &lt;ul class=&quot;nav-menu&quot;&gt;\r\n                &lt;li&gt;&lt;a href=&quot;\/&quot;&gt;\ud83d\udcc4 Full Log&lt;\/a&gt;&lt;\/li&gt;\r\n                &lt;li&gt;&lt;a href=&quot;add-user&quot;&gt;\u2795 Add User&lt;\/a&gt;&lt;\/li&gt;\r\n                &lt;li&gt;&lt;a href=&quot;manage-users&quot;&gt;\ud83d\udc64 Manage Users&lt;\/a&gt;&lt;\/li&gt;\r\n            &lt;\/ul&gt;\r\n        &lt;\/div&gt;\r\n    &lt;\/nav&gt;\r\n    &lt;div class=&quot;main-container&quot;&gt;\r\n        &lt;section class=&quot;main-section&quot;&gt;\r\n            &lt;h2&gt;\ud83d\udc64 User Log&lt;\/h2&gt;\r\n            &lt;table id=&quot;tableData&quot;&gt;\r\n                &lt;thead&gt;\r\n                    &lt;tr&gt;\r\n                        &lt;th&gt;QR Code&lt;\/th&gt;\r\n                        &lt;th&gt;Role&lt;\/th&gt;\r\n                        &lt;th&gt;Delete&lt;\/th&gt;\r\n                    &lt;\/tr&gt;\r\n                &lt;\/thead&gt;\r\n                &lt;tbody&gt;\r\n                    &lt;!-- Data from users.txt will be loaded here --&gt;\r\n                &lt;\/tbody&gt;\r\n            &lt;\/table&gt;\r\n        &lt;\/section&gt;\r\n    &lt;\/div&gt;\r\n    &lt;div class=&quot;main-container&quot;&gt;\r\n        &lt;a href=&quot;get?delete=users&quot;&gt;&lt;button class=&quot;button button-delete&quot;&gt;\ud83d\uddd1\ufe0f Delete users.txt File&lt;\/button&gt;&lt;\/a&gt;\r\n    &lt;\/div&gt;\r\n    &lt;script&gt;\r\n        \/\/ JavaScript to load and parse users.txt\r\n        async function loadTableData() {\r\n            try {\r\n                const response = await fetch('view-users');\r\n                const data = await response.text();\r\n                const rows = data.trim().split('\\n').slice(1); \/\/ Skip the header line\r\n\r\n                const tableBody = document.querySelector('#tableData tbody');\r\n                rows.forEach((row, index) =&gt; {\r\n                    const columns = row.split(',');\r\n                    const tr = document.createElement('tr');\r\n                    \/\/ Add remaining columns\r\n                    columns.forEach(column =&gt; {\r\n                        const td = document.createElement('td');\r\n                        td.textContent = column;\r\n                        tr.appendChild(td);\r\n                    });\r\n                    \/\/ Create and add row number cell with a delete link\r\n                    const noCell = document.createElement('td');\r\n                    const deleteLink = document.createElement('a');\r\n                    deleteLink.href = `get?delete-user=${index + 1}`;\r\n                    deleteLink.textContent = &quot;\u274c Delete User #&quot; + (index + 1);\r\n                    noCell.appendChild(deleteLink);\r\n                    tr.appendChild(noCell);\r\n\r\n                    tableBody.appendChild(tr);\r\n                });\r\n            } catch (error) {\r\n                console.error('Error loading log data:', error);\r\n            }\r\n        }\r\n        \/\/ Call the function to load log data\r\n        loadTableData();\r\n    &lt;\/script&gt;\r\n&lt;\/body&gt;\r\n&lt;\/html&gt;<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/ESP32-CAM-Arduino-IDE\/raw\/master\/ESP32-CAM-QR-Code-User-Management-WS\/data\/manage-users.html\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<p>Copy the following to the <span class=\"rnthl rntliteral\">add-user.html<\/span> file.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-html\">&lt;!DOCTYPE html&gt;\r\n&lt;html lang=&quot;en&quot;&gt;\r\n&lt;head&gt;\r\n    &lt;meta charset=&quot;UTF-8&quot;&gt;\r\n    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;\r\n    &lt;title&gt;Add User&lt;\/title&gt;\r\n    &lt;link rel=&quot;stylesheet&quot; href=&quot;style.css&quot;&gt;\r\n&lt;\/head&gt;\r\n&lt;body&gt;\r\n    &lt;nav&gt;\r\n        &lt;div class=&quot;nav-container&quot;&gt;\r\n            &lt;a href=&quot;\/&quot; class=&quot;brand&quot;&gt;User Management&lt;\/a&gt;\r\n            &lt;ul class=&quot;nav-menu&quot;&gt;\r\n                &lt;li&gt;&lt;a href=&quot;\/&quot;&gt;\ud83d\udcc4 Full Log&lt;\/a&gt;&lt;\/li&gt;\r\n                &lt;li&gt;&lt;a href=&quot;add-user&quot;&gt;\u2795 Add User&lt;\/a&gt;&lt;\/li&gt;\r\n                &lt;li&gt;&lt;a href=&quot;manage-users&quot;&gt;\ud83d\udc64 Manage Users&lt;\/a&gt;&lt;\/li&gt;\r\n            &lt;\/ul&gt;\r\n        &lt;\/div&gt;\r\n    &lt;\/nav&gt;\r\n    &lt;div class=&quot;main-container&quot;&gt;\r\n        &lt;section class=&quot;main-section&quot;&gt;\r\n            &lt;h2&gt;\u2795 Add User&lt;\/h2&gt;\r\n            &lt;p&gt;Enter the QR Code data.&lt;\/p&gt;&lt;br&gt;\r\n            &lt;form action=&quot;get&quot; class=&quot;user-form&quot;&gt;\r\n                &lt;label for=&quot;qrCode&quot;&gt;QR Code&lt;\/label&gt;\r\n                &lt;input type=&quot;text&quot; id=&quot;qrCode&quot; name=&quot;qrCode&quot; required&gt;\r\n                &lt;label for=&quot;role&quot;&gt;Role&lt;\/label&gt;\r\n                &lt;select id=&quot;role&quot; name=&quot;role&quot;&gt;\r\n                    &lt;option value=&quot;admin&quot;&gt;Admin&lt;\/option&gt;\r\n                    &lt;option value=&quot;user&quot;&gt;User&lt;\/option&gt;\r\n                &lt;\/select&gt;\r\n                &lt;button type=&quot;submit&quot;&gt;\u2705 Save&lt;\/button&gt;\r\n            &lt;\/form&gt;\r\n        &lt;\/section&gt;\r\n    &lt;\/div&gt;\r\n&lt;\/body&gt;\r\n&lt;\/html&gt;<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/ESP32-CAM-Arduino-IDE\/raw\/master\/ESP32-CAM-QR-Code-User-Management-WS\/data\/add-user.html\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<p>Copy the following to the <span class=\"rnthl rntliteral\">get.html<\/span> file.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-html\">&lt;!DOCTYPE html&gt;\r\n&lt;html lang=&quot;en&quot;&gt;\r\n&lt;head&gt;\r\n    &lt;meta charset=&quot;UTF-8&quot;&gt;\r\n    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;\r\n    &lt;title&gt;Add User&lt;\/title&gt;\r\n    &lt;link rel=&quot;stylesheet&quot; href=&quot;style.css&quot;&gt;\r\n&lt;\/head&gt;\r\n&lt;body&gt;\r\n    &lt;nav&gt;\r\n        &lt;div class=&quot;nav-container&quot;&gt;\r\n            &lt;a href=&quot;\/&quot; class=&quot;brand&quot;&gt;User Management&lt;\/a&gt;\r\n            &lt;ul class=&quot;nav-menu&quot;&gt;\r\n                &lt;li&gt;&lt;a href=&quot;\/&quot;&gt;\ud83d\udcc4 Full Log&lt;\/a&gt;&lt;\/li&gt;\r\n                &lt;li&gt;&lt;a href=&quot;add-user&quot;&gt;\u2795 Add User&lt;\/a&gt;&lt;\/li&gt;\r\n                &lt;li&gt;&lt;a href=&quot;manage-users&quot;&gt;\ud83d\udc64 Manage Users&lt;\/a&gt;&lt;\/li&gt;\r\n            &lt;\/ul&gt;\r\n        &lt;\/div&gt;\r\n    &lt;\/nav&gt;\r\n    &lt;div class=&quot;main-container&quot;&gt;\r\n        &lt;section class=&quot;main-section&quot;&gt;\r\n            &lt;p&gt;%inputmessage%&lt;\/p&gt;\r\n        &lt;\/section&gt;\r\n    &lt;\/div&gt;\r\n&lt;\/body&gt;\r\n&lt;\/html&gt;<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/ESP32-CAM-Arduino-IDE\/raw\/master\/ESP32-CAM-QR-Code-User-Management-WS\/data\/get.html\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"css-file\">CSS File<\/h2>\n\n\n\n<p>Copy the following to the <span class=\"rnthl rntliteral\">style.css<\/span> file. Feel free to change it to make the web page look as you wish.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-css\">\/* General Styles *\/\r\n* {\r\n    margin: 0;\r\n    padding: 0;\r\n    box-sizing: border-box;\r\n}\r\n\r\nbody {\r\n    font-family: Arial, sans-serif;\r\n    background-color: #f4f4f9;\r\n    color: #333;\r\n    display: flex;\r\n    flex-direction: column;\r\n    align-items: center;\r\n    height: 100vh;\r\n    margin: 0;\r\n}\r\n\r\n\/* Navigation Bar Styles *\/\r\nnav {\r\n    width: 100%;\r\n    background-color: #333;\r\n    padding: 1rem 0;\r\n}\r\n\r\n.nav-container {\r\n    max-width: 1200px;\r\n    margin: 0 auto;\r\n    display: flex;\r\n    justify-content: space-between;\r\n    align-items: center;\r\n    padding: 0 1rem;\r\n}\r\n\r\n.brand {\r\n    color: #fff;\r\n    text-decoration: none;\r\n    font-size: 1.5rem;\r\n    font-weight: bold;\r\n}\r\n\r\n.nav-menu {\r\n    list-style-type: none;\r\n    display: flex;\r\n}\r\n\r\n.nav-menu li {\r\n    margin-left: 1.5rem;\r\n}\r\n\r\n.nav-menu a {\r\n    color: #fff;\r\n    text-decoration: none;\r\n    font-size: 1rem;\r\n    transition: color 0.3s;\r\n}\r\n\r\n.nav-menu a:hover, .nav-menu a.active {\r\n    color: #f4f4f9;\r\n}\r\n\r\n.main-container {\r\n    display: flex;\r\n    justify-content: center;\r\n    align-items: center;\r\n    flex-grow: 1;\r\n    width: 100%;\r\n}\r\n\r\n.main-section {\r\n    max-width: 900px;\r\n    padding: 2rem;\r\n    background-color: #fff;\r\n    border-radius: 5px;\r\n    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);\r\n    text-align: center;\r\n}\r\n\r\n.main-section h2 {\r\n    margin-bottom: 1rem;\r\n    color: #333;\r\n}\r\n\r\n.user-form label {\r\n    display: block;\r\n    margin-bottom: 0.5rem;\r\n    font-weight: bold;\r\n    color: #333;\r\n}\r\n\r\n.user-form input, .user-form select {\r\n    width: 100%;\r\n    padding: 0.5rem;\r\n    margin-bottom: 1rem;\r\n    border: 1px solid #ddd;\r\n    border-radius: 4px;\r\n}\r\n\r\n.user-form button {\r\n    width: 100%;\r\n    padding: 0.7rem;\r\n    background-color: #333;\r\n    color: #fff;\r\n    border: none;\r\n    border-radius: 4px;\r\n    font-size: 1rem;\r\n    cursor: pointer;\r\n    transition: background-color 0.3s;\r\n}\r\n\r\n.user-form button:hover {\r\n    background-color: #555;\r\n}\r\n\r\n\r\n.button {\r\n    display: inline-block;\r\n    padding: 10px 20px;\r\n    margin: 10px;\r\n    font-size: 16px;\r\n    border: none;\r\n    border-radius: 5px;\r\n    cursor: pointer;\r\n    transition-duration: 0.4s;\r\n}\r\n\r\n.button-delete {\r\n    background-color: #780320;\r\n    color: #fff;\r\n}\r\n\r\n.button-home {\r\n    background-color: #333;\r\n    color: #fff;\r\n}\r\n\r\n#tableData {\r\n    font-family: Arial, Helvetica, sans-serif;\r\n    border-collapse: collapse;\r\n    width: 100%;\r\n  }\r\n  \r\n#tableData td, #tableData th {\r\n    border: 1px solid #ddd;\r\n    padding: 8px;\r\n}\r\n\r\n#tableData tr:nth-child(even) {\r\n    background-color: #f2f2f2;\r\n}\r\n\r\n#tableData tr:hover {\r\n    background-color: #ddd;\r\n}\r\n\r\n#tableData th {\r\n    padding-top: 12px;\r\n    padding-bottom: 12px;\r\n    text-align: left;\r\n    background-color: #1f1f1f;\r\n    color: white;\r\n}<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/ESP32-CAM-Arduino-IDE\/raw\/master\/ESP32-CAM-QR-Code-User-Management-WS\/data\/style.css\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Code &#8211; ESP32-CAM QR Code Reader Web Server<\/h2>\n\n\n\n<p>Copy the QR Code reader code to your Arduino IDE.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-c\">\/*********\n  Rui Santos &amp; Sara Santos - Random Nerd Tutorials\n  Complete instructions at https:\/\/RandomNerdTutorials.com\/esp32-cam-qr-code-reader-web-server\/\n  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.\n  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n*********\/\n\n#include &lt;Arduino.h&gt;\n#include &lt;ESP32QRCodeReader.h&gt;\n#include &lt;AsyncTCP.h&gt;\n#include &lt;ESPAsyncWebServer.h&gt;\n#include &lt;LittleFS.h&gt;\n#include &quot;FS.h&quot;\n#include &quot;SD_MMC.h&quot;\n#include &lt;time.h&gt;\n#include &lt;WiFi.h&gt;\n\n\/\/ Replace with your network credentials\nconst char* ssid = &quot;REPLACE_WITH_YOUR_SSID&quot;;\nconst char* password = &quot;REPLACE_WITH_YOUR_PASSWORD&quot;;\n\n\/\/ FOR THIS PROJECT, YOUR ESP32-CAM NEEDS TO HAVE PSRAM.\n\/\/ Some of the compatible boards: CAMERA_MODEL_AI_THINKER | CAMERA_MODEL_WROVER_KIT | CAMERA_MODEL_ESP_EYE\n\/\/ CAMERA_MODEL_M5STACK_PSRAM | CAMERA_MODEL_M5STACK_V2_PSRAM | CAMERA_MODEL_M5STACK_WIDE  \nESP32QRCodeReader reader(CAMERA_MODEL_AI_THINKER);\n\nlong timezone = 0;\nbyte daysavetime = 1;\n\nconst int ledPin = 4;\n\n\/\/ Create AsyncWebServer object on port 80\nAsyncWebServer server(80);\n\nconst char* PARAM_INPUT_1 = &quot;qrCode&quot;;\nconst char* PARAM_INPUT_2 = &quot;role&quot;;\nconst char* PARAM_INPUT_3 = &quot;delete&quot;;\nconst char* PARAM_INPUT_4 = &quot;delete-user&quot;;\n\nString inputMessage;\nString inputParam;\n\nvoid onQrCodeTask(void *pvParameters) {\n  struct QRCodeData qrCodeData;\n\n  while (true) {\n    if (reader.receiveQrCode(&amp;qrCodeData, 100)) {\n      Serial.println(&quot;Scanned new QRCode&quot;);\n      if (qrCodeData.valid) {\n        String qrCodeString = String((const char *)qrCodeData.payload);\n        Serial.print(&quot;Valid payload: &quot;);\n        Serial.println(qrCodeString);\n\n        String role = getRoleFromFile(&quot;\/users.txt&quot;, qrCodeString);\n        if (role != &quot;&quot;) {\n          Serial.print(&quot;Role for QR Code: &quot;);\n          Serial.print(qrCodeString);\n          Serial.print(&quot; is &quot;);\n          Serial.println(role);\n        } else {\n          role = &quot;unknown&quot;;\n          Serial.print(&quot;QR Code: &quot;);\n          Serial.print(qrCodeString);\n          Serial.println(&quot; not found, set user role to unknown&quot;);\n        }\n        String sdMessage = qrCodeString + &quot;,&quot; + role;\n        appendFile(SD_MMC, &quot;\/log.txt&quot;, sdMessage.c_str());\n        digitalWrite(ledPin, HIGH);\n        delay(1000);\n        digitalWrite(ledPin, LOW);\n      }\n      else {\n        Serial.print(&quot;Invalid payload: &quot;);\n        Serial.println((const char *)qrCodeData.payload);\n      }\n    }\n    vTaskDelay(100 \/ portTICK_PERIOD_MS);\n  }\n}\n\n\/\/ Write to the SD card\nvoid writeFile(fs::FS &amp;fs, const char * path, const char * message) {\n  Serial.printf(&quot;Writing file: %s\\n&quot;, path);\n\n  File file = fs.open(path, FILE_WRITE);\n  if(!file) {\n    Serial.println(&quot;Failed to open file for writing&quot;);\n    return;\n  }\n  if(file.print(message)) {\n    Serial.println(&quot;File written&quot;);\n  } else {\n    Serial.println(&quot;Write failed&quot;);\n  }\n  file.close();\n}\n\n\/\/ Append data to the SD card\nvoid appendFile(fs::FS &amp;fs, const char * path, const char * message) {\n  Serial.printf(&quot;Appending to file: %s\\n&quot;, path);\n\n  File file = fs.open(path, FILE_APPEND);\n  if(!file) {\n    Serial.println(&quot;Failed to open file for appending&quot;);\n    return;\n  }\n\n  time_t t = file.getLastWrite();\n  struct tm *tmstruct = localtime(&amp;t);\n\n  char bufferDate[50]; \/\/ Adjust buffer size as needed\n  snprintf(bufferDate, sizeof(bufferDate), &quot;%d-%02d-%02d&quot;, \n          (tmstruct-&gt;tm_year) + 1900, \n          (tmstruct-&gt;tm_mon) + 1, \n          tmstruct-&gt;tm_mday);\n  char bufferTime[50]; \/\/ Adjust buffer size as needed\n  snprintf(bufferTime, sizeof(bufferTime), &quot;%02d:%02d:%02d&quot;, \n          tmstruct-&gt;tm_hour, \n          tmstruct-&gt;tm_min, \n          tmstruct-&gt;tm_sec);\n          \n  String lastWriteTime = bufferDate;\n  String finalString = String(bufferDate) + &quot;,&quot; + String(bufferTime) + &quot;,&quot; + String(message) + &quot;\\n&quot;;\n  Serial.println(lastWriteTime);\n  if(file.print(finalString.c_str())) {\n    Serial.println(&quot;Message appended&quot;);\n  } else {\n    Serial.println(&quot;Append failed&quot;);\n  }\n  file.close();\n}\n\n\/\/ Append data to the SD card\nvoid appendUserFile(fs::FS &amp;fs, const char * path, const char * message) {\n  Serial.printf(&quot;Appending to file: %s\\n&quot;, path);\n\n  File file = fs.open(path, FILE_APPEND);\n  if(!file) {\n    Serial.println(&quot;Failed to open file for appending&quot;);\n    return;\n  }\n\n  String finalString = String(message) + &quot;\\n&quot;;\n\n  if(file.print(finalString.c_str())) {\n    Serial.println(&quot;Message appended&quot;);\n  } else {\n    Serial.println(&quot;Append failed&quot;);\n  }\n  file.close();\n}\n\nvoid deleteFile(fs::FS &amp;fs, const char *path) {\n  Serial.printf(&quot;Deleting file: %s\\n&quot;, path);\n  if (fs.remove(path)) {\n    Serial.println(&quot;File deleted&quot;);\n  } else {\n    Serial.println(&quot;Delete failed&quot;);\n  }\n\n  \/\/ If the log.txt file doesn't exist, create a file on the SD card and write the header\n  File file = SD_MMC.open(&quot;\/log.txt&quot;);\n  if(!file) {\n    Serial.println(&quot;Creating new log.txt file...&quot;);\n    writeFile(SD_MMC, &quot;\/log.txt&quot;, &quot;Date,Time,QR_Code,Role\\r\\n&quot;);\n  }\n  else {\n    Serial.println(&quot;log.txt file already exists&quot;);  \n  }\n  file.close();\n\n  \/\/ If the users.txt file doesn't exist, create a file on the SD card and write the header\n  file = SD_MMC.open(&quot;\/users.txt&quot;);\n  if(!file) {\n    Serial.println(&quot;Creating new users.txt file...&quot;);\n    writeFile(SD_MMC, &quot;\/users.txt&quot;, &quot;QR_Code,Role\\r\\n&quot;);\n  }\n  else {\n    Serial.println(&quot;users.txt file already exists&quot;);  \n  }\n  file.close();\n}\n\nString processor(const String&amp; var){\n  return String(&quot;HTTP GET request sent to your ESP on input field (&quot; \n                + inputParam + &quot;) with value: &quot; + inputMessage +\n                &quot;&lt;br&gt;&lt;a href=\\&quot;\/\\&quot;&gt;&lt;button class=\\&quot;button button-home\\&quot;&gt;Return to Home Page&lt;\/button&gt;&lt;\/a&gt;&quot;);\n}\n\nvoid deleteLineFromFile(const char* filename, int lineNumber) {\n  File file = SD_MMC.open(filename);\n  if (!file) {\n    Serial.println(&quot;Failed to open file for reading.&quot;);\n    return;\n  }\n\n  \/\/ Read all lines except the one to delete\n  String lines = &quot;&quot;;\n  int currentLine = 0;\n  while (file.available()) {\n    String line = file.readStringUntil('\\n');\n    if (currentLine != lineNumber) {\n      lines += line + &quot;\\n&quot;;\n    }\n    currentLine++;\n  }\n  file.close();\n\n  \/\/ Write back all lines except the deleted one\n  file = SD_MMC.open(filename, FILE_WRITE);\n  if (!file) {\n    Serial.println(&quot;Failed to open file for writing.&quot;);\n    return;\n  }\n\n  file.print(lines);\n  file.close();\n  Serial.println(&quot;Line deleted successfully.&quot;);\n}\n\nString getRoleFromFile(const char* filename, String qrCode) {\n  File file = SD_MMC.open(filename);\n  if (!file) {\n    Serial.println(&quot;Failed to open file for reading.&quot;);\n    return &quot;&quot;;\n  }\n\n  \/\/ Skip the header line\n  file.readStringUntil('\\n');\n  \n  \/\/ Read each line and check for QR Code\n  while (file.available()) {\n    String line = file.readStringUntil('\\n');\n    \n    int commaIndex = line.indexOf(',');\n    if (commaIndex &gt; 0) {\n      String fileQrCode = line.substring(0, commaIndex);\n      String role = line.substring(commaIndex + 1);\n\n      \/\/ Compare qrCode\n      if (fileQrCode == qrCode) {\n        file.close();\n        role.trim();  \/\/ Remove any extra spaces or newline characters\n        return role;\n      }\n    }\n  }\n  file.close();\n  return &quot;&quot;;  \/\/ Return empty string if qrCode not found\n}\n\nvoid initLittleFS() {\n  if(!LittleFS.begin()){\n    Serial.println(&quot;An Error has occurred while mounting LittleFS&quot;);\n        return;\n  }\n}\n\nvoid initWifi() {\n  \/\/ Connect to Wi-Fi\n  WiFi.begin(ssid, password);\n  int connectAttempt = 0;\n  Serial.println(&quot;Connecting to WiFi..&quot;);\n  while (WiFi.status() != WL_CONNECTED) {\n    delay(500);\n    Serial.print(&quot;.&quot;);\n    connectAttempt ++;\n    if (connectAttempt == 10){ \n      ESP.restart();\n    }\n  }\n  \/\/ Print ESP32 Local IP Address\n  Serial.print(&quot;\\nESP IP Address: &quot;);\n  Serial.println(WiFi.localIP());\n}\n\nvoid initTime() {\n  Serial.println(&quot;Initializing Time&quot;);\n  struct tm tmstruct;\n  tmstruct.tm_year = 0;\n  getLocalTime(&amp;tmstruct);\n  Serial.printf(\n    &quot;Time and Date right now is : %d-%02d-%02d %02d:%02d:%02d\\n&quot;, (tmstruct.tm_year) + 1900, (tmstruct.tm_mon) + 1, tmstruct.tm_mday, tmstruct.tm_hour, tmstruct.tm_min,\n    tmstruct.tm_sec\n  );\n}\n\nvoid initSDCard() {\n  if (!SD_MMC.begin(&quot;\/sdcard&quot;, true)) {\n    Serial.println(&quot;Card Mount Failed&quot;);\n    return;\n  }\n  uint8_t cardType = SD_MMC.cardType();\n\n  if (cardType == CARD_NONE) {\n    Serial.println(&quot;No SD card attached&quot;);\n    return;\n  }\n\n  Serial.print(&quot;SD Card Type: &quot;);\n  if (cardType == CARD_MMC) {\n    Serial.println(&quot;MMC&quot;);\n  } else if (cardType == CARD_SD) {\n    Serial.println(&quot;SDSC&quot;);\n  } else if (cardType == CARD_SDHC) {\n    Serial.println(&quot;SDHC&quot;);\n  } else {\n    Serial.println(&quot;UNKNOWN&quot;);\n  }\n\n  uint64_t cardSize = SD_MMC.cardSize() \/ (1024 * 1024);\n  Serial.printf(&quot;SD Card Size: %lluMB\\n&quot;, cardSize);\n\n  \/\/ If the log.txt file doesn't exist, create a file on the SD card and write the header\n  File file = SD_MMC.open(&quot;\/log.txt&quot;);\n  if(!file) {\n    Serial.println(&quot;log.txt file doesn't exist&quot;);\n    Serial.println(&quot;Creating file...&quot;);\n    writeFile(SD_MMC, &quot;\/log.txt&quot;, &quot;Date,Time,QR_Code,Role\\r\\n&quot;);\n  }\n  else {\n    Serial.println(&quot;log.txt file already exists&quot;);  \n  }\n  file.close();\n\n  \/\/ If the users.txt file doesn't exist, create a file on the SD card and write the header\n  file = SD_MMC.open(&quot;\/users.txt&quot;);\n  if(!file) {\n    Serial.println(&quot;users.txt file doesn't exist&quot;);\n    Serial.println(&quot;Creating file...&quot;);\n    writeFile(SD_MMC, &quot;\/users.txt&quot;, &quot;QR_Code,Role\\r\\n&quot;);\n  }\n  else {\n    Serial.println(&quot;users.txt file already exists&quot;);  \n  }\n  file.close();\n}\n\nvoid setup() {\n  Serial.begin(115200);  \/\/ Initialize serial communication\n  while (!Serial);       \/\/ Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4).\n\n  reader.setup();\n  Serial.println(&quot;\\nSetup QRCode Reader&quot;);\n  reader.beginOnCore(1);\n  Serial.println(&quot;Begin on Core 1&quot;);\n  xTaskCreate(onQrCodeTask, &quot;onQrCode&quot;, 4 * 1024, NULL, 4, NULL);\n\n  initWifi();\n  initLittleFS();\n  configTime(3600 * timezone, daysavetime * 3600, &quot;time.nist.gov&quot;, &quot;0.pool.ntp.org&quot;, &quot;1.pool.ntp.org&quot;);\n  initTime();\n  initSDCard();\n\n  pinMode(ledPin, OUTPUT);\n  digitalWrite(ledPin, LOW);\n\n  \/\/ Route for root \/ web page\n  server.on(&quot;\/&quot;, HTTP_GET, [](AsyncWebServerRequest *request){\n    request-&gt;send(LittleFS, &quot;\/full-log.html&quot;);\n  });\n  \/\/ Route for root \/add-user web page\n  server.on(&quot;\/add-user&quot;, HTTP_GET, [](AsyncWebServerRequest *request){\n    request-&gt;send(LittleFS, &quot;\/add-user.html&quot;);\n  });\n  \/\/ Route for root \/manage-users web page\n  server.on(&quot;\/manage-users&quot;, HTTP_GET, [](AsyncWebServerRequest *request){\n    request-&gt;send(LittleFS, &quot;\/manage-users.html&quot;);\n  });\n\n  \/\/ Serve Static files\n  server.serveStatic(&quot;\/&quot;, LittleFS, &quot;\/&quot;);\n\n  \/\/ Loads the log.txt file\n  server.on(&quot;\/view-log&quot;, HTTP_GET, [](AsyncWebServerRequest *request){\n    request-&gt;send(SD_MMC, &quot;\/log.txt&quot;, &quot;text\/plain&quot;, false);\n  });\n  \/\/ Loads the users.txt file\n  server.on(&quot;\/view-users&quot;, HTTP_GET, [](AsyncWebServerRequest *request){\n    request-&gt;send(SD_MMC, &quot;\/users.txt&quot;, &quot;text\/plain&quot;, false);\n  });\n  \n  \/\/ Receive HTTP GET requests on &lt;ESP_IP&gt;\/get?input=&lt;inputMessage&gt;\n  server.on(&quot;\/get&quot;, HTTP_GET, [] (AsyncWebServerRequest *request) {\n    \/\/ GET input1 and input2 value on &lt;ESP_IP&gt;\/get?input1=&lt;inputMessage1&gt;&amp;input2=&lt;inputMessage2&gt;\n    if (request-&gt;hasParam(PARAM_INPUT_1) &amp;&amp; request-&gt;hasParam(PARAM_INPUT_2)) {\n      inputMessage = request-&gt;getParam(PARAM_INPUT_1)-&gt;value();\n      inputParam = String(PARAM_INPUT_1);\n      inputMessage += &quot; &quot; + request-&gt;getParam(PARAM_INPUT_2)-&gt;value();\n      inputParam += &quot; &quot; + String(PARAM_INPUT_2);\n\n      String finalMessageInput = String(request-&gt;getParam(PARAM_INPUT_1)-&gt;value()) + &quot;,&quot; + String(request-&gt;getParam(PARAM_INPUT_2)-&gt;value());\n      appendUserFile(SD_MMC, &quot;\/users.txt&quot;, finalMessageInput.c_str());\n    }\n    else if (request-&gt;hasParam(PARAM_INPUT_3)) {\n      inputMessage = request-&gt;getParam(PARAM_INPUT_3)-&gt;value();\n      inputParam = String(PARAM_INPUT_3);\n      if(request-&gt;getParam(PARAM_INPUT_3)-&gt;value()==&quot;users&quot;) {\n        deleteFile(SD_MMC, &quot;\/users.txt&quot;);\n      }\n      else if(request-&gt;getParam(PARAM_INPUT_3)-&gt;value()==&quot;log&quot;) {\n        deleteFile(SD_MMC, &quot;\/log.txt&quot;);\n      }\n    }\n    else if (request-&gt;hasParam(PARAM_INPUT_4)) {\n      inputMessage = request-&gt;getParam(PARAM_INPUT_4)-&gt;value();\n      inputParam = String(PARAM_INPUT_4);\n      deleteLineFromFile(&quot;\/users.txt&quot;, inputMessage.toInt());\n    }\n    else {\n      inputMessage = &quot;No message sent&quot;;\n      inputParam = &quot;none&quot;;\n    }\n    request-&gt;send(LittleFS, &quot;\/get.html&quot;, &quot;text\/html&quot;, false, processor);\n  });\n  \/\/ Start server\n  server.begin();\n}\n\nvoid loop() {\n\n}<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/ESP32-CAM-Arduino-IDE\/raw\/master\/ESP32-CAM-QR-Code-User-Management-WS\/ESP32-CAM-QR-Code-User-Management-WS.ino\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<p>Before uploading the code, you need to insert your network credentials in the following lines so that the ESP32-CAM can establish a Wi-Fi connection.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>const char* ssid = \"REPLACE_WITH_YOUR_SSID\";\nconst char* password = \"REPLACE_WITH_YOUR_SSID\";<\/code><\/pre>\n\n\n\n<p>For this project, we are using the AI-Thinker ESP32-CAM model, however, if you are using another board you need to define it here:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ FOR THIS PROJECT, YOUR ESP32-CAM NEEDS TO HAVE PSRAM.\n\/\/ Some of the compatible boards: CAMERA_MODEL_AI_THINKER | CAMERA_MODEL_WROVER_KIT | CAMERA_MODEL_ESP_EYE\n\/\/ CAMERA_MODEL_M5STACK_PSRAM | CAMERA_MODEL_M5STACK_V2_PSRAM | CAMERA_MODEL_M5STACK_WIDE\n\nESP32QRCodeReader reader(CAMERA_MODEL_AI_THINKER);<\/code><\/pre>\n\n\n\n<p><strong>Note:<\/strong> your board needs to have PSRAM.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Resources to Help You Understand the Code<\/h3>\n\n\n\n<p>This code is quite long and we won&#8217;t explain in detail how it works because all subjects covered here were already explained in previous projects.<\/p>\n\n\n\n<p>Here&#8217;s a list of the tutorials you should look at to learn about the subjects covered here:<\/p>\n\n\n\n<p><strong>1) <\/strong>Reading QR Codes: <a href=\"https:\/\/randomnerdtutorials.com\/esp32-cam-qr-code-reader-scanner-arduino\/\">ESP32-CAM QR Code Reader\/Scanner (Arduino IDE)<\/a><\/p>\n\n\n\n<p><strong>2)<\/strong> Getting a timestamp using an NTP server: <a href=\"https:\/\/randomnerdtutorials.com\/esp32-date-time-ntp-client-server-arduino\/\">ESP32 NTP Client-Server: Get Date and Time (Arduino IDE)<\/a>.<\/p>\n\n\n\n<p><strong>3)<\/strong> Reading and writing from\/to the microSD card: <a href=\"https:\/\/randomnerdtutorials.com\/esp32-microsd-card-arduino\/\">ESP32: Guide for MicroSD Card Module using Arduino IDE<\/a>.<\/p>\n\n\n\n<p><strong>4)<\/strong> Creating a web server with the ESP32: <a href=\"https:\/\/randomnerdtutorials.com\/?s=web+server\" title=\"\">a list of all our web server projects<\/a>.<\/p>\n\n\n\n<p><strong>5)<\/strong> Sending data from a web page to the ESP32 via HTML form: <a href=\"https:\/\/randomnerdtutorials.com\/esp32-esp8266-input-data-html-form\/\">Input Data on HTML Form ESP32\/ESP8266 Web Server using Arduino IDE<\/a>.<\/p>\n\n\n\n<p><strong>6)<\/strong> Learn more about the ESP32-CAM with our dedicated eBook <a href=\"https:\/\/randomnerdtutorials.com\/esp32-cam-projects-ebook\/\">Build ESP32-CAM Projects using Arduino IDE<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Upload Code to the ESP32-CAM AI-Thinker using the ESP32-CAM-MB USB Programmer<\/h2>\n\n\n\n<p>To upload code to the ESP32-CAM board, we&#8217;ll use the ESP32-CAM-MB programmer. Attach the <a href=\"https:\/\/makeradvisor.com\/tools\/esp32-cam-mb-usb-programmer\/\" target=\"_blank\" rel=\"noopener\" title=\"\">ESP32-CAM-MB micro USB programmer<\/a> to your board (you can <a href=\"https:\/\/randomnerdtutorials.com\/upload-code-esp32-cam-mb-usb\/\">learn how it works by reading this guide<\/a>).<\/p>\n\n\n<div class=\"wp-block-image is-style-default\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"422\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/01\/ESP32-CAM-MB-Micro-USB-Programmer-CH340G-Serial-Chip-OV2640-Camera.jpg?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32-CAM-MB Micro USB Programmer CH340G Serial Chip OV2640 Camera\" class=\"wp-image-101577\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/01\/ESP32-CAM-MB-Micro-USB-Programmer-CH340G-Serial-Chip-OV2640-Camera.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/01\/ESP32-CAM-MB-Micro-USB-Programmer-CH340G-Serial-Chip-OV2640-Camera.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<p>If you have an FTDI programmer, you can follow this tutorial instead: <a href=\"https:\/\/randomnerdtutorials.com\/program-upload-code-esp32-cam\/\">How to Program \/ Upload Code to ESP32-CAM AI-Thinker (Arduino IDE using an FTDI programmer)<\/a>.<\/p>\n\n\n\n<p>Then, connect the board to your computer using a USB cable.<\/p>\n\n\n\n<p>After that, in your Arduino IDE, go to&nbsp;<strong>Tools&nbsp;<\/strong>&gt;&nbsp;<strong>Board&nbsp;<\/strong>and select the&nbsp;<strong>AI-Thinker ESP32-CAM<\/strong>. Or search for that board on the top bar. You must have the&nbsp;<a href=\"https:\/\/randomnerdtutorials.com\/installing-the-esp32-board-in-arduino-ide-windows-instructions\/\">ESP32 add-on installed<\/a>. Otherwise, this board won\u2019t show up on the Boards menu.<\/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=\"586\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/03\/select-AI-Thinker-Arduino-IDE.png?resize=666%2C586&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Select the AI-Thinker ESP32-CAM in Arduino IDE\" class=\"wp-image-168335\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/03\/select-AI-Thinker-Arduino-IDE.png?w=666&amp;quality=100&amp;strip=all&amp;ssl=1 666w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/03\/select-AI-Thinker-Arduino-IDE.png?resize=300%2C264&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 666px) 100vw, 666px\" \/><\/figure><\/div>\n\n\n<p>Go to&nbsp;<strong>Tools&nbsp;<\/strong>&gt;&nbsp;<strong>Port&nbsp;<\/strong>and select the COM port the ESP32-CAM is connected to.<\/p>\n\n\n\n<p class=\"rntbox rntcred\"><strong>Note: <\/strong> if the board doesn&#8217;t show up, it means that you probably don&#8217;t have the CH340C drivers installed on your computer. Go to Google and search &#8220;<strong>CH340C drivers<\/strong>&#8221; followed by your operating system and install the drivers.<\/p>\n\n\n\n<p>Finally, click the&nbsp;<strong>Upload&nbsp;<\/strong>button in your Arduino IDE.<\/p>\n\n\n<div class=\"wp-block-image is-style-default\">\n<figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"32\" height=\"32\" src=\"https:\/\/i2.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2019\/12\/upload-button-arduino-ide.png?resize=32%2C32&amp;quality=100&amp;strip=all&amp;ssl=1\" alt=\"Program ESP32-CAM with Arduino IDE\" class=\"wp-image-91745\"\/><\/figure><\/div>\n\n\n<p>And that&#8217;s it! Your QR code scanner code should be running in your ESP32-CAM.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Upload Code and Data Folder<\/h2>\n\n\n\n<p>After inserting your network credentials, save the code. Go to&nbsp;<strong>Sketch<\/strong>&nbsp;&gt;&nbsp;<strong>Show Sketch Folder<\/strong>, and create a folder called&nbsp;<strong><em>data<\/em><\/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=\"351\" height=\"271\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/arduino-ide-show-sketch-folder.png?resize=351%2C271&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Arduino IDE Open Sketch Folder to create data folder\" class=\"wp-image-158892\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/arduino-ide-show-sketch-folder.png?w=351&amp;quality=100&amp;strip=all&amp;ssl=1 351w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/arduino-ide-show-sketch-folder.png?resize=300%2C232&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 351px) 100vw, 351px\" \/><\/figure><\/div>\n\n\n<p><strong>Inside that folder, you should place the HTML, and CSS files provided previously.<\/strong><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Uploading the Filesystem Image<\/h3>\n\n\n\n<p>Upload those files to the filesystem: press [<strong>Ctrl<\/strong>] + [<strong>Shift<\/strong>] + [<strong>P<\/strong>] on Windows or [<strong>\u2318<\/strong>] + [<strong>Shift<\/strong>] + [<strong>P<\/strong>] on MacOS to open the command palette. Search for the&nbsp;<strong>Upload LittleFS to Pico\/ESP8266\/ESP32<\/strong>&nbsp;command and click on it.<\/p>\n\n\n\n<p>If you don\u2019t have this option is because you didn\u2019t install the filesystem uploader plugin.<a href=\"https:\/\/randomnerdtutorials.com\/arduino-ide-2-install-esp32-littlefs\/\">&nbsp;Check this tutorial<\/a>.<\/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=\"744\" height=\"401\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/upload-files-little-fs-esp32-arduino-ide.png?resize=744%2C401&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Sketch Data Upload LittleFS Arduino IDE\" class=\"wp-image-158893\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/upload-files-little-fs-esp32-arduino-ide.png?w=744&amp;quality=100&amp;strip=all&amp;ssl=1 744w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/upload-files-little-fs-esp32-arduino-ide.png?resize=300%2C162&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 744px) 100vw, 744px\" \/><\/figure><\/div>\n\n\n<p class=\"rntbox rntcred\"><strong>Important:&nbsp;<\/strong>make sure the Serial Monitor is closed before uploading to the filesystem. Otherwise, the upload will fail.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Uploading the Code<\/h3>\n\n\n\n<p>After uploading the code and the files in the <strong><em>data <\/em><\/strong>folder, open the Serial Monitor at a baud rate of 115200. Press the ESP32-CAM EN\/RST button. It should initialize the QR code scanner and the web server. Check the Arduino IDE Serial Monitor window to see if everything is working as expected.<\/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=\"758\" height=\"520\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Reader-Web-Server-Arduino-IDE-Serial-Demonstration.png?resize=758%2C520&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32-CAM QR Code Reader Web Server Arduino IDE Serial Demonstration\" class=\"wp-image-168768\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Reader-Web-Server-Arduino-IDE-Serial-Demonstration.png?w=758&amp;quality=100&amp;strip=all&amp;ssl=1 758w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Reader-Web-Server-Arduino-IDE-Serial-Demonstration.png?resize=300%2C206&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 758px) 100vw, 758px\" \/><\/figure><\/div>\n\n\n<p>It should print the ESP32 IP address. In my case it&#8217;s 192.168.1.76. Save your IP because you&#8217;ll need it in the next step.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Testing the QR Code Reader<\/h2>\n\n\n\n<p>Here are 4 sample QR codes(their corresponding data is in the image caption). You can use any online QR code generator to create custom QR codes with your desired data.<\/p>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\"><div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><a href=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/rui_santos.png?quality=100&#038;strip=all&#038;ssl=1\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"400\" height=\"400\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/rui_santos.png?resize=400%2C400&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"rui_santos QR Code\" class=\"wp-image-168770\" style=\"width:250px;height:auto\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/rui_santos.png?w=400&amp;quality=100&amp;strip=all&amp;ssl=1 400w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/rui_santos.png?resize=300%2C300&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/rui_santos.png?resize=150%2C150&amp;quality=100&amp;strip=all&amp;ssl=1 150w\" sizes=\"(max-width: 400px) 100vw, 400px\" \/><\/a><figcaption class=\"wp-element-caption\">rui_santos<\/figcaption><\/figure><\/div><\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\"><div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><a href=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/sara_santos.png?quality=100&#038;strip=all&#038;ssl=1\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"400\" height=\"400\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/sara_santos.png?resize=400%2C400&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"sara_santos QR Code\" class=\"wp-image-168771\" style=\"width:auto;height:250px\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/sara_santos.png?w=400&amp;quality=100&amp;strip=all&amp;ssl=1 400w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/sara_santos.png?resize=300%2C300&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/sara_santos.png?resize=150%2C150&amp;quality=100&amp;strip=all&amp;ssl=1 150w\" sizes=\"(max-width: 400px) 100vw, 400px\" \/><\/a><figcaption class=\"wp-element-caption\">sara_santos<\/figcaption><\/figure><\/div><\/div>\n<\/div>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\"><div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><a href=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/test_user_1.png?quality=100&#038;strip=all&#038;ssl=1\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"400\" height=\"400\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/test_user_1.png?resize=400%2C400&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"test_user_1 QR Code\" class=\"wp-image-168772\" style=\"width:auto;height:250px\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/test_user_1.png?w=400&amp;quality=100&amp;strip=all&amp;ssl=1 400w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/test_user_1.png?resize=300%2C300&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/test_user_1.png?resize=150%2C150&amp;quality=100&amp;strip=all&amp;ssl=1 150w\" sizes=\"(max-width: 400px) 100vw, 400px\" \/><\/a><figcaption class=\"wp-element-caption\">test_user_1<\/figcaption><\/figure><\/div><\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\"><div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><a href=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/test_user_2.png?quality=100&#038;strip=all&#038;ssl=1\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"400\" height=\"400\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/test_user_2.png?resize=400%2C400&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"test_user_2 QR Code\" class=\"wp-image-168773\" style=\"width:auto;height:250px\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/test_user_2.png?w=400&amp;quality=100&amp;strip=all&amp;ssl=1 400w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/test_user_2.png?resize=300%2C300&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/test_user_2.png?resize=150%2C150&amp;quality=100&amp;strip=all&amp;ssl=1 150w\" sizes=\"(max-width: 400px) 100vw, 400px\" \/><\/a><figcaption class=\"wp-element-caption\">test_user_2<\/figcaption><\/figure><\/div><\/div>\n<\/div>\n\n\n\n<p>Point the ESP32-CAM to a QR code and hold it steady.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"422\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/03\/ESP32-CAM-QR-Code-Scanner-Reader-Testing-Arduino-IDE-Serial-Monitor-Demonstration.jpg?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32-CAM Camera QR Code Scanner Reader Testing Arduino IDE Serial Monitor Demonstration\" class=\"wp-image-168282\" style=\"width:750px;height:auto\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/03\/ESP32-CAM-QR-Code-Scanner-Reader-Testing-Arduino-IDE-Serial-Monitor-Demonstration.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/03\/ESP32-CAM-QR-Code-Scanner-Reader-Testing-Arduino-IDE-Serial-Monitor-Demonstration.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<p>The payload data should be printed in the Arduino IDE Serial Monitor:<\/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=\"772\" height=\"460\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Reader-Web-Server-Arduino-IDE-Serial-Demonstration-Scan-QR-Code.png?resize=772%2C460&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32-CAM QR Code Reader Web Server Arduino IDE Serial Demonstration Scan QR Code\" class=\"wp-image-168769\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Reader-Web-Server-Arduino-IDE-Serial-Demonstration-Scan-QR-Code.png?w=772&amp;quality=100&amp;strip=all&amp;ssl=1 772w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Reader-Web-Server-Arduino-IDE-Serial-Demonstration-Scan-QR-Code.png?resize=300%2C179&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Reader-Web-Server-Arduino-IDE-Serial-Demonstration-Scan-QR-Code.png?resize=768%2C458&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 772px) 100vw, 772px\" \/><\/figure><\/div>\n\n\n<p>If in the Arduino IDE Serial Monitor, you keep getting this message:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Invalid payload: ECC failure<\/code><\/pre>\n\n\n\n<p>You might need to use a smaller QR code, make the camera more stable, and point it directly to the QR code with better lighting conditions.<\/p>\n\n\n\n<p>The ESP32-CAM has some limitations in resolution and struggles with motion, so you need to aim it steadily at the QR code. Also, detecting QR codes can be difficult in poor lighting conditions, whether it&#8217;s too bright or too dark.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Demonstration<\/h2>\n\n\n\n<p>Open a browser on your local network and type the ESP32-CAM IP address. You should get access to the web server page that looks like this, it should have a blank table by default.<\/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=\"720\" height=\"564\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Reader-Web-Server-Check-Full-Log-table.png?resize=720%2C564&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32-CAM QR Code Reader Web Server Check Full Log table\" class=\"wp-image-168764\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Reader-Web-Server-Check-Full-Log-table.png?w=720&amp;quality=100&amp;strip=all&amp;ssl=1 720w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Reader-Web-Server-Check-Full-Log-table.png?resize=300%2C235&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 720px) 100vw, 720px\" \/><\/figure><\/div>\n\n\n<p>Scan some QR codes with your ESP32-CAM. Every time you scan a valid QR code, the built-in flash LED should light up. In your Arduino IDE Serial Monitor, the QR data will be printed:<\/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=\"772\" height=\"460\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Reader-Web-Server-Arduino-IDE-Serial-Demonstration-Scan-QR-Code.png?resize=772%2C460&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32-CAM QR Code Reader Web Server Arduino IDE Serial Demonstration Scan QR Code\" class=\"wp-image-168769\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Reader-Web-Server-Arduino-IDE-Serial-Demonstration-Scan-QR-Code.png?w=772&amp;quality=100&amp;strip=all&amp;ssl=1 772w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Reader-Web-Server-Arduino-IDE-Serial-Demonstration-Scan-QR-Code.png?resize=300%2C179&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Reader-Web-Server-Arduino-IDE-Serial-Demonstration-Scan-QR-Code.png?resize=768%2C458&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 772px) 100vw, 772px\" \/><\/figure><\/div>\n\n\n<p>For testing purposes, I recommend scanning multiple QR codes, so that you have more data displayed in your web server. Copy the data of one of your QR codes (for example: rui_santos). Then, open the <strong>Add User<\/strong> tab.<\/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=\"697\" height=\"54\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/11\/ESP32-RFID-User-Management-System-Open-Add-User-web-page.png?resize=697%2C54&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 RFID User Management System Open Add User web page\" class=\"wp-image-164267\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/11\/ESP32-RFID-User-Management-System-Open-Add-User-web-page.png?w=697&amp;quality=100&amp;strip=all&amp;ssl=1 697w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/11\/ESP32-RFID-User-Management-System-Open-Add-User-web-page.png?resize=300%2C23&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 697px) 100vw, 697px\" \/><\/figure><\/div>\n\n\n<p>Type the QR code data and select the role (user or admin). Finally, click the &#8220;<strong>Save<\/strong>&#8221; button. I repeated this process for the other QR codes mentioned in this post.<\/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=\"716\" height=\"564\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Reader-Web-Server-Add-New-User-with-Role.png?resize=716%2C564&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32-CAM QR Code Reader Web Server Add New User with Role\" class=\"wp-image-168765\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Reader-Web-Server-Add-New-User-with-Role.png?w=716&amp;quality=100&amp;strip=all&amp;ssl=1 716w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Reader-Web-Server-Add-New-User-with-Role.png?resize=300%2C236&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 716px) 100vw, 716px\" \/><\/figure><\/div>\n\n\n<p>Now, if you browse to the <strong>Manager Users<\/strong> web page:<\/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=\"697\" height=\"54\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/11\/ESP32-RFID-User-Management-System-Open-Manage-Users-Tab.png?resize=697%2C54&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 RFID User Management System Open Manage Users Tab\" class=\"wp-image-164268\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/11\/ESP32-RFID-User-Management-System-Open-Manage-Users-Tab.png?w=697&amp;quality=100&amp;strip=all&amp;ssl=1 697w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/11\/ESP32-RFID-User-Management-System-Open-Manage-Users-Tab.png?resize=300%2C23&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 697px) 100vw, 697px\" \/><\/figure><\/div>\n\n\n<p>It loads a table with all the QR Codes and their corresponding user roles, you can click the &#8220;X&#8221; to delete a user.<\/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=\"716\" height=\"552\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Reader-Web-Server-Delete-User.png?resize=716%2C552&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32-CAM QR Code Reader Web Server Delete User\" class=\"wp-image-168766\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Reader-Web-Server-Delete-User.png?w=716&amp;quality=100&amp;strip=all&amp;ssl=1 716w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Reader-Web-Server-Delete-User.png?resize=300%2C231&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 716px) 100vw, 716px\" \/><\/figure><\/div>\n\n\n<p>Scan the QR codes a few more times, then open the web server home page. The log table should have all the entries with a timestamp, QR code and the corresponding user roles.<\/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=\"799\" height=\"762\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Reader-Web-Server-Full-Log-Table.png?resize=799%2C762&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32-CAM QR Code Reader Web Server Full Log Table\" class=\"wp-image-168767\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Reader-Web-Server-Full-Log-Table.png?w=799&amp;quality=100&amp;strip=all&amp;ssl=1 799w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Reader-Web-Server-Full-Log-Table.png?resize=300%2C286&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Reader-Web-Server-Full-Log-Table.png?resize=768%2C732&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 799px) 100vw, 799px\" \/><\/figure><\/div>\n\n\n<p>At the bottom of the <strong>Full Log<\/strong> and <strong>Manager Users<\/strong> web pages, you have the option to delete the <em>log.txt<\/em> and <em>users.txt<\/em> files from the microSD card at any time.<\/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=\"218\" height=\"107\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/11\/ESP32-RFID-User-Management-System-Web-Server-Delete-log-or-users-txt-files.png?resize=218%2C107&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 RFID User Management System Web Server Delete log or users txt files\" class=\"wp-image-164269\"\/><\/figure><\/div>\n\n\n<p>You can also access the web server page on your smartphone.<\/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=\"422\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Reader-Web-Server-User-Management-Project-Demonstration.jpg?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32-CAM QR Code Reader Web Server User Management Project Demonstration\" class=\"wp-image-168775\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Reader-Web-Server-User-Management-Project-Demonstration.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Reader-Web-Server-User-Management-Project-Demonstration.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\">Troubleshooting and Tips<\/h2>\n\n\n\n<p>As we&#8217;ve mentioned earlier, this QR Code scanner uses a lot of memory, so your ESP32-CAM must have PSRAM. Here are some boards that were tested and should work with this example:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>CAMERA_MODEL_AI_THINKER<\/li>\n\n\n\n<li>CAMERA_MODEL_WROVER_KIT<\/li>\n\n\n\n<li>CAMERA_MODEL_ESP_EYE<\/li>\n\n\n\n<li>CAMERA_MODEL_M5STACK_PSRAM<\/li>\n\n\n\n<li>CAMERA_MODEL_M5STACK_V2_PSRAM<\/li>\n\n\n\n<li>CAMERA_MODEL_M5STACK_WIDE<\/li>\n<\/ul>\n\n\n\n<p>If you\u2019re getting any of the following errors, read our&nbsp;<a href=\"https:\/\/randomnerdtutorials.com\/esp32-cam-troubleshooting-guide\/\"><strong>ESP32-CAM Troubleshooting Guide: Most Common Problems Fixed<\/strong><\/a><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Failed to connect to ESP32: Timed out waiting for packet header<\/li>\n\n\n\n<li>Camera init failed with error 0x20001 or similar<\/li>\n\n\n\n<li>Brownout detector or Guru meditation error<\/li>\n\n\n\n<li>Sketch too big error \u2013 Wrong partition scheme selected<\/li>\n\n\n\n<li>Board at COMX is not available \u2013 COM Port Not Selected<\/li>\n\n\n\n<li>Psram error: GPIO isr service is not installed<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Wrapping Up<\/h2>\n\n\n\n<p>In this tutorial, you combined different subjects to build a QR Code Management System and Logger with the ESP32-CAM. Here&#8217;s a list of the subjects we covered: different web server features, getting a timestamp, datalogging, interfacing the built-in camera as a QR code reader, reading and writing files to a microSD card, and much more.<\/p>\n\n\n\n<p>We hope you found this project useful, if you want to learn more about the ESP32-CAM you can read the following guides:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-cam-qr-code-reader-scanner-arduino\/\">ESP32-CAM QR Code Reader\/Scanner (Arduino IDE)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-cam-pir-motion-detector-photo-capture\/\">ESP32-CAM PIR Motion Detector with Photo Capture (saves to microSD card)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-cam-ai-thinker-pinout\/\" title=\"\">ESP32-CAM AI-Thinker Pinout Guide: GPIOs Usage Explained<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-cam-projects-ebook\/\"><strong>Build ESP32-CAM Projects (eBook)<\/strong><\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/projects-esp32-cam\/\"><strong>Read all our ESP32-CAM Projects, Tutorials and Guides<\/strong><\/a><\/li>\n<\/ul>\n\n\n\n<p>Thank you for reading.<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this project, you&#8217;ll build a QR code user management system with a web server that runs on an ESP32-CAM. The ESP32-CAM is constantly using its camera to scan for &#8230; <\/p>\n<p class=\"read-more-container\"><a title=\"ESP32-CAM QR Code Reader User Management System (Web Server)\" class=\"read-more button\" href=\"https:\/\/randomnerdtutorials.com\/esp32-cam-qr-code-reader-web-server\/#more-168608\" aria-label=\"Read more about ESP32-CAM QR Code Reader User Management System (Web Server)\">CONTINUE READING \u00bb<\/a><\/p>\n","protected":false},"author":1,"featured_media":168957,"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,319,264],"tags":[],"class_list":["post-168608","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-esp32-project","category-esp32","category-esp32-arduino-ide","category-esp32-cam","category-project"],"aioseo_notices":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-CAM-QR-Code-Manager-Web-Server.jpg?fit=1920%2C1080&quality=100&strip=all&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/168608","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\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/comments?post=168608"}],"version-history":[{"count":10,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/168608\/revisions"}],"predecessor-version":[{"id":169050,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/168608\/revisions\/169050"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media\/168957"}],"wp:attachment":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media?parent=168608"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/categories?post=168608"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/tags?post=168608"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}