Arduino: A Quick-Start Guide, Second Edition (2015)
Part II. Eleven Arduino Projects
Chapter 10. Networking with Arduino
With a stand-alone Arduino, you can create countless fun and useful projects. But as soon as you turn the Arduino into a networking device, you open up a whole new world of possibilities.
You now have access to all of the information on the Internet, so you could turn your Arduino into a nice, geeky weather station simply by reading data from a weather service. You can also turn the Arduino into a web server that provides sensor data for other devices or computers on your network.
We’ll start with a “naked” Arduino that doesn’t have any network capabilities. As you’ll see, you can still attach it to the Internet and Tweet[91] messages as long as you connect it to a PC.
For our second project, we’ll improve the situation dramatically with an Ethernet shield. Your Arduino will become a full-blown network device that can directly access IP services, such as a Daytime service. This will turn your Arduino into a very accurate clock.
The skills you learn in this chapter are the basis for more advanced techniques and the projects you’ll create in the next chapter.
What You Need
1. An Ethernet shield for the Arduino
2. A TMP36 temperature sensor
3. Some wires
4. A breadboard
5. An Arduino board, such as the Uno, Duemilanove, or Diecimila
6. A USB cable to connect the Arduino to your computer
Using Your PC to Transfer Sensor Data to the Internet
Remember when you connected your PC to the Internet, oh, around twenty years ago? It all started with a 38,400 baud modem, Netscape Navigator 3, and one of those AOL floppy disks or CD-ROMs you got in the mail. Today you probably have broadband access via cable, satellite, or DSL, and it’s probably available everywhere in your house via Wi-Fi. So, we’ll start by using your existing connection to connect your Arduino to the Internet.
In the following figure, you can see a typical setup for connecting an Arduino to the Internet. A program runs on your PC and communicates with the Arduino using the serial port. Whenever the application needs Internet access, the program on the PC deals with it. Using this architecture, you can Tweet interesting sensor data.
We’ll build a system that Tweets a message when the temperature in your working room or office exceeds a certain threshold—32 degrees Celsius (90 degrees Fahrenheit). Build the temperature sensor example from Increasing Precision Using a Temperature Sensor, again (try to do it without looking at the circuit) and upload the following sketch to your Arduino:
Ethernet/TwitterTemperature/TwitterTemperature.ino |
|
Line 1 |
#define CELSIUS |
- |
const unsigned int TEMP_SENSOR_PIN = 0; |
- |
const unsigned int BAUD_RATE = 9600; |
- |
const float SUPPLY_VOLTAGE = 5.0; |
5 |
void setup() { |
- |
Serial.begin(BAUD_RATE); |
- |
} |
- |
|
- |
void loop() { |
10 |
const int sensor_voltage = analogRead(TEMP_SENSOR_PIN); |
- |
const float voltage = sensor_voltage * SUPPLY_VOLTAGE / 1024; |
- |
const float celsius = (voltage * 1000 - 500) / 10; |
- |
#ifdef CELSIUS |
- |
Serial.print(celsius); |
15 |
Serial.println(" C"); |
- |
#else |
- |
Serial.print(9.0 / 5.0 * celsius + 32.0); |
- |
Serial.println(" F"); |
- |
#endif |
20 |
delay(5000); |
- |
} |
This is nearly the same sketch we’ve used before. Keep in mind that you have to set SUPPLY_VOLTAGE to 3.3 in line 4 if you’re using an Arduino that runs with 3.3V instead of 5V.
We support both Celsius and Fahrenheit values now, and you can use a preprocessor constant to control which unit should be used. If you set the constant CELSIUS in the first line, the application outputs the temperature in degree Celsius. If you remove the first line or turn it into a comment line, the application will use Fahrenheit.
To change the application’s behavior, we use the #ifdef preprocessor directive. It checks whether a certain preprocessor constant has been set, and then it compiles code conditionally. In our case, it will compile the Celsius-to-Fahrenheit formula in line 17 only if the constant CELSIUS has not been set.
Upload the sketch, and it will output the current temperature to the serial port every five seconds. Its output looks as follows:
|
27.15 C |
|
26.66 C |
|
27.15 C |
What we need now is a program running on your PC that reads this output and Tweets a message as soon as the temperature is greater than 32 degrees Celsius (90 degrees Fahrenheit). We could use any programming language that is capable of reading from a serial port and that supports Twitter, but because Processing[92] has excellent support for Twitter and the serial port, we’ll use it for this project.
The Arduino and the Internet of Things (IoT)
Today for most people the Internet is a network of computers that can be used for looking up entertaining, useful, or interesting information. In recent years the nature of the Internet has changed tremendously. More and more autonomous and automated devices have joined the Internet. For many people it’s normal already to use a smartphone to surf the web, and in a not-too-distant future, devices such as toasters and refrigerators will be part of the Internet, too. This is the Internet of Things, where everyday objects are able to send and receive data over a network connection.
With the advent of cheap open-source hardware and sensors, web services for publishing sensor data have become popular over the past few years. Such services allow you to publish, read, and analyze sensor data. People from all over the world publish data from their weather stations, environmental sensors, and so on, and they make it available for free on the Internet.
These web services offer even more functions today and make it easy to turn an Arduino into a full-blown member of the Internet of Things—that is, you can integrate your Arduino with Google Mail, Facebook, eBay, and so on.
Popular services are Xively[93] and Temboo.[94] In principle, they all work the same: you register an account, and you get back an API key. Then you can use this key to authenticate against the service and upload sensor data or use other functions of their API. Usually, these services also offer special Arduino libraries that help you to build your applications.
Registering an Application with Twitter
Before we start coding, we have to register our application at the Twitter website to get API keys and an OAuth access token.[95] OAuth is an authentication scheme that allows applications to use other applications’ resources. In our case, we’ll grant our very own application the right to update our Twitter feed without using our Twitter username and password.
To get all of the information needed, create a new application in the applications section of the Twitter website.[96] After you’ve logged in, click the Create New App button and fill out the form:
After you’ve created your new application, go to the Permissions tab and set the application’s access level to Read and Write. Then navigate to the API Keys tab and press the Create My Access Token button. It can take a few moments-refresh the page a few times until the access token is available.
The API Keys tab should contain all information that you need to allow your application to modify your Twitter status. It should look similar to this:
Copy the API key, the API secret, the access token, and the access token secret. You’ll need them in the next section, when we Tweet messages using Processing.
Tweeting Messages with Processing
Processing doesn’t have Twitter support, but in Processing programs we have direct access to Java libraries, and you can find several good Twitter libraries for Java. One of them is Twitter4J.[97] We’ll use it because it’s very mature and has excellent OAuth support.
Download Twitter4J from its website[98] and unpack it to a temporary folder. Depending on the version you’ve downloaded, you’ll find a file named twitter4j-core-x.y.z.jar or twitter4j-core-x.y.z-SNAPSHOT.jar in the folder. Open the Processing IDE, create a new sketch, and then drag and drop the jar file to the IDE. (The jar file will automatically be copied to a local folder named code.) That’s all you have to do to give your application access to the Twitter4J library.
We proceed with some boilerplate code:
Ethernet/TweetTemperature/TweetTemperature.pde |
|
|
import processing.serial.*; |
|
|
|
final float MAX_WORKING_TEMP = 32.0; |
|
final int LINE_FEED = 10; |
|
final int BAUD_RATE = 9600; |
|
final int FONT_SIZE = 32; |
|
final int WIDTH = 320; |
|
final int HEIGHT = 240; |
|
final String API_KEY = "<YOUR API KEY>"; |
|
final String API_SECRET = "<YOUR API SECRET>"; |
|
final String ACCESS_TOKEN = "<YOUR ACCESS TOKEN>"; |
|
final String ACCESS_TOKEN_SECRET = "<YOUR ACCESS TOKEN SECRET>"; |
|
|
|
Serial _arduinoPort; |
|
float _temperature; |
|
boolean _isCelsius; |
|
PFont _font; |
|
|
|
void setup() { |
|
size(WIDTH, HEIGHT); |
|
_font = createFont("Arial", FONT_SIZE, true); |
|
println(Serial.list()); |
|
_arduinoPort = new Serial(this, Serial.list()[0], BAUD_RATE); |
|
_arduinoPort.clear(); |
|
_arduinoPort.bufferUntil(LINE_FEED); |
|
_arduinoPort.readStringUntil(LINE_FEED); |
|
} |
|
|
|
void draw() { |
|
background(255); |
|
fill(0); |
|
textFont(_font, FONT_SIZE); |
|
textAlign(CENTER, CENTER); |
|
if (_isCelsius) |
|
text(_temperature + " \u2103", WIDTH / 2, HEIGHT / 2); |
|
else |
|
text(_temperature + " \u2109", WIDTH / 2, HEIGHT / 2); |
|
} |
As usual, we import the serial libraries for communicating with the Arduino, and then we define some constants we’ll need later. Most of them contain the credentials we need to access the Twitter service. With MAX_WORKING_TEMP, you can define at which temperature the application starts to Tweet. This can be a degrees Celsius or Fahrenheit value. The rest defines a few values we need for the user interface, such as the screen width, the screen height, and the font size.
After that, we define a few member variables. _arduinoPort contains a reference to the Serial object we use to communicate with the Arduino. _temperature contains the last temperature value we received from the Arduino, and _isCelsius is true if the value we read was in degrees Celsius. We need the _font variable to define the font we use to output the temperature on the screen.
In the setup method, we set the window size and create the font we’re going to use. Then we print out a list of all serial devices available. We initialize our _arduinoPort variable with the first one we find, hoping that it’s the Arduino. You could also loop through the list automatically and search for something that looks like an Arduino port name, but that’d be fragile, too.
We call the clear method to empty the serial port’s buffer. With bufferUntil, we make sure that we get notified about serial events only when we’ve received a linefeed character. The call to readStringUntil ensures that we start with a fresh serial buffer that doesn’t contain an incomplete line of data.
The draw method prints the last temperature we received on the screen. It sets the background color to white using background and the text color to black using fill. Then it sets the font and ensures the text we are printing is centered horizontally and vertically. Eventually, we print the temperature using the text method. To make the result look nicer, we use the official Unicode characters for degrees Celsius (\u2103) and Fahrenheit (\u2109).
Now let’s implement the business logic of our “Take me to the beach” alarm:
Ethernet/TweetTemperature/TweetTemperature.pde |
|
|
void serialEvent(Serial port) { |
|
final String arduinoData = port.readStringUntil(LINE_FEED); |
|
if (arduinoData != null) { |
|
final String[] data = split(trim(arduinoData), ' '); |
|
if (data.length == 2 && |
|
(data[1].equals("C") || data[1].equals("F"))) |
|
{ |
|
_isCelsius = data[1].equals("C"); |
|
_temperature = float(data[0]); |
|
if (Float.isNaN(_temperature)) |
|
return; |
|
println(_temperature); |
|
int sleepTime = 5 * 60 * 1000; |
|
if (_temperature > MAX_WORKING_TEMP) { |
|
tweetAlarm(); |
|
sleepTime = 120 * 60 * 1000; |
|
} |
|
try { |
|
Thread.sleep(sleepTime); |
|
} |
|
catch(InterruptedException ignoreMe) {} |
|
} |
|
} |
|
} |
|
|
|
void tweetAlarm() { |
|
ConfigurationBuilder cb = new ConfigurationBuilder(); |
|
cb.setDebugEnabled(true) |
|
.setOAuthConsumerKey(API_KEY) |
|
.setOAuthConsumerSecret(API_SECRET) |
|
.setOAuthAccessToken(ACCESS_TOKEN) |
|
.setOAuthAccessTokenSecret(ACCESS_TOKEN_SECRET); |
|
TwitterFactory tf = new TwitterFactory(cb.build()); |
|
Twitter twitter = tf.getInstance(); |
|
try { |
|
Status status = twitter.updateStatus( |
|
"Someone, please, take me to the beach!" |
|
); |
|
println( |
|
"Successfully updated status to '" + status.getText() + "'." |
|
); |
|
} |
|
catch (TwitterException e) { |
|
e.printStackTrace(); |
|
} |
|
} |
Tweeting Arduinos
A useful and interesting hardware kit is Botanicalls.[99] It checks whether your plants need water, and if they do, it sends a reminder message via http://twitter.com/. As soon as you water the plant, Botanicalls dutifully sends a “Thank You” message. Although the official version of Botanicalls is a specialized piece of hardware, you can build it using an Arduino.[100]
Botanicalls certainly make your life easier. Whether the Tweeting Vending Machine[101] improves your life is a matter of taste. Users of this modified vending machine have to identify themselves using an RFID card. Whenever they buy some sweets, the vending machine Tweets their name and what they’ve bought.
Whenever new data arrives on the serial port, the Processing runtime environment calls the serialEvent method. There we try to read a line of text, and then we check whether it contains a decimal number followed by a blank and a C or an F character. This ensures we’ve read an actual temperature data set and not some digital garbage.
If we got a syntactically correct temperature data set, we convert it into a float object and check to see whether it’s greater than MAX_WORKING_TEMP. (No one should be forced to work at temperatures that high!) If yes, we call tweetAlarm and Tweet a message to encourage some followers to rescue us. Then we wait for two hours until our next check. Otherwise, we wait five minutes and check the temperature again.
tweetAlarm updates our Twitter status and is simple. In good old Java tradition, we create a new Twitter instance using a TwitterFactory. The factory expects a ConfigurationBuilder object that we have initialized with our Twitter application credentials. Finally, we invoke updateStatus. If everything went fine, we print a success message to the console. If anything goes wrong, updateStatus will raise an exception, and we’ll print its stack trace for debugging purposes.
That’s all the code we need, so connect your Arduino to your PC and run it! The following figure shows what happens on Twitter when the temperature in my working room is higher than 32 degrees Celsius. (For your first tests, you might have to change 32.0 to a smaller value. If you don’t have to change it, why aren’t you at the beach?)
Using a full-blown PC as an Internet relay for your Arduino is convenient, but it’s also overkill for most applications. In the next section, you’ll learn how to turn an Arduino into a real networking device.
Communicating Over Networks Using an Ethernet Shield
In the previous section, you learned how to build network applications with an Arduino by using your PC’s network connection. This approach works nicely, but it also has a few disadvantages. The biggest problem is that you need a complete PC, while for many applications the Arduino’s hardware capabilities would be sufficient. In this section, you’ll learn how to solve this problem with an Ethernet shield.
Usually, you can’t connect a naked Arduino to a network. Not only are its hardware capabilities too limited, but also most Arduino boards don’t have an Ethernet port. That means you can’t plug an Ethernet cable into them, and to overcome this limitation, you have to use an Ethernet shield. Such shields come with an Ethernet chip and Ethernet connectors and turn your Arduino into a networking device immediately. You only have to plug it in.
You can choose from several products (the following figure shows some of them); they all are good and serve their purpose well. For prototyping, I prefer the “official” shield,[102] because it comes with sockets for all pins and has a microSD card slot. Alternatively, you can use the Arduino Ethernet,[103] an Arduino board that comes with an Ethernet port and doesn’t need a separate shield.
Hardware is only one aspect of turning an Arduino into a network device. We also need some software for network communication. The Arduino IDE comes with a convenient Ethernet library that contains a few classes related to networking. We’ll use it now to access a Daytime service on the Internet.
A Daytime service[104] returns the current date and time as an ASCII string. Daytime servers listen on either TCP or UDP port 13. You can find many Daytime services on the Internet; one of them runs at time.nist.gov. Before we use the service programmatically with an Arduino, see how it works using the telnet command:
|
maik> telnet time.nist.gov 13 |
|
Trying 192.43.244.18... |
|
Connected to time.nist.gov. |
|
Escape character is '^]'. |
|
56965 14-11-04 20:33:03 00 0 0 867.4 UTC(NIST) * |
|
Connection closed by foreign host. |
As soon as the telnet command connects to the Daytime server, it sends back the current time and date.[105] Then the service shuts down the connection immediately.
Here’s an implementation of exactly the same behavior for an Arduino with an Ethernet shield:
Ethernet/TimeServer/TimeServer.ino |
|
Line 1 |
#include <SPI.h> |
- |
#include <Ethernet.h> |
- |
const unsigned int BAUD_RATE = 9600; |
- |
const unsigned int DAYTIME_PORT = 13; |
5 |
|
- |
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; |
- |
IPAddress my_ip(192, 168, 2, 120); |
- |
IPAddress time_server(192, 43, 244, 18); // time.nist.gov |
- |
EthernetClient client; |
10 |
|
- |
void setup() { |
- |
Serial.begin(BAUD_RATE); |
- |
Ethernet.begin(mac, my_ip); |
- |
} |
15 |
|
- |
void loop() { |
- |
delay(1000); |
- |
Serial.print("Connecting..."); |
- |
|
20 |
if (client.connect(time_server, DAYTIME_PORT) <= 0) { |
- |
Serial.println("connection failed."); |
- |
} else { |
- |
Serial.println("connected."); |
- |
delay(300); |
25 |
while (client.available()) { |
- |
char c = client.read(); |
- |
Serial.print(c); |
- |
} |
- |
|
30 |
Serial.println("Disconnecting."); |
- |
client.stop(); |
- |
} |
- |
} |
First, we include the Ethernet library and define a constant for the Daytime service port. (We also have to include the SPI library, because the Ethernet library depends on it.) Then we define a few global variables:
· mac contains the MAC address we’re going to use for the Ethernet shield. A MAC address is a 48-bit number that uniquely identifies a network device.[106] Usually the manufacturer sets this identifier, but for the Ethernet shield, we have to set it ourselves; we use an arbitrary number.
Important note: the MAC address has to be unique on your network. If you connect more than one Arduino, make sure they all have different MAC addresses! Also note that the Arduino Ethernet and the latest versions of the Ethernet shields have a MAC address that can be found on a sticker on their back side.
· Whenever you connect your PC to the Internet, it probably gets a new IP address via the Dynamic Host Configuration Protocol (DHCP).[107] For most Arduino applications, a DHCP implementation is comparatively costly, so you usually assign an IP address manually. (See how to use DHCP in Using DHCP and DNS.) In most cases, this will be a local address in the 192.168.x.y range; we store this address in the my_ip variable using the Arduino’s IPAddress class. In older versions of the Arduino IDE, you had to use a byte array to store IP addresses. You can still do so, because byte arrays will be converted to IPAddress objects automatically if needed.
· To turn domain names such as time.nist.gov into an IP address, you need access to the Domain Name System (DNS). The Arduino’s standard library supports DNS, but we’ll find out the IP address ourselves. (See how to use DNS in Using DHCP and DNS.) We assign it to time_server. The telnet command already turned the Daytime service domain name into an IP address for us. Alternatively, you can use one of the following commands to determine a domain name’s IP address:
|
maik> host time.nist.gov |
|
time.nist.gov has address 192.43.244.18 |
|
maik> dig +short time.nist.gov |
|
192.43.244.18 |
|
maik> resolveip time.nist.gov |
|
IP address of time.nist.gov is 192.43.244.18 |
|
maik> ping -c 1 time.nist.gov |
|
PING time.nist.gov (192.43.244.18): 56 data bytes |
|
64 bytes from 192.43.244.18: icmp_seq=0 ttl=48 time=173.598 ms |
|
|
|
--- time.nist.gov ping statistics --- |
|
1 packets transmitted, 1 packets received, 0.0% packet loss |
|
round-trip min/avg/max/stddev = 173.598/173.598/173.598/0.000 ms |
Back to the source code! In line 9, we create a new EthernetClient object. This class is part of the Ethernet library and allows us to create network clients that connect to a certain IP address and port. In former versions of the Arduino IDE, this class was named Client.
Now we have to initialize the Ethernet shield itself; we do this in line 13 in the setup function. We have to invoke Ethernet.begin, passing it our MAC and IP address. Then we initialize the serial port so that we can output some debug messages. At this point, we’ve initialized all the components we need, so we can finally connect to the Daytime server and read its output.
Please note that you can also pass the IP address of your network gateway and your subnet mask to Ethernet.begin. This is necessary if you don’t connect the Arduino directly to the Internet but use a router or a cable modem instead. In this case, you can pass the gateway address as follows:
|
// ... |
|
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; |
|
IPAddress my_ip(192, 168, 2, 120); |
|
IPAddress time_server(192, 43, 244, 18); // time.nist.gov |
|
// Insert IP address of your domain name system below: |
|
IPAddress dns(8, 8, 8, 8); |
|
// Insert IP address of your cable or DSL router below: |
|
IPAddress gateway(192, 168, 13, 254); |
|
|
|
EthernetClient client(time_server, DAYTIME_PORT); |
|
void setup() { |
|
Ethernet.begin(mac, my_ip, dns, gateway); |
|
Serial.begin(BAUD_RATE); |
|
} |
|
// ... |
The loop function of our sketch starts with a short delay, allowing all components to initialize properly. This is necessary because the Ethernet shield is an autonomous device that is capable of working in parallel to the Arduino. In line 20, we try to connect to the Daytime service. If the connection cannot be established, we print an error message. Otherwise, we wait for 300 milliseconds to give the service some preparation time, and then we read and print its output character by character.
The client’s interface is similar to that of the Serial class. The available function checks whether some bytes are still available, and read returns the next byte. At the end, we call stop to disconnect from the service, and then we start again.
Note that our program isn’t completely robust. If the server needs longer than 300 milliseconds to deliver its data, our program will not read it. In our case it’s not a big deal, but for more critical applications, you’d better wait until data is available and add a timeout mechanism.
Compile and upload the program to the Arduino. Then open the serial monitor, and you should see something like this:
|
Connecting...connected. |
|
56807 14-11-04 16:34:18 50 0 0 259.2 UTC(NIST) * |
|
Disconnecting. |
|
Connecting...connected. |
|
56807 14-11-04 16:34:20 50 0 0 515.5 UTC(NIST) * |
|
Disconnecting. |
We’re finished! Our Arduino is directly connected to the Internet, and it even does something useful: we’ve turned it into a very accurate clock.
All in all, networking with an Arduino doesn’t differ much from networking with a PC, if you use the Ethernet shield. In the next section, you’ll learn how to use services such as DHCP and DNS with an Arduino.
More Fun with Networking Arduinos
Wearables and e-textiles are getting more and more popular, and they’re still a good way to impress your colleagues and friends. Different types of interactive T-shirts are available in every well-stocked geek shop. Some of them show the current Wi-Fi strength, while others come with a full-blown built-in electronic rock guitar.
With an Arduino LilyPad,[108] a Bluetooth dongle, and an Android phone, you can build a T-shirt that displays the current number of unread emails in your inbox.[109]
Not only can you show the number of unread email messages, you can also use the LilyPad and an XBee module to teach children important information about bees and their behavior.[110]
Using DHCP and DNS
In the preceding section, you learned how to access IP services the “hard” way. That is, you had to know your own IP address and the services’s IP address, too. For your home projects, this is convenient and efficient.
As soon as you create projects that have to run in unknown environments, you have to use a more flexible approach. If you’re going to build an actual product based on a networking Arduino, you certainly don’t want your customers to enter an unused IP address and upload a new sketch before they can use it.
In such cases you need a more flexible solution. In this section you’ll determine service addresses using the Domain Name System (DNS), and you’ll obtain the Arduino’s IP address using the Dynamic Host Configuration Protocol (DHCP).
Here’s a version of our time server example that uses DHCP and DNS:
Ethernet/TimeServerDnsDhcp/TimeServerDnsDhcp.ino |
|
Line 1 |
#include <SPI.h> |
- |
#include <Ethernet.h> |
- |
|
- |
const unsigned int BAUD_RATE = 9600; |
5 |
const unsigned int DAYTIME_PORT = 13; |
- |
|
- |
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; |
- |
char* time_server = "time.nist.gov"; |
- |
EthernetClient client; |
10 |
|
- |
void setup() { |
- |
Serial.begin(BAUD_RATE); |
- |
if (Ethernet.begin(mac) == 0) { |
- |
for (;;) { |
15 |
Serial.println("Could not obtain an IP address using DHCP."); |
- |
delay(1000); |
- |
} |
- |
} else { |
- |
print_ip_address(Ethernet.localIP()); |
20 |
} |
- |
} |
- |
|
- |
|
- |
void loop() { |
25 |
delay(1000); |
- |
Serial.print("Connecting..."); |
- |
if (client.connect(time_server, DAYTIME_PORT) <= 0) { |
- |
Serial.println("connection failed."); |
- |
} else { |
30 |
Serial.println("connected."); |
- |
delay(300); |
- |
|
- |
while (client.available()) { |
- |
char c = client.read(); |
35 |
Serial.print(c); |
- |
} |
- |
|
- |
Serial.println("Disconnecting."); |
- |
client.stop(); |
40 |
} |
- |
} |
- |
|
- |
void print_ip_address(IPAddress ip) { |
- |
const unsigned int OCTETS = 4; |
45 |
Serial.print("We've got the following IP address: "); |
- |
for (unsigned int i = 0; i < OCTETS; i++) { |
- |
Serial.print(ip[i]); |
- |
if (i != OCTETS - 1) |
- |
Serial.print("."); |
50 |
} |
- |
Serial.println(); |
- |
} |
This program does the same as the program in the previous section, but it doesn’t contain any explicit IP addresses. Apart from that, it doesn’t differ much from the original version. The first difference is in line 8. Here we no longer declare the variable time_server as an IPAddress object but as a string. The string contains the name of the server we’re going to connect to.
In line 13, we no longer pass our own IP address to Ethernet’s begin method. In this case, begin tries to obtain an unique IP address using a DHCP server in the local network. If it cannot obtain an IP address, we start an endless loop that prints an error message every second. Otherwise, we print the IP address we’ve got, using a small helper function named print_ip_address.
Eventually, in line 27, we pass our time_server string to the connect method. Note that we didn’t change the line; we’ve only changed the type of the time_server variable. If connect gets a string and not an IPAddress object, it tries to look up the IP address belonging to the server name stored in the string using DNS.
Run the program, and you’ll see output similar to the following:
|
We've got the following IP address: 192.168.2.113 |
|
Connecting...connected. |
|
|
|
56807 14-11-04 16:34:18 50 0 0 259.2 UTC(NIST) * |
|
Disconnecting. |
You might ask yourself why you shouldn’t enjoy the convenience of DHCP and DNS all the time. First of all, DHCP and DNS are two more things that can go wrong. Debugging embedded systems is hard enough already, so you shouldn’t make it harder by using services that you don’t absolutely need. For most applications, hardwired IP addresses will do the job.
Another reason is code size. DHCP and DNS support will increase significantly the size of the resulting binary file. Adding DHCP support to our time service program increased its size by nearly 3,500 bytes. Still, DHCP and DNS are useful tools for certain applications, and it’s great that they’re now part of the Arduino’s standard library.
In the next chapter, you’ll learn how to implement another important network protocol: you will send emails using an Arduino.
Alternative Networking Technologies
Ethernet is one of the most popular and most powerful networking technologies. Using an Ethernet shield, you can easily connect your Arduino to the Internet both as a client and as a server.
Depending on your project’s needs, it’s sometimes better to use a wireless connection. With a Wi-Fi shield,[111] you can easily turn your Arduino into a wireless networking device.
But often you don’t need the full power of Ethernet, especially if you need only short-range communication in a personal area network. You can choose from a variety of options, but Bluetooth and ZigBee[112] are probably the most popular. Excellent solutions for both of them are available for the Arduino.
Finally, you can even participate in cellular networks with your Arduino. Plug in a GSM shield[113] and your SIM card, and you are ready to go.
What If It Doesn’t Work?
Networks are complex and complicated beasts, and many things can go wrong when trying the examples in this chapter. The most common problems are the following:
· You have chosen the wrong serial port in the Processing application. By default, the application uses the first serial port it can find. It might be that you have connected your Arduino to another port. In this case, you have to change the index 0 in the statement arduinoPort = new Serial(this, Serial.list()[0], BAUD_RATE); accordingly.
· You forgot to plug the Ethernet cable into the Ethernet shield.
· Your network router has a MAC whitelist that allows only certain MAC addresses to access the network. Make sure that the MAC address you use in your sketches is whitelisted. Check your router’s documentation.
· You have used the same MAC address twice on your network.
· You’ve used an IP address that isn’t allowed in your network or that is used already by another device. Double-check your IP address.
· You’ve used the wrong credentials for accessing a service such as Twitter. Make sure you use the right OAuth tokens.
· Twitter doesn’t allow duplicate Tweets. So, whenever your application fails to Tweet a message, make sure you haven’t Tweeted it recently.
· Networks have become very reliable over the last couple of decades, but sometimes they are still fragile. So, it might well be that connections fail or that you run into timeouts. Try increasing the delays in your sketches.
Exercises
· Search the Web for other Ethernet shield projects and build at least one of them. A very ambitious project tries to implement a complete web browser on the Arduino, for example.[114]
· Register an account at Xively, Temboo, or any other IoT service. Work through their tutorials and create at least one Arduino application.
· Try at least one additional networking technology, such as Bluetooth, Wi-Fi, or XBee, with your Arduino.
Footnotes
[91] |
http://twitter.com |
[92] |
https://processing.org/ |
[93] |
http://xively.com |
[94] |
https://www.temboo.com/ |
[95] |
http://en.wikipedia.org/wiki/Oauth |
[96] |
https://apps.twitter.com |
[97] |
http://twitter4j.org/ |
[98] |
http://twitter4j.org/en/index.html#download |
[99] |
http://www.botanicalls.com/ |
[100] |
http://www.botanicalls.com/archived_kits/twitter/ |
[101] |
http://www.popsugar.com/tech/Tweeting-Vending-Machine-34558986 |
[102] |
http://www.arduino.cc/en/Main/ArduinoEthernetShield |
[103] |
http://www.arduino.cc/en/Main/ArduinoBoardEthernet |
[104] |
http://en.wikipedia.org/wiki/DAYTIME |
[105] |
See http://www.nist.gov/physlab/div847/grp40/its.cfm for a detailed description of the date string’s format. |
[106] |
http://en.wikipedia.org/wiki/Mac_address |
[107] |
http://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol |
[108] |
http://arduino.cc/en/Main/ArduinoBoardLilyPad |
[109] |
http://blog.makezine.com/2010/03/30/email-counting-t-shirt/ |
[110] |
http://www.instructables.com/id/Interactive-Bee-Game/ |
[111] |
http://arduino.cc/en/Main/ArduinoWiFiShield |
[112] |
http://en.wikipedia.org/wiki/Zigbee |
[113] |
http://arduino.cc/en/Main/ArduinoGSMShield |
[114] |
http://hackaday.io/project/3116-pip-arduino-web-browser |