Arduino Web Client to External Server

hey there all,

I want to control a bunch of relays with an arduino over the internet via an Ethernet shield, however I need the arduino set up as a client connecting to an external server since there will be more then one arduino. This is where I'm stuck what do I need on the server side (php scripts, sql databases, etc...). what I would like to know and need some help with is the code to send/ receive information to/from the server (Arduino side)and all the server side code. Any information regarding this would be very helpful and would be much appreciated

thanks PhayilBoy

It is not clear what you want to do.

I want to control a bunch of relays with an arduino over the internet via an Ethernet shield

This is clear. The Arduino will act as a server, serving up a web page with a form that allows any client to submit the page. The Arduino as server will then parse the submitted data and make the appropriate changes.

however I need the arduino set up as a client connecting to an external server since there will be more then one arduino.

This is not. If you have more than one Arduino, you need more than one Ethernet shield and more than one port, since each Arduino server needs its own port.

If you expect to have a server somewhere that clients can send submit requests to, then separately, the Arduinos as clients would access the data, using different scripts, and do stuff.

There is no way to have a web server push data to the Arduinos, if the Arduino is a client.

This is where I'm stuck what do I need on the server side (php scripts, sql databases, etc...). what I would like to know and need some help with is the code to send/ receive information to/from the server (Arduino side)and all the server side code.

Exactly the same "stuff" as you would need for any other client to access the data. There is nothing Arduino-specific in what you want to do.

Some pictures might make what you want to do clearer.

So what I wanted was a single webpage hosted on a server that has a bunch of radio buttons(or just buttons) that the user can access, so they can turn on or off the relays connected to the arduinos. The arduinos would be connected to the server through there own ethernet shields and control the relays depending on what the user has clicked on the webpage. (I hope that made sense).

So, the only thing common between the client/server relationship involving the PC and the client/server relationship involving the Arduinos is the server and the data store.

There does not appear to be anything difficult about your project. You need to set up a server and have it server up a page to the PC client. The page will have a form with a submit button. The submit action will send a GET request back to the same server, with additional data in the request.

The server will parse the request, and store the data somewhere.

The Arduino clients will make similar GET requests (not identical) to learn what to do.

Thanks paulS,

The server will parse the request, and store the data somewhere.

when you say store the data somewhere, will I need an sql database to store the data?

PhayilBoy

when you say store the data somewhere, will I need an sql database to store the data?

That is entirely up to you. I have no idea how much data you are talking about, how often it will change, how many PC clients you expect, or how many Arduinos you have. I have no idea how you will segregate the data for one Arduino from that for another.

The project seems to barely involve the Arduinos. Most of your questions are completely unrelated to Arduino (not uninteresting, not stupid by any means, just unrelated).

Thanks for all the help Paul,
yeah sorry I didn't intend to ask such unrelated questions, but thanks for answering them anyway

thanks again,
PhayilBoy

Below is some test code you can experiment with. It serves up a web page with clickable control buttons to a client browser. Relay kits like below might be of interest.

http://www.ecrater.com/p/3528455/fp08-8-relay-board-kit-for-pic

//zoomkat 3-17-12
//simple button GET server code to control servo and arduino pin 4
//for use with IDE 1.0
//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
//Powering a servo from the arduino usually DOES NOT WORK.
//note that the below bug fix may be required
// http://code.google.com/p/arduino/issues/detail?id=605 

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

#include <Servo.h> 
Servo myservo;  // create servo object to control a servo 

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
EthernetServer 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();

  myservo.write(90); //set initial servo position if desired
  myservo.attach(7);  //the pin for the servo co
  //enable serial data print 
  Serial.begin(9600); 
  Serial.println("server LED test 1.0"); // so I can keep track of what is loaded
}

void loop(){
  // Create a client connection
  EthernetClient 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); //print to serial monitor for debuging 

          client.println("HTTP/1.1 200 OK"); //send new page
          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>Zoomkat's simple Arduino button</H1>");
          
          // DIY buttons
          client.println("<a href=\"/?on\"\">ON</a>"); 
          client.println("<a href=\"/?off\"\">OFF</a>
"); 

          // mousedown buttons
          client.println("
<input type=\"button\" value=\"ON\" onmousedown=\"location.href ('/?on');\"/>"); 
          client.println("<input type=\"button\" value=\"OFF\" onmousedown=\"location.href ('/?off');\"/>");        
          
          // mousedown radio buttons
          client.println("

<input type=\"radio\" value=\"ON\" onmousedown=\"location.href ('/?on');\"\">ON</>"); 
          client.println("<input type=\"radio\" value=\"OFF\" onmousedown=\"location.href ('/?off');\"\">OFF</>");        
 
          client.println("</BODY>");
          client.println("</HTML>");
 
          delay(1);
          //stopping client
          client.stop();

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

        }
      }
    }
  }
}

@zoomkat

Many Thanks for the example code you posted.

I assume that the section :

          // DIY buttons
          client.println("<a href=\"/?on\"\">ON</a>"); 
          client.println("<a href=\"/?off\"\">OFF</a>
"); 

          // mousedown buttons
          client.println("
<input type=\"button\" value=\"ON\" onmousedown=\"location.href ('/?on');\"/>"); 
          client.println("<input type=\"button\" value=\"OFF\" onmousedown=\"location.href ('/?off');\"/>");        
          
          // mousedown radio buttons
          client.println("

<input type=\"radio\" value=\"ON\" onmousedown=\"location.href ('/?on');\"\">ON</>"); 
          client.println("<input type=\"radio\" value=\"OFF\" onmousedown=\"location.href ('/?off');\"\">OFF</>");

would be a case of selecting which 1 of the 3 types suits the application ?

Also, would it be correct to use an If() statement to determine, from an existing variable, what the current state is, and only dislpay the opposing button / option ? For example, if the integer Relay1state == 0 ( relay is off ) then only display the options to turn it on.

I see you gave the example of the URL to call with :84 for the port number. Would this usually require port 84 on my router to be re-directed to the IP or MAC address of the ethernet shield ?

In addition to this code ( serving up the interface page from the Arduino to the web ) I also need to log some temperature readings ( DS18B20 values ) to a web server based file from within the same sketch. I have the code working for the readings, and can display to the serial monitor and to my LCD, but where / how would I add code to the sketch to send data to the web page ? ( Ethernet board arriving tomorrow, so really keen to have code prepared )

My existing php code on the web server, that does receive data and write it to a txt file is :

$Le = "\r\n";
$eXdata = Trim($_GET["data"]);

	$newdir=date("Y-m-d---H:i:s");
	$writeline = $newdir . "," . $eXdata . $Le;
	$handle = fopen("serveit.txt", 'a');
	fwrite($handle,$writeline);
	fclose($handle);

I changed your code to work on PC with Processing. Will be getting data from XBee to serve it.
Why does DIY buttons work, but not the other 2 on PC?

import processing.net.*;
Server myServer;
String readString=".";
void setup(){
size(200,200);
//myClient=new Client(this,"192.168.1.2",80);
myServer=new Server(this,69);
}
void draw(){
delay(1000);  //reduce CPU
Client client=myServer.available();
if(client!=null) {
println("New connection");
boolean currentLineIsBlank = true;

while (true) {  //uses break
char c=char(client.read());
if(c!=-1) {
        // Serial.write(c);
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
  if (readString.length() < 100) readString+=c;
  if (c == '\n' && currentLineIsBlank) {
    
          client.write("HTTP/1.1 200 OK\n"); //send new page
          client.write("Content-Type: text/html\n");
          client.write("\n");

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

          client.write("<H1>Zoomkat's simple Arduino button</H1>\n");
          
          // DIY buttons
          client.write("<a href=\"/?on\"\">ON</a>\n"); 
          client.write("<a href=\"/?off\"\">OFF</a>
\n"); 

          // mousedown buttons
          client.write("
<input type=\"button\" value=\"ON\" onmousedown=\"location.href ('/?on');\"/>\n"); 
          client.write("<input type=\"button\" value=\"OFF\" onmousedown=\"location.href ('/?off');\"/>\n");        
          
          // mousedown radio buttons
          client.write("

<input type=\"radio\" value=\"ON\" onmousedown=\"location.href ('/?on');\"\">ON</>\n"); 
          client.write("<input type=\"radio\" value=\"OFF\" onmousedown=\"location.href ('/?off');\"\">OFF</>\n");        
 
          client.write("</BODY>\n");
          client.write("</HTML>\n");
          
//println(readString);
          if(readString.indexOf("on") >0) print("On");
          if(readString.indexOf("off") >0) print("Off");
          readString=".";
    
    break;   
    }
  if (c == '\n') currentLineIsBlank = true;
  else if (c != '\r') currentLineIsBlank = false;
}}
delay(1);
client.stop();
}}  //draw, new connection

This is an alternative if you don't have an Ethernet Shield. Works great with XBee to get data from Uno to PC.
This is Processing code for PC, not Arduino code:

It serves a simple web page with pin values. You must write the Arduino code to send the data serially to PC first.
But that's the easy part right?

import processing.net.*;
Server myServer;
void setup(){
size(200,200);
//myClient=new Client(this,"192.168.1.2",80);
myServer=new Server(this,69);
}
void draw(){
delay(1000);  //reduce CPU
Client client=myServer.available();
if(client!=null) {
println("New connection");
boolean currentLineIsBlank = true;

while (true) {  //uses break
char c=char(client.read());
if(c!=-1) {
        // Serial.write(c);
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
  if (c == '\n' && currentLineIsBlank) {
    client.write("HTTP/1.1 200 OK\n");
    client.write("Content-Type: text/html\n");
    client.write("Connnection: close\n");
    client.write("\n");
    client.write("<!DOCTYPE HTML>\n");
    client.write("<html>\n");
        // add a meta refresh tag, so the browser pulls again every 5 seconds:
    client.write("<meta http-equiv=\"refresh\" content=\"5\">\n");
    client.write("Hi\n");
    
    //client.write your digital and analog pin values from XBee here
    
    client.write("</html>\n");
    break;   
    }
  if (c == '\n') currentLineIsBlank = true;
  else if (c != '\r') currentLineIsBlank = false;
}}
delay(10);
client.stop();
}}  //draw, new connection

The onmousedown event is a javascript thing that probably requires a browser that supports javascript actions. The DIY buttons are just clickable links.

http://www.w3schools.com/html5/html5_ref_eventattributes.asp

Yes, I agree the PC browser must have Javascript for those 2. Certainly mine does. What does the Processing code need to make this work? Did I do something wrong when I translated it from Arduino to Processing? I assume it worked on Uno?