Created on: 25 March 2013
Part 13 of the Arduino Ethernet Shield Web Server Tutorial
An Arduino Ethernet shield web server that hosts a web page on the SD card. The web page displays the status of a switch and uses Ajax to update the status of the switch.
In previous parts of this tutorial, an SD card hosted web page was never used to display the status of Arduino inputs – all the web pages displaying I/O were part of the Arduino sketch.
This part of the tutorial now displays an Arduino input on an SD card hosted web page.
A switch is interfaced to pin 3 of the Arduino for this example.
The code (Arduino sketch) and web page for this part of the tutorial are basically a combination of part 4 (Arduino SD card web server) and part 8 (reading switch status automatically using Ajax) of this tutorial.
No video has been included with this tutorial as the output will look the same as part 8 of this tutorial, but with the title and heading text changed.
The web page consisting of HTML and JavaScript (to implement Ajax) is shown below:
This web page is saved to the micro SD card as index.htm – it is basically the same HTML/JavaScript that was produced by the Arduino sketch in part 8 (reading switch status automatically using Ajax), but with the title and heading text changed.
Copy and paste the web page from the listing below.
<!DOCTYPE html> <html> <head> <title>Arduino SD Card Web Page using Ajax</title> <script> function GetSwitchState() { nocache = "&nocache=" + Math.random() * 1000000; var request = new XMLHttpRequest(); request.onreadystatechange = function() { if (this.readyState == 4) { if (this.status == 200) { if (this.responseText != null) { document.getElementById("switch_txt").innerHTML = this.responseText; } } } } request.open("GET", "ajax_switch" + nocache, true); request.send(null); setTimeout('GetSwitchState()', 1000); } </script> </head> <body onload="GetSwitchState()"> <h1>Arduino Switch State from SD Card Web Page using Ajax</h1> <p id="switch_txt">Switch state: Not requested...</p> </body> </html>
The Arduino sketch for this part of the tutorial is shown below. It requires the above HTML/JavaScript to be available on the micro SD card in the index.htm file.
/*-------------------------------------------------------------- Program: eth_websrv_SD_Ajax Description: Arduino web server that serves up a web page that displays the status of a switch connected to pin 3 of the Arduino. The web page is stored on the SD card. The web page contains JavaScript code that uses Ajax to request the state of the switch every second. Hardware: Arduino Uno and official Arduino Ethernet shield. Should work with other Arduinos and compatible Ethernet shields. 2Gb micro SD card formatted FAT16 Push button switch interfaced to pin 3 of the Arduino Software: Developed using Arduino 1.0.5 software Should be compatible with Arduino 1.0 + SD card contains web page called index.htm References: - WebServer example by David A. Mellis and modified by Tom Igoe - SD card examples by David A. Mellis and Tom Igoe - Ethernet library documentation: http://arduino.cc/en/Reference/Ethernet - SD Card library documentation: http://arduino.cc/en/Reference/SD Date: 25 March 2013 Modified: 17 June 2013 - removed the use of the String class Author: W.A. Smith, http://startingelectronics.org --------------------------------------------------------------*/ #include <SPI.h> #include <Ethernet.h> #include <SD.h> // size of buffer used to capture HTTP requests #define REQ_BUF_SZ 40 // MAC address from Ethernet shield sticker under board byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; IPAddress ip(192, 168, 0, 20); // IP address, may need to change depending on network EthernetServer server(80); // create a server at port 80 File webFile; char HTTP_req[REQ_BUF_SZ] = {0}; // buffered HTTP request stored as null terminated string char req_index = 0; // index into HTTP_req buffer void setup() { // disable Ethernet chip pinMode(10, OUTPUT); digitalWrite(10, HIGH); Serial.begin(9600); // for debugging // initialize SD card Serial.println("Initializing SD card..."); if (!SD.begin(4)) { Serial.println("ERROR - SD card initialization failed!"); return; // init failed } Serial.println("SUCCESS - SD card initialized."); // check for index.htm file if (!SD.exists("index.htm")) { Serial.println("ERROR - Can't find index.htm file!"); return; // can't find index file } Serial.println("SUCCESS - Found index.htm file."); pinMode(3, INPUT); // switch is attached to Arduino pin 3 Ethernet.begin(mac, ip); // initialize Ethernet device server.begin(); // start to listen for clients } 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 // buffer first part of HTTP request in HTTP_req array (string) // leave last element in array as 0 to null terminate string (REQ_BUF_SZ - 1) if (req_index < (REQ_BUF_SZ - 1)) { HTTP_req[req_index] = c; // save HTTP request character req_index++; } // 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 if (StrContains(HTTP_req, "ajax_switch")) { // read switch state and send appropriate paragraph text GetSwitchState(client); } else { // web page request // send web page webFile = SD.open("index.htm"); // open web page file if (webFile) { while(webFile.available()) { client.write(webFile.read()); // send web page to client } webFile.close(); } } // display received HTTP request on serial port Serial.println(HTTP_req); // reset buffer index and all buffer elements to 0 req_index = 0; StrClear(HTTP_req, REQ_BUF_SZ); 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 GetSwitchState(EthernetClient cl) { if (digitalRead(3)) { cl.println("Switch state: ON"); } else { cl.println("Switch state: OFF"); } } // sets every element of str to 0 (clears array) void StrClear(char *str, char length) { for (int i = 0; i < length; i++) { str[i] = 0; } } // searches for the string sfind in the string str // returns 1 if string found // returns 0 if string not found char StrContains(char *str, char *sfind) { char found = 0; char index = 0; char len; len = strlen(str); if (strlen(sfind) > len) { return 0; } while (index < len) { if (str[index] == sfind[found]) { found++; if (strlen(sfind) == found) { return 1; } } else { found = 0; } index++; } return 0; }
This sketch works in the same way as the sketch from part 8 (reading switch status automatically using Ajax), except that instead of sending the web page line by line from the Arduino sketch code, the web page is sent from the index.htm file on the SD card.
Because we are using Ajax, the web page (when loaded in the web browser) sends the same request for the switch status as the sketch in part 8 of this tutorial. If we were not using Ajax, then the Arduino would need to read the index.htm file from the SD card and modify the part that shows the switch status, then send back the whole web page with the modified part – depending on if the switch is on or off.