send POST request to Arduino on button event in javascript

I’ve got a small project going on where I am using an Arduino Mega 2560 as a web server. Easy enough getting example code to make something very simple work, like read the value of one of the Arduino ADCs back to the browser screen.

FYI – I’m using the Sparkfun ESP8266 WiFi shield.

My goal is to be able to use a button on the browser to call a function in the Arduino code, and by extension turn on one of the GPIO pins on the Arduino.

I’ve got a Javascript function buried in my code that I can activate with the button. I have verified that the Javascript is being called by the button click. Doing a little bit of reading, it seems that if I create a form object and do the following;

  1. Form.action = “192.168.1.117” (my webserver address)
  2. Form.method = “POST”
  3. Form.submit

I have a Putty terminal monitoring the Arduino web server. I can see when the browser calls the server with a ‘GET’ request, but I can’t seem to make it respond with the ‘POST’ request that I’m trying to initiate with the Javascript code and the button in HTML. Any ideas? The more I read, the more I think I will need to learn how to use php to do this. Is there any way to do it simply with Javascript and HTML?

Thanks,

Steve

My goal is to be able to use a button on the browser to call a function in the Arduino code, and by extension turn on one of the GPIO pins on the Arduino.

For that, you do NOT need to POST to the Arduino. A GET request is far simpler.

Take a look at the following example:

It uses XMLHttpRequests (XHR) to send HTTP requests.

function sendButtonState(button, state) {
  console.log(button+": "+state);

  var request = new XMLHttpRequest();
  request.open("POST", "https://foo.bar/");
  request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  request.send(encodeURI(button)+"="+state);
}

It just sends an HTTP POST request with the body containing a url-encoded key-value pair that represents the state of the button:

POST /database.php HTTP/1.1
Host: localhost
Connection: keep-alive
Content-Length: 10
Origin: http://localhost
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Accept: */*
DNT: 1
Referer: http://localhost/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.8,nl;q=0.6

output_1=0

You could use a HTTP parser on the Arduino, or just parse the text yourself ("\r\n\r\n" marks the end of the header, and the state of the button comes after the '=' sign).

If you want to use HTML forms, this is very easy as well. Take a look at the following examples from my beginner's guide to the ESP8266 that toggle an LED using HTTP POST, and send text to the Arduino using POST.
They were written for the ESP8266 Arduino Core, not for the Arduino Mega, but the principle is the same.
https://tttapa.github.io/ESP8266/Chap10 - Simple Web Server.html

PaulS:
For that, you do NOT need to POST to the Arduino. A GET request is far simpler.

Why would a GET request be simpler?
The HTTP specs don't allow GET requests to have side effects on the server. Changing the state of a GPIO definitely is a side effect.
That being said, a GET request would work as well, but you could have some problems with your browser sending the request twice, or sending the previous request again when you press the "back" button.

Pieter

Why would a GET request be simpler?

Because it can be done without javascript being part of the picture.

PaulS:
Because it can be done without javascript being part of the picture.

You can do a POST request without JS as well:

<form action="/URI" method="POST" enctype="application/x-www-form-urlencoded">
    <input ... >
    <input type="submit" value="Send">
</form>

Pieter

Hi Pieter,

Thanks! This works great, I am seeing the POST request now on the Arduino monitor. I will have to study all the ways to use XMLHttpRequest.

I am having one problem though, I'm not seeing the string value of the send argument POST request on the monitor. This is just a simple string value isn't it? Anything obvious I'm doing wrong? I'm a little concerned about the blank line before the text string in the request, maybe I need to be parsing my request different in the monitor. This is my function, pretty straightforward stuff,

Steve

function button_event()
{
document.getElementById("my_button").innerHTML="blue";
document.getElementById("my_button").style.color="white";
document.getElementById("my_button").style.backgroundColor="blue";
var request = new XMLHttpRequest();
request.open("POST","192.168.1.117");
request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
request.send("myvalue = hello");
}

PieterP:
Why would a GET request be simpler?

Because all the information is in the first header line.

Pretty hard to say without the Arduino code.

Also, there shouldn't be a space between the key and value. Try "myvalue=hello" instead of "myvalue = hello".

Pieter

I tried removing the spaces as you suggested, no change. I think that the argument to the send function just needs to be a string anyway, so I don't think the spaces would matter. The function looks for a blank line to determine the end of the request. I was thinking that this was the problem, as there looks to be a blank line in you example before the name/value pair appears at the end of the POST request. I made some changes to get around this (not shown in code), but I'm still not seeing the name/value pair in the request. I also tried looking at this in the Explorer and Chrome developer tools, didn't see the name value pair appear.

I'm sure this is something very simple and something that will probably be very obvious once I solve the problem.

thanks!.............Steve

Here's the code, standard stuff from the ESP8266 library that was suggested above. I removed the code that would show the Arduino ADC conversion result in the browser and replaced it with my button and Javascript;

while (client.connected())
{
if (client.available())
{
char c = client.read();

index++;

mystring = mystring + (String)c;

Serial.write(c);
// if you've gotten to the end of the line (received a newline
// character) and the line is blank, the http request has ended,
// so you can send a reply
if (c == '\n' && currentLineIsBlank)

{
Serial.println("Sending response");

// send a standard http response header
// use \r\n instead of many println statements to speedup data send
client.print(
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n"
"Connection: close\r\n" // the connection will be closed after completion of the response
"Refresh: 20\r\n" // refresh the page automatically every 20 sec
"\r\n");
client.print("\r\n");
client.print("\r\n");

client.print("<script type="text/javascript">\r\n");
client.print("function button_event()\r\n");
client.print("{\r\n");
client.print("document.getElementById("my_button").innerHTML="blue";\r\n");
client.print("document.getElementById("my_button").style.color="white";\r\n");
client.print("document.getElementById("my_button").style.backgroundColor="blue";\r\n");
client.print("var request = new XMLHttpRequest();\r\n");
client.print("request.open("POST","192.168.1.117");\r\n");
client.print("request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");\r\n");
client.print("request.send("myvalue=hello");\r\n");
client.print("}\r\n");
client.print("\r\n");

client.print("\r\n");
client.print("<button id = "my_button" type="button" style="width:160;height:24; background-color:green" onclick="button_event()">Click Me!\r\n");
client.print("\r\n");
client.print("\r\n");
break;
}
if (c == '\n')
{
// you're starting a new line
currentLineIsBlank = true;
}
else if (c != '\r')
{
// you've gotten a character on the current line
currentLineIsBlank = false;
}
}
}