{"id":97405,"date":"2020-06-16T09:57:46","date_gmt":"2020-06-16T09:57:46","guid":{"rendered":"https:\/\/randomnerdtutorials.com\/?p=97405"},"modified":"2025-03-15T10:51:34","modified_gmt":"2025-03-15T10:51:34","slug":"esp32-iot-shield-pcb-dashboard","status":"publish","type":"post","link":"https:\/\/randomnerdtutorials.com\/esp32-iot-shield-pcb-dashboard\/","title":{"rendered":"ESP32 IoT Shield PCB with Dashboard for Outputs and Sensors"},"content":{"rendered":"\n<p>In this project we&#8217;ll show you how to build an IoT shield PCB for the ESP32 and a web server dashboard to control it. The shield is equipped with a BME280 sensor (temperature, humidity and pressure), an LDR (light dependent resistor), a PIR motion sensor, a status LED, a pushbutton and a terminal socket to connect a relay module or any other output. <\/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\/2020\/06\/ESP32-IoT-Shield-PCB-Dashboard-for-Outputs-and-Sensors-Arduino-IDE.jpg?resize=1200%2C675&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 IoT Shield PCB with Dashboard for Outputs and Sensors\" class=\"wp-image-97547\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Shield-PCB-Dashboard-for-Outputs-and-Sensors-Arduino-IDE.jpg?w=1280&amp;quality=100&amp;strip=all&amp;ssl=1 1280w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Shield-PCB-Dashboard-for-Outputs-and-Sensors-Arduino-IDE.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Shield-PCB-Dashboard-for-Outputs-and-Sensors-Arduino-IDE.jpg?resize=1024%2C576&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Shield-PCB-Dashboard-for-Outputs-and-Sensors-Arduino-IDE.jpg?resize=768%2C432&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/><\/figure><\/div>\n\n\n<p>Alternatively, you can also follow this project by wiring the circuit on a breadboard.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Watch the Video Tutorial<\/h2>\n\n\n\n<p>This project is available in video format and in written format. You can watch the video below or you can scroll down for the written instructions.<\/p>\n\n\n<p style=\"text-align:center\"><iframe width=\"720\" height=\"405\" src=\"https:\/\/www.youtube.com\/embed\/fjLvBkZxZVE?rel=0\" frameborder=\"0\" allowfullscreen><\/iframe><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Resources<\/h3>\n\n\n\n<p>You can find all the resources needed to build this project in the links below (or you can visit the&nbsp;GitHub project):<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/raw.githubusercontent.com\/RuiSantosdotme\/ESP32-IoT-Shield-PCB\/master\/ESP32_IoT_Shield_Dashboard\/ESP32_IoT_Shield_Dashboard.ino\" target=\"_blank\" rel=\"noreferrer noopener\">ESP32 Web Server Code (Arduino IDE)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Shield-PCB-Circuit-Breadboard.jpg\" target=\"_blank\" rel=\"noreferrer noopener\">Schematic diagram<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/RuiSantosdotme\/ESP32-IoT-Shield-PCB\/raw\/master\/Gerber_PCB_ESP32_IoT_Shield_2020-06-10_10-55-31.zip\" target=\"_blank\" rel=\"noreferrer noopener\">Gerber files<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/RuiSantosdotme\/ESP32-IoT-Shield-PCB\/raw\/master\/Project_ESP32%20IoT%20Shield_2020-06-10_09-57-16.zip\" target=\"_blank\" rel=\"noreferrer noopener\">EasyEDA project to edit the PCB<\/a><\/li>\n\n\n\n<li><strong><a href=\"https:\/\/github.com\/RuiSantosdotme\/ESP32-IoT-Shield-PCB\/archive\/master.zip\" target=\"_blank\" rel=\"noreferrer noopener\">Click here to download all the files<\/a><\/strong><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Project Overview<\/h2>\n\n\n\n<p>This project consists of two parts: <\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><a href=\"#designPCB\">Designing and Building the IoT shield <\/a><\/li>\n\n\n\n<li><a href=\"#programPCB\">Programming the IoT shield using Arduino IDE<\/a><\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">IoT Shield Features<\/h3>\n\n\n\n<p>The IoT sensor shield is designed to be stacked to the ESP32. For this reason, if you want to use our PCB, you need the same ESP32 board. We\u2019re using the <a rel=\"noreferrer noopener\" href=\"https:\/\/makeradvisor.com\/tools\/esp32-dev-board-wi-fi-bluetooth\/\" target=\"_blank\">ESP32 DEVKIT DOIT V1<\/a> board (the model with <strong>36 GPIOs<\/strong>).<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"750\" height=\"422\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Sensor-Shield-PCB-and-ESP32-board.jpg?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 IoT Sensor Shield PCB and ESP32 board\" class=\"wp-image-97572\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Sensor-Shield-PCB-and-ESP32-board.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Sensor-Shield-PCB-and-ESP32-board.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 another ESP32 model, you can still follow this project by assembling the circuit on a breadboard or modifying the PCB layout and wiring to match your ESP32 board.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"750\" height=\"422\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Shield-Breadboard-Circuit.jpg?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 IoT Sensor Shield circuit assembled on Breadboard\" class=\"wp-image-97573\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Shield-Breadboard-Circuit.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Shield-Breadboard-Circuit.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 shield consists of:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>BME280 temperature, humidity and pressure sensor;<\/li>\n\n\n\n<li>LDR (light dependent resistor);<\/li>\n\n\n\n<li>PIR motion sensor;<\/li>\n\n\n\n<li>Status on-board LED;<\/li>\n\n\n\n<li>Pushbutton;<\/li>\n\n\n\n<li>3-pin socket that gives you access to GND, 5V and a GPIO where you can connect any output (like a relay module for example).<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">ESP32 IoT Shield Pin Assignment<\/h3>\n\n\n\n<p>The following table describes the pin assignment for each component of the IoT shield:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td><strong>Component<\/strong><\/td><td><strong>ESP32 Pin Assignment<\/strong><\/td><\/tr><tr><td>BME280<\/td><td>GPIO 21 (SDA), GPIO 22 (SCL)<\/td><\/tr><tr><td>PIR Motion Sensor<\/td><td>GPIO 27<\/td><\/tr><tr><td>Light Dependent Resistor (LDR)<\/td><td>GPIO 33<\/td><\/tr><tr><td>Pushbutton<\/td><td>GPIO 18<\/td><\/tr><tr><td>LED<\/td><td>GPIO 19<\/td><\/tr><tr><td>Additional Output<\/td><td>GPIO 32<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>If you want to assign and use different pins,&nbsp;read our <a href=\"https:\/\/randomnerdtutorials.com\/esp32-pinout-reference-gpios\/\">ESP32 Pinout Reference Guide<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Web Server (IoT Dashboard) Features<\/h3>\n\n\n\n<p>To control the shield, we\u2019ll build a web server. However, you can program the sensor shield as you wish with any other web server or to integrate it with a home automation platform.<\/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=\"847\" height=\"798\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Dashboard-Web-Server.jpg?resize=847%2C798&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Web Server IoT Dashboard Features overview\" class=\"wp-image-97548\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Dashboard-Web-Server.jpg?w=847&amp;quality=100&amp;strip=all&amp;ssl=1 847w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Dashboard-Web-Server.jpg?resize=300%2C283&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Dashboard-Web-Server.jpg?resize=768%2C724&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 847px) 100vw, 847px\" \/><\/figure><\/div>\n\n\n<p>Here\u2019s the web server features to control the IoT shield:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>To access the web server, you need to login with username and password (read: <a href=\"https:\/\/randomnerdtutorials.com\/esp32-esp8266-web-server-http-authentication\/\">ESP32 Web Server HTTP Authentication: Username and Password Protected<\/a>).<\/li>\n\n\n\n<li>After authenticating with the right credentials, you can access the web server. There\u2019s an icon at the top of the web page that you can click to logout. Then, you\u2019ll need to login again.<\/li>\n\n\n\n<li>There are two toggle switches: one to control the output socket and another for the on-board status LED.<\/li>\n\n\n\n<li>The status LED can also be controlled using the physical on-shield pushbutton. The state of the LED automatically updates on the web page (like in this tutorial: <a href=\"https:\/\/randomnerdtutorials.com\/esp32-esp8266-web-server-physical-button\/\">Control Outputs with Web Server and a Physical Button Simultaneously<\/a>). The toggle switch for the status LED can be useful to activate or deactivate something on the ESP32 and the LED gives you a visual feedback of what\u2019s going on.<\/li>\n\n\n\n<li>The temperature, humidity and luminosity are displayed on the web server and are automatically updated using server-sent events (SSE).<\/li>\n\n\n\n<li>Finally, there\u2019s a card that indicates if motion was detected. After receiving the &#8220;Motion Detected&#8221; notification, you can click on the card to clear the warning.<\/li>\n<\/ul>\n\n\n\n<p>These are the main features of the ESP32 IoT dashboard we&#8217;re going to build. This combines many of the subjects approached in previous tutorials.<\/p>\n\n\n\n<p>This is just an example on how you can control your shield. The idea is to modify the code to add your own features to the project.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"designPCB\">Testing the Circuit on a Breadboard<\/h2>\n\n\n\n<p>Before designing and building the PCB shield, it\u2019s important to test the circuit on a breadboard. If you don\u2019t want to make a PCB, you can still follow this project by assembling the circuit on a breadboard.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"750\" height=\"422\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Shield-Breadboard-Circuit.jpg?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 IoT Sensor Shield circuit assembled on Breadboard\" class=\"wp-image-97573\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Shield-Breadboard-Circuit.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Shield-Breadboard-Circuit.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<h3 class=\"wp-block-heading\">Parts Required<\/h3>\n\n\n\n<p>To assemble the circuit on a breadboard you need the following parts:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/esp32-dev-board-wi-fi-bluetooth\/\" target=\"_blank\" rel=\"noreferrer noopener\">DOIT ESP32 DEVKIT V1 Board<\/a> (<strong>version with 36 GPIOs<\/strong>)\u00a0\u2013 read\u00a0<a href=\"https:\/\/makeradvisor.com\/esp32-development-boards-review-comparison\/\" target=\"_blank\" rel=\"noreferrer noopener\">Best ESP32 Development Boards<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/3mm-5mm-leds-kit-storage-box\/\" target=\"_blank\" rel=\"noreferrer noopener\">2x 5mm LED<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/resistors-kits\/\" target=\"_blank\" rel=\"noreferrer noopener\">2x 330 Ohm resistor<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/bme280-sensor-module\/\">1x BME280<\/a> (4 pins)<\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/mini-hc-sr505-pir-motion-sensor\/\" target=\"_blank\" rel=\"noreferrer noopener\">1x mini PIR motion sensor<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/photoresistor-light-dependent-resistor-ldr\/\" target=\"_blank\" rel=\"noreferrer noopener\">1x light dependent resistor<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/resistors-kits\/\" target=\"_blank\" rel=\"noreferrer noopener\">2x 10k Ohm resistor<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/pushbuttons-kit\/\" target=\"_blank\" rel=\"noreferrer noopener\">1x pushbutton<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/mb-102-solderless-breadboard-830-points\/\" target=\"_blank\" rel=\"noreferrer noopener\">Breadboard<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/jumper-wires-kit-120-pieces\/\" target=\"_blank\" rel=\"noreferrer noopener\">Jumper wires<\/a><\/li>\n<\/ul>\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>After gathering all the parts, assemble the circuit by following the next schematic diagram:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><a href=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Shield-PCB-Circuit-Breadboard.jpg?quality=100&#038;strip=all&#038;ssl=1\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1170\" height=\"1302\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Shield-PCB-Circuit-Breadboard.jpg?resize=1170%2C1302&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Testing the Circuit on a Breadboard ESP32 IoT PCB Shield\" class=\"wp-image-97430\" style=\"width:878px;height:977px\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Shield-PCB-Circuit-Breadboard.jpg?w=1170&amp;quality=100&amp;strip=all&amp;ssl=1 1170w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Shield-PCB-Circuit-Breadboard.jpg?resize=270%2C300&amp;quality=100&amp;strip=all&amp;ssl=1 270w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Shield-PCB-Circuit-Breadboard.jpg?resize=920%2C1024&amp;quality=100&amp;strip=all&amp;ssl=1 920w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Shield-PCB-Circuit-Breadboard.jpg?resize=768%2C855&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 1170px) 100vw, 1170px\" \/><\/a><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\">Designing the PCB<\/h2>\n\n\n\n<p>To design the circuit and PCB, we used&nbsp;<a rel=\"noreferrer noopener nofollow\" href=\"https:\/\/easyeda.com\/\" target=\"_blank\">EasyEDA<\/a>&nbsp;which is a browser based software to design PCBs. If you want to customize your PCB, you just need to upload the following files:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/github.com\/RuiSantosdotme\/ESP32-IoT-Shield-PCB\/raw\/master\/Project_ESP32%20IoT%20Shield_2020-06-10_09-57-16.zip\" target=\"_blank\" rel=\"noreferrer noopener\">EasyEDA project files to edit the PCB<\/a><\/li>\n<\/ul>\n\n\n\n<p>Designing the circuit works like in any other circuit software tool, you place some components and you wire them together. Then, you assign each component to a footprint.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><a href=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Shield-PCB-Schematic-Circuit-Diagram.png?quality=100&#038;strip=all&#038;ssl=1\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1200\" height=\"494\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Shield-PCB-Schematic-Circuit-Diagram.png?resize=1200%2C494&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 IoT Shield PCB Schematic Circuit Diagram\" class=\"wp-image-97553\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Shield-PCB-Schematic-Circuit-Diagram.png?w=1389&amp;quality=100&amp;strip=all&amp;ssl=1 1389w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Shield-PCB-Schematic-Circuit-Diagram.png?resize=300%2C124&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Shield-PCB-Schematic-Circuit-Diagram.png?resize=1024%2C422&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Shield-PCB-Schematic-Circuit-Diagram.png?resize=768%2C316&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/><\/a><\/figure><\/div>\n\n\n<p>Having the parts assigned, place each component. When you\u2019re happy with the layout, make all the connections and route your PCB.<\/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=\"900\" height=\"500\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Shield-PCB-Schematic.png?resize=900%2C500&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 IoT Shield PCB Schematic footprints\" class=\"wp-image-97552\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Shield-PCB-Schematic.png?w=900&amp;quality=100&amp;strip=all&amp;ssl=1 900w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Shield-PCB-Schematic.png?resize=300%2C167&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Shield-PCB-Schematic.png?resize=768%2C427&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 900px) 100vw, 900px\" \/><\/figure><\/div>\n\n\n<p>Save your project and export the Gerber files.<\/p>\n\n\n\n<p><strong>Note: <\/strong> you can grab the project files and edit them to customize the shield for your own needs.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/github.com\/RuiSantosdotme\/ESP32-IoT-Shield-PCB\/raw\/master\/Gerber_PCB_ESP32_IoT_Shield_2020-06-10_10-55-31.zip\" target=\"_blank\" rel=\"noreferrer noopener\"><strong>Download Gerber .zip file<\/strong><\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/RuiSantosdotme\/ESP32-IoT-Shield-PCB\/raw\/master\/Project_ESP32%20IoT%20Shield_2020-06-10_09-57-16.zip\" target=\"_blank\" rel=\"noreferrer noopener\">EasyEDA project to edit the PCB<\/a><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Ordering the PCBs at PCBWay<\/h2>\n\n\n\n<p>This project is sponsored by PCBWay. <a href=\"https:\/\/randomnerdtutorials.com\/pcbway\" target=\"_blank\" rel=\"noreferrer noopener\">PCBWay<\/a>&nbsp;is a full feature Printed Circuit Board manufacturing service. <\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><a href=\"https:\/\/makeradvisor.com\/pcbway\" target=\"_blank\" rel=\"noopener noreferrer\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"291\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/PCBWay-banner.jpg?resize=750%2C291&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Ordering the PCBs at PCBWay\" class=\"wp-image-97545\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/PCBWay-banner.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/PCBWay-banner.jpg?resize=300%2C116&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/a><\/figure><\/div>\n\n\n<p>Turn your DIY breadboard circuits into <a href=\"https:\/\/randomnerdtutorials.com\/pcbway\" target=\"_blank\" rel=\"noreferrer noopener\">professional PCBs<\/a> &#8211; get 10 boards for approximately $5 + shipping (which will vary depending on your country).<\/p>\n\n\n\n<p>Once you have your Gerber files, you can order the PCB. Follow the next steps to download the file.<\/p>\n\n\n\n<p>1. Download the Gerber files \u2013&nbsp;<a href=\"https:\/\/github.com\/RuiSantosdotme\/ESP32-IoT-Shield-PCB\/raw\/master\/Gerber_PCB_ESP32_IoT_Shield_2020-06-10_10-55-31.zip\" target=\"_blank\" rel=\"noreferrer noopener\">click here to download the .zip file<\/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=\"721\" height=\"576\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/4-PCBWay-Order-PCB-import-zip-folder.png?resize=721%2C576&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"PCBWay Order PCB import zip folder with Gerber files\" class=\"wp-image-97557\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/4-PCBWay-Order-PCB-import-zip-folder.png?w=721&amp;quality=100&amp;strip=all&amp;ssl=1 721w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/4-PCBWay-Order-PCB-import-zip-folder.png?resize=300%2C240&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 721px) 100vw, 721px\" \/><\/figure><\/div>\n\n\n<p>2. Go to <a href=\"https:\/\/randomnerdtutorials.com\/pcbway\" target=\"_blank\" rel=\"noreferrer noopener\">PCBWay website<\/a> and open the PCB Instant Quote page.&nbsp;<\/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=\"900\" height=\"504\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/1-PCBWay-Order-PCB.png?resize=900%2C504&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"PCBWay Order PCB open instant quote page\" class=\"wp-image-97554\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/1-PCBWay-Order-PCB.png?w=900&amp;quality=100&amp;strip=all&amp;ssl=1 900w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/1-PCBWay-Order-PCB.png?resize=300%2C168&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/1-PCBWay-Order-PCB.png?resize=768%2C430&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 900px) 100vw, 900px\" \/><\/figure><\/div>\n\n\n<p>3. PCBWay can grab all the PCB details and automatically fill them for you. Use the \u201cQuick-order PCB (Autofill parameters)\u201d.<\/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=\"900\" height=\"469\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/2-PCBWay-Order-PCB-autofill-parameters.png?resize=900%2C469&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"PCBWay Order PCB autofill parameters\" class=\"wp-image-97555\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/2-PCBWay-Order-PCB-autofill-parameters.png?w=900&amp;quality=100&amp;strip=all&amp;ssl=1 900w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/2-PCBWay-Order-PCB-autofill-parameters.png?resize=300%2C156&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/2-PCBWay-Order-PCB-autofill-parameters.png?resize=768%2C400&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 900px) 100vw, 900px\" \/><\/figure><\/div>\n\n\n<p>4. Press the \u201c+ Add Gerber file\u201d button to upload the provided Gerber files.<\/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=\"939\" height=\"521\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/3-PCBWay-Order-PCB-gerbers-files.png?resize=939%2C521&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"PCBWay Order PCB add gerber file button\" class=\"wp-image-97556\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/3-PCBWay-Order-PCB-gerbers-files.png?w=939&amp;quality=100&amp;strip=all&amp;ssl=1 939w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/3-PCBWay-Order-PCB-gerbers-files.png?resize=300%2C166&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/3-PCBWay-Order-PCB-gerbers-files.png?resize=768%2C426&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 939px) 100vw, 939px\" \/><\/figure><\/div>\n\n\n<p>And that\u2019s it. You can also use the OnlineGerberViewer to check if your PCB is looking as it should.<\/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=\"900\" height=\"332\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/5-PCBWay-Order-PCB-Gerber-files-preview.png?resize=900%2C332&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"PCBWay Order PCB Gerber files preview window\" class=\"wp-image-97558\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/5-PCBWay-Order-PCB-Gerber-files-preview.png?w=900&amp;quality=100&amp;strip=all&amp;ssl=1 900w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/5-PCBWay-Order-PCB-Gerber-files-preview.png?resize=300%2C111&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/5-PCBWay-Order-PCB-Gerber-files-preview.png?resize=768%2C283&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 900px) 100vw, 900px\" \/><\/figure><\/div>\n\n\n<p>If you aren\u2019t in a hurry, you can use the China Post shipping method to lower your cost significantly. In our opinion, we think they overestimate the China Post shipping 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=\"365\" height=\"630\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/6-PCBWay-Order-PCB-china-post.png?resize=365%2C630&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"PCBWay Order PCB China post shipping method\" class=\"wp-image-97559\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/6-PCBWay-Order-PCB-china-post.png?w=365&amp;quality=100&amp;strip=all&amp;ssl=1 365w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/6-PCBWay-Order-PCB-china-post.png?resize=174%2C300&amp;quality=100&amp;strip=all&amp;ssl=1 174w\" sizes=\"(max-width: 365px) 100vw, 365px\" \/><\/figure><\/div>\n\n\n<p>You can increase your PCB order quantity and change the solder mask color. I\u2019ve ordered the Blue color.<\/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=\"1000\" height=\"490\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/7-PCBWay-Order-PCB-final-step.png?resize=1000%2C490&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"PCBWay Order PCB final step and save to cart\" class=\"wp-image-97551\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/7-PCBWay-Order-PCB-final-step.png?w=1000&amp;quality=100&amp;strip=all&amp;ssl=1 1000w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/7-PCBWay-Order-PCB-final-step.png?resize=300%2C147&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/7-PCBWay-Order-PCB-final-step.png?resize=768%2C376&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 1000px) 100vw, 1000px\" \/><\/figure><\/div>\n\n\n<p>Once you\u2019re ready, you can order the PCBs by clicking &#8220;Save to Cart&#8221; and complete your order.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Unboxing<\/h2>\n\n\n\n<p>After approximately one week using the DHL shipping method, I received the PCBs at my office. <\/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\/2020\/06\/PCBWay-Unboxing.jpg?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"PCBWay Unboxing\" class=\"wp-image-97576\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/PCBWay-Unboxing.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/PCBWay-Unboxing.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>Everything comes well packed, and the PCBs are really high-quality. The letters on the silkscreen are really well-printed and easy to read. Additionally, the solder sticks easily to the pads.<\/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\/2020\/06\/PCBWay-Unboxing-PCBs-bare-boards.jpg?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"PCBWay Unboxing PCBs bare boards\" class=\"wp-image-97571\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/PCBWay-Unboxing-PCBs-bare-boards.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/PCBWay-Unboxing-PCBs-bare-boards.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>Besides the PCBs, I also received some stickers, a ruler and a pen. Overall, we\u2019re really satisfied with the PCBWay service.<\/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\/2020\/06\/PCBWay-Unboxing-PCBs.jpg?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"PCBWay Unboxing PCBs\" class=\"wp-image-97577\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/PCBWay-Unboxing-PCBs.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/PCBWay-Unboxing-PCBs.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\">Soldering the Components<\/h2>\n\n\n\n<p>The next step is soldering the components to the PCB. I\u2019ve used an SMD LED and SMD resistors. These can be a bit difficult to solder, but they save a lot of space on the PCB. <\/p>\n\n\n\n<p>Here\u2019s a list of all the components needed to build the PCB shield:<\/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\/2020\/06\/ESP32-IoT-Shield-PCB-assembled-components-parts-required.jpg?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 IoT Sensor Shield components parts required\" class=\"wp-image-97578\" style=\"width:750px;height:422px\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Shield-PCB-assembled-components-parts-required.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Shield-PCB-assembled-components-parts-required.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<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/makeradvisor.com\/smd-leds\/\" target=\"_blank\" rel=\"noreferrer noopener\">1x SMD LED<\/a> (1206)<\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/smd-resistors\" target=\"_blank\" rel=\"noreferrer noopener\">1x 330 Ohm SMD resistors<\/a> (1206)<\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/smd-resistors\" target=\"_blank\" rel=\"noreferrer noopener\">2x 10k Ohm SMD resistor<\/a> (1206)<\/li>\n\n\n\n<li>1x Pushbutton (0.55 mm)<\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/bme280-sensor-module\/\">1x BME280<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/mini-hc-sr505-pir-motion-sensor\/\" target=\"_blank\" rel=\"noreferrer noopener\">1x Mini PIR motion sensor<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/photoresistor-light-dependent-resistor-ldr\/\" target=\"_blank\" rel=\"noreferrer noopener\">1x Light dependent resistor<\/a><\/li>\n\n\n\n<li><a href=\"http:\/\/shrsl.com\/roqk\" target=\"_blank\" rel=\"noreferrer noopener\">1x Screw terminal blocks<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/female-pin-header-socket\" target=\"_blank\" rel=\"noreferrer noopener\">Female pin header socket<\/a> (2.54 mm)<\/li>\n<\/ul>\n\n\n\n<p>Here\u2019s the soldering tools I\u2019ve used:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/makeradvisor.com\/ts80-soldering-iron-review\/\" target=\"_blank\" rel=\"noreferrer noopener\">TS80 mini portable soldering iron<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.banggood.com\/0_5mm-500g-Soldering-Wires-Welding-Iron-Rosin-Core-6040-Lead-Tin-Flux-2_0-Percent-p-1023387.html?p=MA240439985285201910\" target=\"_blank\" rel=\"noreferrer noopener\">Solder 60\/40 0.5mm diameter<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/soldering-mats-review\/\" target=\"_blank\" rel=\"noreferrer noopener\">Soldering mat<\/a><\/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=\"750\" height=\"421\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/TS80-Soldering-Iron-Review-Best-Portable-Soldering-Iron.jpg?resize=750%2C421&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"TS80 Soldering Iron Review Best Portable Soldering Iron\" class=\"wp-image-97549\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/TS80-Soldering-Iron-Review-Best-Portable-Soldering-Iron.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/TS80-Soldering-Iron-Review-Best-Portable-Soldering-Iron.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>Read our review about the TS80 Soldering Iron:&nbsp;<a href=\"https:\/\/makeradvisor.com\/ts80-soldering-iron-review\/\" target=\"_blank\" rel=\"noreferrer noopener\">TS80 Soldering Iron Review \u2013 Best Portable Soldering Iron<\/a>.<\/p>\n\n\n\n<p>Start by soldering the SMD components. Then, solder the header pins. And finally, solder the other components or use header pins if you don\u2019t want to connect the components permanently.<\/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=\"423\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Sensor-Shild-Soldering-Solder-parts-components.jpg?resize=750%2C423&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 PCB Shield soldering with TS80 portable soldering iron\" class=\"wp-image-97584\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Sensor-Shild-Soldering-Solder-parts-components.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Sensor-Shild-Soldering-Solder-parts-components.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>Here\u2019s how the ESP32 IoT Shield looks like after assembling all the parts. It should connect perfectly to the ESP32 DEVKIT DOIT V1 board.<\/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\/2020\/06\/ESP32-IoT-Shield-PCB-assembled.jpg?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 IoT Shield PCB soldered and assembled\" class=\"wp-image-97575\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Shield-PCB-assembled.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Shield-PCB-assembled.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<hr class=\"wp-block-separator has-css-opacity is-style-wide\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"programPCB\">Programming the ESP32 IoT Shield<\/h2>\n\n\n\n<p>The code for this project runs a web server that allows you to monitor and control the IoT shield. The features of the web server were covered previously.<\/p>\n\n\n\n<p>We&#8217;ll program the ESP32 board using Arduino IDE. So make sure you have the ESP32 board add-on installed.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/installing-the-esp32-board-in-arduino-ide-windows-instructions\/\">Installing ESP32 Board in Arduino IDE (Windows, Mac OS X, and Linux)<\/a><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Installing Libraries<\/h3>\n\n\n\n<p>Before uploading the code, make sure you have the following libraries installed:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/github.com\/adafruit\/Adafruit_BME280_Library\" target=\"_blank\" rel=\"noreferrer noopener\">Adafruit_BME280 library<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/adafruit\/Adafruit_Sensor\" target=\"_blank\" rel=\"noreferrer noopener\">Adafruit_Sensor library<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/ESP32Async\/ESPAsyncWebServer\" target=\"_blank\" rel=\"noreferrer noopener\">ESPAsyncWebServer\u00a0<\/a>by ESP32Async<\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/ESP32Async\/AsyncTCP\" target=\"_blank\" rel=\"noreferrer noopener\">AsyncTCP<\/a>\u00a0by ESP32Async<\/li>\n<\/ul>\n\n\n\n<p>To install those libraries, in the Arduino IDE and go to\u00a0<strong>Sketch\u00a0<\/strong>>\u00a0<strong>Include Library<\/strong>\u00a0>\u00a0<strong>Manage Libraries<\/strong>. The Library Manager should open. Search for the libraries&#8217; names and install them.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Code &#8211; ESP32 IoT Shied Web Server Dashboard<\/h3>\n\n\n\n<p>Copy the following code to the Arduino IDE.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-c\">\/*********\r\n  Rui Santos\r\n  Complete project details at https:\/\/RandomNerdTutorials.com\/esp32-iot-shield-pcb-dashboard\/\r\n  The above copyright notice and this permission notice shall be included in all\r\n  copies or substantial portions of the Software.\r\n*********\/\r\n\r\n\/\/ Import required libraries\r\n#include &quot;WiFi.h&quot;\r\n#include &quot;ESPAsyncWebServer.h&quot;\r\n#include &lt;Adafruit_BME280.h&gt;\r\n#include &lt;Adafruit_Sensor.h&gt;\r\n\r\n\/\/ Replace with your network credentials\r\nconst char* ssid = &quot;REPLACE_WITH_YOUR_SSID&quot;;\r\nconst char* password = &quot;REPLACE_WITH_YOUR_PASSWORD&quot;;\r\n\r\n\/\/ Web Server HTTP Authentication credentials\r\nconst char* http_username = &quot;admin&quot;;\r\nconst char* http_password = &quot;admin&quot;;\r\n\r\nAdafruit_BME280 bme;         \/\/ BME280 connect to ESP32 I2C (GPIO 21 = SDA, GPIO 22 = SCL)\r\nconst int buttonPin = 18;    \/\/ Pushbutton\r\nconst int ledPin = 19;       \/\/ Status LED\r\nconst int output = 32;       \/\/ Output socket\r\nconst int ldr = 33;          \/\/ LDR (Light Dependent Resistor)\r\nconst int motionSensor = 27; \/\/ PIR Motion Sensor\r\n\r\nint ledState = LOW;           \/\/ current state of the output pin\r\nint buttonState;              \/\/ current reading from the input pin\r\nint lastButtonState = LOW;    \/\/ previous reading from the input pin\r\nbool motionDetected = false;  \/\/ flag variable to send motion alert message\r\nbool clearMotionAlert = true; \/\/ clear last motion alert message from web page\r\n\r\nunsigned long lastDebounceTime = 0;  \/\/ the last time the output pin was toggled\r\nunsigned long debounceDelay = 50;    \/\/ the debounce time; increase if the output flickers\r\n\r\n\/\/ Create AsyncWebServer object on port 80\r\nAsyncWebServer server(80);\r\nAsyncEventSource events(&quot;\/events&quot;);\r\n\r\nconst char* PARAM_INPUT_1 = &quot;state&quot;;\r\n\r\n\/\/ Checks if motion was detected\r\nvoid IRAM_ATTR detectsMovement() {\r\n  \/\/Serial.println(&quot;MOTION DETECTED!!!&quot;);\r\n  motionDetected = true;\r\n  clearMotionAlert = false;\r\n}\r\n\r\n\/\/ Main HTML web page in root url \/\r\nconst char index_html[] PROGMEM = R&quot;rawliteral(\r\n&lt;!DOCTYPE HTML&gt;&lt;html&gt;\r\n&lt;head&gt;\r\n  &lt;title&gt;ESP IOT DASHBOARD&lt;\/title&gt;\r\n  &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&gt;\r\n  &lt;link rel=&quot;icon&quot; href=&quot;data:,&quot;&gt;\r\n  &lt;link rel=&quot;stylesheet&quot; href=&quot;https:\/\/use.fontawesome.com\/releases\/v5.7.2\/css\/all.css&quot; integrity=&quot;sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr&quot; crossorigin=&quot;anonymous&quot;&gt;\r\n  &lt;style&gt;\r\n    html {font-family: Arial; display: inline-block; text-align: center;}\r\n    h3 {font-size: 1.8rem; color: white;}\r\n    h4 { font-size: 1.2rem;}\r\n    p { font-size: 1.4rem;}\r\n    body {  margin: 0;}\r\n    .switch {position: relative; display: inline-block; width: 120px; height: 68px; margin-bottom: 20px;}\r\n    .switch input {display: none;}\r\n    .slider {position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; border-radius: 68px;   opacity: 0.8;   cursor: pointer;}\r\n    .slider:before {position: absolute; content: &quot;&quot;; height: 52px; width: 52px; left: 8px; bottom: 8px; background-color: #fff; -webkit-transition: .4s; transition: .4s; border-radius: 68px}\r\n    input:checked+.slider {background-color: #1b78e2}\r\n    input:checked+.slider:before {-webkit-transform: translateX(52px); -ms-transform: translateX(52px); transform: translateX(52px)}\r\n    .topnav { overflow: hidden; background-color: #1b78e2;}\r\n    .content { padding: 20px;}\r\n    .card { background-color: white; box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);}\r\n    .cards { max-width: 700px; margin: 0 auto; display: grid; grid-gap: 2rem; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));}\r\n    .slider2 { -webkit-appearance: none; margin: 14px;  height: 20px; background: #ccc; outline: none; opacity: 0.8; -webkit-transition: .2s; transition: opacity .2s; margin-bottom: 40px; }\r\n    .slider:hover, .slider2:hover { opacity: 1; }\r\n    .slider2::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 40px; height: 40px; background: #008B74; cursor: pointer; }\r\n    .slider2::-moz-range-thumb { width: 40px; height: 40px; background: #008B74; cursor: pointer;}\r\n    .reading { font-size: 2.6rem;}\r\n    .card-switch {color: #50a2ff; }\r\n    .card-light{ color: #008B74;}\r\n    .card-bme{ color: #572dfb;}\r\n    .card-motion{ color: #3b3b3b; cursor: pointer;}\r\n    .icon-pointer{ cursor: pointer;}\r\n  &lt;\/style&gt;\r\n&lt;\/head&gt;\r\n&lt;body&gt;\r\n  &lt;div class=&quot;topnav&quot;&gt;\r\n    &lt;h3&gt;ESP IOT DASHBOARD &lt;span style=&quot;text-align:right;&quot;&gt;&amp;nbsp;&amp;nbsp; &lt;i class=&quot;fas fa-user-slash icon-pointer&quot; onclick=&quot;logoutButton()&quot;&gt;&lt;\/i&gt;&lt;\/span&gt;&lt;\/h3&gt;\r\n  &lt;\/div&gt;\r\n  &lt;div class=&quot;content&quot;&gt;\r\n    &lt;div class=&quot;cards&quot;&gt;\r\n      %BUTTONPLACEHOLDER%\r\n      &lt;div class=&quot;card card-bme&quot;&gt;\r\n        &lt;h4&gt;&lt;i class=&quot;fas fa-chart-bar&quot;&gt;&lt;\/i&gt; TEMPERATURE&lt;\/h4&gt;&lt;div&gt;&lt;p class=&quot;reading&quot;&gt;&lt;span id=&quot;temp&quot;&gt;&lt;\/span&gt;&amp;deg;C&lt;\/p&gt;&lt;\/div&gt;\r\n      &lt;\/div&gt;\r\n      &lt;div class=&quot;card card-bme&quot;&gt;\r\n        &lt;h4&gt;&lt;i class=&quot;fas fa-chart-bar&quot;&gt;&lt;\/i&gt; HUMIDITY&lt;\/h4&gt;&lt;div&gt;&lt;p class=&quot;reading&quot;&gt;&lt;span id=&quot;humi&quot;&gt;&lt;\/span&gt;&amp;percnt;&lt;\/p&gt;&lt;\/div&gt;\r\n      &lt;\/div&gt;\r\n      &lt;div class=&quot;card card-light&quot;&gt;\r\n        &lt;h4&gt;&lt;i class=&quot;fas fa-sun&quot;&gt;&lt;\/i&gt; LIGHT&lt;\/h4&gt;&lt;div&gt;&lt;p class=&quot;reading&quot;&gt;&lt;span id=&quot;light&quot;&gt;&lt;\/span&gt;&lt;\/p&gt;&lt;\/div&gt;\r\n      &lt;\/div&gt;\r\n      &lt;div class=&quot;card card-motion&quot; onClick=&quot;clearMotionAlert()&quot;&gt;\r\n        &lt;h4&gt;&lt;i class=&quot;fas fa-running&quot;&gt;&lt;\/i&gt; MOTION SENSOR&lt;\/h4&gt;&lt;div&gt;&lt;p class=&quot;reading&quot;&gt;&lt;span id=&quot;motion&quot;&gt;%MOTIONMESSAGE%&lt;\/span&gt;&lt;\/p&gt;&lt;\/div&gt;\r\n      &lt;\/div&gt;\r\n  &lt;\/div&gt;\r\n&lt;script&gt;\r\nfunction logoutButton() {\r\n  var xhr = new XMLHttpRequest();\r\n  xhr.open(&quot;GET&quot;, &quot;\/logout&quot;, true);\r\n  xhr.send();\r\n  setTimeout(function(){ window.open(&quot;\/logged-out&quot;,&quot;_self&quot;); }, 1000);\r\n}\r\nfunction controlOutput(element) {\r\n  var xhr = new XMLHttpRequest();\r\n  if(element.checked){ xhr.open(&quot;GET&quot;, &quot;\/output?state=1&quot;, true); }\r\n  else { xhr.open(&quot;GET&quot;, &quot;\/output?state=0&quot;, true); }\r\n  xhr.send();\r\n}\r\nfunction toggleLed(element) {\r\n  var xhr = new XMLHttpRequest();\r\n  xhr.open(&quot;GET&quot;, &quot;\/toggle&quot;, true);\r\n  xhr.send();\r\n}\r\nfunction clearMotionAlert() {\r\n  var xhr = new XMLHttpRequest();\r\n  xhr.open(&quot;GET&quot;, &quot;\/clear-motion&quot;, true);\r\n  xhr.send();\r\n  setTimeout(function(){\r\n    document.getElementById(&quot;motion&quot;).innerHTML = &quot;No motion&quot;;\r\n    document.getElementById(&quot;motion&quot;).style.color = &quot;#3b3b3b&quot;;\r\n  }, 1000);\r\n}\r\nif (!!window.EventSource) {\r\n var source = new EventSource('\/events');\r\n source.addEventListener('open', function(e) {\r\n  console.log(&quot;Events Connected&quot;);\r\n }, false);\r\n source.addEventListener('error', function(e) {\r\n  if (e.target.readyState != EventSource.OPEN) {\r\n    console.log(&quot;Events Disconnected&quot;);\r\n  }\r\n }, false);\r\n source.addEventListener('message', function(e) {\r\n  console.log(&quot;message&quot;, e.data);\r\n }, false);\r\n source.addEventListener('led_state', function(e) {\r\n  console.log(&quot;led_state&quot;, e.data);\r\n  var inputChecked;\r\n  if( e.data == 1){ inputChecked = true; }\r\n  else { inputChecked = false; }\r\n  document.getElementById(&quot;led&quot;).checked = inputChecked;\r\n }, false);\r\n source.addEventListener('motion', function(e) {\r\n  console.log(&quot;motion&quot;, e.data);\r\n  document.getElementById(&quot;motion&quot;).innerHTML = e.data;\r\n  document.getElementById(&quot;motion&quot;).style.color = &quot;#b30000&quot;;\r\n }, false); \r\n source.addEventListener('temperature', function(e) {\r\n  console.log(&quot;temperature&quot;, e.data);\r\n  document.getElementById(&quot;temp&quot;).innerHTML = e.data;\r\n }, false);\r\n source.addEventListener('humidity', function(e) {\r\n  console.log(&quot;humidity&quot;, e.data);\r\n  document.getElementById(&quot;humi&quot;).innerHTML = e.data;\r\n }, false);\r\n source.addEventListener('light', function(e) {\r\n  console.log(&quot;light&quot;, e.data);\r\n  document.getElementById(&quot;light&quot;).innerHTML = e.data;\r\n }, false);\r\n}&lt;\/script&gt;\r\n&lt;\/body&gt;\r\n&lt;\/html&gt;)rawliteral&quot;;\r\n\r\nString outputState(int gpio){\r\n  if(digitalRead(gpio)){\r\n    return &quot;checked&quot;;\r\n  }\r\n  else {\r\n    return &quot;&quot;;\r\n  }\r\n}\r\n\r\nString processor(const String&amp; var){\r\n  \/\/Serial.println(var);\r\n  if(var == &quot;BUTTONPLACEHOLDER&quot;){\r\n    String buttons;\r\n    String outputStateValue = outputState(32);\r\n    buttons+=&quot;&lt;div class=\\&quot;card card-switch\\&quot;&gt;&lt;h4&gt;&lt;i class=\\&quot;fas fa-lightbulb\\&quot;&gt;&lt;\/i&gt; OUTPUT&lt;\/h4&gt;&lt;label class=\\&quot;switch\\&quot;&gt;&lt;input type=\\&quot;checkbox\\&quot; onchange=\\&quot;controlOutput(this)\\&quot; id=\\&quot;output\\&quot; &quot; + outputStateValue + &quot;&gt;&lt;span class=\\&quot;slider\\&quot;&gt;&lt;\/span&gt;&lt;\/label&gt;&lt;\/div&gt;&quot;;\r\n    outputStateValue = outputState(19);\r\n    buttons+=&quot;&lt;div class=\\&quot;card card-switch\\&quot;&gt;&lt;h4&gt;&lt;i class=\\&quot;fas fa-lightbulb\\&quot;&gt;&lt;\/i&gt; STATUS LED&lt;\/h4&gt;&lt;label class=\\&quot;switch\\&quot;&gt;&lt;input type=\\&quot;checkbox\\&quot; onchange=\\&quot;toggleLed(this)\\&quot; id=\\&quot;led\\&quot; &quot; + outputStateValue + &quot;&gt;&lt;span class=\\&quot;slider\\&quot;&gt;&lt;\/span&gt;&lt;\/label&gt;&lt;\/div&gt;&quot;;\r\n    return buttons;\r\n  }\r\n  else if(var == &quot;MOTIONMESSAGE&quot;){\r\n    if(!clearMotionAlert) {\r\n      return String(&quot;&lt;span style=\\&quot;color:#b30000;\\&quot;&gt;MOTION DETECTED!&lt;\/span&gt;&quot;);\r\n    }\r\n    else {\r\n      return String(&quot;No motion&quot;);\r\n    }\r\n  }\r\n  return String();\r\n}\r\n\r\n\/\/ Logged out web page\r\nconst char logout_html[] PROGMEM = R&quot;rawliteral(\r\n&lt;!DOCTYPE HTML&gt;&lt;html&gt;\r\n&lt;head&gt;\r\n  &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&gt;\r\n&lt;\/head&gt;\r\n&lt;body&gt;\r\n  &lt;p&gt;Logged out or &lt;a href=&quot;\/&quot;&gt;return to homepage&lt;\/a&gt;.&lt;\/p&gt;\r\n  &lt;p&gt;&lt;strong&gt;Note:&lt;\/strong&gt; close all web browser tabs to complete the logout process.&lt;\/p&gt;\r\n&lt;\/body&gt;\r\n&lt;\/html&gt;\r\n)rawliteral&quot;;\r\n\r\nvoid setup(){\r\n  \/\/ Serial port for debugging purposes\r\n  Serial.begin(115200);\r\n    \r\n  if (!bme.begin(0x76)) {\r\n    Serial.println(&quot;Could not find a valid BME280 sensor, check wiring!&quot;);\r\n    while (1);\r\n  }\r\n  \r\n  \/\/ initialize the pushbutton pin as an input\r\n  pinMode(buttonPin, INPUT);\r\n  \/\/ initialize the LED pin as an output\r\n  pinMode(ledPin, OUTPUT);\r\n  \/\/ initialize the LED pin as an output\r\n  pinMode(output, OUTPUT);\r\n  \/\/ PIR Motion Sensor mode INPUT_PULLUP\r\n  pinMode(motionSensor, INPUT_PULLUP);\r\n  \/\/ Set motionSensor pin as interrupt, assign interrupt function and set RISING mode\r\n  attachInterrupt(digitalPinToInterrupt(motionSensor), detectsMovement, RISING);\r\n  \r\n  \/\/ Connect to Wi-Fi\r\n  WiFi.begin(ssid, password);\r\n  while (WiFi.status() != WL_CONNECTED) {\r\n    delay(1000);\r\n    Serial.println(&quot;Connecting to WiFi..&quot;);\r\n  }\r\n  \/\/ Print ESP32 Local IP Address\r\n  Serial.println(WiFi.localIP());\r\n\r\n  \/\/ Route for root \/ web page\r\n  server.on(&quot;\/&quot;, HTTP_GET, [](AsyncWebServerRequest *request){\r\n   if(!request-&gt;authenticate(http_username, http_password))\r\n      return request-&gt;requestAuthentication();\r\n    request-&gt;send_P(200, &quot;text\/html&quot;, index_html, processor);\r\n  });\r\n  server.on(&quot;\/logged-out&quot;, HTTP_GET, [](AsyncWebServerRequest *request){\r\n    request-&gt;send_P(200, &quot;text\/html&quot;, logout_html, processor);\r\n  });\r\n  server.on(&quot;\/logout&quot;, HTTP_GET, [](AsyncWebServerRequest *request){\r\n    request-&gt;send(401);\r\n  });\r\n  \/\/ Send a GET request to control output socket &lt;ESP_IP&gt;\/output?state=&lt;inputMessage&gt;\r\n  server.on(&quot;\/output&quot;, HTTP_GET, [] (AsyncWebServerRequest *request) {\r\n    if(!request-&gt;authenticate(http_username, http_password))\r\n      return request-&gt;requestAuthentication();\r\n    String inputMessage;\r\n    \/\/ GET gpio and state value\r\n    if (request-&gt;hasParam(PARAM_INPUT_1)) {\r\n      inputMessage = request-&gt;getParam(PARAM_INPUT_1)-&gt;value();\r\n      digitalWrite(output, inputMessage.toInt());\r\n      request-&gt;send(200, &quot;text\/plain&quot;, &quot;OK&quot;);\r\n    }\r\n    request-&gt;send(200, &quot;text\/plain&quot;, &quot;Failed&quot;);\r\n  });\r\n  \/\/ Send a GET request to control on board status LED &lt;ESP_IP&gt;\/toggle\r\n  server.on(&quot;\/toggle&quot;, HTTP_GET, [] (AsyncWebServerRequest *request) {\r\n    if(!request-&gt;authenticate(http_username, http_password))\r\n      return request-&gt;requestAuthentication();\r\n    ledState = !ledState;\r\n    digitalWrite(ledPin, ledState);\r\n    request-&gt;send(200, &quot;text\/plain&quot;, &quot;OK&quot;);\r\n  });\r\n  \/\/ Send a GET request to clear the &quot;Motion Detected&quot; message &lt;ESP_IP&gt;\/clear-motion\r\n  server.on(&quot;\/clear-motion&quot;, HTTP_GET, [] (AsyncWebServerRequest *request) {\r\n    if(!request-&gt;authenticate(http_username, http_password))\r\n      return request-&gt;requestAuthentication();\r\n    clearMotionAlert = true;\r\n    request-&gt;send(200, &quot;text\/plain&quot;, &quot;OK&quot;);\r\n  });\r\n  events.onConnect([](AsyncEventSourceClient *client){\r\n    if(client-&gt;lastId()){\r\n      Serial.printf(&quot;Client reconnected! Last message ID that it got is: %u\\n&quot;, client-&gt;lastId());\r\n    }\r\n    \/\/ send event with message &quot;hello!&quot;, id current millis and set reconnect delay to 1 second\r\n    client-&gt;send(&quot;hello!&quot;,NULL,millis(),1000);\r\n  });\r\n  server.addHandler(&amp;events);\r\n  \r\n  \/\/ Start server\r\n  server.begin();\r\n}\r\n \r\nvoid loop(){\r\n  static unsigned long lastEventTime = millis();\r\n  static const unsigned long EVENT_INTERVAL_MS = 10000;\r\n  \/\/ read the state of the switch into a local variable\r\n  int reading = digitalRead(buttonPin);\r\n\r\n  \/\/ If the switch changed\r\n  if (reading != lastButtonState) {\r\n    \/\/ reset the debouncing timer\r\n    lastDebounceTime = millis();\r\n  }\r\n\r\n  if ((millis() - lastDebounceTime) &gt; debounceDelay) {\r\n    \/\/ if the button state has changed:\r\n    if (reading != buttonState) {\r\n      buttonState = reading;\r\n      \/\/ only toggle the LED if the new button state is HIGH\r\n      if (buttonState == HIGH) {\r\n        ledState = !ledState;\r\n        digitalWrite(ledPin, ledState);\r\n        events.send(String(digitalRead(ledPin)).c_str(),&quot;led_state&quot;,millis());\r\n      }\r\n    }\r\n  }\r\n\r\n  if ((millis() - lastEventTime) &gt; EVENT_INTERVAL_MS) {\r\n    events.send(&quot;ping&quot;,NULL,millis());\r\n    events.send(String(bme.readTemperature()).c_str(),&quot;temperature&quot;,millis());\r\n    events.send(String(bme.readHumidity()).c_str(),&quot;humidity&quot;,millis());\r\n    events.send(String(analogRead(ldr)).c_str(),&quot;light&quot;,millis());\r\n    lastEventTime = millis();\r\n  }\r\n  \r\n  if(motionDetected &amp; !clearMotionAlert){\r\n    events.send(String(&quot;MOTION DETECTED!&quot;).c_str(),&quot;motion&quot;,millis());\r\n    motionDetected = false;\r\n  }\r\n  \r\n  \/\/ save the reading. Next time through the loop, it'll be the lastButtonState:\r\n  lastButtonState = reading;\r\n}\r\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/ESP32-IoT-Shield-PCB\/raw\/master\/ESP32_IoT_Shield_Dashboard\/ESP32_IoT_Shield_Dashboard.ino\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<p>This code is quite long to explain, so you can simply replace the following two variables with your network credentials and the code will work straight away.<\/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_PASSWORD\";<\/code><\/pre>\n\n\n\n<p>If you want to learn how this code works, continue reading. Otherwise, you can skip to the <a href=\"#demonstration\">Demonstration<\/a> section.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">How the Code Works<\/h2>\n\n\n\n<p>Read this section if you want to learn how the code works, or skip to the <a href=\"#demonstration\">next section<\/a>.<\/p>\n\n\n\n<p>The following lines import the required libraries:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#include \"WiFi.h\"\n#include \"ESPAsyncWebServer.h\"\n#include &lt;Adafruit_BME280.h&gt;\n#include &lt;Adafruit_Sensor.h&gt;<\/code><\/pre>\n\n\n\n<p>Insert your network credentials in the following lines so that the ESP32 can connect to your network.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Replace with your network credentials\nconst char* ssid = \"REPLACE_WITH_YOUR_SSID\";\nconst char* password = \"REPLACE_WITH_YOUR_PASSWORD\";<\/code><\/pre>\n\n\n\n<p>The next lines define the username and password to access the web server. By default the username is <strong>admin<\/strong> and the password is<strong> admin<\/strong>. You can change them on the following lines:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Web Server HTTP Authentication credentials\nconst char* http_username = \"admin\";\nconst char* http_password = \"admin\";<\/code><\/pre>\n\n\n\n<p>Create an <span class=\"rnthl rntliteral\">Adafruit_BME280<\/span> object called <span class=\"rnthl rntliteral\">bme<\/span>. This creates an I2C connection to the BME280 on GPIO 21 and GPIO 22.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>Adafruit_BME280 bme;  \/\/ BME280 connect to ESP32 I2C (GPIO 21 = SDA, GPIO 22 = SCL)<\/code><\/pre>\n\n\n\n<p>Then, define the GPIOs the components of the shield are connected to.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>const int buttonPin = 18;    \/\/ Pushbutton\nconst int ledPin = 19;       \/\/ Status LED\nconst int output = 32;       \/\/ Output socket\nconst int ldr = 33;          \/\/ LDR (Light Dependent Resistor)\nconst int motionSensor = 27; \/\/ PIR Motion Sensor<\/code><\/pre>\n\n\n\n<p>Create the following variables to old states. The comments explain what each variable means.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>int ledState = LOW;           \/\/ current state of the output pin\nint buttonState;              \/\/ current reading from the input pin\nint lastButtonState = LOW;    \/\/ previous reading from the input pin\nbool motionDetected = false;  \/\/ flag variable to send motion alert message\nbool clearMotionAlert = true; \/\/ clear last motion alert message from web page<\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">lastDebounceTime<\/span> and the <span class=\"rnthl rntliteral\">debounceDelay<\/span> variables are used to debounce the button. This prevents false positive button presses.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>unsigned long lastDebounceTime = 0; \/\/ the last time the output pin was toggled\nunsigned long debounceDelay = 50;   \/\/ the debounce time; increase if the output flickers<\/code><\/pre>\n\n\n\n<p>Create an <span class=\"rnthl rntliteral\">AsyncWebServer<\/span> object on port 80.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>AsyncWebServer server(80);<\/code><\/pre>\n\n\n\n<p>To automatically display the information on the web server when new readings are available, we\u2019ll use Server-Sent Events (SSE).<\/p>\n\n\n\n<p>The following line creates a new event source on <span class=\"rnthl rntliteral\">\/events<\/span>. Server-Sent Events allow a web page (client) to get updates from a server.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>AsyncEventSource events(\"\/events\");<\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">PARAM_INPUT_1<\/span> variable will be used to check whether a certain URL request contains the parameter &#8220;<span class=\"rnthl rntliteral\">state<\/span>&#8220;.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>const char* PARAM_INPUT_1 = \"state\";<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Interrupt Callback Function<\/h3>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">detectsMovement()<\/span> callback function will be called when the PIR motion sensor senses motion (an interrupt is triggered). The function changes the state of the <span class=\"rnthl rntliteral\">motionDetected<\/span> variable to <span class=\"rnthl rntliteral\">true<\/span> so that we know that motion was detected and set the <span class=\"rnthl rntliteral\">clearMotionAlert<\/span> variable to <span class=\"rnthl rntliteral\">false<\/span> because we want the &#8220;Motion Detected&#8221; message to be displayed on the web server.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void IRAM_ATTR detectsMovement() {\n  \/\/Serial.println(\"MOTION DETECTED!!!\");\n  motionDetected = true;\n  clearMotionAlert = false;\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Building the Web Page<\/h3>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">index_html<\/span> variable contains all the HTML, CSS and JavaScript to build the web page. We won\u2019t go into details on how the HTML and CSS works. We\u2019ll just take a look at how to handle the events sent by the server.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Handle Events<\/h4>\n\n\n\n<p>Create a new&nbsp;<span class=\"rnthl rntliteral\">EventSource<\/span>&nbsp;object and specify the URL of the page sending the updates. In our case, it\u2019s&nbsp;<span class=\"rnthl rntliteral\">\/events<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>if (!!window.EventSource) {\n var source = new EventSource('\/events');<\/code><\/pre>\n\n\n\n<p>Once you\u2019ve instantiated an event source, you can start listening for messages from the server with&nbsp;<span class=\"rnthl rntliteral\">addEventListener()<\/span>.<\/p>\n\n\n\n<p>These are the default event listeners, as shown here in the AsyncWebServer&nbsp;<a href=\"https:\/\/github.com\/me-no-dev\/ESPAsyncWebServer#setup-event-source-in-the-browser\" target=\"_blank\" rel=\"noreferrer noopener\">documentation<\/a>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>source.addEventListener('open', function(e) {\n  console.log(\"Events Connected\");\n}, false);\nsource.addEventListener('error', function(e) {\n if (e.target.readyState != EventSource.OPEN) {\n   console.log(\"Events Disconnected\");\n }\n}, false);\n\nsource.addEventListener('message', function(e) {\n console.log(\"message\", e.data);\n}, false);<\/code><\/pre>\n\n\n\n<p>Then, add the other event listeners. <\/p>\n\n\n\n<p>When you change the status LED state, the ESP32 sends an event (<span class=\"rnthl rntliteral\">led_state<\/span>) with that information so that the dashboard updates automatically.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>source.addEventListener('led_state', function(e) {\n  console.log(\"led_state\", e.data);\n  var inputChecked;\n  if( e.data == 1){ inputChecked = true; }\n  else { inputChecked = false; }\n  document.getElementById(\"led\").checked = inputChecked;\n}, false);<\/code><\/pre>\n\n\n\n<p>When the browser receives this event, it changes the state of the toggle switch element.<\/p>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">motion<\/span> event is sent when motion is detected. When this happens, it changes the content of the message and changes its color.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>source.addEventListener('motion', function(e) {\n  console.log(\"motion\", e.data);\n  document.getElementById(\"motion\").innerHTML = e.data;\n  document.getElementById(\"motion\").style.color = \"#b30000\";\n}, false); <\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">temperature<\/span>, <span class=\"rnthl rntliteral\">humidity<\/span> and <span class=\"rnthl rntliteral\">light<\/span> events are sent to the browser when new readings are available. <\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>source.addEventListener('temperature', function(e) {\n  console.log(\"temperature\", e.data);\n  document.getElementById(\"temp\").innerHTML = e.data;\n}, false);\nsource.addEventListener('humidity', function(e) {\n  console.log(\"humidity\", e.data);\n  document.getElementById(\"humi\").innerHTML = e.data;\n}, false);\nsource.addEventListener('light', function(e) {\n  console.log(\"light\", e.data);\n  document.getElementById(\"light\").innerHTML = e.data;\n}, false);<\/code><\/pre>\n\n\n\n<p>When that happens, we put the received data into the elements with the corresponding id.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">outputState() function<\/h3>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">outputState()<\/span> function is used to check the current output state of a GPIO. It returns &#8220;checked&#8221; if the GPIO is on or an empty string if it isn&#8217;t. The returned string will be used to build the web page with the current outputs states. This way, every time you access the web server you see the current states.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>String outputState(int gpio){\n  if(digitalRead(gpio)){\n    return \"checked\";\n  }\n  else {\n    return \"\";\n  }\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">processor()<\/h3>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">processor()<\/span> function replaces the placeholders on the HTML text with whatever string we want. We use the <span class=\"rnthl rntliteral\">processor()<\/span> function so that when you access the web server page for the first time in a new browser tab, it shows the current GPIO states, and motion sensor state.<\/p>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">BUTTONPLACEHODER<\/span> is replaced with the HTML text to build the button with the right states.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>if(var == \"BUTTONPLACEHOLDER\"){\n  String buttons;\n  String outputStateValue = outputState(32);\n  buttons+=\"&lt;div class=\\\"card card-switch\\\"&gt;&lt;h4&gt;&lt;i class=\\\"fas fa-lightbulb\\\"&gt;&lt;\/i&gt; OUTPUT&lt;\/h4&gt;&lt;label class=\\\"switch\\\"&gt;&lt;input type=\\\"checkbox\\\" onchange=\\\"controlOutput(this)\\\" id=\\\"output\\\" \" + outputStateValue + \"&gt;&lt;span class=\\\"slider\\\"&gt;&lt;\/span&gt;&lt;\/label&gt;&lt;\/div&gt;\";\n  outputStateValue = outputState(19);\n  buttons+=\"&lt;div class=\\\"card card-switch\\\"&gt;&lt;h4&gt;&lt;i class=\\\"fas fa-lightbulb\\\"&gt;&lt;\/i&gt; STATUS LED&lt;\/h4&gt;&lt;label class=\\\"switch\\\"&gt;&lt;input type=\\\"checkbox\\\" onchange=\\\"toggleLed(this)\\\" id=\\\"led\\\" \" + outputStateValue + \"&gt;&lt;span class=\\\"slider\\\"&gt;&lt;\/span&gt;&lt;\/label&gt;&lt;\/div&gt;\";\n  return buttons;\n}<\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">MOTIONMESSAGE<\/span> placeholder is replaced with the <span class=\"rnthl rntliteral\">MOTION DETECTED<\/span> message or <span class=\"rnthl rntliteral\">No motion<\/span> message, depending on the current motion state.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>else if(var == \"MOTIONMESSAGE\"){\n  if(!clearMotionAlert) {\n    return String(\"&lt;span style=\\\"color:#b30000;\\\"&gt;MOTION DETECTED!&lt;\/span&gt;\");\n  }\n  else {\n    return String(\"No motion\");\n  }\n}\nreturn String();<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Logout Page<\/h3>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">logout_html<\/span> variable contains the HTML text to build the logout page. You are redirected to the logout page when you click on the web page logout button.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>const char logout_html&#091;] PROGMEM = R\"rawliteral(\n&lt;!DOCTYPE HTML&gt;&lt;html&gt;\n&lt;head&gt;\n  &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n  &lt;p&gt;Logged out or &lt;a href=\"\/\"&gt;return to homepage&lt;\/a&gt;.&lt;\/p&gt;\n  &lt;p&gt;&lt;strong&gt;Note:&lt;\/strong&gt; close all web browser tabs to complete the logout process.&lt;\/p&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;\n)rawliteral\";<\/code><\/pre>\n\n\n\n<p>In the logout page, there&#8217;s a link that allows you to go back to the login page (root <strong>\/ <\/strong>URL).<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;p&gt;Logged out or &lt;a href=\"\/\"&gt;return to homepage&lt;\/a&gt;.&lt;\/p&gt;<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">setup()<\/h3>\n\n\n\n<p>In the <span class=\"rnthl rntliteral\">setup()<\/span>, initialize the serial monitor.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>Serial.begin(115200);<\/code><\/pre>\n\n\n\n<p>Initialize the BME280 sensor.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>if (!bme.begin(0x76)) {\n  Serial.println(\"Could not find a valid BME280 sensor, check wiring!\");\n  while (1);\n}<\/code><\/pre>\n\n\n\n<p>Set the button as an input, the status led and the additional output as outputs and the PIR motion sensor as an interrupt.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ initialize the pushbutton pin as an input\npinMode(buttonPin, INPUT);\n\/\/ initialize the LED pin as an output\npinMode(ledPin, OUTPUT);\n\/\/ initialize the LED pin as an output\npinMode(output, OUTPUT);\n\/\/ PIR Motion Sensor mode INPUT_PULLUP\npinMode(motionSensor, INPUT_PULLUP);\n\/\/ Set motionSensor pin as interrupt, assign interrupt function and set RISING mode\nattachInterrupt(digitalPinToInterrupt(motionSensor), detectsMovement, RISING);<\/code><\/pre>\n\n\n\n<p>Connect to wi-fi and print the ESP32 IP address.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Connect to Wi-Fi\nWiFi.begin(ssid, password);\nwhile (WiFi.status() != WL_CONNECTED) {\n  delay(1000);\n  Serial.println(\"Connecting to WiFi..\");\n}\n\/\/ Print ESP32 Local IP Address\nSerial.println(WiFi.localIP());<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Handle Requests<\/h3>\n\n\n\n<p>We need to handle what happens when the ESP32 receives a request on a certain URL.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Handle Requests with Authentication<\/h4>\n\n\n\n<p>Every time you make a request to the ESP32 to access the web server, it will check whether you\u2019ve already entered the correct username and password to authenticate.<\/p>\n\n\n\n<p>Basically, to add authentication to your web server, you just need to add the following lines after each request:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>if(!request-&gt;authenticate(http_username, http_password))\n  return request-&gt;requestAuthentication();<\/code><\/pre>\n\n\n\n<p>These lines continuously pop up the authentication window until you insert the right credentials.<\/p>\n\n\n\n<p>You need to do this for all requests. This way, you ensure that you\u2019ll only get responses if you are logged in.<\/p>\n\n\n\n<p>For example, when you try to access the root URL (ESP IP address), you add the previous two lines before sending the page. If you enter the wrong credentials, the browser will keep asking for them.<\/p>\n\n\n\n<p class=\"rntbox rntclblue\"><strong>Recommended reading:<\/strong> <a href=\"https:\/\/randomnerdtutorials.com\/esp32-esp8266-web-server-http-authentication\/\">ESP32\/ESP8266 Web Server HTTP Authentication (Username and Password Protected)<\/a><\/p>\n\n\n\n<p>If you access the root <span class=\"rnthl rntliteral\">\/<\/span> URL and insert the right credentials, send the main web page (saved on the <span class=\"rnthl rntliteral\">index_html<\/span>) variable.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>server.on(\"\/\", HTTP_GET, &#091;](AsyncWebServerRequest *request){\n if(!request-&gt;authenticate(http_username, http_password))\n    return request-&gt;requestAuthentication();\n  request-&gt;send_P(200, \"text\/html\", index_html, processor);\n});<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Handle Logout<\/h4>\n\n\n\n<p>When you click the logout button, the ESP receives a request on the&nbsp;<strong><em>\/logout<\/em><\/strong>&nbsp;URL. When that happens send the response code 401.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>server.on(\"\/logout\", HTTP_GET, &#091;](AsyncWebServerRequest *request){\n  request-&gt;send(401);\n});<\/code><\/pre>\n\n\n\n<p>The response code 401 is an unauthorized error HTTP response status code indicating that the request sent by the client could not be authenticated. So, it will have the same effect as a logout \u2013 it will ask for the username and password and won\u2019t let you access the web server again until you login.<\/p>\n\n\n\n<p>When you click the web server logout button, after one second, the ESP receives another request on the <span class=\"rnthl rntliteral\"><em><strong>\/logged-out<\/strong><\/em><\/span> URL. When that happens, send the HTML text to build the logout page (<span class=\"rnthl rntliteral\">logout_html<\/span> variable).<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>server.on(\"\/logged-out\", HTTP_GET, &#091;](AsyncWebServerRequest *request){\n  request-&gt;send_P(200, \"text\/html\", logout_html, processor);\n});<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Handle Output<\/h4>\n\n\n\n<p>When you click the button to control the output, the ESP receives a request like this <span class=\"rnthl rntliteral\"><em>\/output?state=&lt;inputMessage&gt;<\/em><\/span>. The <span class=\"rnthl rntliteral\">inputMessage<\/span> can be either 0 or 1 (off or on).<\/p>\n\n\n\n<p>The following lines checker whether the request on the <span class=\"rnthl rntliteral\"><em>\/output<\/em><\/span> URL contains the parameter state. If it does, save the value of the state into the <span class=\"rnthl rntliteral\">inputMessage<\/span> variable. Then, control the output GPIO with the value of that message <span class=\"rnthl rntliteral\">digitalWrite(output, inputMessage.toInt());<\/span><\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Send a GET request to control output socket &lt;ESP_IP&gt;\/output?state=&lt;inputMessage&gt;\nserver.on(\"\/output\", HTTP_GET, &#091;] (AsyncWebServerRequest *request) {\n  if(!request-&gt;authenticate(http_username, http_password))\n    return request-&gt;requestAuthentication();\n  String inputMessage;\n  \/\/ GET gpio and state value\n  if (request-&gt;hasParam(PARAM_INPUT_1)) {\n    inputMessage = request-&gt;getParam(PARAM_INPUT_1)-&gt;value();\n    digitalWrite(output, inputMessage.toInt());\n    request-&gt;send(200, \"text\/plain\", \"OK\");\n  }\n  request-&gt;send(200, \"text\/plain\", \"Failed\");\n});<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Handle Status LED<\/h4>\n\n\n\n<p>When you control the status LED, invert the button state.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Send a GET request to control on board status LED &lt;ESP_IP&gt;\/toggle\nserver.on(\"\/toggle\", HTTP_GET, &#091;] (AsyncWebServerRequest *request) {\n  if(!request-&gt;authenticate(http_username, http_password))\n    return request-&gt;requestAuthentication();\n  ledState = !ledState;\n  digitalWrite(ledPin, ledState);\n  request-&gt;send(200, \"text\/plain\", \"OK\");\n});<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Handle Motion<\/h4>\n\n\n\n<p>When you click the motion sensor card after motion being detected, you make a request on the <span class=\"rnthl rntliteral\"><em>\/clear-motion<\/em><\/span> URL. When that happens, set the <span class=\"rnthl rntliteral\">clearMotion<\/span> variable to true.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>server.on(\"\/clear-motion\", HTTP_GET, &#091;] (AsyncWebServerRequest *request) {\n  if(!request-&gt;authenticate(http_username, http_password))\n    return request-&gt;requestAuthentication();\n  clearMotionAlert = true;\n  request-&gt;send(200, \"text\/plain\", \"OK\");\n});<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Server Event Source<\/h3>\n\n\n\n<p>Set up the event source on the server.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>events.onConnect(&#091;](AsyncEventSourceClient *client){\n  if(client-&gt;lastId()){\n    Serial.printf(\"Client reconnected! Last message ID that it got is: %u\\n\", client-&gt;lastId());\n  }\n  \/\/ send event with message \"hello!\", id current millis and set reconnect delay to 1 second\n  client-&gt;send(\"hello!\",NULL,millis(),1000);\n});\nserver.addHandler(&amp;events);<\/code><\/pre>\n\n\n\n<p>Finally, start the web server.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>server.begin();<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">loop()<\/h3>\n\n\n\n<p>In the <span class=\"rnthl rntliteral\">loop()<\/span>, check the pushbutton state. If the button state has changed its state, change the output LED state accordingly, and send an event to the browser to change the output state on the web page.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>int reading = digitalRead(buttonPin);\n\n\/\/ If the switch changed\nif (reading != lastButtonState) {\n  \/\/ reset the debouncing timer\n  lastDebounceTime = millis();\n}\n\nif ((millis() - lastDebounceTime) &gt; debounceDelay) {\n  \/\/ if the button state has changed:\n  if (reading != buttonState) {\n    buttonState = reading;\n    \/\/ only toggle the LED if the new button state is HIGH\n    if (buttonState == HIGH) {\n      ledState = !ledState;\n      digitalWrite(ledPin, ledState);\n      events.send(String(digitalRead(ledPin)).c_str(),\"led_state\",millis());\n    }\n  }\n}<\/code><\/pre>\n\n\n\n<p>Send sensor readings to the browser using server-sent events, every 10 seconds. You can change that period of time in the <span class=\"rnthl rntliteral\">EVENT_INTERVAL_MS<\/span> variable.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>if ((millis() - lastEventTime) &gt; EVENT_INTERVAL_MS) {\n  events.send(\"ping\",NULL,millis());\n  events.send(String(bme.readTemperature()).c_str(),\"temperature\",millis());\n  events.send(String(bme.readHumidity()).c_str(),\"humidity\",millis());\n  events.send(String(analogRead(ldr)).c_str(),\"light\",millis());\n  lastEventTime = millis();\n}<\/code><\/pre>\n\n\n\n<p>When motion is detected and if we haven&#8217;t cleared the notification, send the <span class=\"rnthl rntliteral\">MOTION DETECTED<\/span> message in the event.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>if(motionDetected &amp; !clearMotionAlert){\n  events.send(String(\"MOTION DETECTED!\").c_str(),\"motion\",millis());\n  motionDetected = false;\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"demonstration\">Upload the Code<\/h2>\n\n\n\n<p>To upload code, go to <strong>Tools<\/strong>&gt; <strong>Board <\/strong>and select <strong>DOIT ESP32 DEVKIT V1<\/strong>. Go to <strong>Tools <\/strong>&gt; <strong>Port <\/strong>and select the COM port the ESP32 is connected to. Then, click the upload button:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"32\" height=\"32\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2019\/12\/upload-button-arduino-ide.png?resize=32%2C32&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"\" class=\"wp-image-91745\"\/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\">Testing the Multisensor Shield<\/h2>\n\n\n\n<p>Open the Serial Monitor at a baud rate of 112500. Press the ESP32 RST button to print the ESP IP address.<\/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=\"727\" height=\"445\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IP-Address-Serial-Monitor.jpg?resize=727%2C445&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 IP Address printed in Arduino IDE Serial monitor\" class=\"wp-image-97586\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IP-Address-Serial-Monitor.jpg?w=727&amp;quality=100&amp;strip=all&amp;ssl=1 727w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IP-Address-Serial-Monitor.jpg?resize=300%2C184&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 727px) 100vw, 727px\" \/><\/figure><\/div>\n\n\n<p>Open your browser and type the ESP32 IP address. The following page should load. Insert the username and password to access the web server. By default the username is admin and the password is admin. You can change that on the code.<\/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=\"672\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IOT-dashboard-web-server-login.png?resize=750%2C672&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 IOT dashboard web server login http authentication\" class=\"wp-image-97588\" style=\"width:375px;height:336px\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IOT-dashboard-web-server-login.png?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IOT-dashboard-web-server-login.png?resize=300%2C269&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<p>After inserting the right credentials, you have access to the dashboard functionalities. There are two toggle switches: one to control the status LED and another to control the additional output.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"1045\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-Io-T-Dashboard-Web-Server-Control-Outputs.jpg?resize=750%2C1045&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 IOT dashboard web server control outputs\" class=\"wp-image-97589\" style=\"width:368px;height:512px\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-Io-T-Dashboard-Web-Server-Control-Outputs.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-Io-T-Dashboard-Web-Server-Control-Outputs.jpg?resize=215%2C300&amp;quality=100&amp;strip=all&amp;ssl=1 215w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-Io-T-Dashboard-Web-Server-Control-Outputs.jpg?resize=735%2C1024&amp;quality=100&amp;strip=all&amp;ssl=1 735w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<p>You can control the status LED using the toggle switch and also the shield physical button. The state is automatically updated on the web page. There\u2019s another toggle button to control an additional output like a relay module.<\/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\/2020\/06\/ESP32-IoT-Shield-Breadboard-Circuit-Demonstration.jpg?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 IoT Sensor Shield Breadboard Circuit Demonstration\" class=\"wp-image-97574\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Shield-Breadboard-Circuit-Demonstration.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Shield-Breadboard-Circuit-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><strong>Recommended reading:<\/strong> <a href=\"https:\/\/randomnerdtutorials.com\/esp32-relay-module-ac-web-server\/\">ESP32 Relay Module \u2013 Control AC Appliances (Web Server)<\/a><\/p>\n\n\n\n<p>The web server shows the latest sensor readings. The readings are updated every 10 seconds automatically using server-sent events. This means that when the ESP32 grabs new readings, it sends an event to the client (your browser). When this event happens, it updates the fields with new readings.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"1587\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-Io-T-Dashboard-Web-Server-sensor-readings.png?resize=750%2C1587&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 IoT Dashboard Web Server Display Sensor Readings\" class=\"wp-image-97590\" style=\"width:242px;height:512px\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-Io-T-Dashboard-Web-Server-sensor-readings.png?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-Io-T-Dashboard-Web-Server-sensor-readings.png?resize=142%2C300&amp;quality=100&amp;strip=all&amp;ssl=1 142w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-Io-T-Dashboard-Web-Server-sensor-readings.png?resize=484%2C1024&amp;quality=100&amp;strip=all&amp;ssl=1 484w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-Io-T-Dashboard-Web-Server-sensor-readings.png?resize=726%2C1536&amp;quality=100&amp;strip=all&amp;ssl=1 726w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<p>Finally, there\u2019s a card indicating if motion was detected or not. When motion is detected, it shows the &#8220;Motion Detected&#8221; message. This message is also updated automatically using server-sent events. <\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"541\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-Io-T-Dashboard-Web-Server-Motion.png?resize=750%2C541&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 IoT Dashboard Web Server Motion\" class=\"wp-image-97591\" style=\"width:375px;height:271px\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-Io-T-Dashboard-Web-Server-Motion.png?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-Io-T-Dashboard-Web-Server-Motion.png?resize=300%2C216&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<p>Once, you\u2019ve seen this notification, you can click the motion card. It will clear the warning message and show &#8220;No motion&#8221; instead&#8221;.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"441\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-Io-T-Dashboard-Web-Server-No-Motion.png?resize=750%2C441&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 IoT Dashboard Web Server No Motion\" class=\"wp-image-97592\" style=\"width:375px;height:221px\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-Io-T-Dashboard-Web-Server-No-Motion.png?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-Io-T-Dashboard-Web-Server-No-Motion.png?resize=300%2C176&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\">Wrapping Up<\/h2>\n\n\n\n<p>We hope you\u2019ve found this project useful and you\u2019re able to build it yourself. You can program the IoT Shield with other code suitable for your needs. For example, you can control the output based on the current temperature value or <a href=\"https:\/\/randomnerdtutorials.com\/esp32-esp8266-thermostat-web-server\/\">add a threshold field<\/a>. You can also edit the gerber files and add other features to the ESP32 IoT Shield.<\/p>\n\n\n\n<p>We have other similar projects that include building and designing PCBs that you may like:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/build-an-all-in-one-esp32-weather-station-shield\/\">Build an All-in-One ESP32 Weather Station Shield<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp8266-multisensor-shield\/\">Build a Multisensor Shield for ESP8266<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/power-saving-latching-circuit\/\">EXTREME POWER SAVING with Microcontroller External Wake Up: Latching Power PCB<\/a><\/li>\n<\/ul>\n\n\n\n<p>Learn more about the ESP32 with our resources:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><a href=\"https:\/\/randomnerdtutorials.com\/learn-esp32-with-arduino-ide\/\">Learn ESP32 with Arduino IDE (eBook + video course)<\/a><\/strong><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/micropython-programming-with-esp32-and-esp8266\/\">MicroPython Programming with Arduino IDE<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/projects-esp32\/\">More ESP32 tutorials and projects\u2026<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>In this project we&#8217;ll show you how to build an IoT shield PCB for the ESP32 and a web server dashboard to control it. The shield is equipped with a &#8230; <\/p>\n<p class=\"read-more-container\"><a title=\"ESP32 IoT Shield PCB with Dashboard for Outputs and Sensors\" class=\"read-more button\" href=\"https:\/\/randomnerdtutorials.com\/esp32-iot-shield-pcb-dashboard\/#more-97405\" aria-label=\"Read more about ESP32 IoT Shield PCB with Dashboard for Outputs and Sensors\">CONTINUE READING \u00bb<\/a><\/p>\n","protected":false},"author":1,"featured_media":97547,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[281,276,277,299,264],"tags":[],"class_list":["post-97405","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-esp32-project","category-esp32","category-esp32-arduino-ide","category-0-esp32","category-project"],"aioseo_notices":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/06\/ESP32-IoT-Shield-PCB-Dashboard-for-Outputs-and-Sensors-Arduino-IDE.jpg?fit=1280%2C720&quality=100&strip=all&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/97405","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=97405"}],"version-history":[{"count":1,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/97405\/revisions"}],"predecessor-version":[{"id":167973,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/97405\/revisions\/167973"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media\/97547"}],"wp:attachment":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media?parent=97405"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/categories?post=97405"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/tags?post=97405"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}