Yeah its the official 2.1 version.
Just found another bug in my doorbell script.
Very rarely if you press the button while the motion has triggered it is trying to take two stills at once.
It raises an error and breaks out.
picamera.exc.PiCameraValueError: source port is already connected
sys.excepthook is missing
lost sys.stderr
sys.excepthook is missing
lost sys.stderr
sys.excepthook is missing
lost sys.stderr
Need to check from each instance (motion and button) before the still is captured.
Just a matter of finding a way to implement it.
Python Try, except?
Iām aware of exceptional handling but not bothered to learn it yetā¦
Think I cracked it.
Now if a snapshot is taking place and the other event calls the subroutine, it wont take a snapshot, just copy and rename the most recent (which at this stage would be the image currently being captured)
import numpy as np
import picamera
import picamera.array
from time import gmtime,strftime
import time
import datetime
import subprocess
import paho.mqtt.client as mqtt
import paho.mqtt.publish as publish
import RPi.GPIO as GPIO
import os
import shutil
# Smart doorbell script adapted by Lee Goodman (Meganoodle from example online
# https://www.modmypi.com/blog/raspberry-pi-gpio-sensing-motion-detection
# Detects motion from pi camera and Sends MQTT message to Home assistant
# Detects Button press from GPIO 23 and sends MQTT to home assistant
# COMPONENTS
#
# Raspberry Pi zero W
# Raspberry Pi Camera V2
#
# Door bell button..Momentary (normally open)
# Wifi Dongle or wifi capable pi
#
# SOFTWARE
# Latest version of Raspian
#
# Camera and GPIO must be enabled in raspi-config
#
# GPIO Pinouts
#=======================================
# Door Bell Button-----Raspberry Pi
# Feed-----------------GND
# Load-----------------GPIO 23 (PIN 16)
#=======================================
#
# Setup ================================
# MQTT Variables
auth = {
'username':"pi",
'password':"raspberry"
}
hostip="192.168.0.8"
# File Path
ImagePath='/home/pi/doorbell/camera/'
# Motion detection state
MotionState="0"
# Doorbell button GPIO SETUP
GPIO.setmode(GPIO.BCM)
DB_PIN = 23
GPIO.setup(DB_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
# Doorbell button state variable
DBState="0"
SNAPPING=False
# Functions =============================
# Check dir structure and create if necessary
def CheckDir(dirchk):
chkpath='./'+dirchk
if os.path.isdir(chkpath)==False:
print'Creating '+dirchk+' directory...'
os.mkdir(chkpath)
if os.path.isdir(chkpath)==False:
print'Error creating directory please check the drive is full and your path permissions'
else:
print dirchk+' directory created successfully...'
else:
print'Found '+dirchk+' directory...'
# Check if 'doorapp.conf' exists and create a blank file if necessary
# To be included into programme
def ChkConf():
if os.path.isfile('./conf/door.conf')==False:
print'Creating blank configuration file...'
fconf = open('./conf/door.conf','w')
print >>fconf,'[MQTT HOST]=192.168.0.8'
print >>fconf,'[MQTT PASSWORD]=Anon'
print >>fconf,'[MQTT USERNAME]=Anon'
fconf.close()
print'Configuration file created, please edit "./conf/door.conf"'
else:
print 'Configuration file found.'
def Addlog(loginfo):
logdate=datetime.datetime.now().strftime('%b/%d/%G')
logtime=datetime.datetime.now().strftime('%I:%M:%S%p')
logentry=logdate+" : "+logtime+" : "+loginfo+"--"
flog = open('./doorbell.log','a+')
print >>flog,logentry
flog.close
# Doorbell pressed function
def DOORBELLON(DB_PIN):
#if motion is triggered
if GPIO.input(DB_PIN)<>1:
DBState="1"
PublishMQTT("doorbell/button",DBState)
print "Doorbell Pressed..."
Addlog('Doorbell Pressed.')
#if doorbell is released
if GPIO.input(DB_PIN)<>0:
DBState="0"
PublishMQTT("doorbell/button",DBState)
print "Doorbell Released..."
Addlog('Doorbell Released.')
SNAPSHOT(0)
# Take a snapsots ( file name is the date and time .jpg )
def SNAPSHOT(Pressed):
global SNAPPING
print 'Snapping...'
Tstamp = ImagePath+'DB'+datetime.datetime.now().strftime('%b-%d-%G_%I%M%S%p')+'.jpg'
if SNAPPING == False:
SNAPPING = True
camera.capture ('./camera/recent.jpg')
time.sleep(1)
SNAPPING = False
if Pressed ==0:
Tstamp = ImagePath+'DB-'+datetime.datetime.now().strftime('%b-%d-%G_%I%M%S%p')+'.jpg'
shutil.copy('./camera/recent.jpg',Tstamp)
print 'Snapshot Saved to "'+Tstamp+'"'
print'Snapshot complete'
Tstamp = ImagePath+'MD-'+datetime.datetime.now().strftime('%b-%d-%G_%I%M%S%p')+'.jpg'
if Pressed ==1:
shutil.copy('./camera/recent.jpg',Tstamp)
print 'Snapshot Saved to "'+Tstamp+'"'
print'Snapshot complete'
# Send MQTT payload
def PublishMQTT(topic,payload):
publish.single(topic,
payload=payload,
hostname=hostip,
client_id="doorbell",
auth=auth,
port=1883)
# PICAM Motion detection class
class DetectMotion(picamera.array.PiMotionAnalysis):
def analyse(self, a):
global MotionState
a = np.sqrt(
np.square(a['x'].astype(np.float)) +
np.square(a['y'].astype(np.float))
).clip(0, 255).astype(np.uint8)
# If there're more than 10 vectors with a magnitude greater
# than 60, then say we've detected motion
# and send MQTT motion state to HA
if (a > 60).sum() > 10:
print('Motion detected.')
Addlog('Motion detected.')
SNAPSHOT(1)
MotionState="1"
PublishMQTT("doorbell/motion",MotionState)
else:
# If Motion has only just turned passive send MQTT passive state to HA
if MotionState == "1":
print "Motion Passive."
Addlog('Motion Passive.')
MotionState="0"
PublishMQTT("doorbell/motion",MotionState)
# Main ========================
# Initial Setup
print "Smart Doorbell ... (CTRL+C to exit)"
print "Checking directory stucture..."
CheckDir('camera')
time.sleep(2)
CheckDir('conf')
print " Directory structure check complete."
print "Checking for configuration file..."
ChkConf()
print " Configuration file check complete."
# GPIO Interrupt setup
try:
GPIO.add_event_detect(DB_PIN,GPIO.BOTH, callback=DOORBELLON, bouncetime=200 )
# Main Loop
while 1:
with picamera.PiCamera() as camera:
with DetectMotion(camera) as output:
camera.resolution = (640, 480)
camera.vflip = True
camera.framerate = 20
camera.start_recording('/dev/null', format='h264', motion_output=output)
camera.wait_recording(86400)
camera.stop_recording()
except KeyboardInterrupt:
print " Quit"
GPIO.cleanup()
Thanksā¦Looks quite simple and I will probably see if I can include it, Im sure as the code grows there will be more to handle .
Just scanning through it , it looks simple enough to implement.
lol just an afterthought have it send any errors it flags up to my phone, at least it can make me aware, rather than having to ssh to check.
Done a bit more prototyping, to see what kind of image I can get through the peep viewer barrel.
With the lens on the barrel, I get a wider field of view and the image isnāt great, but probably OK.
If I remove the fish eye lens off the barrel I get a better image but a much smaller field of view. This would require the person at the door to be standing directly in front of the camera.
Overall I think the wider field of view is more desirable, so will try that. Now itās just a case of mounting the pi camera up against the peep hole, and fine tuning the focus of the pi lens to improve the image.
I agree, Im not sure if you could improve it much more , unless the camera was mounted on the inner part of the external panel of the door.
Im guessing thats not going to be easy or not such a desirable option.
Iām planning on using this case, with some modificationsā¦
A nice article, this opeCV route must be possible https://www.hackster.io/luisomoreau/who-is-at-the-coffee-machine-72f36c
Wow
Will have to research this a bit more
it is cheaper than RPi3 and camera module together and it is far more intelligent and robust solution I think
Ill have a read of this, I think this was one of the guides I followed on my pi 2 originally,
But Ill try again at the weekend.
(Im training at work this week so need to focus on that atm).
Thanks openMV looks like a great platform, particularly for an optics person like myself. Iāve got something similar arriving soon https://www.kickstarter.com/projects/1602548140/jevois-open-source-quad-core-smart-machine-vision
Wow just watched the video , looks amazing!
to be honest I donāt really trust the crowdfunding campaigns anymore unless it is already on the market
Iāve lost my money couple of times on the past and I am not confident anymore on supporting small projects
Got it working finally.
import cv2
from picamera import PiCamera
import picamera.array
camera = PiCamera()
camera.vflip = True
#camera.resolution = (640, 480)
#detect faces from haarcascade xml reference file
#returns relevent location data of faces
def detect(path):
img = cv2.imread(path)
cascade = cv2.CascadeClassifier("./haarcascade_frontalface_default.xml")
rects = cascade.detectMultiScale(img, 1.3, 4, cv2.cv.CV_HAAR_SCALE_IMAGE, (20,20))
if len(rects) == 0:
return [], img
rects[:, 2:] += rects[:, :2]
return rects, img
# draws rectangle around detected faces and saves image
def box(rects, img):
ci=1
for x1, y1, x2, y2 in rects:
cv2.rectangle(img, (x1-5, y1-5), (x2+5, y2+5), (127, 255, 0), 2)
sub_face = img[y1:y2, x1:x2]
face_file_name = "./face_" + str(ci) + ".jpg"
cv2.imwrite(face_file_name, sub_face)
ci=ci+1
cv2.imwrite('./detected.jpg', img);
camera.capture ('./one.jpg')
rects, img = detect("./one.jpg")
print "faces Detected = "+str(len(rects))
box(rects, img)
It crops the detected faces too
Perfect! It works real time on the camera feed?
nice!
you seem a bit tired though
Nice! Im by far not a developer/programmer but a ātinkererā. Ive got a zero W coming from overseas as still cant get in australia.
What guide did you use to get cv installed?