Sending serial commands with an Ethernet Shield

I just purchased an Ethernet Shield and have it successfully connected to my Arduino Uno. I've even been able to run the Blink LED sketch from Ovidiu Predescu's example (http://www.webweavertech.com/ovidiu/weblog/archives/000484.html. Unfortunately, I don't understand how it works, but it works.

For my particular project, I really need to be able to send a serial command to my Arduino from a remote web site. To be more specific, I would like to send something like an "H" when a form button on a web page is pressed to turn an LED on. Then, if a second form button is pressed, it should send an "L" to turn the LED off. This is similar to some of the basic serial communication example sketches, just with an Ethernet Shield in the middle.

I'm having a hard time understanding how to make the transition from local serial control to remote serial control using something like Ovidiu's example mentioned above. Any suggestions?

Below is some simple server test code which you should be able to tweek from a text box setup to a dual button. This code switches pin 4 high/low as directed.

//zoomkat 12-18-10
//routerbot code
//for use with IDE 0021
//open serial monitor to see what the arduino receives
//use the \ slash to escape the " in the html 
//address will look like http://192.168.1.102:84/ when submited
//for use with W5100 based ethernet shields

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

byte mac[] = { 
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //physical mac address
byte ip[] = { 
  192, 168, 1, 102 }; // ip in lan
byte gateway[] = { 
  192, 168, 1, 1 }; // internet access via router
byte subnet[] = { 
  255, 255, 255, 0 }; //subnet mask
Server server(84); //server port

String readString; 

//////////////////////

void setup(){

  pinMode(4, OUTPUT); //pin selected to control
  //start Ethernet
  Ethernet.begin(mac, ip, gateway, subnet);
  server.begin();

  //enable serial data print 
  Serial.begin(9600); 
  Serial.println("servertest1"); // so I can keep track of what is loaded
}

void loop(){
  // Create a client connection
  Client client = server.available();
  if (client) {
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();

        //read char by char HTTP request
        if (readString.length() < 100) {

          //store characters to string 
          readString += c; 
          //Serial.print(c);
        } 

        //if HTTP request has ended
        if (c == '\n') {

          ///////////////
          Serial.println(readString);

          //now output HTML data header

          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println();

          client.println("<HTML>");
          client.println("<HEAD>");
          client.println("<TITLE>Arduino GET test page</TITLE>");
          client.println("</HEAD>");
          client.println("<BODY>");

          client.println("<H1>HTML form GET example</H1>");

          client.println("<FORM ACTION=\"http://192.168.1.102:84\" method=get >");

          client.println("Pin 4 \"on\" or \"off\": <INPUT TYPE=TEXT NAME=\"LED\" VALUE=\"\" SIZE=\"25\" MAXLENGTH=\"50\">
");

          client.println("<INPUT TYPE=SUBMIT NAME=\"submit\" VALUE=\"Change Pin 4!\">");

          client.println("</FORM>");

          client.println("
");

          client.println("</BODY>");
          client.println("</HTML>");

          delay(1);
          //stopping client
          client.stop();

          /////////////////////
          if(readString.indexOf("on") >0)//checks for on
          {
            digitalWrite(4, HIGH);    // set pin 4 high
            Serial.println("Led On");
          }
          if(readString.indexOf("off") >0)//checks for off
          {
            digitalWrite(4, LOW);    // set pin 4 low
            Serial.println("Led Off");
          }
          //clearing string for next read
          readString="";

        }
      }
    }
  }
}

Just tried it, it works great. However, this uses the Arduino to host the HTML code for controlling the input/output. I would prefer to set up a separate web site to send commands rather than tax the Arduino to try to supply this information. I also found this example, which I also have working - but I'm not sure how to submit the correct URL without actually taking the user to that page. If I could do this and stay on the same page, it would be perfect.

http://bildr.org/2011/06/arduino-ethernet-pin-control/

That example still uses the arduino as a web server, there is just no actual HTML interface, instead it uses GET. If you really dont want the arduino to be a server at all, you would need to set up a separate website hosted elsewhere that updates a status page when you change an option. The arduino would then have to poll this status page as a client and parse the results. I think that this would actually be more resource intensive.

If you want to have a site that is more complex than what can be hosted from the arduino, then set up your website and form on another computer. Then, have it submit the form information via GET to your arduino's ip, with code similar to that second example.

Below is some simple internet servo control test code I made for testing. The control web page is hosted where ever you want (even on your desktop), and the server code operates on the arduino to control the servos.

Okay, I'm getting close using my second example above, but I'm not quite getting the functionality I expected. By the way, I'm not against using some information stored on the Arduino for web server purposes, but I really want to host the main site elsewhere so I don't have a hundred people trying to connect to my Arduino at the same time.

Here is the simple example I'm trying:

Running on the Arduino:

#include <Ethernet.h>
#include <SPI.h>
boolean reading = false;

  byte ip[] = { 192, 168, 1, 177 };   //ip address to assign the arduino
  byte gateway[] = { 192, 168, 1, 1 }; //ip address of the gatewa or router
  byte subnet[] = { 255, 255, 255, 0 };
  byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x78, 0x97 };
  Server server = Server(80); //port 80

void setup(){

  pinMode(7, OUTPUT);

  Ethernet.begin(mac, ip, gateway, subnet);
  server.begin();
}

void loop(){

  // listen for incoming clients, and process request.
  checkForClient();

}

void checkForClient(){

  Client client = server.available();

  if (client) {

    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    boolean sentHeader = false;

    while (client.connected()) {
      if (client.available()) {

        if(!sentHeader){
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println();
          sentHeader = true;
        }

        char c = client.read();

        if(reading && c == ' ') reading = false;
        if(c == '?') reading = true; //found the ?, begin reading the info

        if(reading){
          Serial.print(c);

           switch (c) {
            case '7':
            //add code here to trigger on 7
              triggerPin(7, client);
              break;
          }
        }

        if (c == '\n' && currentLineIsBlank)  break;

        if (c == '\n') {
          currentLineIsBlank = true;
        }else if (c != '\r') {
          currentLineIsBlank = false;
        }
      }
    }

    delay(1); // give the web browser time to receive the data
    client.stop(); // close the connection:

  } 
}

void triggerPin(int pin, Client client){
  digitalWrite(pin, HIGH);
  delay(500);
  digitalWrite(pin, LOW);
  delay(500);
}

The web site source code for interaction:

<form name="test" action="http://xx.xx.xxx.xxx/?7" method="GET">
<input type="submit" value="Blink" />
</form>

(I filtered out the IP address I am using.) When I use the method "GET" the form does not work. When I use the method "POST" the form works, but it takes the user to a new blank web page. I want the user to stay on the same page.

Update: I see you were using an inline frame for the page that loads. Is it possible to have an inline frame load which is transparent to the user?

Update 2: I found an answer. I simply include an inline frame and added the following attribute:
style="display:none"

I think what you're missing is that this code still has people connecting to your arduino, acting as a server. However, instead of doing so directly, they are doing so through a form on a separate webpage. It really doesn't reduce the load on the arduino by very much at all.

The only way to eliminate using your arduino as a server entirely is to have your separate website save the form data to a file/page on the server. Then, have the arduino poll that file, and act on the data it contains.

Understood. I think the Arduino load is minimal. Now I just need to find a way to allow only one user to use the web site at a time so I don't overload the incoming form requests to the Arduino.

You can minimize the space used on the arduino by making simple DIY buttons like in the below code (only works when the arduino is serving the page). In the referenced link, the inline frame is a bit bucket for the info returned from the server. This is handy when embedding streaming video via javascript in the web page, and keeps from having the entire page refresh. The below pan/tilt uses this (note a wire in the cam has finally broken after ~6 years so the pix is only so-so)

http://web.comporium.net/~shb/wc2000-PT-script.htm

//zoomkat 12-18-10
//routerbot code
//for use with IDE 0021
//open serial monitor to see what the arduino receives
//use the \ slash to escape the " in the html 
//address will look like http://192.168.1.102:84/ when submited
//for use with W5100 based ethernet shields

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

byte mac[] = { 
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //physical mac address
byte ip[] = { 
  192, 168, 1, 102 }; // ip in lan
byte gateway[] = { 
  192, 168, 1, 1 }; // internet access via router
byte subnet[] = { 
  255, 255, 255, 0 }; //subnet mask
Server server(84); //server port

String readString; 

//////////////////////

void setup(){

  pinMode(4, OUTPUT); //pin selected to control
  //start Ethernet
  Ethernet.begin(mac, ip, gateway, subnet);
  server.begin();

  //enable serial data print 
  Serial.begin(9600); 
  Serial.println("servertest1"); // so I can keep track of what is loaded
}

void loop(){
  // Create a client connection
  Client client = server.available();
  if (client) {
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();

        //read char by char HTTP request
        if (readString.length() < 100) {

          //store characters to string 
          readString += c; 
          //Serial.print(c);
        } 

        //if HTTP request has ended
        if (c == '\n') {

          ///////////////
          Serial.println(readString);

          //now output HTML data header

          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println();

          client.println("<HTML>");
          client.println("<HEAD>");
          client.println("<TITLE>Arduino GET test page</TITLE>");
          client.println("</HEAD>");
          client.println("<BODY>");

          client.println("<H1>HTML form GET example</H1>");
          
          client.println("<a href=\"/?on\">ON</a>"); 
          client.println("<a href=\"/?off\">OFF</a>"); 

          client.println("
");

          client.println("</BODY>");
          client.println("</HTML>");

          delay(1);
          //stopping client
          client.stop();

          /////////////////////
          if(readString.indexOf("on") >0)//checks for on
          {
            digitalWrite(4, HIGH);    // set pin 4 high
            Serial.println("Led On");
          }
          if(readString.indexOf("off") >0)//checks for off
          {
            digitalWrite(4, LOW);    // set pin 4 low
            Serial.println("Led Off");
          }
          //clearing string for next read
          readString="";

        }
      }
    }
  }
}