PlatformIO Community

Getting the state of a button from a webpage

Hey everyone !
I’m working on a project that sends data from Arduino to an ESP8266 ( UART com ) and then further to a webpage .
Im using <ESPAsyncWebServer.h> and this is how I served some of the data coming from Arduino , to the webpage :

server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest *request) {
    request->send_P(200, "text/plain", hum.c_str());
});

Anyway , now I want to have a toogle button on my webpage that I can use to control stuff on my Arduino. So I’m guessing that first I need to find the state of the button in my ESP , then send it to Arduino through the serial comm .

So far I only have the button :

 <div class="watering">
<h3>Watering:</h3>
<label class="switch"><input type="checkbox" id="outputState" name="input"
  onchange=toggleCheckbox(this)>
  <div class="slider round"></div>
</label>

Annotation 2020-08-26 161631

If someone can point me in the right direction on how to accomplish what I want to do , that’ll be great

Hi!
I might have a naive idea: to make an Ajax request to ESP8266 on button click?
That could block ESP8266 if button is clicked frequently within seconds, so maybe you could also do some JavaScript tweaks to prevent that.
Sorry I am also a newbie

1 Like

I’ve manage to print on my Serial Monitor when the button is on/off . Code :
HTML:

 <div class="watering">
<h3>Watering:</h3>
<label class="switch"><input type="checkbox" id="outputState" name="input"
  onchange="toggleCheckbox(this)">
  <div class="slider round"></div>
</label>

JS:

function toggleCheckbox(element) {
  let xhr = new XMLHttpRequest();
  if (element.checked) {
xhr.open("GET", "/update?state=1", true);
  }
  else {
xhr.open("GET", "/update?state=0", true);
  }
  xhr.send();
}

Main.cpp ( esp8266 ):

const char *PARAM_INPUT_1 = "state";

server.on("/update", HTTP_GET, [](AsyncWebServerRequest *request) {
    String inputMessage;
    if (request->hasParam(PARAM_INPUT_1))
    {
        inputMessage = request->getParam(PARAM_INPUT_1)->value();
        espSerial.println(inputMessage);
    }
    else
    {
        inputMessage = "No message sent";
    }
    Serial.println(inputMessage);
    request->send(200, "text/plain", "OK");
});

Now I get printed 1 when I slide the button on , and 0 and I slide off . So its ok .
Hope this helps people in the future !

1 Like

Only if you tell me how you got that nice round, fat slider look :wink:

So, I have a checkbox on the main page of a project that also uses ESPAsyncWebServer - in my case it’s a checkbox that governs whether the page auto-refreshes or not.

i.e.

<td><input type="checkbox" onclick="toggleAutoRefresh(this);" id="reloadCB" checked></td>
<td>Auto Refresh</td>

The corresponding javascript looks like this…

function toggleAutoRefresh(cb) {
    if (cb.checked) {
        refreshData = setInterval(updateData, 5000);
    } else {
        clearTimeout(refreshData);
    }
}

Now, in you case, instead of setting the timer, or clearing it, you probably want to poke some endpoint on the ESP so it does then passes the instruction to the Arduino.

To do that, this function may help - it toggles a relay by first querying the current state (as displayed on the page), and then tell the ESP what the new state is to be, via a button.

<td><input type="button" id="relay" value="Load" onclick="toggleRelay()"></td>
function toggleRelay() {
    var url = "";
    var state = document.getElementById("relay").value;
    if (state == "ON") {
        state = "0";
    } else {
        state = "1";
    }
    url = url.concat("/relay", "?set=", state);
    // console.log(url);
    xmlhttp = new XMLHttpRequest();
    xmlhttp.open("GET", url, true);
    xmlhttp.send();
    setTimeout(updateData, 250);
}

and finally the c++ code that responds to the relay set (or get):

  server.on("/relay", HTTP_GET, [](AsyncWebServerRequest *request) {
    String message;
    if (request->hasParam("set"))
    {
      message = request->getParam("set")->value();
      if (request->getParam("set")->value() == "1")
      {
        digitalWrite(RELAY, HIGH);
        message = "Turned relay ON!";
      }
      else if (request->getParam("set")->value() == "0")
      {
        digitalWrite(RELAY, LOW);
        message = "Turned relay OFF!";
      }
    }
    else if (request->hasParam("get"))
    {
      message = "State of relay = " + String(digitalRead(RELAY) ? "OFF" : "ON");
    }
    else
    {
      message = "No message sent";
    }
    request->send(200, "text/plain", message);
  });

edit: lol… I see in between me starting to respond this this about half an hour ago, and pausing for dinner, you’ve essentially solved your problem using similar code. Still want to know what you’re using to style the checkbox though! :laughing:

1 Like

A bit off the topic, but my idea is, would it be better to use POST instead of GET? 'Cause, ya know, POST is basically used to post data to server like in this case. Or does ESP8266 takes more resource to process POST request than GET? Thanks in advance.

Thanks for taking your time to solve my problem !! I will read it , of course, because it looks interesting .
As for the css code :

.watering {
  display: flex;
  align-items: center;
}

/* Slider Button */
.switch {
  position: relative;
  display: inline-block;
  width: 90px;
  height: 34px;
}

.switch input {
  display: none;
}

.slider {
  position: absolute;
  cursor: pointer;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: #ca2222;
  -webkit-transition: .4s;
  transition: .4s;
  border-radius: 34px;
}

.slider:before {
  position: absolute;
  content: "";
  height: 26px;
  width: 26px;
  left: 4px;
  bottom: 4px;
  background-color: white;
  -webkit-transition: .4s;
  transition: .4s;
  border-radius: 50%;
}

input:checked+.slider {
  background-color: #2ab934;
}

input:focus+.slider {
  box-shadow: 0 0 1px #2196F3;
}

input:checked+.slider:before {
  -webkit-transform: translateX(26px);
  -ms-transform: translateX(26px);
  transform: translateX(55px);
}

.slider:after {
  content: 'OFF';
  color: white;
  display: block;
  position: absolute;
  transform: translate(-50%, -50%);
  top: 50%;
  left: 50%;
  font-size: 10px;
  font-family: Verdana, sans-serif;
}

input:checked+.slider:after {
  content: 'ON';
}
1 Like

Dunno which is more efficient. One key difference is that HTTP_GETs are encoded in the URL, whereas HTTP_POST is in the HTTP body… so in the case of a HTTP_GET you get http://mydevice.local/relay?set=0 or http://mydevice.local/relay?set=1, vs the http://mydevice.local/relaySet of a HTTP_POST, and having to grab it from the body of HTTP request.

Edit: It is technically wrong though, since a GET is supposed to be “used to to request data from a specified resource” (not edit or update it), whereas POST is “used to send data to a server to create/update a resource”… so I should be using HTTP_GET to request the current state, and HTTP_POST/HTTP_PUT to set it… but in doing so, I also lose the ability to bookmark a given state, so too bad! lol

1 Like

Much appreciated! :slight_smile: Glad you solved it, and maybe something in that code will be of use for you or someone else! :slight_smile: