4 minute read
Software
132 Hacking Electronics
Software
This sketch is one of the most complicated in the book. However, it is one that can easily be used as a template for other hacks using an Arduino as a web server.
Let’s break this sketch down and look at it a section at a time.
Figure 6-27 Selecting an IP address to use
// web_relay
#include <SPI.h> #include <Ethernet.h>
// MAC address just has to be unique. This should work byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // The IP address will be dependent on your local network:
CHAPTER 6: Hacking Arduino 133
byte ip[] = { 192, 168, 1, 30 }; EthernetServer server(80); int relayPin = A0; char line1[100];
Two libraries have to be included for use with the Ethernet Shield: “SPI” and “Ethernet.” Libraries contain a useful collection of functions for, say, a shield. They greatly simplify the writing of sketches as they can just make use of the library functions.
The “SPI” library is for a kind of serial communication that the Arduino uses to send instructions to the Ethernet Shield, and the “Ethernet” library defines some useful functions for us to use with the Ethernet Shield.
After the two variables that define the Mac address and IP address, the next command creates a new “EthernetServer” object that is used every time we want to do something with the Ethernet. We then define the “relayPin” to use and also create a line buffer of 100 characters that is used later in the code when reading the header that arrives from a browser when you navigate to the page being served by the Arduino.
void setup() { pinMode(relayPin, OUTPUT); Ethernet.begin(mac, ip); server.begin(); }
The setup function initializes the Ethernet library using the Mac and IP addresses that we set earlier. It also sets the pin mode of the “relayPin” to be an OUTPUT.
void loop() { EthernetClient client = server.available(); if (client) { while (client.connected()) { readHeader(client); if (! pageNameIs("/")) { client.stop(); return; } digitalWrite(relayPin, valueOfParam('a'));
134 Hacking Electronics
client.println("HTTP/1.1 200 OK"); client.println("Content-Type: text/html"); client.println();
// send the body client.println("<html><body>"); client.println("<h1>Relay Remote</h1>");
client.println("<h2><a href='?a=1'/>On</a></h2>"); client.println("<h2><a href='?a=0'/>Off</a></h2>"); client.println("</body></html>");
client.stop(); } } }
The loop function is responsible for servicing any requests that come to the web server from a browser. If a request is waiting for a response, then calling “server.available” will return us a “client”. If client exists (tested by the first “if” statement), we can then determine if it is connected to the web server by calling “client.connected”.
We will come to the “readHeader” function later. This function and “pageNameIs” are used to determine that the browser is actually contacting the page for setting the relay. This is because browsers will often send two requests to a server page, one to try and find an icon for the web site, and a second to the page itself. This code allows us to ignore the icon request.
The next line sets the relay pin using “digitalWrite”. The value it sets the output to is whatever value the request parameter “a” is set to. This will be either “1” or “0”.
The next three lines of code print out a return header. This just tells the browser what type of content to display. In this case, just HTML.
Once the header has been written, it simply remains to write the remaining HTML back to the browser. This must include the usual “<html>” and “<body>” tags, and also includes a “<h1>” header tag and two “<h2>” tags that are also hyperlinks to this same page, but with the request parameter “a” set to either “0” or “1”.
Finally, “client.stop” tells the browser that the message is complete and the browser will display the page.
CHAPTER 6: Hacking Arduino 135
void readHeader(EthernetClient client) { // read first line of header char ch; int i = 0; while (ch != '\n') { if (client.available()) { ch = client.read(); line1[i] = ch; i ++; } } line1[i] = '\0'; Serial.println(line1); }
The final three functions in the sketch are general-purpose functions that I tend to use over and over again when making an Arduino web server like this.
The first, “readHeader”, reads the header of the request coming from the browser into the buffer “line”. We can then use this in the next two functions.
boolean pageNameIs(char* name) { // page name starts at char pos 4 // ends with space int i = 4; char ch = line1[i]; while (ch != ' ' && ch != '\n' && ch != '?') { if (name[i-4] != line1[i]) { return false; } i++; ch = line1[i]; } return true; }
The function “pageNameIs” returns true if the page name part of the header matches the argument supplied. This is what