Motion Sensing Loop Error Python? - python

Hi Guys I have been working on this code for quite a while but once the code has sensed motion, taken a picture and sent it off as an email attachment it works once but once the state returns to ready it comes up with this error but I can't understand why. I apologise for including the whole code because although the error states line 43 I'm not to sure what's causing it to go wrong.
any suggestions would be greatly appreciated. I am a beginner in python programming so I may be missing something very obvious. By the way I'm running this on a raspberry pi for anyone who would like to test out the code.
Thanks
import os, re
import sys
import smtplib
import RPi.GPIO as GPIO
import time
import picamera
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
GPIO.setmode(GPIO.BCM)
GPIO_PIR = 4
print "PIR Module Test (CTRL-C to exit)"
GPIO.setup(GPIO_PIR,GPIO.IN)
Current_State = 0
Previous_State = 0
cam = picamera.PiCamera()
try:
print "Waiting for PIR to settle ..."
while GPIO.input(GPIO_PIR)==1:
Current_State = 0
print " Ready"
while True :
Current_State = GPIO.input(GPIO_PIR)
if Current_State==1 and Previous_State==0:
print " Motion detected!"
cam.capture('/home/pi/Eaglecam/surveillance.jpg')
print('picture taken')
cam.close()
SMTP_SERVER = 'smtp.gmail.com'
SMTP_PORT = 587
sender = '*******************'
password = "secret!!"
recipient = '*********************'
subject = 'INTRUDER DETECTER!!'
message = 'INTRUDER ALLERT!! INTRUDER ALERT!! CHECK OUT THIS PICTURE OF THE INTRUDER! SAVE THIS PICTURE AS EVIDENCE!'
directory = "/home/pi/Eaglecam/"
def main():
msg = MIMEMultipart()
msg['Subject'] = 'INTRUDER ALERT'
msg['To'] = recipient
msg['From'] = sender
files = os.listdir(directory)
jpgsearch = re.compile(".jpg", re.IGNORECASE)
files = filter(jpgsearch.search, files)
for filename in files:
path = os.path.join(directory, filename)
if not os.path.isfile(path):
continue
img = MIMEImage(open(path, 'rb').read(), _subtype="jpg")
img.add_header('Content-Disposition', 'attachment', filename=filename)
msg.attach(img)
part = MIMEText('text', "plain")
part.set_payload(message)
msg.attach(part)
session = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)
session.ehlo()
session.starttls()
session.ehlo
session.login(sender, password)
session.sendmail(sender, recipient, msg.as_string())
session.quit()
if __name__ == '__main__':
print(' Email Sent')
Previous_State=1
elif Current_State==0 and Previous_State==1:
print " Ready"
Previous_State=0
time.sleep(0.01)
except KeyboardInterrupt:
print " Quit"
GPIO.cleanup()
Here is the Error:
Traceback (most recent call last):
File "/home/pi/Python/hi2.py", line 43, in <module>
cam.capture('/home/pi/Eaglecam/surveillance.jpg')
File "/usr/lib/python2.7/dist-packages/picamera/camera.py", line 1446, in capture
camera_port, output_port = self._get_ports(use_video_port, splitter_port)
File "/usr/lib/python2.7/dist-packages/picamera/camera.py", line 708, in _get_ports
self._camera[0].output[self.CAMERA_CAPTURE_PORT]
TypeError: 'NoneType' object has no attribute '__getitem__'

Try not persisting your cam object...picamera flushes and closes as it sees fit so you may be having problems calling the object repeatedly with the code you are using. Also, you are calling the .close() method on your cam object after if takes the first picture. I might accomplish this like so:
surv_pic = open('/home/pi/Eaglecam/surveillance.jpg', 'wb')
if Current_State==1 and Previous_State==0:
print " Motion detected!"
with picamera.PiCamera() as cam:
##if camera is not producing pictures because it is not warmed up yet uncomment the next two lines
##cam.start_preview()
##time.sleep(2)
cam.capture(surv_pic)
surv_pic.close()
SMTP_SERVER = 'smtp.gmail.com'
## continue as is from here

Related

How do i rerun a python script after it has finished

I'm trying to rerun my script after it has finished running
preferably after 30 seconds i have tried some methods but can't find out how to continue with my code
my code:
import os.path
import os
import sys
import smtplib
import time
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from PIL import ImageGrab
def enviar_email():
email = 'x.com'
password = 'x'
subject = 'This is the subject'
message = 'This is my message'
file_location = 'ss1.jpg'
msg = MIMEMultipart()
msg['x'] = email #sender
msg['x'] = email #receiver
msg['Subject'] = subject
msg.attach(MIMEText(message, 'plain'))
# Setup the attachment
filename = os.path.basename(file_location)
attachment = open(file_location, "rb").read()
image = MIMEImage(attachment, name=filename)
msg.attach(image)
# Attach the attachment to the MIMEMultipart object
# msg.attach(part)
server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
server.login(email, password)
text = msg.as_string()
server.sendmail(email, email, text)
server.quit()
def main():
imagem = ImageGrab.grab()
imagem.save('ss1.jpg', 'jpeg')
enviar_email()
print("Taking screenshot...")
if _name_ == '_main_':
main()
time.sleep(10)
os.execl(sys.executable, sys.executable, *sys.argv)
i tried adding:
time.sleep(10)
os.execl(sys.executable, sys.executable, *sys.argv)
but the script did not restart any advice how i can make it so that it restarts the script ?
You can call main() function again after time.sleep(10). Try this:
if _name_ == '_main_':
main()
time.sleep(10)
main()
Use the while loop :
if __name__=='__main__':
while True:
do_something()
You can even pair it with a try/except block like this :
if __name__=='__main__':
while True:
try:
do_something()
except:
print('Error Occured in running the script, Rerunning...')
This will prevent the script from abruptly stopping in case of an error.
For re running the script a specific number of times, you can define a count variable and break it when it matches a value, like this:
if __name__=='__main__':
count=0
no_of_runs=5
while True:
try:
if count==no_of_runs:
break
else:
do_something()
count+=1
except:
print('Error occured, Rerunning...')
pass
You can use schedule library for this purpose.
#!pip install schedule
import schedule
import time
while True:
# Checks whether a scheduled task
# is pending to run or not
schedule.your_function()
time.sleep(1)

Python Script To Continually Run (Better)

The below script is a working prototype of a script that runs on a rasberry pi and its job is to grab files from a specified folder on a flashdrive when plugged in. After that point it emails the files as attachments. Now, everything works perfect, but not logically in the way I want. I have a really janky while True: loop with janky sleep timers to kind delay some things. Ideally I need help developing a way for all of this to happen only ONCE per usb drive plug in. Then it would go into "Idle mode" waiting for the next stick. As of now, without my added sleep timers, It would just continually run over and over. I've been stuck trying to logically figure out a way to make it work how I would like.
Thanks in advance!
import smtplib, ssl
import shutil
import os
from time import sleep
from distutils import dir_util
from psutil import disk_partitions
from datetime import datetime
from datetime import date
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
now = datetime.now()
current_time = now.strftime("%H:%M:%S")
today = date.today()
day = today.strftime("%B %d, %Y")
def CopyFilesFromSD():
try:
dir_util.copy_tree(driver+'/REDACTED', '/home/pi/Desktop/Transferred Files')
print("Files Succesfully Copied")
if 'rw' in opts:
with open(driver+'/Transfer_Log_REDACTED.txt', 'a', encoding = 'utf-8') as fp:
fp.write("\nFiles Succesfully Transferred to REDACTED on " + day + " at " + current_time)
except:
print("Device unmounted during transfer process!")
sleep(10)
def SendFiles():
dir_path = "/home/pi/Desktop/Transferred Files/"
files = os.listdir(dir_path)
msg = MIMEMultipart()
msg['To'] = "REDACTED"
msg['From'] = "REDACTED"
msg['Subject'] = "REDACTED"
password = "REDACTED"
body = MIMEText('Test.', 'html', 'utf-8')
msg.attach(body)
for f in files:
file_path = os.path.join(dir_path, f)
attachment = MIMEApplication(open(file_path, "rb").read(), _subtype="txt")
attachment.add_header('Content-Disposition','attachment', filename=f)
msg.attach(attachment)
context = ssl.create_default_context()
with smtplib.SMTP_SSL("REDACTED", 465, context=context) as server:
server.login(msg['From'], password)
server.sendmail(
msg['From'], msg['To'], msg.as_string()
)
shutil.rmtree(dir_path, ignore_errors = False)
sleep(5)
while True:
sleep(1)
for item in disk_partitions():
if 'nodev' in item.opts:
driver, opts = item.mountpoint, item.opts
CopyFilesFromSD()
SendFiles()
break
else:
continue
break
Answered by iScripters in the comment section:
https://betterprogramming.pub/how-to-run-a-python-script-on-insertion-of-a-usb-device-2e86d38dcdb
This will allow for the python script to only be ran when USB insertion is detected. No need to have a constant running program looking for drives.

Running python script in Raspbian terminal, but nothing shows up, why?

I am new to raspberry pi and am trying to set my Raspberry pi 3B+ so that upon clicking a button, it should all the functions declared in gpio_callback. However I get no output at all. What am I doing wrong?
import picamera
import boto3
s3 = boto3.resource('s3')
import RPi.GPIO as GPIO
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
def gpio_callback(self):
capture_image()
time.sleep(0.3)
print('Captured')
upload_image()
time.sleep(2)
send_email()
GPIO.add_event_detect(17, GPIO.FALLING, callback=gpio_callback, bouncetime=3000)
def capture_image():
with picamera.PiCamera() as camera:
camera.resolution = (640, 480)
camera.start_preview()
camera.capture('sample.jpg')
camera.stop_preview()
camera.close()
return
def upload_image():
file = open('sample.jpg','rb')
object = s3.Object('xywz','sample.jpg')
ret = object.put(Body=file,
Metadata={'FullName':'Guest'}
)
print(ret)
return
def send_email():
fromaddr = "abcd#gmail.com"
toaddr = "abcd#hotmail.com"
msg = MIMEMultipart()
msg['From'] = fromaddr
msg['To'] = toaddr
msg['Subject'] = "New Guest"
body = "A new guest is waiting at your front door. Photo of the guest is attached."
msg.attach(MIMEText(body, 'plain'))
filename = "sample.jpg"
attachment = open("/home/pi/sample.jpg", "rb")
part = MIMEBase('application', 'octet-stream')
part.set_payload((attachment).read())
encoders.encode_base64(part)
part.add_header('Content-Disposition', "attachment; filename= %s" % filename)
msg.attach(part)
server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
server.login(fromaddr, "xxxxxx")
text = msg.as_string()
server.sendmail(fromaddr, toaddr, text)
server.quit()
My hunch is I have declared the functions, but not exactly executing a command to callgpio_callback. I can't get head around this.
Can someone help me?

Raspberry pi:send only last captured image using webcam

I have captured image using webcam and when i press button it sends mail.I use while loop as shown in below code,this code is running perfectly but problem is this program send so many image(also send earlier capured image)while we stop the program to run,so there are so many images attached in one mail only.Now i want program continuonsly running in raspberry pi but still it should be mail only last captured image so what i have to do changes for that?
Thanks in advance.
This is my code:
import smtplib
import time
import subprocess
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.MIMEImage import MIMEImage
import RPi.GPIO as GPIO
# Define these once; use them twice!
strFrom = 'example#gmail.com'
strTo = 'example#gmail.com'
#create email
# Create the root message and fill in the from, to, and subj$
msgRoot = MIMEMultipart()
msgRoot['Subject'] = 'subject'
msgRoot['From'] = strFrom
msgRoot['To'] = strTo
GPIO.setmode(GPIO.BCM)
GPIO.setup(4, GPIO.IN)
print "press button to send email"
while True:
input=GPIO.input(4)
if input == True:
print "button pressed"
subprocess.Popen(["fswebcam","-r 640x480", "capture.jpg"])
time.sleep(2)
# This example assumes the image is in the current
# directory
fp = open('capture.jpg', 'rb')
msgImage = MIMEImage(fp.read())
fp.close()
msgRoot.attach(msgImage)
# send mail
s = smtplib.SMTP('smtp.gmail.com',587)
s.starttls()
s.login('example#gmail.com' , 'password')
s.sendmail(strFrom, strTo,msgRoot.as_string())
s.close()
print "Email sent"
time.sleep(0.2)
msgRoot.attach(msgImage)
msgRoot.set_payload(msImage) #Such modified
Because you are using the same copy of the annex has been superimposed on the upswing

Button Press To Shutdown Raspberry Pi Python

I am writing a script for a surveillance camera. I have programmed it to take a picture when motion is detected (PIR sensor) then attach the photo to an email, to a chosen recipient. However because I am running this without a screen, mouse or keyboard attached I had no way to turn the device off without pulling the plug! so I created a script to turn off the computer on a button press(this works fine on its own) however, because the rest of the code is in a loop I don't know where to place it. Keeping in mind I need to be able to turn it off any where in the code.
If you have any ideas they would be appreciated
Thanks
James
import os, re
import sys
import smtplib
import RPi.GPIO as GPIO
import time
import picamera
inport os
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import time
import RPi.GPIO as gpio
GPIO.setmode(GPIO.BCM)
GPIO_PIR = 4
print ("PIR Module Test (CTRL-C to exit)")
GPIO.setup(GPIO_PIR,GPIO.IN)
Current_State = 0
Previous_State = 0
try:
print ("Waiting for PIR to settle ...")
while GPIO.input(GPIO_PIR)==1:
Current_State = 0
print (" Ready")
while True :
Current_State = GPIO.input(GPIO_PIR)
surv_pic = open('/home/pi/Eaglecam/surveillance.jpg', 'wb')
if Current_State==1 and Previous_State==0:
print(" Motion detected!")
with picamera.PiCamera() as cam:
cam.capture(surv_pic)
surv_pic.close()
print(' Picture Taken')
SMTP_SERVER = 'smtp.gmail.com'
SMTP_PORT = 587
sender = '**************'
password = "**********"
recipient = '**************'
subject = 'INTRUDER DETECTER!!'
message = 'INTRUDER ALLERT!! INTRUDER ALERT!! CHECK OUT THIS PICTURE OF THE INTRUDER! SAVE THIS PICTURE AS EVIDENCE!'
directory = "/home/pi/Eaglecam/"
def main():
msg = MIMEMultipart()
msg['Subject'] = 'INTRUDER ALERT'
msg['To'] = recipient
msg['From'] = sender
files = os.listdir(directory)
jpgsearch = re.compile(".jpg", re.IGNORECASE)
files = filter(jpgsearch.search, files)
for filename in files:
path = os.path.join(directory, filename)
if not os.path.isfile(path):
continue
img = MIMEImage(open(path, 'rb').read(), _subtype="jpg")
img.add_header('Content-Disposition', 'attachment', filename=filename)
msg.attach(img)
part = MIMEText('text', "plain")
part.set_payload(message)
msg.attach(part)
session = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)
session.ehlo()
session.starttls()
session.ehlo
session.login(sender, password)
session.sendmail(sender, recipient, msg.as_string())
session.quit()
if __name__ == '__main__':
print(' Email Sent')
Previous_State=1
elif Current_State==0 and Previous_State==1:
print(" Ready")
Previous_State=0
time.sleep(0.01)
import time
import RPi.GPIO as gpio
except KeyboardInterrupt:
print('Quit')
GPIO.cleanup()
Here is the shutdown section of the script. Where would I place this in the loop?
gpio.setmode(gpio.BCM)
gpio.setup(7, gpio.IN, pull_up_down=gpio.PUD_UP)
buttonReleased = True
while buttonReleased:
gpio.wait_for_edge(7, gpio.FALLING)
buttonReleased = False
for i in range(1):
time.sleep(0.1)
if gpio.input(7):
buttonReleased = True
break
Two separate scripts would be unnecessary for this project.
You can do this a couple ways.
Create a global boolean variable called shutdownButton or whatever. Use a callback function for the GPIO pin, and set shutdownButton = True in the callback. And then change your main loop to be while not shutdownButton: instead of while True:.
You could just change your main loop to while gpio.input(7): instead of while True: (assuming you are pulling the pin up and then grounding it down with your switch).
And then finally just add a shutdown like os.system('sudo shutdown -h now') or call some other script you want to run to clean it up. The point is you just need a function to break out of your main loop when the button has been pressed and then shut down your pi at the end of the program.
There are other ways to do this also (I personally like the kernel patches from Adafruit that allow a power switch configuration to be added to /etc/modprobe.d...) but I only listed methods that applied directly to your question.

Categories