SparkFun Inventor's Kit for Edison Experiment Guide

Pages
Contributors: Shawn Hymel
Favorited Favorite 4

Experiment 4: Email Notifier

Introduction

While flashing an LED is not the most interesting activity, we could use the LED as a way to notify us if something is happening. For example, we could turn on an LED if we have a new email. That way, we would know that we needed to check our inbox!

To do this, we will have the Edison log in to an email account, read the number of unread emails, and turn on an LED if it is over 0.

NOTE: This example shows how to connect to Gmail and Yahoo mail servers. If you are not using one of those, you still might be able to connect (see here for a list of IMAP servers), but only Gmail and Yahoo have been tested. Also, you will need to enter your username and password as plain text into the code. It's a fun project, but you don't have to do it if you are not comfortable with that!

Parts Needed

We'll be using the same circuit as in the previous example, so you don't need to build anything new! In addition to the Edison and Block Stack, you will need the following parts:

  • 1x Breadboard
  • 1x RGB LED
  • 1x NPN Transistor
  • 1x 1kΩ Resistor
  • 1x 100Ω Resistor
  • 5x Jumper Wires
Using the Edison by itself or don't have the kit? No worries! You can still have fun and follow along with this experiment. We suggest using the parts below:
Resistor Kit - 1/4W (500 total)

Resistor Kit - 1/4W (500 total)

COM-10969
$8.95
188
Breadboard - Self-Adhesive (White)

Breadboard - Self-Adhesive (White)

PRT-12002
$5.50
48
Break Away Headers - Straight

Break Away Headers - Straight

PRT-00116
$1.75
20
LED - RGB Diffused Common Cathode

LED - RGB Diffused Common Cathode

COM-09264
$2.25
2
Female Headers

Female Headers

PRT-00115
$1.75
8
Jumper Wires Standard 7" M/M - 30 AWG (30 Pack)

Jumper Wires Standard 7" M/M - 30 AWG (30 Pack)

PRT-11026
$2.45
20
Transistor - NPN, 60V 200mA (2N3904)

Transistor - NPN, 60V 200mA (2N3904)

COM-00521
$0.55

Intel® Edison

DEV-13024
25 Retired

SparkFun Block for Intel® Edison - GPIO

DEV-13038
4 Retired

SparkFun Block for Intel® Edison - Base

DEV-13045
16 Retired

Suggested Reading

Concepts

External Modules

In the previous few examples, we have been relying on the MRAA module to control various hardware from the Edison. MRAA comes pre-installed on the Edison, so we did not have to perform any extra steps to install it. However, in this example, we will use node-imap, which contains several useful functions for connecting to Internet Message Access Protocol (IMAP) servers and retrieving email.

If we were to log in to the Edison via SSH or serial terminal, we could install Node.js packages (e.g. modules) using the npm command (e.g. npm install imap). However, with the XDK, we can tell the IDE to install necessary modules automatically whenever we upload code. This is accomplished by adding the library name to a list of dependencies in the project. The specifics on how to do this can be found in "The Code" section.

Callbacks

MicroTAC Elite VIP cellular phone

I wonder if caller ID was a feature

A callback is a piece of code (often a function) that is expected to be called by another piece of code at a convenient time. A popular way to use callbacks in web programming is to assign a function to a mouse click event. For example:

language:JavaScript
element.on('click', myFunction);

myFunction() {
    console.log("Hi!");
}

Whenever a user clicks on the web page element (called element in this example), myFunction() gets called. In this instance, myFunction() is the callback, and our assignment, element.on('click', myFunction);, is known as creating an event handler. See here to learn more about the .on() event handler.

Hardware Hookup

The circuit is the same as in the previous experiment.

Red LED with Edison Fritzing

Having a hard time seeing the circuit? Click on the Fritzing diagram to see a bigger image.

The Code

Create a new project in the XDK. Click on package.json in the files browser on the left pane. Add the line

language:JavaScript
"imap": "0.8.16"

under "dependencies". This will tell the XDK to download and install the node-imap v0.8.16 module before running the program.

Adding a new library

NOTE: If you are using Gmail, you will need to go to the account security settings page and turn access for less secure apps to ON. We recommend turning it off once you are done with this exercise (unless you want to keep a permanent email notifier!).

Copy the following code into main.js. If you are not using Gmail, you can comment out (or delete) the part labeled "Set email credentials (Gmail)". If you are using Yahoo, you will want to uncomment the part labeled "Set email credentials (Yahoo)".

Finally, change the <username> and <password> parts to your actual email username and password.

language:JavaScript
/*jslint node:true, vars:true, bitwise:true, unparam:true */
/*jshint unused:true */
// Leave the above lines for propper jshinting

/**
 * SparkFun Inventor's Kit for Edison
 * Experiment 4: Email Notifier
 * This sketch was written by SparkFun Electronics
 * October 29, 2015
 * https://github.com/sparkfun/Inventors_Kit_For_Edison_Experiments
 *
 * Connect to an email service and turn on an LED if there are any unread
 * emails.
 *
 * Released under the MIT License(http://opensource.org/licenses/MIT)
 */

// Import the MRAA and IMAP modules
var mraa = require('mraa');
var Imap = require('imap');

// Set up a digital output on MRAA pin 20 (GP12)
var ledPin = new mraa.Gpio(20);
ledPin.dir(mraa.DIR_OUT);

// It's usually a good idea to set the LED to an initial state
ledPin.write(0);

// Global LED variable to know if the LED should be on or off
var led = 0;

// Set email credentials (Gmail)
// Turn on "Acess for less secure apps" in Google account settings
// https://www.google.com/settings/security/lesssecureapps
var imap = new Imap({
  user: "<username>@gmail.com",
  password: "<password>",
  host: "imap.gmail.com",
  port: 993,
  tls: true
});

// Set email credentials (Yahoo)
/*var imap = new Imap({
  user: "<username>@yahoo.com",
  password: "<password>",
  host: "imap.mail.yahoo.com",
  port: 993,
  tls: true
});*/

// Open the mail box with the name "INBOX"
function openInbox(cb) {
  imap.openBox("INBOX", true, cb);
}

// This is called when a connection is successfully made to the IMAP server.
// In this case, we open the Inbox and look for all unread ("unseen")
// emails. If there are any unread emails, turn on a LED.
imap.on('ready', function() {
    openInbox(function(err, box) {
        if (err) throw err;

        // Search for unread emails in the Inbox
        imap.search(["UNSEEN"], function(err, results) {
            if (err) throw err;

            // Print the number of unread emails
            console.log("Unread emails: " + results.length);

            // If there are unread emails, turn on an LED
            if (results.length > 0) {
                ledPin.write(1);
            } else {
                ledPin.write(0);
            }

            // Close the connection
            imap.end();
        });
    });
});

// If we get an error (e.g. failed to connect), print that error
imap.on('error', function(err) {
    console.log(err);
});

// When we close the connection, print it to the console
imap.on('end', function() {
  console.log("Connection closed.");
});

// Call this function over and over again
periodicActivity();
function periodicActivity() //
{
    // Perform a quick connection to the IMAP server and look for unread emails
    imap.connect();

    // Wait for 10 seconds before checking for emails again
    setTimeout(periodicActivity, 10000);
}

What You Should See

When uploading the code, you might see some notifications that the XDK is downloading and installing npm packages. Just be patient while the packages are installed.

XDK installing npm packages

When you run the code, it should connect to your email account and print to the console the number of unread emails every 10 seconds.

Unread emails

I really should get in the habit of checking my emails more often

If you have one or more unread emails, the red LED should come on.

Edison email notifier

Code to Note

Callbacks

I know that we talked about callbacks in the Concepts section, but now we get to see them in action. The node-imap package heavily relies on them, so it is important to get used to them if you plan to use that package in the future.

imap.on is used several times. This function gets called when something particular happens in our program. These are known as "Connection Events" according to the Application Program Interface (API) documentation. We can define particular connection events using strings.

For example, imap.on('ready', function() {...}); allows us to define a function (as noted by the function() keyword) that is called whenever a successful connection is made with the IMAP server.

imap.on('error', function() {...}); is called if there is a problem making a connection.

imap.on('end', function() {...}); is called whenever the connection with the server is closed.

There is another seemingly odd callback. In our imap.on('ready',...) code, we call openInbox(function(err, box) {...});. A few lines above, we define the openInbox() function, which tells the imap object to open our inbox and then call another function (as denoted by cb for "callback"). This callback function (cb) is the function we defined inside openInbox(function(err, box) {...});. So yes, we call a function that accepts another function as a parameter, which then calls that function as a callback. Don't worry if this was confusing; it is a bit hard to follow. Knowing how to use the .on() callback functions is the most important part of this exercise.

Error Handling

Being able to appropriately deal with errors is a very useful ability in a program. The example relies on if (err) throw err; to determine if an error has occurred (e.g. could not connect to the IMAP server).

If we dig into the node-imap code, we would likely find a few catch statements. if (err) only executes the second part (throw err) if an err actually exists (not null or undefined). throw stops execution within that loop, function, etc., and program control is passed to the first catch statement it finds within the calling stack (e.g. look for a function that called the callback withing a try/catch statement).

If an error occurs, the node-imap module calls our callback function imap.on('error', function() {...});, which lets us handle the error. In this case, all we do is print the error to the console.

Troubleshooting

  • It won't connect to the IMAP server -- This could be caused by several reasons:
    • Make sure your Edison has Internet access
    • Ensure you are using the correct IMAP server settings (Gmail and Yahoo examples are given in the code)
    • Check that your email and password are correct in the code
  • The LED won't come on -- As always, double-check the wiring. Make sure you are seeing Unread emails: is appearing in the console, and that number is at least 1. Be patient, as it can take a few seconds for the program to make a connection to the IMAP server.

Going Further

Challenges

  1. Have the LED flash rapidly when there are unread emails.
  2. Have the LED turn on only when there are unread emails from a particular sender (e.g. a friend or your boss). You will need to carefully read the examples in the node-imap documentation.
  3. When you receive a new email, print its contents to the console and flash the LED. Hint: Take a look at the mail(...) callback in Connection Events in the node-imap documentation.

Digging Deeper