Control Input Output of ESP8266 with AJAX

I used to brag about Arduino YUN being the IoT enabler. Then came along super cheap ESP8266 but there was an entry barrier to using it as it seemed like someone who is proficient in Electronics only could make it work. Then came companies like Adafruit, Sparkfun, etc who spoon fed the makers with a version of ESP8266 suitable to their skill level. Prior to this I wanted to experiment with it but never did. Then I procured 3 Adafruit ESP8266 Huzzahs and played with LUA programming. Arduino IDE supporting the ESP8266 was icing on the cake as anyone who has worked on Arduino could now work on ESP8266.

Although I have a degree in Electronics Engineering and have done programming in school and college, I have never worked in that field as I work on Computer Networks. I consider makers to be “Jack of all trade, Master of one”, so rather than learning all technologies associated with making, it is helpful if you get related stuff from people who have already done it. So when I find something which has not been documented and can be helpful to others, I write about it. If you have read my post on “Control Input Output of Arduino Yun with AJAX“, I wish to achieve something similar in this article. This post could not have been possible without the help of “ESP8266 Tutorial” as working with YUN HTML is easier than working with HTML on ESP8266. YUN has a separate HTML file and INO file. ESP8266 is having just one file and to put tons of HTML code in it is difficult. The above mentioned article describes how to easily do that.

Inputs and Outputs to the ESP8266

We will use one Digital Input, one Analog Input, One PWM Output and couple of Digital Outputs. I will not go into much details as to how to use the inputs and outputs as if you have reached this stage, then you probably know how to program inputs and outputs and the way they are connected to the ESP8266. All the components are basic so you should easily have it.

ESP8266 AJAX

1) Digital Input: Pin 4 of the ESP8266 will be used as a digital input. This means that pin 4 will sense a 1 or a 0 on the pin. Depending on the input, the text of the output on the web page will change asynchronously i.e. without page reload. For this purpose, we will use a simple push button switch. When pressed, the output will be OFF as it is connected to GND and when released, the output will be ON due to Input Pullup.

2) Digital Output: We will use LEDs connected to pin 12 and pin 13 as output. Depending upon the input we provide to the ESP8266 via the web interface, the LEDs will be either ON or OFF. Also, the text below buttons 12 and 13 will be either ON or OFF depending on the actual state of the LEDs.

3) Analog Input: ESP8266 has only one analog sensing pins denoted as A and used in IDE as A0. We will connect an LDR to it. This will give varying values depending upon the brightness around it. The Analog input is limited to 1V so you to scale down the analog signal accordingly.

4) Analog Output: We will connect another LED to pin 5 of the ESP8266. The way ESP8266 provides analog output is through PWM which means when we change the value of the input on the web interface, the Duty cycle of the Pulse Width Modulated signal changes hence giving the effective output of analog change. When we change the slider on the page, the brightness of the LED will change.

The Web Interface

The Web Interface consists of either user input to the ESP8266 or change in the status in web page depending on status of pins.

ESP8266 web AJAX

Analog Input: The text box field will reflect the values of the Ambient Light brightness in Lux.

Digital Input: This value will change from Off to On depending upon the status of the Digital pin 4.

PWM Output: PWM output from a pin has a value ranging from 0 to 255. The slider sets the value of Pin 5 from 0 to 255. Also, the text below it shows the current value of the output.

Digital Output: We have used Pin 12 and 13 as output on ESP8266. The output will change depending upon what we do to the GPIO 12 and 13 on the page. If we click the button once, the output on the pin will toggle to digital one and the button text below will change to On. Click once again and it will toggle the pin to digital zero and reflect the change on the page by turning button text Off.

Project Files

You can find the INO file here and the library file here.

Usage of files

Opening and saving the INO file will create a folder for itself in Arduino folder. You will have to copy the folder indexl (containing the indexl.h file) in the Arduino Libraries folder.

Demo of the Project (Watch it in Full screen and Full HD)

HTML Code of Web page explained

The HTML code is present in the indexl.h file in a format which can be understood by the ESP8266. We will take snippets of the code and discuss it here. First we will look into the code that makes the page. We will not go into the details as to the formatting, just the things which form part of the interaction.

<input type=”text” style=”text-align: center;” name=”analog” id=”analog0″ value=”0″ size=”6″ readonly/>

This is the text box below “Ambient Light in Lux”. The important thing to note here is the id and the value. The script requires that we have an id and a value so that we could reference it into a script and change its value.

<p id=”text4″>Off</p>

This is the text below GPIO 4. The current text is On but as soon as the script will run and the status of pin 4 will change to 0 depending on push button press, the text will be replaced by Off. The script will reference the id of text4 to change the text.

<input type=”hidden” name=”pin” value=”5″ id=”pin5″ />
<input type=”range” style=”width: 90px; height: 30px;” id=”dac5″ min=”0″ max=”255″ value=”0″ step=”1″ onchange=”sendDac(document.getElementById(‘pin5’).value,
this.value);”/>
<span id=”valueDac5″>0</span>

These codes are representing the GPIO 5 slider. The first field is hidden which means you will not see anything about it but it is important because it has a value and an id which will be referenced later. The second line is the code of the slider as depicted by the input=range. The starting value is 0 and the ending value is 255 and the step is 1. 0 to 255 represents the values PWM can take. Also, moving the slider will cause an event “sendDAC” which will send the current value of the slider with the value of pin5 to the script. We will discuss the scripts later on. valueDac5 (the number below the slider) currently has a value of 0 but will be replaced by another value depending upon the output of the script.

<input type=”hidden” name=”pin” value=”12″ id=”pin12″ />
<input type=”hidden” name=”action” value=”0″ id=”action12″ />
<button onclick=”sendbutton(document.getElementById(‘pin12’).value,document.getElementById(‘action12’).value);”/>GPIO 12</button>
<p id=”text12″>Off</p></td>

The code above represents the Digital output pin 12. The first line represents the value of pin12 to be referenced later. The second line represents the action that will be taken when we click the button. The action will be either 0 or 1. Initially the text below the button will be Off as the value of action12 is 0. Later on, the text will change to On as we click the button triggering the event “sendbutton” which sends the value of pin12 and the value of action12 to the script.

<p id=”description”> – </p>

There will be many times we will get response from the ESP8266 and we will place that in the id description so that we can see the communication.

Now that we are done with the way the page looks and acts, let us take a look at the way the page will behave when it receives the events.

Code for Auto update of Status

window.onload=Pinstatus;
function Pinstatus(){
morestatus();
}

The above portion is the script part of the html code. When the window will load in a user PC, the “Pinstatus” script will run. This script calls another script “morestatus”.

function morestatus(){
setTimeout(morestatus, 4000);
document.getElementById(“description”).innerHTML = “Processing Status”;
server = “status/99”;
request = new XMLHttpRequest();
request.onreadystatechange = updateasyncstatus;
request.open(“GET”, server, true);
request.send(null);
}

The timeout on the script causes it to run every 4 seconds. You remember the description field in the previous section at the end. That description will be replaced by “Processing Status” in the page by the innerHTML attribute. The “request = new XMLHttpRequest()”creates a new request and on a state change, it calls another script “updateasyncstatus”. “request.open(“GET”, server, true)” creates a GET request with a value of server which in total amounts to “http://ip address of ESP8266/status/99”. Also, the true indicates that it is an Asynchronous request which means the page will not required to be reloaded. “request.send(null)” sends the created request to the ESP8266.

The script updateasyncstatus updates the state of the page i.e. all the parameters we were talking about before – the text, text boxes, the sliders, etc.

function updateasyncstatus(){
if ((request.readyState == 4) && (request.status == 200))
{
result = request.responseText;      //result will store the response received from  ESP8266
document.getElementById(“description”).innerHTML = result;   //description will now show the response received
fullset = result.split(“#”);

The response we receive from the ESP8266 will be of the format status#4=1#12=0#13=0#5=0#A0=756. What the result.split will do is split the string at “#” into an array of “pin and its value” pair. So the array will look like 4=1,12=0,13=0,A0=756. fullset will store this array and you can call any entry based upon fullset[position of entry].

In the following “for loop”, we will further segregate the values to make them usable. The for loop will run as long as the length of the response received.

for(i = 1; i < fullset.length; i++){
PinPair = fullset[i];                                                  //for the value of i=1, PinPair will be “4=1”
singleset = PinPair.split(“=”);       //this will cause PinPair to split at “=” into an array of [4,1]
PN = singleset[0];                                                    //PN will hold the pin number,example 4
Pinstatus = singleset[1];                               //this will hold the status of pin 4, for example 1
if (PN > 11)                                           //  if pin number is greater than 11 i.e. pin 12 and 13
{
ActNum = “action” + PN;                                                  // eg for pin 12, ActNum=action12
TxtNum = “text” + PN;                                                                                // TxtNum=text12
if (Pinstatus == 0)
{
PinAct = “1”;                    //If the current status of pin 12 is 0, set text to Off and PinAct to 1
text = “Off”;
}
else
{
PinAct = “0”;
text = “On”;
}

document.getElementById(ActNum).value = PinAct” will change the value of action12 in main HTML to 1. What this will do is the next time when you click on GPIO 12 i.e. pin12, it will send a value of 1 as currently its value is 0. This makes it a toggle switch.

“document.getElementById(TxtNum).innerHTML = text;” will change the text below button 12 to be Off as pin status is 0.

if (PN == 4)
{
TxtNum = “text” + PN;
if (Pinstatus == 1)
{
text = “On”;
}
else
{
text = “Off”;
}
document.getElementById(TxtNum).innerHTML = text;
}

In the case of pin 4, since it is not a toggle switch, we do not require PinAct. If Pin status is 1, text2 in the HTML will be replaced by On and vice versa.

if (PN == 5 )
{
PinVal = parseInt(singleset[1]);   //Since pin 5 is analog output, it has values between 0 and 255. This integer value will need to be extracted from the array using parseInt() in order to be usable.
DacNum = “dac” + PN;                                                                                                 //dac5
ValNum = “valueDac” + PN;                                                                               //valueDAC5
document.getElementById(DacNum).value = PinVal;  //This will set the value of dac5 to the actual value from 0 to 255 in the HTML page i.e. the slider

document.getElementById(ValNum).innerHTML = PinVal;  //This will display the value of valueDAC5 below the slider

if (PN.substr(0,1) == “A”)                                                //if the pin is an analog input pin A
{
PinVal = parseFloat(singleset[1]);                       //the value of A0 received from ESP8266
AnalogNum = “analog” + PN.substr(1,2);                                                              //analog0
document.getElementById(AnalogNum).value = PinVal;                       //This will change the value in the text box analog0 to the value of light brightness received from ESP8266

Code for Changing Digital Output and Auto update of Digital Status

The Page updates the status of pins asynchronously every 4 seconds. The following script will change the status of the pin when the button (12 or 13) is pressed and it will also command the ESP8266 to change the digital output (pin 12 or 13). When we press pin 12 for example, the script sends 2 values with the script. The 2 values – “pin number” and “action” will be used here. (Note: The following explanation will use pin 12 as an example with a pin state of 1.)

function sendbutton(Pin,action){
document.getElementById(“description”).innerHTML = “Processing Button Click”;
server = “digital/” + Pin + “/” + action;                                                            //digital/12/1
request = new XMLHttpRequest();
request.onreadystatechange = updateasyncbutton;
request.open(“GET”, server, true);
request.send(null) ;

AJAX request will be created and sent as “http://ip address of ESP8266/digital/12/1 to ESP8266 and updateasyncbutton script will be run. updateasyncbutton script will process the response coming back from ESP8266 i.e. in the form of digital,12,1.

Code for Changing PWM Output and Auto update of Slider

The following script kicks in when the value of slider 5 changes. The event will send 2 values i.e. Pin=5 and value=position of slider

function sendDac(Pin,value){
ValNum = “valueDac” + Pin;                                                                                //valueDac5
document.getElementById(ValNum).innerHTML=value;
document.getElementById(“description”).innerHTML = “Processing Slider”;
server = “dac/” + Pin + “/” + value;                                                                       //dac/5/190
request = new XMLHttpRequest();
request.onreadystatechange = updateasyncDac;
request.open(“GET”, server, true);
request.send(null);

The above code creates and sends a request to ESP8266 as “http://ip address of ESP8266/dac/5/190 and runs script updateasyncDac. What this function does is change the value of slider and the value below it.

Arduino Sketch explained

#include <ESP8266WiFi.h>
#include “indexl.h”                                                             //This file contains the HTML code

const char* ssid = “SSID”;
const char* password = “PASSWORD”;

// Create an instance of the server
// specify the port to listen on as an argument
WiFiServer server(80);

int dac = 0;                                                                                      //The initial value of pin 5
int DigitalPin[] = {4, 12, 13};                      //the array holding the digital pins so that we can reference them easily using for loops
int DacPin = 5;

void setup() {
Serial.begin(115200);
delay(10);
pinMode(4,INPUT);
pinMode(4, INPUT_PULLUP);                     //Using Input Pullup for the digital input to work
pinMode(12,OUTPUT);
pinMode(13,OUTPUT);

// Connect to WiFi network
Serial.println();
Serial.println();
Serial.print(“Connecting to “);
Serial.println(ssid);

WiFi.begin(ssid, password);

while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(“.”);
}
Serial.println(“”);
Serial.println(“WiFi connected”);

// Start the server
server.begin();
Serial.println(“Server started”);

// Print the IP address
Serial.println(WiFi.localIP());
}

void loop() {
// Check if a client has connected
WiFiClient client = server.available();
if (!client) {
return;
}

// Wait until the client sends some data
Serial.println(“new client”);
while(!client.available()){
delay(1);
}

// Read the first line of the request
String command1 = client.readStringUntil(‘/’); //This stores the irrelevant portion of the URL
String command = client.readStringUntil(‘/’); //This will parse the rest of the URL into valid inputs

if (command == “digital”) {                                                            //for example /digital/12/1
int pin, value;
pin = client.parseInt();                                                                     //for /digital/12/1, pin=12
Serial.println(pin);
if (client.read() == ‘/’) {
value = client.parseInt();                                                              //for /digital/12/1, value=1
digitalWrite(pin, value);                                                         //lights LED connected to Pin 12
}
else {
value = digitalRead(pin);
}
client.print(F(“digital,”));
client.print(pin);
client.print(F(“,”));
client.println(value);                                                               //sends digital,12,1 to web page
}
else if (command == “dac”){                                                             //for example /dac/5/190
int pin, value;
pin = client.parseInt();                                                                           //for /dac/5/190, pin=5
if (client.read() == ‘/’) {
value = client.parseInt();                                                               //for /dac/5/190, value=190
dac = value;                                       //dac is used as a placeholder for storing slider value
analogWrite(pin, value);                                                        //lights led on pin 5 using PWM
}
else {
value = dac;
}
client.print(F(“dac,”));
client.print(pin);
client.print(F(“,”));
client.println(value);                                                                //sends dac,5,190 to web page
}
else if (command == “status”) {                                                         //for example /status/99
int pin, value;
client.print(F(“status”));                                            //the string of data will start with “status”
for (int thisPin = 0; thisPin < 3; thisPin++) {                              //which means pins 4,12,13
pin = DigitalPin[thisPin];                                                          //for thispin=0, DigitalPin[0]=4
value = digitalRead(pin);                                                                //status of pin4 i.e. 0 or 1
client.print(F(“#”));
client.print(pin);
client.print(F(“=”));
client.print(value);
}
{
pin = DacPin;
value = dac;
client.print(F(“#”));
client.print(pin);
client.print(F(“=”));
client.print(value);
}
{
value = analogRead(A0);
float lux=value;
client.print(F(“#A0”));
client.print(F(“=”));
client.print(lux);
}                          //after for loop, the string will be status#4=0#12=0#13=1#5=0#A0=756.00
client.println(“”);
}
else {
String s = “HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n”; //Send web page if request is empty i.e. the initial request
s += file1;
client.flush();
// Send the response to the client in bursts of 2000
while(s.length()>2000)
{
String dummy = s.substring(0,2000);
client.print(dummy);
s.replace(dummy,” “);
}

client.print(s);
delay(1);
Serial.println(“Client disconnected”);

// The client will actually be disconnected
// when the function returns and ‘client’ object is destroyed
}
}

28 thoughts on “Control Input Output of ESP8266 with AJAX

  1. Pingback: Control Input Output of Arduino Yun with AJAX | Baba AweSam

  2. Dear Baba AveSam
    I have got some missing files. I have uploaded the library, still it gets another error. Could you send the following libraries so that it will work better. salih.okur@gmail.com

    #include

    ^

    compilation terminated.

    exit status 1

  3. Dear Samir thanks alot for your help. I tried everything in the links. But I have still the following message coming from IDE during the upload. It cuts without upload to the Arduino Mega.

    trying to connect
    flush start
    setting serial port timeouts to 1 ms
    setting serial port timeouts to 1000 ms
    flush complete
    espcomm_send_command: sending command header
    espcomm_send_command: sending command payload
    read 0, requested 1
    warning: espcomm_sync failed
    error: espcomm_open failed
    error: espcomm_upload_mem failed
    SO NO UPLOAD TO THE ARDUINO MEGA.
    Do you have any suggestions?

  4. Hello
    Thank you it is working fine
    But it is working only on my Android Phone
    It is not working on My PC! (tested firefox and chrome)

    What need to be enabled on my PC ?

  5. Hi Baba AveSam

    I’m a nob when in comes to Webstuffs, and while I can get your project running on my ESP-01 I fail to map my outputs correctly.

    Are you able to give a very simple example where you have a static weeb page that controls one GPIO pin on button click?

    Thanks for all your work!

  6. Excellent code Baba AveSam,
    I find on my IOS phone the page displays but doesn’t update the analog values and the GPIO wont toggle etc. Within IE11 everything works perfect. Do you have any idea why?

  7. Hi.
    I have tried to download the files from your dropbox but i am unable to do so. Could you re-share them?
    Thanks in advance.

      • I could not directly download them. I sent them to my personal dropbox and downloaded them there.

        Thank you! 😀

  8. Hi, it’s an excellent work. I want a change with the push button operation so the led GPIO 13 goes to HIGH if is it LOW or LOW if is it HIGH. Can you suggest the changes in the code ?

    • Whatever you want, after that enter the following code. Replace 12 with 13 for your requirement
      if(digitalRead(12))
      {
      digitalWrite(12, 0);
      client.print(F(“12,0”));
      }
      else
      {
      digitalWrite(12, 1);
      client.print(F(“12,1”));
      }

  9. hi samirsogay,

    Your example was very useful and trigger me to start my own project and webserver. I have a question regarding HTML code, this part is very difficult to code unless we use kind of WYSIWYG. Do you have any suggestion, can we program using this kind of software instead of pure coding. imagine if your webserver has multiple pages or it is little bit complicated, would be very difficult start coding from scratch…

    Any idea is very helpful. one of the functionality I am looking for is to make a graph in Html, have you came across ? Do you have any idea how to make a graph in your webserver without using any internet connectivity to outside world for api.

    thanks for help

    Navid

    • Hi Navid,

      There is a software called converthtml.exe which will convert your page to be usable in an esp8266. As far as the graph is concerned, I did see an example in arduino IDE but i am not able to find it. It was either in ESP8266 or Arduino YUN examples.

  10. Hello,

    the program is working fine, both on my phone and PC.
    I want to put more function on the page and I can’t get it. For example I have a DS18B20 temperature sensor and I can’t integrate in the page to show the temperature.
    I made just to show in the status line at the end the temperature. Now I want to have it in the table, new row. My reading function is getTemp(). Client.println(getTemp()); just show the temp in the line.
    Can you help me to make it working in the table?

    Thank you.

  11. Wow. I’m working on a simple project that is different than your specific project, but the very big amount of work that you put in will make my project AWESOME! I really appreciate the information on this page.

    If all goes well and I can manage to modify everything to my liking, I will be posting another comment describing my modifications.

    Thanks a million!!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s