{"id":96150,"date":"2020-04-21T14:18:32","date_gmt":"2020-04-21T14:18:32","guid":{"rendered":"https:\/\/randomnerdtutorials.com\/?p=96150"},"modified":"2025-03-17T12:13:38","modified_gmt":"2025-03-17T12:13:38","slug":"esp32-esp8266-web-server-physical-button","status":"publish","type":"post","link":"https:\/\/randomnerdtutorials.com\/esp32-esp8266-web-server-physical-button\/","title":{"rendered":"ESP32\/ESP8266: Control Outputs with Web Server and a Physical Button Simultaneously"},"content":{"rendered":"\n<p>This tutorial shows how to control the ESP32 or ESP8266 outputs using a web server and a physical button simultaneously. The output state is updated on the web page whether it is changed via physical button or web server.<\/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\/04\/ESP32-ESP8266-Control-Outputs-with-Web-Server-and-Physical-Button-Simultaneously.jpg?resize=1200%2C675&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 ESP8266 NodeMCU: Control Outputs with Web Server and a Physical Button Simultaneously Arduino IDE\" class=\"wp-image-96257\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/04\/ESP32-ESP8266-Control-Outputs-with-Web-Server-and-Physical-Button-Simultaneously.jpg?w=1280&amp;quality=100&amp;strip=all&amp;ssl=1 1280w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/04\/ESP32-ESP8266-Control-Outputs-with-Web-Server-and-Physical-Button-Simultaneously.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/04\/ESP32-ESP8266-Control-Outputs-with-Web-Server-and-Physical-Button-Simultaneously.jpg?resize=1024%2C576&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/04\/ESP32-ESP8266-Control-Outputs-with-Web-Server-and-Physical-Button-Simultaneously.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><strong>Recommended reading:<\/strong> <a href=\"https:\/\/randomnerdtutorials.com\/esp32-esp8266-input-data-html-form\/\">Input Data on HTML Form ESP32\/ESP8266 Web Server<\/a><\/p>\n\n\n\n<p>The ESP32\/ESP8266 boards will be programmed using Arduino IDE. So make sure you have these boards installed:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/installing-esp32-arduino-ide-2-0\/\">Installing ESP32 Board in Arduino IDE (Windows, Mac OS X, and Linux)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/installing-esp8266-nodemcu-arduino-ide-2-0\/\">Installing ESP8266 Board in Arduino IDE (Windows, Mac OS X, Linux)<\/a><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Project Overview<\/h2>\n\n\n\n<p>Let&#8217;s take a quick look at how the project works.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"900\" height=\"717\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/04\/ESP32-ESP8266-Web-Server-With-Physical-Button-Project-Overview.png?resize=900%2C717&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 ESP8266 NodeMCU Web Server With Physical Button Project Overview\" class=\"wp-image-96256\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/04\/ESP32-ESP8266-Web-Server-With-Physical-Button-Project-Overview.png?w=900&amp;quality=100&amp;strip=all&amp;ssl=1 900w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/04\/ESP32-ESP8266-Web-Server-With-Physical-Button-Project-Overview.png?resize=300%2C239&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/04\/ESP32-ESP8266-Web-Server-With-Physical-Button-Project-Overview.png?resize=768%2C612&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 900px) 100vw, 900px\" \/><\/figure><\/div>\n\n\n<ul class=\"wp-block-list\">\n<li>The ESP32 or ESP8266 hosts a web server that allows you to control the state of an output;<\/li>\n\n\n\n<li>The current output state is displayed on the web server; <\/li>\n\n\n\n<li>The ESP is also connected to a physical pushbutton that controls the same output;<\/li>\n\n\n\n<li>If you change the output state using the physical puhsbutton, its current state is also updated on the web server.<\/li>\n<\/ul>\n\n\n\n<p>In summary, this project allows you to control the same output using a web server and a push button simultaneously. Whenever the output state changes, the web server is updated.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Schematic Diagram<\/h2>\n\n\n\n<p>Before proceeding, you need to assemble a circuit with an LED and a pushbutton. We\u2019ll connect the LED to <span class=\"rnthl rntcblue\">GPIO 2<\/span> and the pushbutton to <span class=\"rnthl rntcgreen\">GPIO 4<\/span>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Parts Required<\/h3>\n\n\n\n<p>Here\u2019s a list of the parts you need to build the circuit:<\/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\">ESP32<\/a>&nbsp;(read&nbsp;<a href=\"https:\/\/makeradvisor.com\/esp32-development-boards-review-comparison\/\" target=\"_blank\" rel=\"noreferrer noopener\">Best ESP32 Dev Boards<\/a>) or <a aria-label=\" (opens in a new tab)\" href=\"https:\/\/makeradvisor.com\/tools\/esp8266-esp-12e-nodemcu-wi-fi-development-board\/\" target=\"_blank\" rel=\"noreferrer noopener\">ESP8266<\/a><\/li>\n\n\n\n<li><a aria-label=\" (opens in a new tab)\" href=\"https:\/\/makeradvisor.com\/tools\/3mm-5mm-leds-kit-storage-box\/\" target=\"_blank\" rel=\"noreferrer noopener\">5 mm LED<\/a><\/li>\n\n\n\n<li><a aria-label=\" (opens in a new tab)\" href=\"https:\/\/makeradvisor.com\/tools\/mb-102-solderless-breadboard-830-points\/\" target=\"_blank\" rel=\"noreferrer noopener\">330 Ohm resistor<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/pushbuttons-kit\/\">Pushbutton<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/resistors-kits\/\">10k Ohm resistor<\/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 aria-label=\" (opens in a new tab)\" 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<h3 class=\"wp-block-heading\">ESP32 Schematic<\/h3>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"1035\" height=\"695\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/04\/ESP32-LED-Pushbutton.png?resize=1035%2C695&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Digital Input and Digital Output Schematic Circuit LED Pushbutton\" class=\"wp-image-96272\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/04\/ESP32-LED-Pushbutton.png?w=1035&amp;quality=100&amp;strip=all&amp;ssl=1 1035w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/04\/ESP32-LED-Pushbutton.png?resize=300%2C201&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/04\/ESP32-LED-Pushbutton.png?resize=1024%2C688&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/04\/ESP32-LED-Pushbutton.png?resize=768%2C516&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 1035px) 100vw, 1035px\" \/><\/figure><\/div>\n\n\n<h3 class=\"wp-block-heading\">ESP8266 NodeMCU Schematic<\/h3>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1011\" height=\"582\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/04\/ESP8266-LED-pushbutton_bb.png?resize=1011%2C582&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP8266 NodeMCU Digital Input and Digital Output Schematic Circuit LED Pushbutton\" class=\"wp-image-96274\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/04\/ESP8266-LED-pushbutton_bb.png?w=1011&amp;quality=100&amp;strip=all&amp;ssl=1 1011w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/04\/ESP8266-LED-pushbutton_bb.png?resize=300%2C173&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/04\/ESP8266-LED-pushbutton_bb.png?resize=768%2C442&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 1011px) 100vw, 1011px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\">Installing Libraries &#8211; Async Web Server<\/h2>\n\n\n\n<p>To build the web server you need to install the following libraries:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>ESP32:<\/strong>&nbsp;install the&nbsp;<a href=\"https:\/\/github.com\/ESP32Async\/ESPAsyncWebServer\" target=\"_blank\" rel=\"noopener\" title=\"\">ESPAsyncWebServer<\/a> and the&nbsp;<a href=\"https:\/\/github.com\/ESP32Async\/AsyncTCP\" target=\"_blank\" rel=\"noopener\" title=\"\">AsyncTCP&nbsp;<\/a>libraries&nbsp;(by ESP32Async).<\/li>\n\n\n\n<li><strong>ESP8266:<\/strong>&nbsp;install the&nbsp;<a href=\"https:\/\/github.com\/ESP32Async\/ESPAsyncWebServer\" target=\"_blank\" rel=\"noopener\" title=\"\">ESPAsyncWebServer<\/a>&nbsp;and the&nbsp;<a href=\"https:\/\/github.com\/ESP32Async\/ESPAsyncTCP\" target=\"_blank\" rel=\"noopener\" title=\"\">ESPAsyncTCP<\/a>&nbsp;libraries (by ESP32Async).<\/li>\n<\/ul>\n\n\n\n<p>You can install those libraries in the Arduino IDE Library Manager. Go to <strong>Sketch <\/strong>&gt; <strong>Include Library<\/strong> &gt; <strong>Manage Libraries<\/strong> and search for the libraries&#8217; names.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">ESP Web Server Code<\/h2>\n\n\n\n<p>Copy the following code to your Arduino IDE.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-c\">\/*********\n  Rui Santos &amp; Sara Santos - Random Nerd Tutorials\n  Complete project details at https:\/\/RandomNerdTutorials.com\/esp32-esp8266-web-server-physical-button\/\n  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n*********\/\n\n\/\/ Import required libraries\n#ifdef ESP32\n  #include &lt;WiFi.h&gt;\n  #include &lt;AsyncTCP.h&gt;\n#else\n  #include &lt;ESP8266WiFi.h&gt;\n  #include &lt;ESPAsyncTCP.h&gt;\n#endif\n#include &lt;ESPAsyncWebServer.h&gt;\n\n\/\/ Replace with your network credentials\nconst char* ssid = &quot;REPLACE_WITH_YOUR_SSID&quot;;\nconst char* password = &quot;REPLACE_WITH_YOUR_PASSWORD&quot;;\n\nconst char* PARAM_INPUT_1 = &quot;state&quot;;\n\nconst int output = 2;\nconst int buttonPin = 4;\n\n\/\/ Variables will change:\nint ledState = LOW;          \/\/ the current state of the output pin\nint buttonState;             \/\/ the current reading from the input pin\nint lastButtonState = LOW;   \/\/ the previous reading from the input pin\n\n\/\/ the following variables are unsigned longs because the time, measured in\n\/\/ milliseconds, will quickly become a bigger number than can be stored in an int.\nunsigned long lastDebounceTime = 0;  \/\/ the last time the output pin was toggled\nunsigned long debounceDelay = 50;    \/\/ the debounce time; increase if the output flickers\n\n\/\/ Create AsyncWebServer object on port 80\nAsyncWebServer server(80);\n\nconst char index_html[] PROGMEM = R&quot;rawliteral(\n&lt;!DOCTYPE HTML&gt;&lt;html&gt;\n&lt;head&gt;\n  &lt;title&gt;ESP Web Server&lt;\/title&gt;\n  &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&gt;\n  &lt;style&gt;\n    html {font-family: Arial; display: inline-block; text-align: center;}\n    h2 {font-size: 3.0rem;}\n    p {font-size: 3.0rem;}\n    body {max-width: 600px; margin:0px auto; padding-bottom: 25px;}\n    .switch {position: relative; display: inline-block; width: 120px; height: 68px} \n    .switch input {display: none}\n    .slider {position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; border-radius: 34px}\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}\n    input:checked+.slider {background-color: #2196F3}\n    input:checked+.slider:before {-webkit-transform: translateX(52px); -ms-transform: translateX(52px); transform: translateX(52px)}\n  &lt;\/style&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n  &lt;h2&gt;ESP Web Server&lt;\/h2&gt;\n  %BUTTONPLACEHOLDER%\n&lt;script&gt;function toggleCheckbox(element) {\n  var xhr = new XMLHttpRequest();\n  if(element.checked){ xhr.open(&quot;GET&quot;, &quot;\/update?state=1&quot;, true); }\n  else { xhr.open(&quot;GET&quot;, &quot;\/update?state=0&quot;, true); }\n  xhr.send();\n}\n\nsetInterval(function ( ) {\n  var xhttp = new XMLHttpRequest();\n  xhttp.onreadystatechange = function() {\n    if (this.readyState == 4 &amp;&amp; this.status == 200) {\n      var inputChecked;\n      var outputStateM;\n      if( this.responseText == 1){ \n        inputChecked = true;\n        outputStateM = &quot;On&quot;;\n      }\n      else { \n        inputChecked = false;\n        outputStateM = &quot;Off&quot;;\n      }\n      document.getElementById(&quot;output&quot;).checked = inputChecked;\n      document.getElementById(&quot;outputState&quot;).innerHTML = outputStateM;\n    }\n  };\n  xhttp.open(&quot;GET&quot;, &quot;\/state&quot;, true);\n  xhttp.send();\n}, 1000 ) ;\n&lt;\/script&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;\n)rawliteral&quot;;\n\n\/\/ Replaces placeholder with button section in your web page\nString processor(const String&amp; var){\n  \/\/Serial.println(var);\n  if(var == &quot;BUTTONPLACEHOLDER&quot;){\n    String buttons =&quot;&quot;;\n    String outputStateValue = outputState();\n    buttons+= &quot;&lt;h4&gt;Output - GPIO 2 - State &lt;span id=\\&quot;outputState\\&quot;&gt;&lt;\/span&gt;&lt;\/h4&gt;&lt;label class=\\&quot;switch\\&quot;&gt;&lt;input type=\\&quot;checkbox\\&quot; onchange=\\&quot;toggleCheckbox(this)\\&quot; id=\\&quot;output\\&quot; &quot; + outputStateValue + &quot;&gt;&lt;span class=\\&quot;slider\\&quot;&gt;&lt;\/span&gt;&lt;\/label&gt;&quot;;\n    return buttons;\n  }\n  return String();\n}\n\nString outputState(){\n  if(digitalRead(output)){\n    return &quot;checked&quot;;\n  }\n  else {\n    return &quot;&quot;;\n  }\n  return &quot;&quot;;\n}\n\nvoid setup(){\n  \/\/ Serial port for debugging purposes\n  Serial.begin(115200);\n\n  pinMode(output, OUTPUT);\n  digitalWrite(output, LOW);\n  pinMode(buttonPin, INPUT);\n  \n  \/\/ Connect to Wi-Fi\n  WiFi.begin(ssid, password);\n  while (WiFi.status() != WL_CONNECTED) {\n    delay(1000);\n    Serial.println(&quot;Connecting to WiFi..&quot;);\n  }\n\n  \/\/ Print ESP Local IP Address\n  Serial.println(WiFi.localIP());\n\n  \/\/ Route for root \/ web page\n  server.on(&quot;\/&quot;, HTTP_GET, [](AsyncWebServerRequest *request){\n    request-&gt;send(200, &quot;text\/html&quot;, index_html, processor);\n  });\n\n  \/\/ Send a GET request to &lt;ESP_IP&gt;\/update?state=&lt;inputMessage&gt;\n  server.on(&quot;\/update&quot;, HTTP_GET, [] (AsyncWebServerRequest *request) {\n    String inputMessage;\n    String inputParam;\n    \/\/ GET input1 value on &lt;ESP_IP&gt;\/update?state=&lt;inputMessage&gt;\n    if (request-&gt;hasParam(PARAM_INPUT_1)) {\n      inputMessage = request-&gt;getParam(PARAM_INPUT_1)-&gt;value();\n      inputParam = PARAM_INPUT_1;\n      digitalWrite(output, inputMessage.toInt());\n      ledState = !ledState;\n    }\n    else {\n      inputMessage = &quot;No message sent&quot;;\n      inputParam = &quot;none&quot;;\n    }\n    Serial.println(inputMessage);\n    request-&gt;send(200, &quot;text\/plain&quot;, &quot;OK&quot;);\n  });\n\n  \/\/ Send a GET request to &lt;ESP_IP&gt;\/state\n  server.on(&quot;\/state&quot;, HTTP_GET, [] (AsyncWebServerRequest *request) {\n    request-&gt;send(200, &quot;text\/plain&quot;, String(digitalRead(output)).c_str());\n  });\n  \/\/ Start server\n  server.begin();\n}\n  \nvoid loop() {\n  \/\/ read the state of the switch into a local variable:\n  int reading = digitalRead(buttonPin);\n\n  \/\/ check to see if you just pressed the button\n  \/\/ (i.e. the input went from LOW to HIGH), and you've waited long enough\n  \/\/ since the last press to ignore any noise:\n\n  \/\/ If the switch changed, due to noise or pressing:\n  if (reading != lastButtonState) {\n    \/\/ reset the debouncing timer\n    lastDebounceTime = millis();\n  }\n\n  if ((millis() - lastDebounceTime) &gt; debounceDelay) {\n    \/\/ whatever the reading is at, it's been there for longer than the debounce\n    \/\/ delay, so take it as the actual current state:\n\n    \/\/ if the button state has changed:\n    if (reading != buttonState) {\n      buttonState = reading;\n\n      \/\/ only toggle the LED if the new button state is HIGH\n      if (buttonState == HIGH) {\n        ledState = !ledState;\n      }\n    }\n  }\n\n  \/\/ set the LED:\n  digitalWrite(output, ledState);\n\n  \/\/ save the reading. Next time through the loop, it'll be the lastButtonState:\n  lastButtonState = reading;\n}\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/ESP\/ESP_Web_Server_Physical_Button.ino\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<p>You just need to enter your network credentials (SSID and password) and the web server will work straight away. The code is compatible with both the <a rel=\"noreferrer noopener\" aria-label=\"ESP32 (opens in a new tab)\" href=\"https:\/\/makeradvisor.com\/tools\/esp32-dev-board-wi-fi-bluetooth\/\" target=\"_blank\">ESP32<\/a> and <a rel=\"noreferrer noopener\" aria-label=\"ESP8266 (opens in a new tab)\" href=\"https:\/\/makeradvisor.com\/tools\/esp8266-esp-12e-nodemcu-wi-fi-development-board\/\" target=\"_blank\">ESP8266<\/a> boards and controls <span class=\"rnthl rntcblue\">GPIO 2<\/span> &#8211; you can change the code to control any other GPIO.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">How the Code Works<\/h2>\n\n\n\n<p>We&#8217;ve already explained in great details how web servers like this work in previous tutorials (<a href=\"https:\/\/randomnerdtutorials.com\/esp32-dht11-dht22-temperature-humidity-web-server-arduino-ide\/\">DHT Temperature Web Server<\/a>), so we&#8217;ll just take a look at the relevant parts for this project.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Network Credentials<\/h3>\n\n\n\n<p>As said previously, you need to insert your network credentials in the following lines:<\/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<h3 class=\"wp-block-heading\">Button State and Output State<\/h3>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">ledState<\/span> variable holds the LED output state. For default, when the web server starts, it is <span class=\"rnthl rntliteral\">LOW<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>int ledState = LOW; \/\/ the current state of the output pin<\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">buttonState<\/span> and <span class=\"rnthl rntliteral\">lastButtonState<\/span> are used to detect whether the pushbutton was pressed or not.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>int buttonState;            \/\/ the current reading from the input pin\nint lastButtonState = LOW;  \/\/ the previous reading from the input pin<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Button (web server)<\/h3>\n\n\n\n<p>We didn&#8217;t include the HTML to create the button on the the <span class=\"rnthl rntliteral\">index_html<\/span> variable. That&#8217;s because we want to be able to change it depending on the current LED state that can also be changed with the pushbutton.<\/p>\n\n\n\n<p>So, we&#8217;ve create a placeholder for the button <span class=\"rnthl rntliteral\">%BUTTONPLACEHOLDER%<\/span> that will be replaced with HTML text to create the button later on the code (this is done in the <span class=\"rnthl rntliteral\">processor()<\/span> function).<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;h2&gt;ESP Web Server&lt;\/h2&gt;\n%BUTTONPLACEHOLDER%<\/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 any placeholders on the HTML text with actual values. First, it checks whether the HTML texts contains any placeholders <span class=\"rnthl rntliteral\">%BUTTONPLACEHOLDER%<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>if(var == \"BUTTONPLACEHOLDER\"){<\/code><\/pre>\n\n\n\n<p>Then, call the <span class=\"rnthl rntliteral\">outputState()<\/span> function that returns the current output state. We save it in the <span class=\"rnthl rntliteral\">outputStateValue<\/span> variable.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>String outputStateValue = outputState();<\/code><\/pre>\n\n\n\n<p>After that, use that value to create the HTML text to display the button with the right state:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>buttons+= \"&lt;h4&gt;Output - GPIO 2 - State &lt;span id=\\\"outputState\\\"&gt;&lt;span&gt;&lt;\/h4&gt;&lt;label class=\\\"switch\\\"&gt;&lt;input type=\\\"checkbox\\\" onchange=\\\"toggleCheckbox(this)\\\" id=\\\"output\\\" \" + outputStateValue + \"&gt;&lt;span class=\\\"slider\\\"&gt;&lt;\/span&gt;&lt;\/label&gt;\";<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">HTTP GET Request to Change Output State (JavaScript)<\/h3>\n\n\n\n<p>When you press the button, the <span class=\"rnthl rntliteral\">toggleCheckbox()<\/span> function is called. This function will make a request on different URLs to turn the LED on or off.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>function toggleCheckbox(element) {\n  var xhr = new XMLHttpRequest();\n  if(element.checked){ xhr.open(\"GET\", \"\/update?state=1\", true); }\n  else { xhr.open(\"GET\", \"\/update?state=0\", true); }\n  xhr.send();\n}<\/code><\/pre>\n\n\n\n<p>To turn on the LED, it makes a request on the <em><strong>\/update?state=1<\/strong><\/em> URL:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>if(element.checked){ xhr.open(\"GET\", \"\/update?state=1\", true); }<\/code><\/pre>\n\n\n\n<p>Otherwise, it makes a request on the<strong><em> \/update?state=0<\/em><\/strong> URL.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">HTTP GET Request to Update State (JavaScript)<\/h3>\n\n\n\n<p>To keep the output state updated on the web server, we call the following function that makes a new request on the <strong><em>\/state<\/em><\/strong> URL every second.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>setInterval(function ( ) {\n  var xhttp = new XMLHttpRequest();\n  xhttp.onreadystatechange = function() {\n    if (this.readyState == 4 &amp;&amp; this.status == 200) {\n      var inputChecked;\n      var outputStateM;\n      if( this.responseText == 1){ \n        inputChecked = true;\n        outputStateM = \"On\";\n      }\n      else { \n        inputChecked = false;\n        outputStateM = \"Off\";\n      }\n      document.getElementById(\"output\").checked = inputChecked;\n      document.getElementById(\"outputState\").innerHTML = outputStateM;\n    }\n  };\n  xhttp.open(\"GET\", \"\/state\", true);\n  xhttp.send();\n}, 1000 ) ;<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Handle Requests<\/h3>\n\n\n\n<p>Then, we need to handle what happens when the ESP32 or ESP8266 receives requests on those URLs.<\/p>\n\n\n\n<p>When a request is received on the root <strong><em>\/<\/em><\/strong> URL, we send the HTML page as well as the processor.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>server.on(\"\/\", HTTP_GET, &#091;](AsyncWebServerRequest *request){\n  request-&gt;send_P(200, \"text\/html\", index_html, processor);\n});<\/code><\/pre>\n\n\n\n<p>The following lines check whether you received a request on the <strong><em>\/update?state=1<\/em><\/strong> or <strong><em>\/update?state=0<\/em><\/strong> URL and changes the <span class=\"rnthl rntliteral\">ledState<\/span> accordingly.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>server.on(\"\/update\", HTTP_GET, &#091;] (AsyncWebServerRequest *request) {\n  String inputMessage;\n  String inputParam;\n  \/\/ GET input1 value on &lt;ESP_IP&gt;\/update?state=&lt;inputMessage&gt;\n  if (request-&gt;hasParam(PARAM_INPUT_1)) {\n    inputMessage = request-&gt;getParam(PARAM_INPUT_1)-&gt;value();\n    inputParam = PARAM_INPUT_1;\n    digitalWrite(output, inputMessage.toInt());\n    ledState = !ledState;\n  }\n  else {\n    inputMessage = \"No message sent\";\n    inputParam = \"none\";\n  }\n  Serial.println(inputMessage);\n  request-&gt;send(200, \"text\/plain\", \"OK\");\n});<\/code><\/pre>\n\n\n\n<p>When a request is received on the <strong><em>\/state<\/em><\/strong> URL, we send the current output state:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>server.on(\"\/state\", HTTP_GET, &#091;] (AsyncWebServerRequest *request) {\n  request-&gt;send(200, \"text\/plain\", String(digitalRead(output)).c_str());\n});<\/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>, we debounce the pushbutton and turn the LED on or off depending on the value of the <span class=\"rnthl rntliteral\">ledState<\/span> variable.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>digitalWrite(output, ledState);<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Demonstration<\/h2>\n\n\n\n<p>Upload the code to your ESP32 or ESP8266 board. <\/p>\n\n\n\n<p>Then, open the Serial Monitor at a baud rate of 115200. Press the on-board EN\/RST button to get is 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=\"647\" height=\"445\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/04\/ESP32-IP-Address.png?resize=647%2C445&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 ESP8266 NodeMCU Web Server IP Address Arduino IDE Serial Monitor\" class=\"wp-image-96249\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/04\/ESP32-IP-Address.png?w=647&amp;quality=100&amp;strip=all&amp;ssl=1 647w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/04\/ESP32-IP-Address.png?resize=300%2C206&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 647px) 100vw, 647px\" \/><\/figure><\/div>\n\n\n<p>Open a browser on your local network, and type the ESP IP address. You should have access to the web server as shown below.<\/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=\"595\" height=\"457\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/04\/Output-web-server-ESP8266-ESP32-physical-button.png?resize=595%2C457&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 ESP8266 NodeMCU Control Outputs with Web Server and a Physical Button Simultaneously Turn Off\" class=\"wp-image-96251\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/04\/Output-web-server-ESP8266-ESP32-physical-button.png?w=595&amp;quality=100&amp;strip=all&amp;ssl=1 595w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/04\/Output-web-server-ESP8266-ESP32-physical-button.png?resize=300%2C230&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 595px) 100vw, 595px\" \/><\/figure><\/div>\n\n\n<p>You can toggle the button on the web server to turn the LED on.<\/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=\"595\" height=\"457\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/04\/Output-web-server-on-ESP8266-ESP32-physical-button.png?resize=595%2C457&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 ESP8266 NodeMCU Control Outputs with Web Server and a Physical Button Simultaneously Turn On\" class=\"wp-image-96252\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/04\/Output-web-server-on-ESP8266-ESP32-physical-button.png?w=595&amp;quality=100&amp;strip=all&amp;ssl=1 595w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/04\/Output-web-server-on-ESP8266-ESP32-physical-button.png?resize=300%2C230&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 595px) 100vw, 595px\" \/><\/figure><\/div>\n\n\n<p>You can also control the same LED with the physical pushbutton. Its state will always be updated automatically on the web server.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"422\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/03\/ESP32-Input-Output-Button-Pressed-LED-On-Arduino-IDE.jpg?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Input Output Button Pressed LED On Arduino IDE\" class=\"wp-image-95248\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/03\/ESP32-Input-Output-Button-Pressed-LED-On-Arduino-IDE.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/03\/ESP32-Input-Output-Button-Pressed-LED-On-Arduino-IDE.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure>\n\n\n\n<p>Watch the next quick video for a live demonstration:<\/p>\n\n\n<div style=\"text-align:center\"><iframe src=\"https:\/\/player.vimeo.com\/video\/410198496?color=ff9933&title=1&byline=0&portrait=0\" width=\"720\" height=\"405\" frameborder=\"0\" webkitallowfullscreen mozallowfullscreen allowfullscreen><\/iframe><\/div><\/br>\n\n\n\n<h2 class=\"wp-block-heading\">Wrapping Up<\/h2>\n\n\n\n<p>In this tutorial you&#8217;ve learned how to control ESP32\/ESP8266 outputs with a web server and a physical button at the same time. The output state is always updated whether it is changed via web server or with the physical button.<\/p>\n\n\n\n<p>Other projects you may like:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-esp8266-web-server-outputs-momentary-switch\/\">ESP32\/ESP8266 Web Server: Control Outputs with Momentary Switch<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/display-images-esp32-esp8266-web-server\/\">Display Images in ESP32 and ESP8266 Web Server<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-esp8266-input-data-html-form\/\">Input Data on HTML Form ESP32\/ESP8266 Web Server<\/a><\/li>\n\n\n\n<li><a style=\"font-size: inherit; background-color: initial;\" href=\"https:\/\/randomnerdtutorials.com\/esp32-web-server-spiffs-spi-flash-file-system\/\">ESP32 Web Server using SPIFFS (SPI Flash File System)<\/a><\/li>\n<\/ul>\n\n\n\n<p>Learn more about the ESP32 and ESP8266 with our resources:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/learn-esp32-with-arduino-ide\/\">Learn ESP32 using Arduino IDE<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/home-automation-using-esp8266\/\">Home Automation using ESP8266<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/projects-esp32\/\">More ESP32 tutorials &#8230;<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/projects-esp8266\/\">More ESP8266 tutorials &#8230;<\/a><\/li>\n<\/ul>\n\n\n\n<p>Thanks for reading.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This tutorial shows how to control the ESP32 or ESP8266 outputs using a web server and a physical button simultaneously. The output state is updated on the web page whether &#8230; <\/p>\n<p class=\"read-more-container\"><a title=\"ESP32\/ESP8266: Control Outputs with Web Server and a Physical Button Simultaneously\" class=\"read-more button\" href=\"https:\/\/randomnerdtutorials.com\/esp32-esp8266-web-server-physical-button\/#more-96150\" aria-label=\"Read more about ESP32\/ESP8266: Control Outputs with Web Server and a Physical Button Simultaneously\">CONTINUE READING \u00bb<\/a><\/p>\n","protected":false},"author":5,"featured_media":96257,"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-96150","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\/04\/ESP32-ESP8266-Control-Outputs-with-Web-Server-and-Physical-Button-Simultaneously.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\/96150","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/comments?post=96150"}],"version-history":[{"count":2,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/96150\/revisions"}],"predecessor-version":[{"id":168081,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/96150\/revisions\/168081"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media\/96257"}],"wp:attachment":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media?parent=96150"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/categories?post=96150"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/tags?post=96150"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}