Analog Inputs and Switches using AJAX

Created on: 20 February 2013

Part 9 of the Arduino Ethernet Shield Web Server Tutorial

Updating the status of more than one switch that is interfaced to the Arduino web server, as well as showing the value of one of the analog inputs.

JavaScript is used to make AJAX calls to request the switch status and analog value from the web server.

This video shows the switches and analog input updated on the web page without flicker. Only parts of the web page are updated using AJAX.

Circuit Diagram

The circuit diagram below shows how the switches are interfaced to the Arduino (with Ethernet shield plugged into it). A potentiometer is interfaced to analog input A2 so that the value on A2 can be changed and updated on the web page.

Circuit Diagram of Switches and a Potentiometer Connected to an Arduino Uno
Circuit Diagram of Switches and a Potentiometer Connected to an Arduino Uno

The Sketch

The Arduino sketch is a modified version of the sketch from the previous tutorial.

/*--------------------------------------------------------------
  Program:      eth_websrv_AJAX_IN

  Description:  Uses Ajax to update the state of two switches
                and an analog input on a web page. The Arduino
                web server hosts the web page.
                Does not use the SD card.
  
  Hardware:     Arduino Uno and official Arduino Ethernet
                shield. Should work with other Arduinos and
                compatible Ethernet shields.
                
  Software:     Developed using Arduino 1.0.3 software
                Should be compatible with Arduino 1.0 +
  
  References:   - WebServer example by David A. Mellis and 
                  modified by Tom Igoe
                - Ethernet library documentation:
                  http://arduino.cc/en/Reference/Ethernet
                - Learning PHP, MySQL & JavaScript by
                  Robin Nixon, O'Reilly publishers

  Date:         20 February 2013
 
  Author:       W.A. Smith, http://startingelectronics.org
--------------------------------------------------------------*/

#include <SPI.h>
#include <Ethernet.h>

// MAC address from Ethernet shield sticker under board
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(10, 0, 0, 20); // IP address, may need to change depending on network
EthernetServer server(80);  // create a server at port 80

String HTTP_req;            // stores the HTTP request

void setup()
{
    Ethernet.begin(mac, ip);  // initialize Ethernet device
    server.begin();           // start to listen for clients
    Serial.begin(9600);       // for diagnostics
    pinMode(7, INPUT);        // switch is attached to Arduino pin 7
    pinMode(8, INPUT);        // switch is attached to Arduino pin 8
}

void loop()
{
    EthernetClient client = server.available();  // try to get client

    if (client) {  // got client?
        boolean currentLineIsBlank = true;
        while (client.connected()) {
            if (client.available()) {   // client data available to read
                char c = client.read(); // read 1 byte (character) from client
                HTTP_req += c;  // save the HTTP request 1 char at a time
                // last line of client request is blank and ends with \n
                // respond to client only after last line received
                if (c == '\n' && currentLineIsBlank) {
                    // send a standard http response header
                    client.println("HTTP/1.1 200 OK");
                    client.println("Content-Type: text/html");
                    client.println("Connection: keep-alive");
                    client.println();
                    // AJAX request for switch state
                    if (HTTP_req.indexOf("ajax_switch") > -1) {
                        // read switch state and analog input
                        GetAjaxData(client);
                    }
                    else {  // HTTP request for web page
                        // send web page - contains JavaScript with AJAX calls
                        client.println("<!DOCTYPE html>");
                        client.println("<html>");
                        client.println("<head>");
                        client.println("<title>Arduino Web Page</title>");
                        client.println("<script>");
                        client.println("function GetSwitchAnalogData() {");
                        client.println(
                            "nocache = \"&nocache=\" + Math.random() * 1000000;");
                        client.println("var request = new XMLHttpRequest();");
                        client.println("request.onreadystatechange = function() {");
                        client.println("if (this.readyState == 4) {");
                        client.println("if (this.status == 200) {");
                        client.println("if (this.responseText != null) {");
                        client.println("document.getElementById(\"sw_an_data\")\
.innerHTML = this.responseText;");
                        client.println("}}}}");
                        client.println(
                        "request.open(\"GET\", \"ajax_switch\" + nocache, true);");
                        client.println("request.send(null);");
                        client.println("setTimeout('GetSwitchAnalogData()', 1000);");
                        client.println("}");
                        client.println("</script>");
                        client.println("</head>");
                        client.println("<body onload=\"GetSwitchAnalogData()\">");
                        client.println("<h1>Arduino AJAX Input</h1>");
                        client.println("<div id=\"sw_an_data\">");
                        client.println("</div>");
                        client.println("</body>");
                        client.println("</html>");
                    }
                    // display received HTTP request on serial port
                    Serial.print(HTTP_req);
                    HTTP_req = "";            // finished with request, empty string
                    break;
                }
                // every line of text received from the client ends with \r\n
                if (c == '\n') {
                    // last character on line of received text
                    // starting new line with next character read
                    currentLineIsBlank = true;
                } 
                else if (c != '\r') {
                    // a text character was received from client
                    currentLineIsBlank = false;
                }
            } // end if (client.available())
        } // end while (client.connected())
        delay(1);      // give the web browser time to receive the data
        client.stop(); // close the connection
    } // end if (client)
}

// send the state of the switch to the web browser
void GetAjaxData(EthernetClient cl)
{
    int analog_val;
    
    if (digitalRead(7)) {
        cl.println("<p>Switch 7 state: ON</p>");
    }
    else {
        cl.println("<p>Switch 7 state: OFF</p>");
    }
    if (digitalRead(8)) {
        cl.println("<p>Switch 8 state: ON</p>");
    }
    else {
        cl.println("<p>Switch 8 state: OFF</p>");
    }
    // read analog pin A2
    analog_val = analogRead(2);
    cl.print("<p>Analog A2: ");
    cl.print(analog_val);
    cl.println("</p>");
}

Web Page Code

The above sketch produces the following HTML code:

HTML code with JavaScript produced by Arduino sketch
HTML Code Produced by Arduino Sketch - click for a bigger image

Modifications to the Sketch

Arduino pins 7 and 8 are both configured as inputs in the setup() part of the sketch.

The JavaScript function that handles the AJAX call has been renamed. The Arduino function that responds to the AJAX call has also been renamed.

A HTML <div> has been created below the H1 header in the HTML code and given the id "sw_an_data". The div is invisible on the page, but it serves as a place for the JavaScript to put the information (switch and analog values) sent back from the Arduino.

Sending the Request for Data from the Browser

The JavaScript function GetSwitchAnalogData() is called every second. Every second, it sends a GET request to the Arduino web server.

Receiving and Processing the AJAX Request on the Arduino

When the Arduino receives the AJAX request, it runs the GetAjaxData() function. This function reads the state of the two switches and sends the switches' statuses (ON or OFF) back to the web browser. The function also reads the value on the A2 analog pin and sends the value back to the browser.

Displaying the New Data in the Web Browser

When the web browser receives the data requested from the Arduino, it simply inserts it into the div that has the ID sw_an_data.