Arduino: A Quick-Start Guide, Second Edition (2015)

Part II. Eleven Arduino Projects

Chapter 11. Creating a Burglar Alarm with Email Notification

In the preceding chapter, you learned how to access networking services with the Arduino in various ways. Adding networking capabilities to an Arduino enables you to create countless useful projects. In this chapter, you’ll use your newly gained knowledge to build a real-world project: a burglar alarm that uses email notification.

The burglar alarm will send you an email whenever it detects movement in your living room during your absence. To achieve this, you first have to learn how to send emails. You already know a lot about networking with an Arduino, so this won’t be too difficult.

You also need to know how to detect motion. So you’ll also learn how passive infrared (PIR) sensors work and how you can control them with an Arduino.

At the end of the chapter, not only will you have learned some useful skills, but you’ll also feel much safer when the burglar alarm is running.

What You Need

images/parts_burglar_alarm_with_numbers

1.    An Ethernet shield for the Arduino

2.    A PIR motion 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

Emailing from the Command Line

Although email is an important service, only a few people know how it actually works behind the scenes. To send emails from an Arduino, we could choose the easy path and use a PC as an email relay, as we did in Tweeting Messages with Processing, to Tweet messages. As real hackers, we’ll follow a more sophisticated path and implement a subset of the Simple Mail Transfer Protocol (SMTP).[115]

SMTP is a typical Internet protocol. It uses only text, and it is mainly line-based; that is, you exchange information line by line. A typical email consists of only a few attributes: a sender, a receiver, a subject, and a message body. To transmit an email, you have to send a request to an SMTP server. The request has to adhere to the SMTP specification.

Before we send an email using an Arduino and an Ethernet shield, you should learn how to send an email from a command line using the telnet command. To do so, you have to find an SMTP server that actually allows you to send emails. This isn’t as easy as it sounds.

The biggest problem is that over the years, SMTP servers got very good at detecting spam messages. Often you can’t send an email manually using a telnet session because the SMTP server thinks it’s spam. Usually, the SMTP server will accept your commands, but eventually it will tell you that it won’t send your email.

Also, many SMTP servers today insist on encrypted connections, which is a good thing. Implementing the cryptographic algorithms on an Arduino is quite difficult and uses a lot of resources.

So, even with your email provider’s SMTP server, you might run into big problems when you try to use it for sending emails from your Arduino.

To overcome such issues, you can use a special SMTP service, such as SMTP2GO.[116] Most of these services support unencrypted connections and do not restrict access in any way. Of course, you have to pay for the service if the number of emails you send exceeds a certain limit. Most services offer a free account that allows you to send a few emails per day or per month. As of this writing, SMTP2GO allows you to send twenty emails per day for free. If your burglar alarm sends more than twenty emails per day, you should consider moving to a new neighborhood anyway.

To follow this chapter’s email examples, I strongly suggest you register an account at a free SMTP service, such as SMTP2GO. If you have access to an unrestricted SMTP server already, you can use that one, of course.

The following telnet session shows you how to send an email using SMTP2GO:

 

maik> telnet smtpcorp.com 2525

 

Trying 207.58.147.66...

 

Connected to smtpcorp.com.

 

Escape character is '^]'.

 

220 smtpcorp.com ESMTP Exim 4.80 Sun, 01 Jun 2014 18:22:28 +0000

 

EHLO

 

250-smtpcorp.com Hello dslb-088-077-003-169.pools.example.net [88.77.3.169]

 

250-SIZE 52428800

 

250-8BITMIME

 

250-PIPELINING

 

250-AUTH CRAM-MD5 PLAIN LOGIN

 

250-STARTTLS

 

250 HELP

 

AUTH LOGIN

 

334 VXNlcm5hbWU6

 

bm90bXl1c2VybmFtZQ==

 

334 UGFzc3dvcmQ6

 

bm90bXlwYXNzd29yZA==

 

235 Authentication succeeded

 

MAIL FROM:<arduino@example.com>

 

250 OK

 

RCPT TO:<info@example.com>

 

250 Accepted <info@example.com>

 

DATA

 

354 Enter message, ending with "." on a line by itself

 

from:arduino@example.com

 

to:info@example.com

 

subject:This is a test

 

 

 

Really, it is a test!

 

.

 

250 OK id=1WrAQ9-4gfLuZ-5U

 

QUIT

 

221 smtpcorp.com closing connection

 

Connection closed by foreign host.

Although it’s more complex, this session is similar to our Daytime example. We only send more complex commands. (By the way, you don’t have to write the commands in uppercase.) Please note that we’re connecting to port 2525, which is not the standard SMTP port (25). Check your SMTP service provider’s website to see what port you have to use.

We start the session using EHLO. We use the EHLO command to tell the SMTP server that we’d like to use a slightly extended version of SMTP that supports authentication.

After that, we send the AUTH LOGIN command to tell the SMTP server that we’d like to send our username and password. The SMTP server sends back the string VXNlcm5hbWU6. It looks a bit weird at first, but it’s only the string “Username:” encoded using Base64.[117]

We send our username and encode it using Base64, too. The SMTP server’s reply is UGFzc3dvcmQ6 (“Password:”), so we send our password (encoded using Base64).

Note that although Base64 data looks cryptic, it’s not encrypted at all. It’s as insecure as plain text, and there are software developers who can read Base64 data as quickly as regular text. You can find countless Base64 converters on the Web, and there’s a Base64 library for nearly every programming language.

After the authentication succeeds, we tell the server that we’d like to send an email using MAIL FROM:. The email address we provide with this command will be used by the server in case our email bounces back. Note that the server sends back a response line for every request. These responses always start with a three-digit status code.

The RCPT TO: command sets the recipient’s email address. If you’d like to send an email to more than one recipient, you have to repeat the command for each of them.

With the DATA command, we tell the server that we now start to transmit the email’s attributes. Email attributes are mainly a list of key/value pairs where key and value are delimited by a colon. So in the first three lines, we set the attributes “from,” “to,” and “subject,” and they all have the meaning you’d expect when sending an email.

You separate the email’s body from the attributes using a blank line. To mark the end of the email body, send a line containing a single period. Send the QUIT command to end the session with the SMTP server.

You should find a new email in your inbox or in your spam folder. If not, try another SMTP server first. Things can still go wrong, and although simple in theory, SMTP can be a complex beast in practice. SMTP servers often return helpful error messages that might help you quickly solve your problem.

If you want to give your current SMTP server a try, you have to find out its address first. Open a terminal and enter the following:

 

maik> nslookup

 

> set type=mx

 

> gmail.com

 

Server: 192.168.2.1

 

Address: 192.168.2.1#53

 

Non-authoritative answer:

 

gmail.com mail exchanger = 5 gmail-smtp-in.l.google.com.

 

gmail.com mail exchanger = 10 alt1.gmail-smtp-in.l.google.com.

 

gmail.com mail exchanger = 20 alt2.gmail-smtp-in.

 

> exit

This command returns a list of all mail exchange servers (MX) that belong to the domain gmail.com (replace it with the domain of your email provider) and that are available on your network. In this case they all belong to Google Mail, and you cannot use them to send emails from your Arduino, because Google Mail insists on an encrypted connection.

Provided your email provider is less restrictive, you can try to send an email using no authentication and no encryption at all. Open a connection to the SMTP standard port 25 and replace the server name smtp.example.com and all email addresses accordingly in the following telnet session:

 

maik> telnet smtp.example.com 25

 

Trying 93.184.216.119...

 

Connected to smtp.example.com.

 

Escape character is '^]'.

 

220 mx.example.com ESMTP q43si10820020eeh.100

 

HELO

 

250 mx.example.com at your service

 

MAIL FROM: <arduino@example.com>

 

250 2.1.0 OK q43si10820020eeh.100

 

RCPT TO: <info@example.com>

 

250 2.1.5 OK q43si10820020eeh.100

 

DATA

 

354 Go ahead q43si10820020eeh.100

 

from: arduino@example.com

 

to: info@example.com

 

subject: This is a test

 

 

 

Really, this is a test!

 

.

 

250 2.0.0 OK 1286819789 q43si10820020eeh.100

 

QUIT

 

221 2.0.0 closing connection q43si10820020eeh.100

 

Connection closed by foreign host.

Here we send the HELO command (the spelling is correct) to establish a session with the SMTP server that doesn’t need authentication information. The rest of the conversation looks exactly like our previous example.

Sometimes you have to try a few things before you’re able to send an email from your command line. Don’t proceed until you succeed, because sending email from your command line is the basis for the next section, in which you’ll learn how to send emails with an Arduino.

Emailing Directly from an Arduino

To send an email from the Arduino, we’ll basically implement the telnet session from the previous chapter. Instead of hardwiring the email’s attributes into the networking code, we’ll create create something more advanced.

We start with an Email class:

Ethernet/Email/email.h

 

#ifndef __EMAIL__H_

 

#define __EMAIL__H_

 

 

 

class Email {

 

String _from, _to, _subject, _body;

 

 

 

public:

 

 

 

Email(

 

const String& from,

 

const String& to,

 

const String& subject,

 

const String& body

 

) : _from(from), _to(to), _subject(subject), _body(body) {}

 

 

 

const String& getFrom() const { return _from; }

 

const String& getTo() const { return _to; }

 

const String& getSubject() const { return _subject; }

 

const String& getBody() const { return _body; }

 

};

 

 

 

#endif

This class encapsulates an email’s four most important attributes—the email addresses of the sender and the recipient, a subject, and a message body. We store all attributes as String objects.

Wait a minute…a String class? Yes! The Arduino IDE comes with a full-blown string class.[118] It doesn’t have as many features as the C++ or Java string classes, but it’s still way better than messing around with char pointers. You’ll see how to use it in a few paragraphs.

The rest of our Email class is pretty straightforward. In the constructor, we initialize all instance variables, and we have methods for getting every single attribute. We now need an SmtpService class for sending Email objects:

Ethernet/Email/smtp_service.h

Line 1 

#ifndef __SMTP_SERVICE__H_

#define __SMTP_SERVICE__H_

 

#include "email.h"

 

class SmtpService {

boolean _use_auth;

IPAddress _smtp_server;

unsigned int _port;

10 

String _username;

String _password;

 

void read_response(EthernetClient& client) {

delay(4000);

15 

while (client.available()) {

const char c = client.read();

Serial.print(c);

}

}

20 

 

void send_line(EthernetClient& client, String line) {

const unsigned int MAX_LINE = 256;

char buffer[MAX_LINE];

line.toCharArray(buffer, MAX_LINE);

25 

Serial.println(buffer);

client.println(buffer);

read_response(client);

}

 

30 

public:

 

SmtpService(

const IPAddress& smtp_server,

const unsigned int port) : _use_auth(false),

35 

_smtp_server(smtp_server),

_port(port) { }

 

SmtpService(

const IPAddress& smtp_server,

40 

const unsigned int port,

const String& username,

const String& password) : _use_auth(true),

_smtp_server(smtp_server),

_port(port),

45 

_username(username),

_password(password) { }

 

void send_email(const Email& email) {

EthernetClient client;

50 

Serial.print("Connecting...");

 

if (client.connect(_smtp_server, _port) <= 0) {

Serial.println("connection failed.");

} else {

55 

Serial.println("connected.");

read_response(client);

if (!_use_auth) {

Serial.println("Using no authentication.");

send_line(client, "helo");

60 

}

else {

Serial.println("Using authentication.");

send_line(client, "ehlo");

send_line(client, "auth login");

65 

send_line(client, _username);

send_line(client, _password);

}

send_line(

client,

70 

"mail from: <" + email.getFrom() + ">"

);

send_line(

client,

"rcpt to: <" + email.getTo() + ">"

75 

);

send_line(client, "data");

send_line(client, "from: " + email.getFrom());

send_line(client, "to: " + email.getTo());

send_line(client, "subject: " + email.getSubject());

80 

send_line(client, "");

send_line(client, email.getBody());

send_line(client, ".");

send_line(client, "quit");

client.println("Disconnecting.");

85 

client.stop();

}

}

};

 

90 

#endif

Admittedly, this is a lot of code, but we’ll walk through it step by step. First, the SmtpService class encapsulates the SMTP server’s IP address and its port. These attributes are required in any case. In addition, we store a username and a password in case someone’s going to use an authenticated connection.

To communicate with an SMTP server, we have to read its responses, and we do that using the private read_response method starting on line 13. It waits for four seconds (SMTP servers usually are very busy, because they have to send a lot of spam), and then it reads all the data sent back by the server and outputs it to the serial port for debugging purposes.

Before we can process responses, we have to send requests. send_line, beginning in line 21, sends a single command to an SMTP server. You have to pass the connection to the server as an EthernetClient instance, and the line you’d like to send has to be a String object.

To send the data stored in a String object, we need to access the character data it refers to. We can use toCharArray or getBytes to retrieve this information. These two methods do not return a pointer to the string’s internal buffer. Instead, they expect you to provide a sufficiently large chararray and its size. That’s why we copy line’s content to buffer before we output it to the serial and Ethernet ports. After we’ve sent the data, we read the server’s response and print it to the serial port.

There aren’t any surprised in the public interface. There are two constructors. The first, on line 32, expects the SMTP server’s IP address and its port. If you use it, the SmtpService class assumes you’re not using authentication.

To authenticate against the SMTP service using a username and a password, you have to use the second constructor, starting in line 38. In addition to the SMTP server’s IP address and port, it expects the username and password encoded in Base64.

The send_email method is the largest piece of code in our class, but it’s also one of the simplest. It mimics exactly our telnet session. The only thing worth mentioning is line 57. Here we check whether authentication information has been provided in the constructor. If not, we send theHELO command. If authentication information has been provided, we send the EHLO command and the corresponding authentication information.

Let’s use our classes now to actually send an email:

Ethernet/Email/Email.ino

Line 1 

#include <SPI.h>

#include <Ethernet.h>

#include "smtp_service.h"

 

const unsigned int SMTP_PORT = 2525;

const unsigned int BAUD_RATE = 9600;

const String USERNAME = "bm90bXl1c2VybmFtZQ=="; // Encoded in Base64.

const String PASSWORD = "bm90bXlwYXNzd29yZA=="; // Encoded in Base64.

 

10 

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

IPAddress my_ip(192, 168, 2, 120);

 

// Insert IP address of your SMTP server below!

IPAddress smtp_server(0, 0, 0, 0);

15 

 

SmtpService smtp_service(smtp_server, SMTP_PORT, USERNAME, PASSWORD);

 

void setup() {

Ethernet.begin(mac, my_ip);

20 

Serial.begin(BAUD_RATE);

delay(1000);

Email email(

"arduino@example.com",

"info@example.net",

25 

"Yet another subject",

"Yet another body"

);

smtp_service.send_email(email);

}

30 

 

void loop() {}

No surprises here. We define constants for the SMTP port, the MAC address, the username, the password, and so on; then we create an SmtpService instance. In the setup function, we initialize the Ethernet shield and the serial port, then wait for a second to let things settle down. In line 22, we create a new Email object and pass it to the send_email method.

Figure 28, A typical SMTP session on the Arduino shows this in action (including authentication).

images/raw_smtp


Figure 28. A typical SMTP session on the Arduino

Now we know how to send emails with an Arduino, but to build our burglar alarm, we still have to learn how to detect motion.

Detecting Motion Using a Passive Infrared Sensor

Detecting motion is a useful technique, and you probably already know devices that turn on the light in your garden or at your door whenever someone is near enough. Most use passive infrared sensors (PIR)[119] for motion detection.

Nearly every object emits infrared light and a PIR sensor measures exactly this kind of light. Detecting motion is comparatively easy if you’re already able to receive the infrared radiation emitted by objects in the sensor’s field of view. If the sensor receives the infrared light emitted by a wall and suddenly a human being or an animal moves in front of the wall, the infrared light signal will change.

Off-the-shelf sensors hide these details, so you can use a single digital pin to check whether someone is moving in the sensor’s field of view. The Parallax PIR sensor[120] is a good example of such a device, and we can use it as the basis of our burglar alarm.

images/pir_sensor


Figure 29. Top and bottom of a passive infrared sensor

The PIR sensor has three pins: power, ground, and signal. Connect power to the Arduino’s 5V supply, ground to one of the Arduino’s GND pins, and signal to digital pin 2. In the following figure, you see a circuit diagram that connects a PIR sensor from Adafruit[121] to an Arduino. Note that PIR sensors from different vendors often differ in the order of their connectors. The PIR sensor in Figure 29, Top and bottom of a passive infrared sensor is different, so you should always make sure you connect the correct pins.

images/pir_circuit

The PIR sensor usually also has a jumper that you can use for changing its behavior. For our project, it has to be in position H; the jumper has to cover the pin next to the H. (Lady Ada has an excellent tutorial on PIR sensors.)[122]

Then enter the following code in the Arduino IDE:

Ethernet/MotionDetector/MotionDetector.ino

Line 1 

const unsigned int PIR_INPUT_PIN = 2;

const unsigned int BAUD_RATE = 9600;

 

class PassiveInfraredSensor {

int _input_pin;

 

public:

PassiveInfraredSensor(const int input_pin) {

_input_pin = input_pin;

10 

pinMode(_input_pin, INPUT);

}

const bool motion_detected() const {

return digitalRead(_input_pin) == HIGH;

}

15 

};

 

PassiveInfraredSensor pir(PIR_INPUT_PIN);

 

void setup() {

20 

Serial.begin(BAUD_RATE);

}

 

void loop() {

if (pir.motion_detected()) {

25 

Serial.println("Motion detected");

} else {

Serial.println("No motion detected");

}

delay(200);

30 

}

With the constant PIR_INPUT_PIN, you can define the digital pin you’ve connected your PIR sensor to. In line 4, we begin the definition of a class named PassiveInfraredSensor that encapsulates all things related to PIR sensors.

We define a member variable named _input_pin that stores the number of the digital pin we’ve connected our sensor to. Then we define a constructor that expects the pin number as an argument and assigns it to our member variable.

The only method we need to define is motion_detected. It returns true if it has currently detected a motion and false otherwise. So, it has to check only whether the current state of the sensor’s digital pin is HIGH or LOW.

Compile the sketch and upload it to your Arduino. You should see an output similar to the following screenshot when you start to wave your hand in front of the sensor.

images/pir_output

Now we’ve built the two main components of our burglar alarm, and the only thing left to do is to bring them both together. We’ll do that in the next section.

Bringing It All Together

With our PassiveInfraredSensor and SmtpService classes, it’s a piece of cake to build a burglar alarm with email notifications. Connect the PIR sensor to the Ethernet shield, as shown in the following figure.

images/burglar_alarm

Then enter the following code in your Arduino IDE:

Ethernet/BurglarAlarm/burglar_alarm.h

Line 1 

#ifndef __BURGLAR_ALARM_H__

#define __BURGLAR_ALARM_H__

#include "pir_sensor.h"

#include "smtp_service.h"

 

class BurglarAlarm {

PassiveInfraredSensor _pir_sensor;

SmtpService _smtp_service;

void send_alarm() {

10 

Email email(

"arduino@example.com",

"info@example.net",

"Intruder Alert!",

"Someone's moving in your living room!"

15 

);

_smtp_service.send_email(email);

}

 

public:

20 

BurglarAlarm(

const PassiveInfraredSensor& pir_sensor,

const SmtpService& smtp_service) :

_pir_sensor(pir_sensor),

_smtp_service(smtp_service)

25 

{

}

 

 

void check() {

30 

Serial.println("Checking");

if (_pir_sensor.motion_detected()) {

Serial.println("Intruder detected!");

send_alarm();

}

35 

}

};

#endif

This defines a class named BurglarAlarm that aggregates all the code we’ve written so far. It encapsulates a SmtpService instance and a PassiveInfraredSensor object. Its most complex method is send_alarm, which sends a predefined email.

The rest of the BurglarAlarm class is pretty straightforward. Beginning on line 20, we define the constructor that initializes all private members. If the PIR sensor detects movement, the check method sends an email.

Let’s use the BurglarAlarm class:

Ethernet/BurglarAlarm/BurglarAlarm.ino

 

#include <SPI.h>

 

#include <Ethernet.h>

 

#include "burglar_alarm.h"

 

 

 

const unsigned int PIR_INPUT_PIN = 2;

 

const unsigned int SMTP_PORT = 25;

 

const unsigned int BAUD_RATE = 9600;

 

const String USERNAME = "bm90bXl1c2VybmFtZQ=="; // Encoded in Base64.

 

const String PASSWORD = "bm90bXlwYXNzd29yZA=="; // Encoded in Base64.

 

 

 

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

 

IPAddress my_ip(192, 168, 2, 120);

 

 

 

// Insert IP address of your SMTP server below!

 

IPAddress smtp_server(0, 0, 0, 0);

 

PassiveInfraredSensor pir_sensor(PIR_INPUT_PIN);

 

SmtpService smtp_service(smtp_server, SMTP_PORT, USERNAME, PASSWORD);

 

BurglarAlarm burglar_alarm(pir_sensor, smtp_service);

 

 

 

void setup() {

 

Ethernet.begin(mac, my_ip);

 

Serial.begin(BAUD_RATE);

 

delay(20 * 1000);

 

}

 

 

 

void loop() {

 

burglar_alarm.check();

 

delay(3000);

 

}

First we include all of the libraries we need, and we define constants for the PIR sensor pin and our MAC address. Then we define SmtpService and PassiveInfraredSensor objects and use them to define a BurglarAlarm instance. Note that we pass a username and a password, implying that we’re using an authenticated SMTP connection to send our emails. If you use an unauthenticated connection, you can safely remove the USERNAME and PASSWORD parameters and all of their occurrences.

In the setup method, we define the serial port and the Ethernet shield. I’ve also added a delay of twenty seconds, which gives you enough time to leave the room before the alarm begins to work.

The loop function is simple, too. It delegates all the work to BurglarAlarm’s check method. In the following figure, you can see what happens when the burglar alarm detects an intruder.

images/burglar_alarm_output

Did you notice how easy object-oriented programming on an embedded device can be? We’ve cleanly hidden in two small classes the complexity of both email and the PIR sensor. To build the burglar alarm, we then only had to write some glue code.

One word regarding privacy: do not abuse the project in this chapter to observe other people without their knowledge. Not only is it unethical, but in many countries it’s even illegal!

In this and the preceding chapter, you learned different ways to connect the Arduino to the Internet. Some of them require an additional PC, while others need an Ethernet shield, but they all open the door to a whole new range of embedded computing applications.

Networking is one of those techniques that may have a direct impact on the outside world. In the next chapter, you’ll learn about another technique that has similar effects: you’ll learn how to control devices remotely.

What If It Doesn’t Work?

The burglar alarm is a networking project, so you should check all the things mentioned in What If It Doesn’t Work?. In addition, you should double-check the connection parameters and authentication information for your email provider. Did you use the correct IP address for your email provider? Did you use the right SMTP port? Did you use the right username and password? Did you use the right Base64 version of the username and password?

PIR sensors are fairly simple devices. Still, you can wire them the wrong way, so if the motion detection doesn’t work, double-check the wiring.

Exercises

·        Build a project similar to the burglar alarm, but use another type of sensor. There’s tons of inspiration out there on the Web.[123]

·        Add the current timestamp to the burglar alarm email. Get the timestamp from a Daytime service.

·        Add support for DHCP and DNS to the burglar alarm.

·        Add support for Base64 to the burglar alarm, so you no longer have to manually encode your username and password. A Base64 library is available.[124]

·        Add a piezo buzzer to the project and emit a beeping sound whenever a burglar is detected.

·        Get a TTL Serial Camera[125] and attach photos of the burglar to your emails. This is a fairly advanced exercise. You have to learn how to control the camera, and you also have to learn how to send email attachments.

Footnotes

[115]

http://en.wikipedia.org/wiki/Smtp

[116]

http://www.smtp2go.com/

[117]

http://en.wikipedia.org/wiki/Base64 At http://www.freeformatter.com/base64-encoder.html, you can convert text into Base64 strings.

[118]

http://arduino.cc/en/Reference/StringObject

[119]

http://en.wikipedia.org/wiki/Passive_infrared_sensor

[120]

http://www.parallax.com/product/555-28027

[121]

http://www.adafruit.com/products/189

[122]

https://learn.adafruit.com/pir-passive-infrared-proximity-motion-sensor

[123]

http://www.tigoe.net/pcomp/code/arduinowiring/873

[124]

https://github.com/adamvr/arduino-base64

[125]

https://learn.adafruit.com/ttl-serial-camera/overview