6
\$\begingroup\$

I'm learning how to use Python with the Raspberry Pi. I successfully followed the tutorial for how to have a Python script run on the Pi to check for new email and turn on an LED if any new messages are in an inbox. I wanted to give myself a challenge by adding a feature to blink a secondary LED to indicate the number of waiting messages. I played around for a while and got a script working, but would like to know if I implemented this correctly.

Am I using threading correctly? Is there an easier way to check a feed every n seconds, and if new messages are present, then continually run blink() until the next feed check?

#!/user/bin/env python
from threading import Thread, Event
from time import sleep
import feedparser
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
BLUE_LED = 17
BIG_LED = 23
GPIO.setup(BLUE_LED, GPIO.OUT)
GPIO.setup(BIG_LED, GPIO.OUT)
USERNAME = "[email protected]"
PASSWORD = "gzvioCNiAvFvKoqY"
class Repeat(Thread):
 def __init__(self,delay,function,*args,**kwargs):
 Thread.__init__(self)
 self.abort = Event()
 self.delay = delay
 self.args = args
 self.kwargs = kwargs
 self.function = function
 def stop(self):
 self.abort.set()
 def run(self):
 while not self.abort.isSet():
 self.function(*self.args,**self.kwargs)
 self.abort.wait(self.delay)
def blink(count):
 for x in range(0, count):
 print "blink", x + 1
 GPIO.output(BLUE_LED, True)
 sleep(.25)
 GPIO.output(BLUE_LED, False)
 sleep(.25)
 sleep(1) #pause between blinks
try:
 while True:
 print "Starting b"
 b = Repeat(1,blink,0)
 b.start()
 big_led = 0
 print "---> ---> Checking feed"
 messages = int(feedparser.parse("https://" + USERNAME + ":" + PASSWORD + "@mail.google.com/gmail/feed/atom")["feed"]["fullcount"])
 if messages >= 1:
 # turn on big LED
 print "Turning on Big LED"
 GPIO.output(BIG_LED, True)
 big_led = 1
 print "There are", messages, "unread email messages"
 b = Repeat(1,blink,messages)
 b.start()
 else:
 print "There are no new messages"
 if big_led == 1:
 print "Turning off Big LED"
 GPIO.output(BIG_LED, False)
 sleep(60) # check the feed every minute for new mail
 print "Stopping b"
 b.stop()
 b.join()
except (KeyboardInterrupt, SystemExit):
 b.stop()
 b.join()
 GPIO.cleanup()
 print 'Program Stopped Manually!'
 raise
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Apr 14, 2014 at 14:46
\$\endgroup\$
4
  • 1
    \$\begingroup\$ I would replace Thread.__init__(self) with the super(Repeat, self).__init__() as it is a better way of calling base functions. \$\endgroup\$ Commented Apr 15, 2014 at 18:18
  • \$\begingroup\$ Also consider breaking up larger lines into smaller portions to keep on track with PEP8's "Limit all lines to a maximum of 79 characters" rule. And use the sting.format function when surrounding strings with more text. ie) "https://{}:{}@...".format(username,password) \$\endgroup\$ Commented Apr 15, 2014 at 18:29
  • \$\begingroup\$ Minor point: the try...except could quite possibly be better a try...finally. \$\endgroup\$ Commented Apr 16, 2014 at 15:38
  • \$\begingroup\$ Great suggestions! Thank you. I'm going to try Veedrac's structure below and look up what PEP8 says. I generally like to avoid writing long lines of code. \$\endgroup\$ Commented Apr 17, 2014 at 22:10

1 Answer 1

4
\$\begingroup\$

That looks about right. Your thread doesn't do very much, though, so you might want to consider something like so (untested):

def blink(abort, delay, count):
 while not abort.isSet():
 for x in range(0, count):
 print "blink", x + 1
 GPIO.output(BLUE_LED, True)
 sleep(.25)
 GPIO.output(BLUE_LED, False)
 sleep(.25)
 sleep(1) #pause between blinks
 abort.wait(delay)

Then later

thread_stop = Event()
b = threading.Thread.run(target=blink, args=(thread_stop, 1, 0))

which prevents need for the whole class. It's not a suggestion as much as a note that you did more than you needed to.

Note that your blink should really be using abort.wait and should cooperate with the other abort.wait to have sensible timings.

answered Apr 16, 2014 at 15:54
\$\endgroup\$
2
  • \$\begingroup\$ Thanks for your answer Veedrac. I'll give your suggestion a try. I didn't know about about.wait which seems like exactly what I was going for. Good to know I at least got the threading aspect right—even though it is doing very little. \$\endgroup\$ Commented Apr 17, 2014 at 22:07
  • \$\begingroup\$ The start parameter of range defaults to zero, so you can write for x in range(count) which is the Python idiom for this scenario. \$\endgroup\$ Commented Apr 18, 2014 at 7:18

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.