PIR sensors + Arduino + Python + email alerts - python

We are working on a project for school, and we have 2 PIR motion sensors running off an Arduino microcontroller. We are able to view the output of the serial port in both the Ardunio IDE and Python IDLE.
What we want to do next is, after about 30 seconds of motion being detected, sending out an email alert, seeing that we don't have Ethernet capability at this point, we figured the easiest way would be to grab the emailing through Python.
How to achieve this?
Update:
At this point we can send an email from Python, we can read the Arduino serial port in Python, but we just have an issue putting it all together.
This is what our Python code looks like, at the while 1: is where confusion happens:
import smtplib,serial
ser = serial.Serial(port=2, baudrate=9200)
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email import Encoders
import os
gmail_user = "usr#gmail.com"
gmail_pwd = "pw"
def mail(to, subject, text, attach):
msg = MIMEMultipart()
msg['From'] = gmail_user
msg['To'] = to
msg['Subject'] = subject
msg.attach(MIMEText(text))
part = MIMEBase('application', 'octet-stream')
part.set_payload(open(attach, 'rb').read())
Encoders.encode_base64(part)
part.add_header('Content-Disposition',
'attachment; filename="%s"' % os.path.basename(attach))
msg.attach(part)
mailServer = smtplib.SMTP("smtp.gmail.com", 587)
mailServer.ehlo()
mailServer.starttls()
mailServer.ehlo()
mailServer.login(gmail_user, gmail_pwd)
mailServer.sendmail(gmail_user, to, msg.as_string())
# Should be mailServer.quit(), but that crashes...
mailServer.close()
while 1: **// CONFUSION HAPPENS HERE //** <----------------------
ser.readline()
if ser.readline() = "motion"
do this mail sequence?
mail("usr2#gmail.com",
"Alarm Alert!",
"Both Motion Sensor A & B have been active for over # seconds",
"stor_fight.jpg")
Any tips would be much appreciated.

I'm not sure exactly which part of this process you're having trouble with, but here's a sketch of a solution:
You can use the pyserial library to communicate with the Arduino from python when the Arduino is plugged into the computer via USB.
On the python side, your code would look like this:
serial = serial.Serial("/dev/tty.usbserial-A6007btF", 38400) # the serial name you can see in the Arduino GUI - you might just need to say "COM1" on Windows
result = serial.readline(); # blocks until you get something from the Arduino
if result == "motion":
# send email here
On the Arduino side, you'd just do something like this:
void loop()
{
if(30 seconds have passed with motion)
Serial.println("motion");
}
Make sense?

ser.readline()
if ser.readline() = "motion"
This code reads a line from the serial port twice and discards the first one.
You also need a double-equals for comparison, and the line will (I assume...) have carriage-return characters on the end of it.
You might want to try something like
if ser.readline().starts_with("motion")

From the question, I think you already know how to read from the serial port.
So I'd suggest something like this
import time,smtplib
beginTime = time.time() + 86400 # stay one day ahead for now
while True:
if serial port has values : # ie. motion detected
beginTime = time.time()
if time.time() - beginTime > 30 :
mailObj = smtplib.SMTP('smtp_server_here', smtp_server_port)
mailObj.sendmail('from', 'to..', 'message')
beginTime = time.time() + 86400 # reset time
I hope that helps

You need to use the serial library in your Arduino sketch. See section Communication/Serial on this page:
http://arduino.cc/en/Reference/HomePage
There are examples for the serial library in folder 4.Communication of the Arduino environment.
On your host machine, use the pySerial module, as suggested by jder.
You might also find this page in the Arduino Playground to be a useful starting point:
http://www.arduino.cc/playground/Interfacing/Python

From what I can tell the board has a standard RS-232 port. You can make a listener Python script that accepts a signal from the board when the event occurs then fire off a method that sends the email. If you want a nicely designed piece look into Twisted, which has packages for serial port comm and mail. Otherwise check:
http://docs.python.org/library/email
http://www.varesano.net/blog/fabio/serial+rs232+connections+python

Related

How can I check a folder every couple hours and send an email if something is found in it, using Python?

Let's say I have a script that checks this one folder to see if there is anything in there that I want.
I'd like to have this script run somewhere in the background (this would be cooler) or execute every 2 hours or so and send me an email if there is anything found.
how can I do this?
So you essentially have two parts:
1) How to set up my a scheduled script?
Assuming you're on Windows you can follow the steps here: Schedule Python Script - Windows 7
to set up a scheduled script either through the gui or the command line.
The output of that script can be boolean in nature and prompt the execution of the second part of your question.
2) How to send an email?
For this you could try this code:
# Import smtplib for the actual sending function
import smtplib
# Import the email modules we'll need
from email.mime.text import MIMEText
# Open a plain text file for reading. For this example, assume that
# the text file contains only ASCII characters.
fp = open(textfile, 'rb')
# Create a text/plain message
msg = MIMEText(fp.read())
fp.close()
# me == the sender's email address
# you == the recipient's email address
msg['Subject'] = 'The contents of %s' % textfile
msg['From'] = me
msg['To'] = you
# Send the message via our own SMTP server, but don't include the
# envelope header.
s = smtplib.SMTP('localhost')
s.sendmail(me, [you], msg.as_string())
s.quit()
More information for this step can be found here: How to send an email with Python?

Accessing Gmail SMTP via Python - AUTH issues

I'm writing this currently for an assignment but years back I had the same problem and just gave up. Further searches had me try a variety of things and I cannot get past the login portion.
from socket import *
from ssl import *
msg = "\r\n I love computer networks!"
endmsg = "\r\n.\r\n"
clientSocket = socket(AF_INET, SOCK_STREAM)
mailserver = getaddrinfo('smtp.gmail.com',465, AF_INET, SOCK_STREAM, IPPROTO_TCP)[0][4]
clientSocket = wrap_socket(clientSocket)
clientSocket.connect(mailserver)
recv = clientSocket.recv(1024)
print recv
if recv[:3] != '220':
print '220 reply not received from server.'
clientSocket.send('EHLO Nolan\r\n')
recv = clientSocket.recv(1024)
print recv
if recv1[:3] != '250':
print '250 reply not received from server.'
clientSocket.send('AUTH LOGIN ' + 'my Google email'.encode('base64','strict'))
recv = clientSocket.recv(1024)
print recv
print recv.split()[1].decode('base64')
clientSocket.send("my password".encode('base64','strict'))
recv = clientSocket.recv(1024)
print recv
# And onto other tasks
I'm under the impression I don't need STARTTLS as I start the connection with SSL. If I change AUTH LOGIN to AUTH PLAIN it doesn't know how to decode it. If I use PLAIN but don't encode it my program just hangs. If I terminate it with "\n\r" (not encoded) I get a broken pipe. Using the code above I get the password request.
Then sending the password I get 535-5.7.8 Username and Password not excepted.It's the same password I sign in with?!? I already setup my account to allow less secure devices. 2-step verification... started the process seems to be orientated to mobile phones, not my python app.
I've changed EHLO to use my IP, as I believe RFC 5321 says that's how it should be. Didn't matter.
I've looked through RFC 4954...
I dug into smtplib to uncover "AUTH PLAIN " + encode_base64("\0%s\0%s" % (user,pass),eol='') Just hangs... waiting...
I have no clue.
Update
I changed the smtplib to output every string submitted. This confuses me even more:
ehlo [127.0.1.1]
AUTH PLAIN [almost forgot one can decode this base64]==
mail FROM:<[gmail account]>
rcpt TO:<[hotmail account]>
data
quit
My AUTH string is exactly the same but it hangs. And I am receiving the email at my hotmail account (using smtplib, not my code).
If you want a basic, non-SSL connection to Gmail, you can use this:
import smtplib
gmail = smtplib.SMTP("smtp.gmail.com",587)
gmail.ehlo() #open the connection
gmail.starttls()
gmail.login("gmaillogin","gmailpassword") #login*
gmail.quit() #close the connection
*Note: You will need to generate a gmail application password from your google account.
Edit:
If you want to use SSL encryption, use this (thanks to furas):
import smtplib
gmail = smtp.SMTP_SSL("smtp.gmail.com",465)
gmail.ehlo()
gmail.login("gmaillogin","gmailpassword")
gmail.quit()
As is typically my fashion, it's the simple things. I just spent hours looking over one program and Googling only to have one error pop out at me: the parameter order in my definition was not how I used it in my code.
Here... I changed my code to use AUTH PLAIN and the issue... I had been putting in '\n\r' not '\r\n' (if I had ended the command with anything, only omitted because '\n\r' produced errors on some commands and went through okay on others). Thank you for classical music to study by on your favorite streaming video site. It raised my intelligence briefly. :)
clientSocket.send('AUTH PLAIN ' + encode_base64("\0%s\0%s" % ([email],[password]), eol="") + '\r\n')

pySerial buffering gpsd coordinates on Raspberry Pi

I am having quite a frustrating issue, and I'm quite new to Python/Raspberry pi
I have a script that is to match gps coordinates with a SSID filtered iwlist scan and then email the resulting file out whenever there is a wifi connection.
My issue is, the results are continuously buffered, so the gps coordinates could be significantly far away from the scanned SSIDs.
I have the serial line being flushed at the beginning of the while loop, but it doesn't seem to work. I also have python running un-buffered (-u, but that may only be for the text files..) I added Output.flush(), but I have not been able to test it yet. Figured I'd ask first.
So, my question is, is there a way to turn off the serial line buffer so every iteration is getting the GPS coordinate at the time the while loop is executing? All of my text files have file.flush() after they have been written. Does that need to be before the files are written, or would that not affect the serial buffer? What am I missing?
Any help would be appreciated
#!/usr/bin/python -u
import os
import gps
import time
import serial
import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email import Encoders
username = 'gmail account'
password = 'account password'
port = serial.Serial("/dev/ttyAMA0", baudrate=9600)
#Setting GPS session, listen on port 2947 (gpsd) of localhost
session = gps.gps("localhost", "2947")
session.stream(gps.WATCH_ENABLE | gps.WATCH_NEWSTYLE)
#Begin GPS and WiFi Scan loop..
while True:
try:
port.flushInput()
#port.flushOutput() commented out because I haven't tested with this yet.
time.sleep(.5)
report = session.next()
#Uncomment below for report data
#print report
if report['class'] == 'TPV':
if hasattr(report, 'lat' and 'lon'):
#setting GPS variables and strings
latitude = report.lat
latString = "%f" %(latitude)
longitude = report.lon
lonString = "%f" %(longitude)
#WiFi scan and parse script. I don't think it is necessary to post,
#but if it is, I will. All text files are flushed before being closed
#Email when connected
ping = os.system('sudo ping -c4 8.8.8.8')
try:
if ping == 0:
msg = MIMEMultipart()
msg['Subject'] = "GPS/WiFi data from GPS PILOT"
msg['From'] = username
msg['To'] = username
body = "GPS/WiFi data attached.."
msg.attach(MIMEText(body, 'plain'))
part = MIMEBase('application', "octet-stream")
part.set_payload(open("/home/pi/gpsMaster/dataLog.csv", "rb").read())
Encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="GPSWiFi_Scan.csv"')
msg.attach(part)
server = smtplib.SMTP('smtp.gmail.com:587')
server.ehlo()
server.starttls()
server.login(username, password)
server.sendmail(username, username, msg.as_string())
server.quit()
os.system("sudo rm /home/pi/gpsMaster/dataLog.csv")
else:
pass
except smtplib.SMTPException:
os.system('sudo reboot now')
#Adding loop delay
time.sleep(10)
#Loop ending exceptions
except KeyError:
pass
except IOError:
print ("ERROR")
#os.system('sudo reboot now')
except KeyboardInterrupt:
quit()
except StopIteration:
session = None
os.system("sudo reboot now")
I was having a similar issue. I fixed by flushing input and output.
port.flushInput()
port.flushOutput()
I appreciate that this is an old question, but it is still relevant as I hit the same problem. The issue is due to:
time.sleep(10)
in the main loop. The gpsd thread is adding received data to a queue which is accessed via:
report = session.next()
This mean that when you get to pull the next sample, over time it will drift further and further from reality (you are using GPS coordinates that lag behind your current location). We have a big queue, the consumer is pulling data much more slowly than it is being added due to the 10s sleep. I had much fun solving this and only by cutting the system to its bare essentials did I finally happen across the cause. The solution is to pull the data as soon as it is available, but discard as many data points as necessary until your delay time has been achieved. This stops the gpsd queue getting out of sync as the gpsd Python client is consuming them too slowly which causes coordinate drift over time.
Pseudo code (it can be polished, an exercise left for the reader):
import time
start = time.time()
while True:
# Consume the report from the gpsd
report = session.next()
# What time is it?
now = time.time()
# Magic number of 10s
if now > (start + 10):
# use the data contained in report
# Update with the latest time ready for the next iteration.
start = now

smtplib sending multiple messages instead of one

I am trying to run a python script at bootup which will take a ~10 second video on applying an external input (such as push button, IR sensor etc, and in our case an ultrasonic sensor), and then mail this video to specified email addresses using the SMTPlib library of Python.
All of this is working fine. However, when using this input multiple times, the Raspberry Pi sends multiple videos (taken by pushing the button in the past) to the email address instead of the one initiated by the last input. Hence, pushing the button 1 time would send 1 video; pushing it 2 times would send a new one along with the last one; pushing it 3 times would send a new one and the last two as well, and so on.
I even tried inserting an os.remove() right after the mail is sent in the python script. After running the program, running an ls shows the file is indeed deleted. Yet somehow, these deleted videos make its way into the email. Could it be it is stored somewhere in the memory when smtplib is used?
The script in mention is below :
from email.mime.multipart import MIMEMultipart
from email import encoders
from email.message import Message
from email.mime.audio import MIMEAudio
from email.mime.base import MIMEBase
from email.mime.image import MIMEImage
from email.mime.text import MIMEText
emailfrom = "xyz#abc.com"
emailto = "xyz123#abc.com"
username = "xyz#abc.com"
password = "pass"
msg = MIMEMultipart()
msg["From"] = emailfrom
msg["To"] = emailto
msg["Subject"] = "Email Subject -- "
msg.preamble = "Email Body --"
while(True):
d=0
# Possibly the relevant section
d = pulse_d*17150
d= round(d, 2)
if(d<100):
with picamera.PiCamera() as camera:
camera.start_preview()
camera.start_recording('/home/pi/video.h264')
time.sleep(5)
camera.stop_recording()
camera.stop_preview()
time.sleep(5)
fileToSend = "/home/pi/video.h264"
ctype, encoding = mimetypes.guess_type(fileToSend)
if ctype is None or encoding is not None:
GPIO.output(test, True)
ctype = "application/octet-stream"
maintype, subtype = ctype.split("/", 1)
fp = open(fileToSend, "rb")
GPIO.output(test,False)
attachment = MIMEBase(maintype, subtype)
attachment.set_payload(fp.read())
fp.close()
encoders.encode_base64(attachment)
attachment.add_header("Content-Disposition", "attachment", filename=fileToSend)
msg.attach(attachment)
server = smtplib.SMTP("smtp.gmail.com:587")
server.starttls()
server.login(username,password)
server.sendmail(emailfrom, emailto, msg.as_string())
server.quit()
os.remove("/home/pi/video.h264")
I think you should create new message instead of reuse the old one.
Move the code where you create msg inside while loop
The problem is here:
msg.attach(attachment)
You attach files to the same message, but don't remove old attachments.

How to send an e-mail from a Python script that is being run on "Google App Engine"?

How could I send an e-mail from my Python script that is being run on "Google App Engines" to one of my mail boxes?
I am just a beginner and I have never tried sending a message from a Python script. I have found this script (IN THIS TUTORIAL):
Here is the same script as a quote:
import sys, smtplib
fromaddr = raw_input("From: ")
toaddr = string.splitfields(raw_input("To: "), ',')
print "Enter message, end with ^D:"
msg = ''
while 1:
line = sys.stdin.readline()
if not line:
break
msg = msg + line
# The actual mail send
server = smtplib.SMTP('localhost')
server.sendmail(fromaddr, toaddrs, msg)
server.quit()
but I hardly understand how I could have this script run from "Google App Engine":
1) Firstly, I don't quite understand what e-mail address I need to place right after From: in this line:
fromaddr = raw_input("From: ")
Can I just place here any e-mail address of any e-mail boxes that I have?
2) Secondly, let's say I want to send a message to this e-mail address of mine brilliant#yahoo.com . Then the next line, I guess, must look this way:
toaddr = string.splitfields(raw_input("To: brilliant#yahoo.com"), ',')
Is this right?
3) Thirdly, let's say, the message that I want to send will be this sentence: Cats cannot fly! Then, I guess, the line that starts with msg = must look this way:
msg = 'Cats cannot fly!'
Is this correct?
4) If I upload this script as an application to "GAE", how often will it be sending this message to my mail box? Will it send this message to me only once or it will be sending it to me every second all the time until I delete the application? (This is why I haven't tried uploading this script so far)
Thank You all in advance for Your time and patience.
Sure - just use the Mail API as outlined in the docs:
Python
Java

Categories