ESP-01 Webserver does not start when button connected

I am trying to apply the following Random Nerd Turotial on and ESP-01.

My code is

/*********
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/esp32-esp8266-web-server-physical-button/
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*********/

// Import required libraries
#ifdef ESP32
  #include <WiFi.h>
  #include <AsyncTCP.h>
#else
  #include <ESP8266WiFi.h>
  #include <ESPAsyncTCP.h>
#endif
#include <ESPAsyncWebServer.h>

// Replace with your network credentials
const char* ssid = "ssid";
const char* password = "pwd";

const char* PARAM_INPUT_1 = "state";

//IO0 = 0
//IO1 = 1
//IO2 = 2
//IO3 = 3

const int output =2;
const int buttonPin =0; //3

// Variables will change:
int ledState = LOW;          // the current state of the output pin
int buttonState;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin

// the following variables are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int.
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers

// Create AsyncWebServer object on port 80
AsyncWebServer server(80);

const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
  <title>ESP Web Server</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <style>
    html {font-family: Arial; display: inline-block; text-align: center;}
    h2 {font-size: 3.0rem;}
    p {font-size: 3.0rem;}
    body {max-width: 600px; margin:0px auto; padding-bottom: 25px;}
    .switch {position: relative; display: inline-block; width: 120px; height: 68px} 
    .switch input {display: none}
    .slider {position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; border-radius: 34px}
    .slider:before {position: absolute; content: ""; height: 52px; width: 52px; left: 8px; bottom: 8px; background-color: #fff; -webkit-transition: .4s; transition: .4s; border-radius: 68px}
    input:checked+.slider {background-color: #2196F3}
    input:checked+.slider:before {-webkit-transform: translateX(52px); -ms-transform: translateX(52px); transform: translateX(52px)}
  </style>
</head>
<body>
  <h2>ESP Web Server</h2>
  %BUTTONPLACEHOLDER%
<script>function toggleCheckbox(element) {
  var xhr = new XMLHttpRequest();
  if(element.checked){ xhr.open("GET", "/update?state=1", true); }
  else { xhr.open("GET", "/update?state=0", true); }
  xhr.send();
}

setInterval(function ( ) {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      var inputChecked;
      var outputStateM;
      if( this.responseText == 1){ 
        inputChecked = true;
        outputStateM = "On";
      }
      else { 
        inputChecked = false;
        outputStateM = "Off";
      }
      document.getElementById("output").checked = inputChecked;
      document.getElementById("outputState").innerHTML = outputStateM;
    }
  };
  xhttp.open("GET", "/state", true);
  xhttp.send();
}, 1000 ) ;
</script>
</body>
</html>
)rawliteral";

// Replaces placeholder with button section in your web page
String processor(const String& var){
  //Serial.println(var);
  if(var == "BUTTONPLACEHOLDER"){
    String buttons ="";
    String outputStateValue = outputState();
    buttons+= "<h4>Output - GPIO 2 - State <span id=\"outputState\"><span></h4><label class=\"switch\"><input type=\"checkbox\" onchange=\"toggleCheckbox(this)\" id=\"output\" " + outputStateValue + "><span class=\"slider\"></span></label>";
    return buttons;
  }
  return String();
}

String outputState(){
  if(digitalRead(output)){
    return "checked";
  }
  else {
    return "";
  }
  return "";
}

void setup(){
  // Serial port for debugging purposes
  Serial.begin(115200);

  pinMode(output, OUTPUT);
  digitalWrite(output, LOW);
  pinMode(buttonPin, INPUT);
  
  // Connect to Wi-Fi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi..");
  }

  // Print ESP Local IP Address
  Serial.println(WiFi.localIP());

  // Route for root / web page
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/html", index_html, processor);
  });

  // Send a GET request to <ESP_IP>/update?state=<inputMessage>
  server.on("/update", HTTP_GET, [] (AsyncWebServerRequest *request) {
    String inputMessage;
    String inputParam;
    // GET input1 value on <ESP_IP>/update?state=<inputMessage>
    if (request->hasParam(PARAM_INPUT_1)) {
      inputMessage = request->getParam(PARAM_INPUT_1)->value();
      inputParam = PARAM_INPUT_1;
      digitalWrite(output, inputMessage.toInt());
      ledState = !ledState;
    }
    else {
      inputMessage = "No message sent";
      inputParam = "none";
    }
    Serial.println(inputMessage);
    request->send(200, "text/plain", "OK");
  });

  // Send a GET request to <ESP_IP>/state
  server.on("/state", HTTP_GET, [] (AsyncWebServerRequest *request) {
    request->send(200, "text/plain", String(digitalRead(output)).c_str());
  });
  // Start server
  server.begin();
}
  
void loop() {
  // read the state of the switch into a local variable:
  int reading = digitalRead(buttonPin);

  // check to see if you just pressed the button
  // (i.e. the input went from LOW to HIGH), and you've waited long enough
  // since the last press to ignore any noise:

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer than the debounce
    // delay, so take it as the actual current state:

    // if the button state has changed:
    if (reading != buttonState) {
      buttonState = reading;

      // only toggle the LED if the new button state is HIGH
      if (buttonState == HIGH) {
        ledState = !ledState;
      }
    }
  }

  // set the LED:
  digitalWrite(output, ledState);

  // save the reading. Next time through the loop, it'll be the lastButtonState:
  lastButtonState = reading;
}

My schematic is below.

If my button is disconnected, everything boots up fine. I can then connect the button and control the LED with the browser or the button.

If I however try and boot up with the button connected, nothing appears to work i.e. I can't browse the the webserver and pressing the button does nothing.

Not sure what is causing this or how I fix it.

GPIO0 must be pulled high on boot. The 10k pulldown could be putting the ESP into flash mode. If it's wired as the schematic shows, it should never work.

Ha Ha - caught! :astonished:

The "Random Nerd Tutorial" (corrected) shows this inappropriate arrangement connected to GPIO4, not GPIO0 as you have it - since you are constrained with the ESP-01.

But as is so often with "tutorials" by inexperienced "newbies", it shows buttons connected to Vcc and LEDs connected to ground. Proper practice is always (well, almost) to have the button connect to ground with a pull-up resistor to Vcc (if needed) and in this case, the LED and resistor to Vcc. This means that both I/O ports will be pulled HIGH on boot-up and the ESP-01 will start normally (unless the button was pressed on boot-up).

While critical in your arrangement, this is unfortunately misleading if not critical in the "tutorial". :roll_eyes:

I often wonder if we're here to fix Instructables and Random Nerd tutorials?

So, as Paul said, move the 10k to pull up GPIO0, and put the switch from GPIO0 to ground.

Here is the changes that I made (there was a comment made about the LED but I am not sure if something should be changed there).

Regarding "I often wonder if we're here to fix Instructables and Random Nerd tutorials?", both these sites have played a pivotal role in driving my (an others) exploration in the maker and electronics spaces. They have provided me with a sandpit to play in. When I get stuck I then come to these forums where I gain an better and more correct understanding. Unfortunately as electronics is something that I have only started playing with over the last few years (and given that it is in no way connected to my may job) I am likely to suffer many noob errors for years to come yet :slight_smile:

Thanks all for your continued help :slight_smile:

Zululander:
there was a comment made about the LED but I am not sure if something should be changed there

You have the LED connected to GPIO2. The same thing applies here as to GPIO0 - it must not be pulled down on booting, if anything it must be pulled up. The red LED you specify indicates forward voltage (albeit at 20 mA) between 1.7 and 2.4 V which means you are holding GPIO2 down very close to half of the supply voltage and it is a bit of a toss-up as to whether it will be read by the processor as HIGH or LOW - which is to say, whether the processor (ESP8266) will boot normally or not.

So just as the pull-up on GPIO0 should pull up to 3.3 V, so should the LED. This would be less critical with a white LED with a higher threshold voltage.

Zululander:
Regarding "I often wonder if we're here to fix Instructables and Random Nerd tutorials?", both these sites have played a pivotal role in driving my (an others) exploration in the maker and electronics spaces. They have provided me with a sandpit to play in. When I get stuck I then come to these forums where I gain an better and more correct understanding.

Which is perhaps very convenient for people in your situation, but playing mightily on the benevolence of those here who are endlessly helping people to correct the simple but extremely troublesome blunders propagated by those other sites! :roll_eyes:

Final Question (I hope).

Everything is working as it should except that when turning on the LED ring flash on a random number of lights while the circuit boots up. I therefore decided to add a delay on the power to the LED so that the LED only powers on once the circuit has stablised. I used a 555 timer as discussed in a tutorial that I found.

My questions are:

  1. Have I approached this correctly?
  2. Have I drawn my schematic correctly i.e. checking that I am using the Net Ports correctly.

First, fix your ESP. CH_PD and RST need to be pulled high using a 10K resistor.
Rather than mess with GPIO2, use TX (GPIO1) or RX (GPIO3). The flickering of the LEDS is coming from GPIO2 which will switch between high and low during boot. I don't recall what's going on, just that GPIO2 is not "clean" during boot.

Next- you are powering the LED ring from an NE555 output? How much current does your LED ring draw? (The 555 is limited to 225mA).

Rather than use the 555, move the LED data line to GPIO1 or GPIO3.

Hi,

ESP. CH_PD was a mistake on the diagram. It is being pulled up. If I try pulling the RST up then the board appears to continually reboots.

The 555 was there just to delay power to the LED ring but since changing the data to GPO3 that is no longer needed; thanks for that.