Saturday, September 19, 2015

Controlling Your Hardware from the Web Using Arduino

Using Arduino Ethernet shield 2 to control a hardware from the web is discussed. Arduino Ethernet 2 Library is used to implement in an Arduino Uno board as a server in an example as well as a client in an another example. The latest version Arduino IDE ( 1.7.6 in our case ) is used in the following examples. An Arduino Uno board with Ethernet shield 2 is shown below.


Figure. Arduino Uno paired with Arduino Ethernet shield 2.


As a Web Server


The MAC address for your particular Ethernet Shield 2 is required to initialize Ethernet. The MAC address can be found on the sticker on the shield 2. For this example, to assign the Arduino with an IP address automatically, your router is required to be DHCP enabled.
As a web server, Arduino assumes that it is end of communication when it receives blank line ( two consecutive new line characters - "\n" without any other character in between except "\r" ) from a client.
// MAC address that is found on the sticker pasted on Ethernet shield v2
byte mac[]={0x90, 0xA2, 0xDA, 0x0F, 0xF9, 0x51};

// Initialize the Ethernet server (port 80 is default for HTTP)
EthernetServer server(80);
EthernetClient client;

Ethernet shield 2 also has an SD Card reader. Since, the SPI interface is shared with the SD card reader also, it is required to disable pin 4 (enable pin) by pulling it to high output state when using Ethernet.
pinMode(4, OUTPUT);//to disable SD card
digitalWrite(4, HIGH);
  
Serial.print("Beginning Ethernet...");
if (!Ethernet.begin(mac)) { Serial.println("failed."); return; }
else {Serial.println("success.");}
  
Serial.println("Starting server...");
server.begin();
  
Serial.print("IP address: ");
Serial.println(Ethernet.localIP());

In this example, a red LED at a digital output and a green LED at an analog output are controlled from a web browser. A switch is also attached to the Arduino board and its status is also updated on the web page every 5 seconds. When the program is started, an IP address assigned by the router is printed on the serial output.


Figure. IP address of the Arduino Shield 2 is shown in Serial Monitor.


The code for the example is shown below. The source can be found on GitHub - Arduino Ethernet Shield 2.
// Name: web_server_led.ino
// By: Yan Naing Aye
// Description: Arduino Uno paired with Ethernet shield v2 as a web server 
// that controls an LED
// http://cool-emerald.blogspot.sg/

#include <SPI.h>
#include <Ethernet2.h>

//Start of Declaration for Hardware ------------------------------------
class MyHardware {
   public:
      int RLED_Pin; 
      int RLED_Val;
      int GLED_Pin;   
      int GLED_Val;
      int SW1_Pin;   
      int SW1_Val;
      MyHardware();
      void begin();
      void update();
};
MyHardware::MyHardware() {
  RLED_Pin=5;   
  RLED_Val=0;
  GLED_Pin=6;   
  GLED_Val=128;
  SW1_Pin=0;   
  SW1_Val=0;
}
void MyHardware::begin() {
  pinMode(RLED_Pin, OUTPUT);
  digitalWrite(RLED_Pin, RLED_Val);
  
  pinMode(GLED_Pin, OUTPUT);
  analogWrite(GLED_Pin, GLED_Val);
  
  pinMode(SW1_Pin, INPUT);
  SW1_Val = digitalRead(SW1_Pin);
}
void MyHardware::update() { 
 //Start of Switch 1 input-------------------- 
  SW1_Val = digitalRead(SW1_Pin);
  //End of Switch 1 ------------------------------------
  
}
MyHardware H;
//End of Declaration for Hardware ------------------------------------

// MAC address that is found on the sticker pasted on Ethernet shield v2
byte mac[]={0x90, 0xA2, 0xDA, 0x0F, 0xF9, 0x51};

// Initialize the Ethernet server (port 80 is default for HTTP)
EthernetServer server(80);
EthernetClient client;

enum ServerState { Chk_END, Chk_NORMAL, Chk_CONTROL };
ServerState s = Chk_END;

char c;

void setup() {
  Serial.begin(9600);
  H.begin();
  
  pinMode(4, OUTPUT);//to disable SD card
  digitalWrite(4, HIGH);
  
  Serial.print("Beginning Ethernet...");
  if (!Ethernet.begin(mac)) { Serial.println("failed."); return; }
  else {Serial.println("success.");}
  
  Serial.println("Starting server...");
  server.begin();
  
  Serial.print("IP address: ");
  Serial.println(Ethernet.localIP());
}

void loop() {
  // listen for incoming clients
  client = server.available();
  if (client) {
    Serial.println("New client.");
    while (client.connected()) {
      if (client.available()) {
        c = client.read(); Serial.write(c); //read and echo        
        if (s == Chk_CONTROL) ProcessCmd(c);
        
        //check and update the server state
        if(c=='?') s=Chk_CONTROL; 
        else if(c=='\n'){ 
          if(s==Chk_END) { HTTP_Response(); break;}
          else s=Chk_END;
        } 
        else if(c!='\r') { s=Chk_NORMAL; }
      }
    }
    delay(1);// give the web browser time to receive the data
    client.stop();// close the connection
    Serial.println("Client disconnected.");
    Ethernet.maintain();
  }
  H.update();
}

void ProcessCmd(char c) {
  //Start of red LED digital output--------------------
  if(c=='R') {            
    H.RLED_Val=client.parseInt(); 
    digitalWrite(H.RLED_Pin, H.RLED_Val); 
  }
  //End of red LED ------------------------------------
  
  //Start of Green LED analog output--------------------
  else if(c=='G') {            
    H.GLED_Val=client.parseInt(); 
    analogWrite(H.GLED_Pin, H.GLED_Val);
  }
  //End of Green LED ------------------------------------
}
void HTTP_Response() {
  // send a standard http response header
  client.println("HTTP/1.1 200 OK");
  client.println("Content-Type: text/html");
  client.println("Connection: close"); 
  client.println("Refresh: 5");  // refresh the page automatically every 5 sec
  client.println();
  client.println("<!DOCTYPE HTML>");
  client.println("<html>");
  client.println("<head>");
  client.println("<meta name='referrer' content='none'>");
  client.println("<script>");
  client.println("function SendCtrl(c,v){");
  client.println("window.location.href = \"?\"+c+\"=\"+v;");
  client.println("}");
  client.println("</script>");
  client.println("</head>");
  client.println("<body>");
  
  //Start of red LED digital output--------------------
  client.println("<div>");
  char* cStr[]={"255", "128"};
  char* vStr[]={"1", "0"};
  client.println("<br/>Click this button to toggle the red LED: ");
  client.print("<button name='R' type='button' style='background-color: rgb(");
  client.print(cStr[H.RLED_Val]); 
  client.println(",0,0);'onclick='SendCtrl(this.name,this.innerHTML);'>");
  client.println(vStr[(int)H.RLED_Val]);
  client.println("</button><br/>");
  client.println("</div>");
  //End of red LED ------------------------------------
  
  //Start of Green LED analog output--------------------
  client.println("<div>");
  client.println("<br/>Drag the slider to adjust the brightness of green LED: ");
  client.print("<input name='G' type='range' value='");
  client.print(String(H.GLED_Val)); 
  client.println("' min='0' max='255'");
  client.println(" onchange='SendCtrl(this.name,this.value);'>");
  client.println("</div>");
  //End of Green LED ------------------------------------
  
  //Start of Switch 1 input--------------------
  client.println("<div>");
  if(!H.SW1_Val) { client.println("<p style='color:rgb(0,255,0);'>SW1 ON</p>");}
  else { client.println("<p style='color:rgb(128,0,0);'>SW1 OFF</p>");}
  client.println("</div>");
  //End of Switch 1 ------------------------------------
  
  client.println("</body>");
  client.println("</html>");  
}

After starting the program, when the Ethernet initialization is successful, its IP address can be found on Serial Monitor. That IP address can be input to the address bar of a web browser on the local network to see the hardware status shown on a web page produced by the Arduino board. Toggle button controls the red LED and slide bar controls the brightness of the green LED. The status of the switch attached to the Arduino is also updated on web page by ON, OFF messages.


Figure. Controlling and checking the hardware from a web browser.


A web browser on a mobile phone can also be used when it is connected to the Local network. To allow the hardware to be controlled from the internet, it is better to reserve an IP address for that MAC address on the router and change the router setting to perform port forwarding. It is also good to setup dynamic DNS.



As a Web Client


An example for Web client is shown below.
// Based on a work at https://www.arduino.cc/en/Tutorial/WebClient

#include <SPI.h>
#include <Ethernet2.h>
// MAC address that is found on the sticker pasted on Ethernet shield v2
byte mac[]={0x90, 0xA2, 0xDA, 0x0F, 0xF9, 0x51};

// Initialize the Ethernet server (port 80 is default for HTTP)
char server[]="mc1500.com";//name address for server
char page[]="mcalrp.php";//page to open
EthernetClient client;
void setup() {
  Serial.begin(9600);
  
  pinMode(4, OUTPUT);//to disable SD card
  digitalWrite(4, HIGH);
  
  Serial.print("Beginning Ethernet...");
  if (!Ethernet.begin(mac)) { Serial.println("failed."); return; }
  else {Serial.println("success.");}
  
  // give the Ethernet shield a second to initialize:
  delay(1000);
  
  Serial.print("IP address: ");
  Serial.println(Ethernet.localIP());
  
  Serial.println("connecting...");
  // if you get a connection, report back via serial:
  if (client.connect(server, 80)) {
    Serial.println("connected");
    client.print("GET /");
    client.print(page);
    client.println(" HTTP/1.1");
    client.print("Host: ");
    client.println(server);
    client.println("Connection: close");
    client.println();
  } else {
    Serial.println("connection failed");
  }
}

void loop() {
  // if there are incoming bytes available
  // from the server, read them and print them:
  if (client.available()) {
    char c = client.read();
    Serial.print(c);
  }

  // if the server's disconnected, stop the client:
  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();

    // do nothing forevermore:
    while (true);
  }
}



Reference:
[1] Jeremy Blum, "Exploring Arduino: Tools and Techniques for Engineering Wizardry", Wiley; 1 edition, July 2013. exploringarduino.com
[2] https://www.arduino.cc/en/Tutorial/WebServer
[3] http://labs.arduino.org/Ethernet+2+Library
[4] http://labs.arduino.org/EthernetServer%28%29
[5] https://www.arduino.cc/en/Tutorial/WebClient

No comments:

Post a Comment

Comments are moderated and don't be surprised if your comment does not appear promptly.