Building Your First Project - Playing with the BeagleBone - BeagleBone For Dummies (2015)

BeagleBone For Dummies (2015)

Part VI

Playing with the BeagleBone

Visit www.dummies.com/cheatsheet/beaglebone for additional Dummies content related to the BeagleBone.

In this part …

· Having some fun with the BeagleBone by taking on more advanced projects

· Analyzing your email with Python and read messages on an LCD screen

· Discovering how to use the BeagleBone as a tool for home automation projects

· Using a home automation web server to interact with your BeagleBone

Chapter 14

Building Your First Project

In This Chapter

Preparing to build a complete, functional, and useful apparatus

Dividing and conquering to build the project incrementally

Wiring up an LCD and programming an email reader

Building a device that reads and displays your emails

This chapter shows you how to build a lasting, complete, and useful project.

In the completed project, your BeagleBone functions as a small, energy-efficient apparatus that notifies you when you receive an email, and allows you to use buttons and an LCD screen to go through your entire mailbox and read any message.

Getting Started

Before you get to work, you need to assemble your supplies. Here’s the shopping list:

· A breadboard

· Many jumper wires

· A 3.3V liquid crystal display (LCD) screen, preferably one that’s 20 character by 4 line and is compatible with the Hitachi HD44780 LCD controller

· Four pushbuttons

· Four 10K Ω resistors

· A light-emitting diode (LED)

· A 470 Ω or 220 Ω resistor

· An Ethernet cable and a stable connection to the web

· Two potentiometers, preferably 5K Ω and 10K Ω

· A buzzer

So that you know what your objective is for this project, Figure 14-1 shows the completed email notifier and reader.

Figure 14-1: LCD email notifier and reader.

The best way to build a project that integrates various pieces of hardware and software is to divide and conquer. You work incrementally, because building and testing one part before moving on to the next usually yields the best results. If instead you wire up everything, write all the code, and turn on the device without having tested the parts, you’ll most likely get unexpected results, and debugging the whole thing is much harder and tedious than testing and debugging each part individually.

Here’s the attack strategy for this chapter:

1. Create a program that can print a simple message on the LCD.

2. Create a program that reads your email and prints the important details on the terminal.

3. Integrate this program into the main one, while adding buttons to select the email and scroll the message.

4. Add an LED and a buzzer to notify you when a new email arrives.

Wiring Up the LCD

In this section, you wire up the LCD and create a script to print a simple message on it. You do this by creating a function that drives the screen; when that’s done, all you have to do is have the function receive the message from the web as a parameter rather than as a message written by you.

Figure 14-2 shows a standard 20x4 LCD Hitachi HD44780 LCD, which is the type we recommend for this project.

Figure 14-2: A standard HD44780 LCD.

If you use a different LCD from the one we recommend, you may have to add wiring. Hitachi’s LCDs feature built-in resistors for the backlight LEDs, but some other LCDs may not, which means that you have to integrate them yourself. Be sure to read the important parts of the datasheet with care! If you’re still unsure, you can always add an 1K Ω resistor between 3.3V and the LCD’s pin 15. We strongly recommend, however, that you get an LCD as similar as possible to the one we used. In any case, all lines of code that depend on the LCD you use have a comment that says so.

There are several LCDs that require 5V to operate. We strongly recommend that you stay away from those and use a 3.3V LCD because this project is a complex one that involves lots of wiring. If you mistakenly plug 5V into the BeagleBone, you may blow up its processor.

Wiring the LCD

Follow these steps to wire up the LCD (and check Figure 14-3 for reference):

1. Connect 3.3V to the power rails of the breadboard.

You can get the voltage from the BeagleBone’s pins P9_3 and P9_4.

2. Connect ground (GND) to another rail of the breadboard.

Pins P9_1, P9_2, P8_1 and P8_2 of the BeagleBone all provide ground.

3. Power the LCD.

Use jumper wires to connect the 3.3V to LCD pin 2 (VDD) and LCD pin 15 (LED+). If your LCD doesn’t feature built-in resistors for the backlight LEDs, place a resistor between pin 15 and the 3.3V. To set your ground, connect GND to LCD pin 1 (VSS) and LCD pin 5 (R/W).

4. Add a potentiometer to control the contrast.

Connect one of the outer leads to 3.3V and another outer lead to GND; the middle lead connects to LCD pin 3 (VO/contrast).

5. Connect the BeagleBone’s pin P8_8 to LCD pin 4 (RS).

6. Connect the BeagleBone’s pin P8_10 to LCD pin 6 (E/clock enable).

7. Connect the BeagleBone’s pin P8_18 to LCD pin 11 (DB4).

8. Connect the BeagleBone’s pin P8_16 to LCD pin 12 (DB5).

9. Connect the BeagleBone’s pin P8_14 to LCD pin 13 (DB6).

10. Connect the BeagleBone’s pin P8_12 to LCD pin 14 (DB7).

11. Connect 3.3V to LCD pin 15 (A/+backlight).

12. Connect GND to LCD pin 16 (K/-backlight).

If your circuit doesn’t work, you might need to troubleshoot it with a multimeter. Check www.dummies.com/cheatsheet/beaglebone to see how to do so.

Writing the code for the LCD

Before you get into any actual coding, you need to install Adafruit’s Python library, which features plenty of functions that you can use with the LCD.

We encourage you to visit www.dummies.com/cheatsheet/beaglebone to download all the code for this chapter. Sometimes, typing the code yourself or copying and pasting can lead to unexpected errors that can be quite time-consuming to figure out. Downloading the code ensures that you don’t have any snippet of code missing.

Figure 14-3: LCD wired to BeagleBone Black.

Start by installing some necessary dependencies. Most likely, you already have these dependencies installed, but just to make sure, enter the following commands:

sudo apt-get update
sudo apt-get install build-essential python-dev python-smbus python-pip git
sudo pip install Adafruit_BBIO

Create a dedicated folder for this project. We created ours on /var/lib/cloud9 and called it email_notifier. Change to the directory where you created the folder, and type the following on the command line:

cd /var/lib/cloud9/email_notifier
git clone https://github.com/adafruit/Adafruit_Python_CharLCD.git
cd Adafruit_Python_CharLCD
sudo python setup.py install

git clone is a useful command that clones entire repositories from GitHub. In this case, you clone the necessary source code to install the LCD library.

Before you see the code that runs the script, here’s an introduction to the LCD functions that you use for your program:

· clear(): Clears the LCD, erasing any message that was printed on it previously.

· message(string): Writes the desired string to the display. Note that the LCD can’t realize when it reaches the end of a line; thus, messages must include \n (newline) to use all the rows of the LCD.

You can use many other functions with the LCD. Even though they’re not necessary for this project, they’re interesting and can be useful for plenty of tasks (or even for improvements on this project). You can get a complete rundown of these functions by typing the following on the command line:

python
>>>import Adafruit_CharLCD as LCD
>>>help(LCD.Adafruit_CharLCD)

The backlight() function won’t work due to the fact that you connected the backlight pin directly to 3.3V and not a GPIO; thus, you have no control over it. We opted to do this for simplicity because controlling the backlight isn’t really important for this project.

To start writing the code, create a file named LCD.py, and type the following:

#!/usr/bin/python
import math
import time

import Adafruit_CharLCD as LCD

lcd_rs = 'P8_8'
lcd_en = 'P8_10'
lcd_d4 = 'P8_18'
lcd_d5 = 'P8_16'
lcd_d6 = 'P8_14'
lcd_d7 = 'P8_12'
lcd_backlight = 'P8_7'

# Define LCD column and row size for 20x4 LCD.
# Change depending on your LCD
# We use these a lot so we define them as constants
LCD_COLUMNS = 20
LCD_ROWS = 4

# Initialize the LCD using the pins above.
lcd = LCD.Adafruit_CharLCD(lcd_rs, lcd_en, lcd_d4, lcd_d5, lcd_d6, lcd_d7, LCD_COLUMNS, LCD_ROWS, lcd_backlight)

message = "Hello\nWorld!"
lcd.clear()
lcd.message(message)
time.sleep(10)
lcd.clear()

This script does the following things:

1. Imports libraries.

2. Creates variables referring to the pins of the LCD that are connected to the BeagleBone. These variables are necessary to initialize the LCD.

3. Defines constants referring to the number of columns and rows that the LCD features. These two values are important when you want to display bigger messages.

4. Initializes the LCD.

5. Creates a string to hold the message you want to print.

6. Clears the LCD’s previous message and displays the new message.

7. Waits 10 seconds and then clears the LCD message.

Running the script for the LCD

After saving, you can press F5 to see a result similar to Figure 14-4. Feel free to play around. Send other messages, experiment with other functions to, for example, scroll messages sideways and change the contrast. Get a feel for how to work with an LCD, because this skill is both useful and fun.

If you don’t see anything, you may not have enough contrast. If everything was wired correctly, the contrast is defined by the potentiometer; rotate it to see whether rotation solves the problem. If not, recheck the code and the wiring.

Figure 14-4: Hello world!

Programming the Email Reader

This part of this chapter shows you how you can use Python code to access your email and print details about the most recently received messages on the console terminal. When that’s done, you merely have to adapt this program and the one you created earlier in this chapter to display the message on your LCD.

To check your email with Python, you use what’s known as the Universal Feed Parser. feedparser is a Python library that analyzes feeds in all known formats of web standards.

This project uses Gmail as an example for the following reasons:

· It’s the most popular email provider worldwide.

· Gmail is very developer-friendly, so accessing its feed is easy and straightforward.

Explaining how to access the feed of every email provider is beyond the scope of this book, so we strongly recommend that you use a Gmail account to get through the remainder of this chapter and find out how to parse a feed. With some Internet research, you should be able to adapt the feed parser for this specific application for a different email provider or any other web-based application — provided that the provider or website allows you to access its feed. Later in this section, you can see some more information on how to do so.


Parsing web feeds

Web feeds allow programmers to create software that checks for updates published on a website. For programmers to do this, though the site owner needs to use specialized software to publish a feed of content in standard format that the computer can interpret. Then this feed can be read by programs such as the one you create in this section.

Website owners use different standards to publish their feeds. Atom, RSS, and RDF are probably the most popular standards. Things change somewhat from standard to standard.


One last thing before you start coding. You need to install the following libraries:

sudo apt-get install python-pip python2.7-dev
sudo pip install feedparser
sudo easy_install -U distribute

Enter the following code:

#!/usr/bin/python

import feedparser
import time

USERNAME = "YOUR_USERNAME" # just the part before the @ sign, add yours here
PASSWORD = "YOUR_PASSWORD"

MAIL_CHECK_FREQ = 10 # check mail every 10 seconds

while True:
d = feedparser.parse("https://" + USERNAME + ":" + PASSWORD "@gmail.google.com/gmail/feed/atom")
print(d.entries[0].published) #prints email's date
print(d.entries[0].title) #prints email's title
print(d.entries[0].author) #prints email's author
print(d.entries[0].description) #prints email message
time.sleep(MAIL_CHECK_FREQ)

This code shouldn’t be too hard to understand. After the libraries are imported, three constants are declared: two strings to hold your username and password, and an integer to define the frequency at which this program runs. The MAIL_CHECK_FREQ constant is used with a time.sleep() function at the end of the while True: loop. Without including the time.sleep() function, your program would run at the CPU frequency (1 GHz), which is 1 nanosecond per instruction (on a BeagleBone Black). It’s safe to assume that you don’t receive that many emails in such a short period of time.

What’s important for you to understand here is the part where the feed parser functions are used. First, you create an object that you name d; this object holds the feed after it has been parsed (analyzed) by the function feedparser.parse(). Afterward, you can access each entry of the email by using d.entries; the index 0 stands for the most recent email. You can check whichever email you want by using another index up to 20 entries.

You can find more about Python’s feedparser at https://pythonhosted.org/feedparser. You should go to Common RSS Elements for matters specific to what you’re doing in this section. If you want to try getting your own email or some other website running with the feedparser, you should read more on the previously mentioned website, as well as do an Internet search on your website/email provider’s feed.

When you run the script, information about the latest email you received should print on the console output. This information is updated every CHECK_MAIL_FREQ seconds. The next section shows how to make the output print on an LCD.

Putting It All Together

This project uses two pushbuttons to swap messages in succession. One pushbutton selects the previous message, and the other selects the next message.

What makes this program somewhat complex is the fact that you need to implement some way to scroll down for messages that have more total characters than the LCD can display at any time — that is, rows × columns. For this purpose, you use another two pushbuttons that scroll the message up or down.

Wiring the pushbuttons

The opposite leads of a pushbutton are disconnected, and when a user presses the button, the leads establish a connection. You can quickly test that feature by using a multimeter in continuity mode. Follow these steps or refer to Figure 14-5 to add each of the pushbuttons to your circuit:

1. Attach one of the pusbhutton leads to the 3.3V breadboard rail.

2. Attach a 10K Ω resistor to the opposite lead of the pushbutton.

3. Connect the other lead of the resistor to the ground rail.

4. Repeat the same process for all four pushbuttons.

5. Insert a jumper wire between the pushbutton and the resistor into the BeagleBone’s pin for that pushbutton.

The left pushbutton, which scrolls up, is attached to P8_15. The next pushbutton scrolls down and is attached to P8_13. The third pushbutton selects the previous email and is connected to P8_11. The last pushbutton selects the next email and is connected to P8_9.

Figure 14-5: LCD and four pushbuttons wired to the BeagleBone Black.

Understanding the concept

This section provides a short summary of how the algorithm is done without getting into any specifics of the code. The following sections explain each part minutely.

After importing libraries and initializing modules, you set up some important variables. You use functions to do the following things:

· Get the date of the latest email received

· Parse the latest email, saving all the relevant data, including the number of entries

· Display the first four lines of the most recent email, which consists of title, author, and the first two lines of the message

· Create a time stamp so that you can create conditions that depend on the elapsed time

When that’s done, you move on to the while True: loop, which does the following things:

1. It checks for new email.

· If there is new email, the variables — one that holds the number of the current message and one that’s responsible for scrolling the message on the LCD — are reset to 0, and the LCD screen is updated with the latest email.

· If not, a check is done to see whether any of the buttons has been pressed.

· If the Previous button has been pressed, a function runs to select the previous message; parse the email to save the relevant data, including the number of entries; and display the message on the LCD.

· Else if the Next button has been pressed, a function runs to select the next message; parse the email to save the relevant data, including the number of entries; and display the message on the LCD.

· Else if the Scroll Up button has been pressed, the code decrements by 1 the variable that’s responsible for scrolling the message on the LCD; then the current message is displayed.

· Else if the Scroll Down button has been pressed, the variable that’s responsible for scrolling the message on the LCD is incremented by 1; then the current message is displayed.

2. Using the time stamp, the code checks whether the program has been running for longer than 60 seconds. If so, the email is checked again for any new messages, and the time stamp is reset.

3. The program is halted for 5 seconds at every iteration of the while True: loop.

The following sections cover specifics.

Writing the code

As always, the first thing to do is import libraries, as follows:

#!/usr/bin/python
# Email Notifier
# Importing libraries
import math
import time
import feedparser
import Adafruit_CharLCD as LCD
import Adafruit_BBIO.GPIO as GPIO

Next, you define variables for the BeagleBone pins that you’ll use as pushbuttons:

# Defining variables
button_scroll_up = "P8_15"
button_scroll_down = "P8_13"
button_previous = "P8_11"
button_next = "P8_9"

Then you initialize all the inputs:

# Initializing all the inputs
GPIO.setup(button_scroll_up, GPIO.IN)
GPIO.setup(button_scroll_down, GPIO.IN)
GPIO.setup(button_previous, GPIO.IN)
GPIO.setup(button_next, GPIO.IN)

Following that, you add events to detect the button presses:

# Setting buttons to detect rising edge events
GPIO.add_event_detect(button_scroll_up, GPIO.RISING)
GPIO.add_event_detect(button_scroll_down, GPIO.RISING)
GPIO.add_event_detect(button_previous, GPIO.RISING)
GPIO.add_event_detect(button_next, GPIO.RISING)

Using events to work with buttons is a nonblocking technique. The program continues running even if no button is pressed; it doesn’t wait. You can read more about events in Chapter 9.

Next, you initialize some important variables and constants:

USERNAME = "YOUR_USERNAME" # Just the part before the @ sign, add yours here
PASSWORD = "YOUR_PASSWORD" # Replace with your password
LOOP_FREQ = 5 # Check buttons every 5 seconds
CHECK_LATEST_MAIL = 60 # Check for a new email every 60 seconds

current_message = 0 # Store position of our current message selected
scroll = 0 # Store how much you want to scroll down or up your mail

The variable current_message has a value that changes depending on the presses of the Previous and Next buttons. The scroll variable changes depending on the presses of the Scroll Up and Scroll Down pushbuttons.

Next, you set up the LCD by configuring it according to the BeagleBone pins that are connected to it, defining constants for the number of rows and columns you have (you’ll be using these constants a lot), and finally initializing the LCD by using the characteristics you defined. You also clear the screen to get rid of any messages that could have been there before you started running the program.

# BeagleBone LCD configuration
lcd_rs = 'P8_8'
lcd_en = 'P8_10'
lcd_d4 = 'P8_18'
lcd_d5 = 'P8_16'
lcd_d6 = 'P8_14'
lcd_d7 = 'P8_12'
lcd_backlight = 'P8_7'

# Define LCD column and row size for 20x4 LCD
# You can change the columns and rows size to any LCD size. For example 16x2
LCD_COLUMNS = 20
LCD_ROWS = 4

# Initialize the LCD using the pins above
lcd = LCD.Adafruit_CharLCD(lcd_rs, lcd_en, lcd_d4, lcd_d5, lcd_d6, lcd_d7, lcd_columns, lcd_rows, lcd_backlight)
# Clear LCD screen
lcd.clear()

After that come the function definitions. Those functions are the real brains of the program, and each one of them deserves special attention.

Select previous mail

This function gets as a parameter the current_message variable, which holds a value from 0 to 19 that decides which entry of the feed parser (in other words, which email in your inbox) you want to display. The main part of the code calls this function whenever the Previous button is pressed and returns current_message - 1 to indicate that you want to display the previous message. Note that the program returns 0 if you attempt to go beyond that.

# Select previous mail
def select_previous_message(current_message):
current_message -= 1
if current_message < 0: # can't go further than this
current_message = 0
return current_message

Select next mail

This function works in a similar fashion to the preceding one, except that it happens when the Next button is pressed, and it returns current_message + 1 to indicate that you want to display the next message.

# Select next mail
def select_next_message(current_message, number_entries):
if current_message < (number_entries-1): # can't go further than this
current_message += 1
return current_message

Note that this function also receives the parameter number_entries, which holds the number of emails inside your mailbox (up to a maximum of 20). You can increase the variable only if it hasn’t surpassed the number of entries — hence, that if. Also note that current_message is used as an index, and indexes start at 0, which is why you compare current_message with number_entries - 1 rather than simply number_entries.

Return date of latest mail

This function runs every CHECK_LATEST_MAIL seconds and parses the email in the same fashion described in the preceding sections. After saving all the data from the email at the variable m, you simply return the date of the most recent email. If there are no emails in the mailbox, you return an empty string.

# Return date of latest mail
def latest_mail_date():
m = "" # Clear m list
# Save all mail date in list called m
m = feedparser.parse("https://" + USERNAME + ":" + PASSWORD + "@gmail.google.com/gmail/feed/atom")
# Check if m list is empty
if len(m.entries) == 0:
date = ""
else:
# Save our latest mail date in variable date
date = m.entries[0].published
return date

Read and save current mail

This function does all the heavy-lifting. The function takes the entry that you want to read (0 if no buttons were pressed) and does the following things sequentially:

1. The function clears the previous list of parsed email data and saves the data from the current email in an object called m:

m = "" # Clear m list
# Save all mail date in list called m
m = feedparser.parse("https://" + USERNAME + ":" + PASSWORD + "@gmail.google.com/gmail/feed/atom")

2. The function checks the length of m to know the number of emails in your mailbox and saves the value in number_entries. This variable is returned at the end of the function call. Afterward, the function checks whether the mailbox is empty and saves mail_data as an empty list if that’s the case. This variable is also returned at the end of the function.

# Store the number of unread mails in number_entries variable
number_entries = len(m.entries)
# If no emails in inbox, returns mail_data empty
if number_entries == 0:
mail_data = []

If the mailbox isn’t empty, the function saves the email’s author, title, and message in three variables and creates a temporary variable to hold all that data, with the fields separated by \n, separating each field line by line. Additionally, a special null character, \0, is added at the end of the message to detect in a simple way when the end of the message has been reached.

Keep in mind that the feed parser can fetch only the first 100 characters of an email’s feed.

author = m.entries[current_message].author # Save author name
title = m.entries[current_message].title # Save mail title
message = m.entries[current_message].description # Save first 100 characters of our mail
# Create a string with all the data in a temporary variable
tmp_mail_data = "A:" + author + "\n" + "T:" + title + "\n" + "M:" + message + "\0"

3. After clearing the variables i, tmp_data, and mail_data, the program goes through each character of the tmp_mail_data string to find the relevant information and saves it, ready to be sent to the LCD, in tmp_data.

Before you go any further, it’s important that you understand the task of four variables within this function:

· tmp_mail_data saves all the data that you want from the parser, separated by \n characters.

· tmp_data is a variable that saves the data in a format ready to be displayed on the LCD, which means placing \n every 20 or 16 characters (depending on your LCD).

· mail_data is the main string to be sent to be displayed on the LCD.

· i is just a counter that lets you know when you’ve copied a number of characters equal to LCD_COLUMNS. When that happens, it’s time to display the message on the LCD in a new line.

Thus, you have a for loop that goes through each character in tmp_mail_data and does the following things:

5. Adds the character to tmp_data.

6. Checks for the end of a line (LCD_COLUMNS) or \n. If the code reaches the end of a line without finding \n, it adds \n. Then the code appends the data to the mail_data list, using the append() function. When this if happens, the code fetches the next line to be displayed on the LCD, which means resetting the tmp_data and i variables.

7. Otherwise, if the code detects \0, the end of the message has been reached. It appends this last part of the message to mail_data, also using the rstrip() function. The rstrip() function removes a character from a string. You want to remove \0 because it’s merely there to help you figure out when you reach the end; you don’t want it to be part of the message.

8. Increments i at every iteration of the for loop.

9. Returns mail_data and number_entries.

for character in tmp_mail_data:
tmp_data += character # Concatenate each character in our variable tmp_data
# Check if you reached the max number of characters per row
# or if it is time to do newline
if i == lcd_columns or character == '\n':
# Add a newline to the end of string, if it doesn't have one yet
if character != '\n':
tmp_data += "\n"
# Appends the data to our list
mail_data.append(tmp_data)
# Reset variables
tmp_data = ""
i=0
# If we reached the last character, it appends the last data in our mail_data list
elif character == '\0':
mail_data.append(tmp_data.rstrip('\0'))
i += 1 # Increment variable i by 1
return mail_data, number_entries

Here’s the complete code:

# Read and save current mail
def read_save_mail(current_message):
m = "" # Clear m list
# Save all mail date in list called m
m = feedparser.parse("https://" + USERNAME + ":" + PASSWORD + "@gmail.google.com/gmail/feed/atom")
# Store the number of unread mails in number_entries variable
number_entries = len(m.entries)
# If no emails in inbox, returns mail_data empty
if number_entries == 0:
mail_data = []
else:
author = m.entries[current_message].author # Save author name
title = m.entries[current_message].title # Save mail title
message = m.entries[current_message].description # Save first 100 characters of our mail
# Create a string with all the data in a temporary variable
tmp_mail_data = "A:" + author + "\n" + "T:" + title + "\n" + "M:" + message + "\0"
# Clear variables i, tmp_data and mail_data
i = 0
tmp_data = ""
mail_data = []
# Go through each character of tmp_mail_data string
for character in tmp_mail_data:
tmp_data += character # Concatenate each character in our variable tmp_data
# Check if you reached the max number of characters per row
# or if it is time to do newline
if i == lcd_columns or character == '\n':
# Add a newline to the end of string, if it doesn't have one
yet if character != '\n':
tmp_data += "\n"
# Appends the data to our list
mail_data.append(tmp_data)
# Reset variables
tmp_data = ""
i=0
# If we reached the last character, it appends the last data in our mail_data list
elif character == '\0':
mail_data.append(tmp_data.rstrip('\0'))
i += 1 # Increment variable i by 1
return mail_data, number_entries

Display selected mail in the LCD screen

This last function displays the email on the LCD, using all the variables you’ve created so far. It takes mail_data and number_entries from the preceding function as parameters, as well as current_message, which depended on the Previous and Next button presses. Another parameter is the scroll variable, which should be a value (minimum 0) indicating whether you want to scroll the message up or down, depending on which button (Scroll Up or Scroll Down) has been pressed.

The function clears the LCD screen and checks for the number of entries as follows:

· If the number of entries is bigger than 0, the mailbox isn’t empty, and the function has work to do. After resetting the variables i and tmp_data, the code goes through each row of the LCD in a while loop.

In this while loop, that runs while i is less than lcd_rows, the code prepares the message to be displayed line by line. The tmp_data variable saves the part of the mail_data variable that you want to display, depending on the current line as well as the use of the Scroll Up and Scroll Down buttons.

After this loop, the message is ready to be displayed inside the tmp_data string. When sending the message to the LCD through lcd.message(), though, the code strips it of the final \n.

· Otherwise, if the number of entries is 0, display a message saying that there are no emails in your mailbox.

# Display selected mail in the LCD screen
# Each time the button_scroll_down is pressed, it scrolls down our mail by one line
def display_message(mail_data, number_entries, current_message, scroll):
lcd.clear() # Clear LCD screen
# Check if there is a mail to display
if number_entries > 0:
# Reset variables before while loop
i = 0
tmp_data = ""
# Goes through each row of our LCD
while i < lcd_rows:
# Prepare message to be displayed in LCD screen
tmp_data += mail_data[scroll+i]
i += 1 # Increment variable i by 1
# Display final message in LCD screen
lcd.message(tmp_data.rstrip('\n'))
else:
# Display following message in your LCD, if there are no new mails
lcd.message("No new emails in\n your inbox...")

Setup

The next part of the code is straightforward. It simply uses the functions you created to define initial conditions, and it creates a time_stamp to see when exactly the program started running.

# Initial setup
# Updates variables and LCD screen with the latest mail
recent_date = latest_mail_date()
date = recent_date
mail_data, number_entries = read_save_mail(current_message)
display_message(mail_data, number_entries, current_message, scroll)
time_stamp = time.time()

The time_time() function checks the current time in seconds since the January 1, 1970. By saving that value into a variable, you create a time stamp. You can then use the time_time() function again and compare the value it returns to your time stamp to see how many seconds have passed since the last call of the time_time() function. Chapter 11 talks a little bit more about time stamps and the time library.

The while True: loop

The while True: loop deals with detecting events on the buttons, calling all the required functions to display the email that you want, as well as the part that you desired (scrolled up or scrolled down). It’s important to note that at the end of the loop, the time.time() function determines whether CHECK_LATEST_MAIL has elapsed so your program accesses your email only every CHECK_LATEST_MAIL seconds.

while True:
# check if we have a new mail
if date != recent_date:
# Reset our variables
current_message = 0
scroll = 0
# Update our variables and LCD screen with the latest mail
mail_data, number_entries = read_save_mail(current_message)
display_message(mail_data, number_entries, current_message, scroll)
recent_date = latest_mail_date()
else:
# Detect if we have pressed button previous
if GPIO.event_detected(button_previous):
scroll = 0 # Reset scroll variable
# Update our variables and LCD screen with the latest mail
current_message = select_previous_message(current_message)
mail_data, number_entries = read_save_mail(current_message)
display_message(mail_data, number_entries, current_message, scroll)
# Detect if we have pressed the button next
elif GPIO.event_detected(button_next):
scroll = 0 # Reset scroll variable
# Update our variables and LCD screen with the latest mail
current_message = select_next_message(current_message, number_entries)
mail_data, number_entries = read_save_mail(current_message)
display_message(mail_data, number_entries, current_message, scroll)
# Detect if we have pressed the button scroll up
elif GPIO.event_detected(button_scroll_up):
if scroll > 0:
scroll -= 1 # Decrements our variable 1 position
# Scrolls down one line of text in our message
display_message(mail_data, number_entries, current_message, scroll)
# Detect if we have pressed the button scroll down
elif GPIO.event_detected(button_scroll_down):
if (scroll+lcd_rows) < len(mail_data):
scroll += 1 # Increments our variable 1 position
# Scrolls down one line of text in our message
display_message(mail_data, number_entries, current_message, scroll)
# 60 second timer, to check if we have received a new mail
if time.time() - time_stamp > CHECK_LATEST_MAIL:
date = latest_mail_date() # Update variable date with the most recent mail date
time_stamp = time.time() # Resets our timer
# Wait 5 seconds
time.sleep(LOOP_FREQ)

Adding the LED and Buzzer

No advanced electronics project is complete without an LED. Also, if this program is supposed to notify you whenever you receive an email, having a buzzer outputting sound whenever a new mail arrives would be fun. This section adds a cherry on the top of your project.

In our experience, some buzzers that are simply connected to a voltage without anything in between output a deafening, ridiculously sharp sound that will probably give you nightmares. Given that fact, this project includes a potentiometer that enables you to reduce the intensity of the buzzer, or even mute it, by limiting the current that goes into the buzzer. We suggest that you double-check your wiring and your code before you run this script. Buzzers are fun, but if you happen to have a bug that makes it stay on forever, you may want to throw your BeagleBone out the window. If that happens, remember that you can turn off the buzzer quickly by pulling the wire that connects it to GND or 3.3V. It’s generally inadvisable to pull wires on powered-on circuits, but a nonstopping buzzer is almost a national emergency.

Wiring the LED and buzzer

Follow these steps or check Figure 14-6 to wire up these new additions:

1. Connect the positive leg (longer lead) of an LED to P9_16 by using a jumper.

2. Connect a 220 Ω or 470 Ω resistor between the LED and GND.

3. Connect one of the outer legs of the potentiometer to P9_14.

You could use the buzzer alone, but this project uses a potentiometer in series with the buzzer so that you can limit its output or even mute it.

4. Connect the other outer leg of the potentiometer to GND.

5. Connect the middle leg of the potentiometer to the positive wire — the red one — of the buzzer.

6. Connect the buzzer’s negative wire — the black one — to GND.

Figure 14-6: LCD, buttons, LED, and buzzer wired to the BeagleBone Black.

Writing the code for the LED and buzzer

To add functionality for the LED and the buzzer to your code, follow these steps:

1. Initialize two more variables.

buzzer = "P9_14"
led = "P9_16"

2. Set up two general purpose input/output (GPIO) outputs.

GPIO.setup(buzzer, GPIO.OUT)
GPIO.setup(led, GPIO.OUT)

3. Change the code of the first if of the while True: loop, which checks for new email.

# check if we have a new mail
if date != recent_date:
# New stuff starts here
# If we have a new mail, it turns our buzzer ON for 2 seconds and the LED for 10 seconds.
GPIO.output(buzzer, GPIO.HIGH)
GPIO.output(led, GPIO.HIGH)
time.sleep(2)
GPIO.output(buzzer, GPIO.LOW)
time.sleep(8)
GPIO.output(led, GPIO.LOW)
# New stuff ends here
# Reset our variables
current_message = 0
scroll = 0
# Update our variables and LCD screen with the latest mail
mail_data, number_entries = read_save_mail(current_message)
display_message(mail_data, number_entries, current_message, scroll)
recent_date = latest_mail_date()

Running the script of the complete project

It’s time to try the script! Save the latest file — the one that contains the code for the complete project — and run it. Set those LOOP_FREQ and CHECK_LATEST_MAIL constants to values that you feel comfortable with. Send yourself tons of emails (you can do this automatically with the script in Chapter 10 in the section “Sending an Email with Python”) to see whether everything is working properly.

All the code for this project is available at www.dummies.com/cheatsheet/beaglebone.