HTML Text Box to Send Text to Arduino Web Server

An Arduino and Ethernet shield are used as a web server to host a web page that contains a text box. Text can be typed into the web page text box using a web browser and sent to the Arduino by clicking a button on the web page.

An HTML textarea is used in an HTML form to create the text box. JavaScript is used to send the text to the Arduino using a HTTP GET request when the button on the web page is clicked. This is useful for any Arduino project that needs to receive text from a web page using a text box.

The Arduino code for this project follows the format of the Ajax I/O web server from the Arduino Ethernet shield web server tutorial, except that it calls the JavaScript function that sends the GET request when the button on the web page is clicked rather than periodically sending the GET request to the Arduino web server.

The video below shows the Arduino web page being accessed by a web browser and text being sent to the Arduino.

 

Arduino Hardware, Software and HTML Page Setup

Hardware

An Arduino Uno and Arduino Ethernet shield with 2GB micro SD card were used to test the project. Most Arduino boards that are compatible with the Ethernet shield should work.

Setup

Copy the HTML from below to a file called index.htm on the micro SD card and insert it into the Ethernet shield micro SD card socket. Load the Arduino sketch from below to the Arduino — first change the MAC and IP address in the sketch to suit your own network. In the Arduino IDE Serial Monitor window, set the baud rate at the bottom of the window to 115200.

Running the Project

With the Arduino connected to the Ethernet network, first open the Serial Monitor window, then open a web browser and surf to the IP address set in the sketch. Text can be typed into the text box on the web page and sent to the Arduino. The Arduino will display the text in the Serial Monitor window if the line of text is not too long (the length is set by buffer arrays in the Arduino code).

Arduino Text Box Sketch

The Arduino text box sketch listing called text_area is shown below. Copy and paste it to the Arduino IDE.

/*--------------------------------------------------------------
  Program:      text_area

  Description:  Arduino web server that gets text from an HTML
                textarea text box on the hosted web page.
                The web page is stored on the micro SD card.
  
  Date:         23 June 2015
 
  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   90
// size of buffer that stores the incoming string
#define TXT_BUF_SZ   50

// 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;                    // the web page file on the SD card
char HTTP_req[REQ_BUF_SZ] = {0}; // buffered HTTP request stored as null terminated string
char req_index = 0;              // index into HTTP_req buffer
char txt_buf[TXT_BUF_SZ] = {0};  // buffer to save text to

void setup()
{
    // disable Ethernet chip
    pinMode(10, OUTPUT);
    digitalWrite(10, HIGH);
    
    Serial.begin(115200);       // 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.");
    
    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
                // limit the size of the stored received HTTP request
                // 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");
                    // remainder of header follows below, depending on if
                    // web page or XML page is requested
                    // Ajax request - send XML file
                    if (StrContains(HTTP_req, "ajax_inputs")) {
                        // send rest of HTTP header
                        client.println("Content-Type: text/xml");
                        client.println("Connection: keep-alive");
                        client.println();

                        // print the received text to the Serial Monitor window
                        // if received with the incoming HTTP GET string
                        if (GetText(txt_buf, TXT_BUF_SZ)) {
                          Serial.println("\r\nReceived Text:");
                          Serial.println(txt_buf);
                        }
                    }
                    else {  // web page request
                        // send rest of HTTP header
                        client.println("Content-Type: text/html");
                        client.println("Connection: keep-alive");
                        client.println();
                        // 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();
                        }
                    }
                    // 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)
}

// extract text from the incoming HTTP GET data string
// returns true only if text was received
// the string must start with "&txt=" and end with "&end"
// if the string is too long for the HTTP_req buffer and
// "&end" is cut off, then the function returns false
boolean GetText(char *txt, int len)
{
  boolean got_text = false;    // text received flag
  char *str_begin;             // pointer to start of text
  char *str_end;               // pointer to end of text
  int str_len = 0;
  int txt_index = 0;
  
  // get pointer to the beginning of the text
  str_begin = strstr(HTTP_req, "&txt=");
  if (str_begin != NULL) {
    str_begin = strstr(str_begin, "=");  // skip to the =
    str_begin += 1;                      // skip over the =
    str_end = strstr(str_begin, "&end");
    if (str_end != NULL) {
      str_end[0] = 0;  // terminate the string
      str_len = strlen(str_begin);

      // copy the string to the txt buffer and replace %20 with space ' '
      for (int i = 0; i < str_len; i++) {
        if (str_begin[i] != '%') {
          if (str_begin[i] == 0) {
            // end of string
            break;
          }
          else {
            txt[txt_index++] = str_begin[i];
            if (txt_index >= (len - 1)) {
              // keep the output string within bounds
              break;
            }
          }
        }
        else {
          // replace %20 with a space
          if ((str_begin[i + 1] == '2') && (str_begin[i + 2] == '0')) {
            txt[txt_index++] = ' ';
            i += 2;
            if (txt_index >= (len - 1)) {
              // keep the output string within bounds
              break;
            }
          }
        }
      }
      // terminate the string
      txt[txt_index] = 0;
      got_text = true;
    }
  }

  return got_text;
}

// 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;
}


Text Box HTML Page

Copy the HTML below and save it to a file called index.htm on the SD card.

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>Text Box using textarea</title>
        <script>

        strText = "";
        
        function SendText()
        {
            nocache = "&nocache=" + Math.random() * 1000000;
            var request = new XMLHttpRequest();
            
            strText = "&txt=" + document.getElementById("txt_form").form_text.value + "&end=end";
            
            request.open("GET", "ajax_inputs" + strText + nocache, true);
            request.send(null);
        }
        </script>
    </head>

    <body onload="GetArduinoIO()">
        <form id="txt_form" name="frmText">
            <textarea name="form_text" rows="10" cols="40"></textarea>
        </form>
        <input type="submit" value="Send Text" onclick="SendText()" />
    </body>

</html>

How the Text Box Sketch Works

JavaScript embedded in the web page sends the text from the text box to the Arduino as part of a HTTP GET request when the button on the web page is clicked.

Format of the String

This image shows what the string looks like before it is sent to the Arduino.

HTML Text Box and Text String

HTML Text Box and Text String

The text from the text box is put between &txt= and &end=end before being sent. The Arduino uses this text to find the string in the incoming HTTP GET request.

When the text reaches the Arduino, it has been altered with the spaces in the text changed to %20 as shown in the image below.

String from the Text Box Received by Arduino

String from the Text Box Received by Arduino

The Arduino sketch must change %20 in the text back to spaces.

Processing the String in the Arduino Sketch

The function GetText() is used to get the text box string from the incoming HTTP GET request. The HTTP_req array holds the beginning of the incoming GET request as shown in the above image — starting with GET /ajax_inputs&txt…

The GetText() function first gets a pointer to the beginning of the text box string by searching for &txt= and then terminating the string when it finds &end. A for loop is used to copy the string to the txt array (which is a pointer to the global txt_buf array). While the copying is taking place, the code looks for spaces that are encoded as %20 and changes them into spaces.

Limitations of the Arduino Text Box Sketch

The sketch is limited by the size of the buffer that saves the incoming HTTP GET request as well as the size of the array that stores the string from the text box. These two array buffers have been kept small so that the code will be able to run on an Arduino Uno.

If the string from the text box is too big for the HTTP buffer on the Arduino so that the string is truncated before the terminating &end, then the text will not be displayed in the Serial Monitor window because the GetText() function will return false.

This is just a simple demonstration that uses GET to send text. It would be better to send the text using POST instead and this will be added as a tutorial at a later stage.

 

Switching LEDs on from a Web Page using Arduino

The Arduino and Ethernet shield are set up as a web server. The web page that the server hosts allows two LEDs to be controlled by clicking checkboxes on the web page.

This video shows the Arduino and web page in action:

The LEDs are interfaced to pin 2 and pin 3 of the Arduino.

This is an answer to a question from the Arduino web server blog entry relating to the article on Arduino Web Server LED Control. The question is on how to control two LEDs from a web page.

The Arduino sketch for this solution:
eth_websrv_LED2.zip
This code is a hack from some previous code that I wrote and so does not look exactly like the code from the sketch that the question is related to.

Changing Text and Button Color using AJAX and the Arduino Web Server

This is an answer to the question about part 7 of the Arduino Ethernet shield web server tutorial (using Ajax) posted on the blog entry for the tutorial. The question is on how to change the text that shows the status of a switch on a web page as well as the color of the button on the web page. The switch is interfaced to the Arduino Ethernet web server.

This video shows the solution to the question in operation, but the color of the button text is changed instead of the color of the button (because it looked better):

 

The Arduino sketch for this solution sends the following web page (HTML with JavaScript and CSS) to the web browser:

HTML with JavaScript and CSS from Arduino Web Server

Click for a bigger image

 

 

 

 

 

 

 

 

 

The sketch for this solution can be downloaded here: eth_websrv_AJAX_switch_colour.zip

Solution Explanation

The idea is to send the status of the switch (either ON or OFF) as well as the button HTML code with text color to the web browser. This is done every time that an Ajax call is made. An initial Ajax call is made when the page loads. Additional Ajax calls are made every time the button on the web page is clicked. In other words the status of the switch is displayed on the web page the first time that the web page is loaded and then every time that the button on the web page is clicked. The button text will be colored red when the switch is open and colored green when the switch is closed.

The Arduino sketch is a modified version of the sketch from part 7 of the tutorial: Arduino Web Server Switch Status Using AJAX Manually

The following is modified in the sketch:

First of all, a div is created with the ID “data_to_update”. Both elements to be updated (text and button) will be inserted here by JavaScript code after they have been received from the Arduino web server. This will occur after an Ajax call. The div looks as follows on the web page:
<div id="data_to_update">
<p id="switch_txt">Switch state: Not requested...</p>
</div>

The div could have been left empty as everything in the div will be replaced after the Ajax call.

Next, the following line of JavaScript code replaces everything between the opening and closing div tags when the Arduino responds to the Ajax call:
document.getElementById("data_to_update").innerHTML = this.responseText;

The last modification to the code is to make sure the JavaScript function GetSwitchState() is called at least once when the page is loaded. If it is not called, the button will not be visible on the web page and therefore the user will not be able to click the button to make Ajax calls. The onload event is used to run this function once when the web page loads by adding a call in the body tag of the HTML page:
<body onload="GetSwitchState()">

In the Arduino sketch, the Arduino responds to the Ajax call from the web page by sending the button status text and the button with color information. This is done in the Arduino sketches’ GetSwitchState() function. This function checks the state of the interfaced push-button switch and responds as follows:
If the switch is open, it sends OFF paragraph text and red button text:
cl.println("<p>Switch state: OFF</p><button type=\"button\" style=\"color: red;\" onclick=\"GetSwitchState()\">Get Switch State</button>");
The above line of Arduino code sends these lines of HTML with CSS to color the button text red:
<p>Switch state: OFF</p>
<button type="button" style="color: red;" onclick="GetSwitchState()">Get Switch State</button>");

If the switch is closed, this line of Arduino code is run:
cl.println("<p>Switch state: ON</p><button type=\"button\" style=\"color: green;\" onclick=\"GetSwitchState()\">Get Switch State</button>");
which sends this HTML with CSS code to color the button text green:
<p>Switch state: ON</p>
<button type="button" style="color: green;" onclick="GetSwitchState()">Get Switch State</button>");