Table of Contents

Hello World!

The internet is full of computers. Your Arduino is a (tiny) computer so it's time to go online!

We're using an ethernet shield to connect your Arduino to the outside world. Ethernet is the most common networking system in use and if you look around your home or office you may find ethernet cables running from your PC to your broadband router of office network. Ethernet cables are often called simply “network cables” or “Cat 5”.

Why don't we just connect the ethernet cable straight to the I/O pins on the Arduino? Unfortunately, Arduinos just aren't quick enough to handle driving the ethernet signals directly. The ethernet shield we're using here has a specialised ethernet chip that handles this for us, allowing the Arduino to get on with higher level jobs - like deciding what to send over the network - and leave all the messy work to the shield.

Setting up

Going online

The first step when connecting to the internet is to connect to your local network. This step is pretty unexciting, but it's the base to work from and makes sure that the basics work before we move on.

Computers (and your Arduino) each need a unique hardware address, called a MAC address, to attach to the local network. They also need another unique address to allow communication with other devices, called an IP address.

In this case the Arduino will already know its MAC address but will need to ask the network for an IP address (your computer does this every time you connect to a network using ethernet or WiFi). This first test makes sure that this IP address request works.

Run the Arduino software and open the example Ethernet→DHCPAddressPrinter, it should look a bit like this:

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

// Enter a MAC address for your controller below, make one up!
byte mac[] = {  
  0x02, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 };

// Initialize the Ethernet client library
EthernetClient client;

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);

  // start the Ethernet connection:
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // no point in carrying on, so do nothing forevermore:
    for(;;)
      ;
  }
  // print your local IP address:
  Serial.print("My IP address: ");
  for (byte thisByte = 0; thisByte < 4; thisByte++) {
    // print the value of each byte of the IP address:
    Serial.print(Ethernet.localIP()[thisByte], DEC);
    Serial.print("."); 
  }
  Serial.println();
}

void loop() {

}
IMPORTANT! At the top of the sketch is the hardware MAC address that the Arduino will use. Change this to something random, otherwise you might find someone else's Arduino is using the same address and that would break things! The MAC address is six bytes long, each byte can be a value between 0x00 (decimal 0) and 0xFF (decimal 255) so change the numbers to something else (but leave the first byte at 0x02).

Upload the code to the Arduino and open the serial monitor. You should hopefully see the message “My IP address: xxx.xxx.xxx.xxx” with the Arduino's IP address printed out. If not, call a helper over!

Grabbing some data

So now we're online, what can we do? How about grabbing some data from the web? This is called “scraping” and is a way for your Arduino to get some useful data from the internet.

You could scrape the weather forecast from the Met Office, or the current Bitcoin price, but we're going to find out if the Hacklab is open. This data is online because we use it on our website. The box by the door has green and red buttons, long-pressing the green button sets the lab to “open”, our website updates and we tweet it.

The open/closed value is part of our Space API data, which you can see here. The JSON file is designed to be machine-readable, the important bit we're looking for is the line: “open”: true,

Here's the Arduino code to connect to the server, request the JSON file and then find the lab status line. It's quite long, but commented, so run it and have a read through to see if you can figure out how it works:

/*
  This sketch connects to Edinburgh Hacklab's Space API server and pulls
  a JSON file of the lab's status. The JSON is "parsed" for the open status
  of the lab (either true or false).
  
  The lab's open/closed status is output to the serial port.
 
  This sketch is based on Tom Igoe's (now outdated) Twitter client example and
  uses an Ethernet shield.
 */

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

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = { 
  0x02, 0xAA, 0xBE, 0xCC, 0xBE, 0x01 };

// initialise the Ethernet library instance
EthernetClient server;

// configuration variables
const unsigned long requestInterval = 10000;            // delay (in mS) between requests
char serverName[] = "spaceapi.edinburghhacklab.com";    // Server to connect to
char fileName[]   = "/spaceapi.json";                   // File to request from the server

// state variables to keep track of what we're doing at the moment
boolean requested;                    // whether you've made a request since connecting
unsigned long lastAttemptTime = 0;    // last time you connected to the server, in milliseconds

String currentLine = "";              // string to hold the current line of text from server
String labStatus = "";                // string to hold the labStatus
boolean readingLabStatus = false;     // if we're currently reading the lab status


void setup() {
  // reserve space for the strings:
  currentLine.reserve(256);
  labStatus.reserve(50);

  // Open serial to the host
  Serial.begin(9600);

  // attempt a DHCP connection:
  Serial.println("Attempting to get an IP address using DHCP...");

  if (Ethernet.begin(mac) == 0)
  {
    Serial.println("Failed to configure Ethernet using DHCP");
    // no point in carrying on, so do nothing forever
    while(1);
  }
  
  Serial.print("My IP address:");
  Serial.println(Ethernet.localIP());

  // connect to the server
  connectToServer();
}


// Loop function, keeps checking for the server connection and new characters in
void loop()
{
  if (server.connected())
  {
    if (server.available())
    {
      // read incoming byte
      char inChar = server.read();
      Serial.print(inChar);

      // add incoming byte to end of line
      currentLine += inChar; 

      // if you get a newline, clear the line so it starts filling again
      if (inChar == '\n')
      {
        currentLine = "";
      } 

      // if the current line starts with "  "open": ", the it will
      // be followed by the lab status of "true" or "false". Notice the backslashes
      // to escape the quotes in the string
      if ( currentLine.startsWith("  \"open\": "))
      {
        // labStatus is coming next! Set a flag to start grabbing it
        readingLabStatus = true; 
      }
      
      
      // If we're reading the status in, then add it to the labStatus string until
      // we hit a comma (end of line). Ignore any space characters.
      if(readingLabStatus)
      {
        if (inChar != ',')
        {
          if(inChar != ' ')
          {
            labStatus += inChar;
          }
        } 
        else 
        {
          // we've reached the end of the labStatus string!
          Serial.print("\n\nGot lab status of: ");
          Serial.println(labStatus);
          
          // Reset variables for next time around the loop
          readingLabStatus  = false;
          currentLine       = "";
          labStatus         = "";
          
          // we don't need anything else from the server now so close the connection
          server.stop();
        }
      }
    }   
  }
  else if (millis() - lastAttemptTime > requestInterval)
  {
    // if we're not connected and enough time has passed since
    // the last check attempt to connect again
    connectToServer();
  }
}

void connectToServer()
{
  // attempt to connect, and wait a millisecond
  Serial.println("Connecting to server...");
  
  if (server.connect(serverName, 80))
  {
    String get = "GET ";
    get += fileName;
    get += " HTTP/1.1";
     
    String host = "HOST: ";
    host += serverName;
    
    Serial.println("Making HTTP request...");
    
    // make HTTP GET request to the server
    server.println(get);
    server.println(host);
    server.println();
  }
  
  // note the time of this connect attempt:
  lastAttemptTime = millis();
}   
challenge_yourself.jpg Intermediate
(1) How about adding the LCD module you've already used and displaying the status on that? You'll need to merge in some code from the LCD tutorial but make sure you don't use pins 10, 11, 12 or 13 for the LCD as they're used by the Ethernet shield.

Harder
(2) Scrape some other data! How about the current weather in Edinburgh from Open Weather Map's API? See if you can grab the current temperature.