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.
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!
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(); }
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. |