Sunday, February 22, 2009

GMail Notifier on an Arduino

The exams are over and I've been hacking a bit on the Arduino today. So I came up with a simple hack which blinks an LED on the Arduino if you've got unread mails in your Gmail inbox. I assume that you're familiar with the basics of Arduino.

Equipment

  • A computer with an internet connection

  • Python

  • pySerial

  • Arduino ( I'm using Duemilanove )

  • Red LED

  • Pushbutton (optional)

  • Wires

On the computer

A python script will run continuously on the computer, and fetch the Gmail RSS feed every few minutes. pySerial will be used to notify the Arduino of new mails.

Here are our imports and constants

# ~ Gmail Notifier for Arduino
# ~ This file is released under the public domain

import httplib
import getpass
import base64
import re
import time
import serial

INTERVAL = 5 # check every INTERVAL minutes

serv = 'mail.google.com'
path = '/mail/feed/atom'
# ask user name and password and encode them for authentication

auth = base64.encodestring(
'%s:%s'%(raw_input('Username: '),
getpass.getpass()))


So first, fetching the feed. We'll use httplib. Here is the code:

def getfeed():
print 'Checking...'
conn = httplib.HTTPSConnection(serv)
conn.putrequest('GET', path)
conn.putheader('Authorization', 'Basic %s'%auth)
conn.endheaders()
return conn.getresponse().read()


Next lets get the count. Gmail replies in the following format. In the case of new mails there is more information, but we don't care about that. We're mainly interested in fullcount.

<?xml version="1.0" encoding="UTF-8"?>
<feed version="0.3" xmlns="http://purl.org/atom/ns#">
<title>Gmail - Inbox for nsm.nikhil@gmail.com</title>
<tagline>New messages in your Gmail Inbox</tagline>
<fullcount>0</fullcount>
<link rel="alternate" href="http://mail.google.com/mail" type="text/html" />
<modified>2009-02-22T11:00:33Z</modified>
</feed>


So we'll use regular expressions to get the count.

def count(data):
matches = re.findall('<fullcount>([0-9]+)</fullcount>', data)
if len(matches) == 0:
print 'Error in parsing feed, check user name and password are correct'
return 0
return int(matches[0])


We'll need to write this to the serial port.

def writeSer(data):
try:
# the best way to find this out is to launch the Arduino environment
# and see what it says under Tools -> Serial Port
ser = serial.Serial('/dev/ttyUSB0')
ser.write(data)
except serial.serialutil.SerialException:
print 'Error writing to serial device'
raise


Now that we're done with the functions, it's time to make them work together


# subtract so that we check first time
last_check = time.time() - INTERVAL*60

while True:
if time.time() - last_check < INTERVAL*60:
continue
last_check = time.time()
msgs = count(getfeed())
print msgs,'mails'
writeSer(str(msgs))



Thats the computer part.

On the Arduino


The circuit :



The LED is on pin 13 and goes to ground. The button takes 5V through the power pins on the analog side, via a 220 ohm resistor. The other leg is grounded. Pin 4 can be used to read the state of the button. The wire from pin 4 connects to the 5V leg of the button.

The code is dead simple and so is presented together.


int ledPin = 13; // connect led to digital pin 13, or use default small one
int bPin = 4; // connect button to digital pin 4
boolean blink = false; // holds our current state

int INTERVAL = 200; // led blink rate in milliseconds

void setup() {
Serial.begin(9600);
pinMode(ledPin, OUTPUT);
}

void loop() {
if(Serial.available() > 0)
blink = Serial.read() > 48;// 48 is 0 is ASCII

if(digitalRead(bPin) == LOW) // button pressed
blink = false;

// blink is true if we got serial input
// or we had got serial input and button hasn't been pressed yet.
if(blink) {
digitalWrite(ledPin, HIGH);
delay(INTERVAL);
digitalWrite(ledPin, LOW);
delay(INTERVAL);
}
else
digitalWrite(ledPin, LOW);
}


The button is used to switch off the blinking once you've noticed that you've got mail and don't want it to keep blinking till the next check.

Running

Verify and Upload the code to the Arduino. You can try entering numbers in the Serial Monitor to check that the circuit works. Remember to switch off the Serial Monitor.

Now start your script, python mailarduino.py. Enter authentication details. Now sit back and relax... oh wait, you've got mail.

Full python script ( mailarduino.py )

import httplib
import getpass
import base64
import re
import time
import serial

INTERVAL = 5 # check every INTERVAL minutes

serv = 'mail.google.com'
path = '/mail/feed/atom'

auth = base64.encodestring(
'%s:%s'%(raw_input('Username: '),
getpass.getpass()))

def count(data):
matches = re.findall('<fullcount>([0-9]+)</fullcount>', data)
if len(matches) == 0:
print 'Error in parsing feed, check user name and password are correct'
return 0
return int(matches[0])

def getfeed():
print 'Checking...'
conn = httplib.HTTPSConnection(serv)
conn.putrequest('GET', path)
conn.putheader('Authorization', 'Basic %s'%auth)
conn.endheaders()
return conn.getresponse().read()

def writeSer(data):
try:
ser = serial.Serial('/dev/ttyUSB0')
ser.write(data)
except serial.serialutil.SerialException:
print 'Error writing to serial device'
raise

last_check = time.time() - INTERVAL*60 # subtract so that we check first time

while True:
if time.time() - last_check < INTERVAL*60:
continue
last_check = time.time()
msgs = count(getfeed())
print msgs,'mails'
writeSer(str(msgs))

11 comments:

  1. I've been wanting to do something like this for a while now but instead of just being for GMail it would also notify when someone pings me on IRC or IM (Via a hook into the window system or something so when the taskbar flashes so does the LED).

    Mine was also going to be wireless so I could stick it on my workbench (Which is not near my PC) and use a raw AVR but that's just details. =)

    I'll notify you if I ever get around to actually building it.

    ReplyDelete
  2. Ya that would be cool.

    Why don't you put an easter egg into KWin such that it continuously attempts to write to the serial port if there is a window requesting attention? :)

    ReplyDelete
  3. Dude i want to buy an arduino duemilanove searched a lot but not able to find a single place to buy it in india . Where did u get u r board from .

    ReplyDelete
  4. this is a really cool project i'd love to build a notifier that tells me which friends are on gmail chat, a light for each friend, hidden behind a pic of the friend. when they are available to chat there pic lights up i dont really know where to start tho with regards getting the information from gmail. i'm pretty new to this.
    any pointers would be really appreciated.

    ReplyDelete
  5. well you might want to use jabber.py ( jabberpy.sf.net ) or xmpppy ( http://xmpppy.sourceforge.net/ )
    to communicate with Google Talk.

    I've no idea how they work, but you should be able to figure that out. Basically you want to be a XMPP client and then send the events out to your serial port.

    ReplyDelete
  6. does this work without an internet connection??
    also... could you post what script we put on arduino and what script we put in python?? I am a beginner and need help!! :-P

    ReplyDelete
  7. no it won't work without an internet connection.

    put mailarduino.py ( last part of post ) on the computer ( .py is for python )

    Put "the code is dead simple and so is presented together" [code follows] on the arduino

    ReplyDelete
  8. I put this together, but the python script says that there is no such module as "serial", even though I have installed pyserial. Any ideas?

    ReplyDelete
  9. This comment has been removed by a blog administrator.

    ReplyDelete
  10. Dial Facebook helpline number and instantly resolve all issues of Facebook account. Facebook toll free number team(24*7) available to solve issues of mail account.Customer Support Service Number

    ReplyDelete