benmason
Posts: 23
Joined: Sat Jan 19, 2013 7:40 pm

Push button to send email

Thu Jan 31, 2013 1:38 am

Hi All,

I am trying to code a program (as part of my learning to use GPIO and Python) which will send an email once a GPIO input goes high.

The code below should have waited for a button connected between 3.3v and GPIO 17 to be pushed and then sent the test email. however as soon as the program runs it Prints the text and then sends the email without any hardware being attached and as such no input to pin 17.

The email code works as I receive the mail,

Code: Select all

import smtplib
from email.mime.text import MIMEText
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.IN)
print "press button to send email"
input = GPIO.input(17)
if input == True:
        #create email 
        message = """Test email send via RPi and Python"""
        msg = MIMEText(message)
        msg['subject'] = 'Rpi test'
        msg['from'] = 'my email address>'
        msg['to'] = 'recipient email'
        # send mail
        s = smtplib.SMTP('smtp.o2.co.uk')
        s.login('username' , 'password')
        s.sendmail(msg['From'], msg['To'], msg.as_string())
        s.quit
Any help greatly appreciated.

Ben

haincha
Posts: 16
Joined: Tue Sep 25, 2012 11:53 pm

Re: Push button to send email

Thu Jan 31, 2013 3:07 am

Not a pro, nor do I have experience with the GPIO. But, I imagine that the program is sending the email away because input has a value thus being True.

Do a print input, to get it's value.

Then change your if statement to a while statement.

Because it isn't going to wait for any input. It is either going to send the email or not upon running.

If there is a while loop, it will loop until your variable changes.

I hope I am at least of some help.

To clarify a little.

Code: Select all

while input = value:
     #doesn't have to have anything in here really.
else:
       your email code.

User avatar
alexeames
Forum Moderator
Forum Moderator
Posts: 2808
Joined: Sat Mar 03, 2012 11:57 am
Location: UK
Contact: Website

Re: Push button to send email

Thu Jan 31, 2013 8:35 am

Actually there are three issues here:

1) It could be your GPIO port is floating if you have not used a pullup or pull-down resistor (although I don't think that's what it is in this case)

2) Probably an issue of types. When you read a port in RPi.GPIO it gives you a boolean value of True of False. There may be other ways of doing it, but in my scripts I've found the easiest way to handle a comparison of a Boolean is to make it a string first.

e.g.

Code: Select all

pressed_or_not = str(GPIO.input(25))
if pressed_or_not == 'True':
    whatever
You can see what sort of variable you are dealing with using:

Code: Select all

print type(pressed_or_not)
3) In your code, I think it is just testing whether or not the input has a value, not what it actually is

Try this...

Code: Select all

input = str(GPIO.input(17))
if input == 'True':
There is another issue in that it's only going to test the button condition once. Using a while loop as mentioned above could help you get round this issue.
Alex Eames RasPi.TV, RasP.iO

benmason
Posts: 23
Joined: Sat Jan 19, 2013 7:40 pm

Re: Push button to send email

Thu Jan 31, 2013 11:42 am

Thank you everyone, I will post the results when I have tried them.

User avatar
rurwin
Forum Moderator
Forum Moderator
Posts: 4205
Joined: Mon Jan 09, 2012 3:16 pm
Contact: Website

Re: Push button to send email

Thu Jan 31, 2013 11:56 am

Converting a boolean to a string is horribly inefficient and you should never test a boolean for equality anyway; it is redundant, inefficient and difficult to maintain. This is the correct paradigm:

if the GPIO is active high (pulled down and switched to +V):

Code: Select all

isPressed = GPIO.input(17)
if isPressed :
or if the GPIO is active low (pulled up and switched to ground):

Code: Select all

isPressed = not GPIO.input(17)
if isPressed :
By naming the variable according to the condition if it is true, you allow the IF to make sense as English prose without the redundant comparison, and so you don't get confused. By making the variable refer to something that is meaningful to you and the program, rather than the arbitrary wiring of the switch, the code becomes more straight-forward and more readable, you get less confused and, if the switch wiring ever changes, you only have to fix it in one place.

User avatar
alexeames
Forum Moderator
Forum Moderator
Posts: 2808
Joined: Sat Mar 03, 2012 11:57 am
Location: UK
Contact: Website

Re: Push button to send email

Thu Jan 31, 2013 12:16 pm

Excellent - thank you Rurwin :) I'll be able to streamline my code in several programs to make them more efficient now. It's completely obvious now I've seen you mention it. :lol:
Last edited by alexeames on Thu Jan 31, 2013 12:33 pm, edited 2 times in total.
Alex Eames RasPi.TV, RasP.iO

User avatar
rurwin
Forum Moderator
Forum Moderator
Posts: 4205
Joined: Mon Jan 09, 2012 3:16 pm
Contact: Website

Re: Push button to send email

Thu Jan 31, 2013 12:23 pm

benmason wrote: The code below should have waited for a button connected between 3.3v and GPIO 17 to be pushed and then sent the test email. however as soon as the program runs it Prints the text and then sends the email without any hardware being attached and as such no input to pin 17.
There are two possible reasons for that:
1. You could be getting noise on the input pin.
2. An unattached input could read high.
The second alternative is probably the case. Whichever, the solution is to pull the pin down to ground with a resistor, either externally or internally using RPi.GPIO.

You will need a while loop around the if as others have said. If you want to be able to push the button more than once every time you run the program, then you will also have to detect when the button stops being pressed, and you will need to wait for the switch contacts to stop bouncing. If you neglect either of these you will send yourself lots and lots of email.

benmason
Posts: 23
Joined: Sat Jan 19, 2013 7:40 pm

Re: Push button to send email

Thu Jan 31, 2013 5:29 pm

The finished and working code looks like this,

Code: Select all

#import mod
import smtplib
from email.mime.text import MIMEText
import RPi.GPIO as GPIO
import time
#setup gpio pins
GPIO.cleanup()
GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.IN)
#Print message on screen
print "Push button to send email,"
#start loop
loop = "1"
while loop == "1":
        #test GPIO for input
        if GPIO.input(17):
                #create email 
                message = """Test email send via RPi and Python"""
                msg = MIMEText(message)
                msg['subject'] = 'Rpi test'
                msg['from'] = 'My email>'
                msg['to'] = 'Their email'
                # send mail
                s = smtplib.SMTP('smtp server')
                s.login('user name' , 'Password')
                s.sendmail(msg['From'], msg['To'], msg.as_string())
                s.quit
                print "Email sent"
                time.sleep(2)
        while GPIO.input(17):
                pass
It works just as I wanted with the only snag being it must be run as root, how can I make it work with the pi user on Rasbian?

Many thanks to all contributors.

Ben

-rst-
Posts: 1316
Joined: Thu Nov 01, 2012 12:12 pm
Location: Dublin, Ireland

Re: Push button to send email

Thu Jan 31, 2013 5:45 pm

benmason wrote:It works just as I wanted with the only snag being it must be run as root, how can I make it work with the pi user on Rasbian?
You probably cannot, as most of the ways the GPIO libraries get access to the system resources require root permissions...

P.S. In case you are interested in learning good coding habits, you could look at replacing that 'while loop = "1":' with 'while True:' ;) If you at some point want to actually use a variable there to be able to break out the loop, it would be best to use 'loop = True' and 'while loop:'
http://raspberrycompote.blogspot.com/ - Low-level graphics and 'Coding Gold Dust'

User avatar
alexeames
Forum Moderator
Forum Moderator
Posts: 2808
Joined: Sat Mar 03, 2012 11:57 am
Location: UK
Contact: Website

Re: Push button to send email

Thu Jan 31, 2013 10:30 pm

-rst- wrote:P.S. In case you are interested in learning good coding habits, you could look at replacing that 'while loop = "1":' with 'while True:' ;) If you at some point want to actually use a variable there to be able to break out the loop, it would be best to use 'loop = True' and 'while loop:'
These tips are gold-dust to those of us relatively new to Python and/or self taught. Keep them coming please. :D
Alex Eames RasPi.TV, RasP.iO

User avatar
rurwin
Forum Moderator
Forum Moderator
Posts: 4205
Joined: Mon Jan 09, 2012 3:16 pm
Contact: Website

Re: Push button to send email

Thu Jan 31, 2013 11:25 pm

One of my friends once used the following construct, which we couldn't fault ;-)

Code: Select all

Sinclair_Produces_A_Decent_Home_Micro = False
...
DO
...
UNTIL Sinclair_Produces_A_Decent_Home_Micro

benmason
Posts: 23
Joined: Sat Jan 19, 2013 7:40 pm

Re: Push button to send email

Sun Feb 03, 2013 11:23 pm

Thanks for the advice,

How would one break a While True loop?

User avatar
croston
Posts: 667
Joined: Sat Nov 26, 2011 12:33 pm
Location: Blackpool
Contact: Website

Re: Push button to send email

Sun Feb 03, 2013 11:30 pm

benmason wrote:Thanks for the advice, How would one break a While True loop?
Use the 'break' statement. Exampke:

Code: Select all

while True:
    print("You will see this line.")
    break
    print ("But not this line")
Also see:
http://docs.python.org/2/tutorial/contr ... s-on-loops

-rst-
Posts: 1316
Joined: Thu Nov 01, 2012 12:12 pm
Location: Dublin, Ireland

Re: Push button to send email

Mon Feb 04, 2013 10:54 am

croston wrote:
benmason wrote:Thanks for the advice, How would one break a While True loop?
Use the 'break' statement. Exampke:

Code: Select all

while True:
    print("You will see this line.")
    break
    print ("But not this line")
Also see:
http://docs.python.org/2/tutorial/contr ... s-on-loops
Or just use the Ctrl+C key combination... which would be best to handle in the code using 'except KeyboardInterrupt' to be able to do cleanup (like GPIO.cleanup() to avoid the 'in use' warning...).

The 'while True' is supposed to be an infinite loop (well, maybe a 'busy loop' or 'idle loop' to be exact): most typically used in a server/daemon type application that is supposed to never exit. Quite often of course used in code examples/samples, where (due to keeping the code short and simple) there is no logic to handle a real exit condition.

As I mentioned earlier, if there is a certain condition where you would want to exit the loop, use a variable:

Code: Select all

doLoop = True
while doLoop:
    ...
    if some_condition_met:
        doLoop = False
Of course, would be best to name the variable somehow meaningful (obviously depending on the use-case) like:

Code: Select all

exitButtonPressed = False
while not exitButtonPressed:
    ...
    exitButtonPressed = checkButtonPress()
or

Code: Select all

isDone = False
while not isDone:
    ...
    if some_condition_met:
        isDone = True
...the idea being that the code is easy to read and understand.


Inspired by rurwin's example, I dug up this bit of C code that is possibly the clearest (most readable) way to write an infinite loop:

Code: Select all

#define EVER (;1;)
...
    for EVER {
        ...
    }
;)
http://raspberrycompote.blogspot.com/ - Low-level graphics and 'Coding Gold Dust'

N1TI
Posts: 2
Joined: Sat Dec 12, 2015 3:33 pm

Re: Push button to send email

Mon Dec 28, 2015 10:30 pm

Could you post a copy of your final optimized code for this? I have a similar need.

Thanks,

Tim

Return to “Python”

Who is online

Users browsing this forum: No registered users and 13 guests