3

I'm trying to setup a concurrent photo capture and immediate email of said capture (triggered by a PIR motion sensor) in a Python script. Basically what I'm trying to accomplish is to have my Pi take a picture with the attached 8MP picamera and have it send the picture via email. I have successfully created a script that can accomplish both these tasks, but no photos are captured while the PIR sensor is triggered until the task of sending out the email with the first capture is completed. Is it possible to do both of these tasks concurrently on the Pi Zero? I have attached the relevant code below.

Many thanks in advance!

from gpiozero import MotionSensor
from picamera import PiCamera
from datetime import datetime
#import subprocess
import time
import smtplib
import os
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email import Encoders
gmail_user = "xxxxxx@gmail.com" #Sender email address
gmail_pwd = "xxxxxxxxx" #Sender email password
to = "xxxxxxxxxx@gmail.com" #Receiver email address
subject = "foo"
text = "bar"

camera = PiCamera()
pir = MotionSensor(4)
camera.resolution = (3280,1845)
camera.sharpness = 11
camera.saturation = 4
camera.brightness = 50
camera.hflip = True
camera.vflip = True
#camera.iso = 1600
#camera.awb_mode = 'auto'
camera.exposure_mode = "night"
timeInterval = 2
filepath = "/home/pi/camsecurity_stills/"

try:
    print 'PIR Motion Triggered Photo Capture'
    time.sleep(10)
    print 'Ready'

    while True:
        pir.wait_for_motion()
        filename = datetime.now().strftime("%m%d%Y_%H%M%S.jpg")
        path = filepath + filename
        camera.capture(path, format='jpeg', quality=100)
        print "Captured %s" % filename

        attach = path

        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())
        mailServer.close()
        print "Email Sent"
        time.sleep(timeInterval)
except KeyboardInterrupt:
    print 'Quit'
1

You don't need a subprocess here. Just send Emails, regardless of the computer your code is running on, in a different thread:

import threading

def send_mail():
    ...

thread = threading.Thread(target=send_mail, args=())
thread.start()

This will not block your main code from being executed.

  • What is the advantage of threading over sub-processing in this specific case? – Fantilein1990 Nov 23 '16 at 9:14
  • @Fantilein1990 - In this specific case, there's no advantage. It's just more easy to share objects between threads in comparison to sharing objects between different processes. In the end, I think it doesn't matter, but I'm using the above code for some while now :) – linusg Nov 23 '16 at 10:26
  • This solved my issue successfully! Thank you very much! Happy turkey day to everyone :) – Dai San Nov 24 '16 at 23:31
3

Well, the way you wrote your script, it does everything sequentially - one line after another. However, there are ways to execute commands parallely using python on a Raspberry Pi, whether it's a zero, a 3b or something else.

The keywords you are looking for are threads and sub-processes (both links are for Python2.7, but you'll find the Python3 documentation on the same webpage). Both are fairly similar in implementation and results for most purposes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.