Code below. So far working well and have captures several images of birds. Also triggered by cars in the background but I could experiment with the trigger_threshold. The images are only recorded when motion is detected. I haven’t characterised the latency, but should only be limited by the frame rate I guess. More detail at https://picamera.readthedocs.io/en/release-1.13/recipes2.html#recording-motion-vector-data
from future import division
import picamera
import numpy as np
import time
from time import gmtime,strftime
def write(self, s):
# Load the motion data from the string to a numpy array
data = np.fromstring(s, dtype=motion_dtype)
# Re-shape it and calculate the magnitude of each vector
data = data.reshape((self.rows, self.cols))
data = np.sqrt(
np.square(data['x'].astype(np.float)) +
np.square(data['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
if (data > 60).sum() > trigger_threshold:
time_string = strftime("%Y-%m-%d %H:%M:%S", gmtime())
print('Motion detected at ' + time_string + '_file_' + str(self.file_counter) )
file_string = 'File_r2_' + str(self.file_counter) + '.jpg'
camera.capture(file_string) # basic capture
self.file_counter = self.file_counter + 1
# camera.capture_continuous('img{counter:03d}.jpg')
# Pretend we wrote all the bytes of s
return len(s)
with picamera.PiCamera() as camera:
camera.resolution = (640, 480)
camera.framerate = 30
camera.start_recording(
# Throw away the video data, but make sure we’re using H.264
‘/dev/null’, format=‘h264’,
# Record motion data to our custom output object
motion_output=MyMotionDetector(camera)
)
camera.wait_recording(recording_minutes*60) # make continuous
camera.stop_recording()
Fantastic!
Glad to see you making progress. I have been a little busy decorating the past couple of weeks so not done anything other than searching for options, libraries, and examples.
I will be getting back to it soon. though so I will continue to post my updates on this thread.
played with your code, I added a bit at the end to allow it to restart the recording when it finished.
while true:
with picamera.PiCamera() as camera:
camera.resolution = (640, 480)
camera.framerate = 30
camera.start_recording(
# Throw away the video data, but make sure we're using H.264
'/dev/null', format='h264',
# Record motion data to our custom output object
motion_output=MyMotionDetector(camera)
)
camera.wait_recording(30) # make continuous
camera.stop_recording()
Ive been playing around and adapted it some more now.
It sends MQTT to home assistant when motion is detected and when it goes passive.
It works quite well.
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
# MQTT Variables
auth = {
'username':"####",
'password':"##########"
}
hostip="192.168.0.8"
MotionState="0"
#PreMotState="0"
# Send MQTT payload
def PublishMQTT(topic,payload):
publish.single(topic,
payload=payload,
hostname=hostip,
client_id="doorbell",
auth=auth,
port=1883)
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
if (a > 60).sum() > 10:
time_string = strftime("%Y-%m-%d %H:%M:%S", gmtime())
print('Motion detected at ' + time_string)
Tstamp = datetime.datetime.now().strftime('%b-%d-%G_%I%M%S%p-%G')+'.jpg'
#file_string = 'File_r2_' + time_string + '.jpg'
camera.capture(Tstamp) # basic capture
MotionState="1"
PublishMQTT("doorbell/motion",MotionState)
else:
if MotionState == "1":
print "Motion Passive."
MotionState="0"
PublishMQTT("doorbell/motion",MotionState)
while True:
with picamera.PiCamera() as camera:
with DetectMotion(camera) as output:
camera.resolution = (640, 480)
camera.start_recording(
'/dev/null', format='h264', motion_output=output)
camera.wait_recording(30)
camera.stop_recording()
I left it running over night in my dining room (curtains drawn , doors closed and no pets to trigger) on average Im getting 100 false positives per hour.
It seems it is detecting the brightness differences, there were more FP’s between 4:50am and 7am (sunrise).
So it does need tweaking a lot. I will start by increasing the vectors trigger and see how I get on .
I might add a data logger so it can analyse the data, saves me doing it manually.
I have ordered a noir camera for the door bell Ill give that a try when it arrives (in my theory should be less FP’s).
No havent added the button press to the code yet Im toying with the idea of using an off the shelf RF doorbell, hack in to the button press frequency,I already have a heap of 433mhz recievers .
I will still include the GPIO part,I still need to solder the header into the Zero W to use it though.
Got it all setup and running on my pi zero now with doorbell button wired to GPIO 23 and GND
Running great so far.
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
#
# COMPONENTS
#
# Raspberry Pi 2 (Will use Pi zero when it arrives)
# Raspberry Pi Camera V2
# Motion sensor...HC-SR501
# Door bell button..Momentary (normally open)
# Wifi Dongle
#
# 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"
# 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,'[SCHEDULED SNAPSHOT]=True'
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.'
# 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..."
localtime = time.asctime( time.localtime(time.time()) )
print "Local current time :", localtime
#if doorbell is released
if GPIO.input(DB_PIN)<>0:
DBState="0"
PublishMQTT("doorbell/button",DBState)
print "Doorbell Released..."
# Take a snapsots ( file name is the date and time .jpg )
def SNAPSHOT(Pressed):
print 'Snapping...'
Tstamp = ImagePath+datetime.datetime.now().strftime('%b-%d-%I%M%S%p-%G')+'.jpg'
camera.capture ('/home/pi/doorbell/camera/frequent.jpg')
if Pressed<>1:
shutil.copy('/home/pi/doorbell/camera/frequent.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 > 70).sum() > 15:
time_string = strftime("%Y-%m-%d %H:%M:%S", gmtime())
print('Motion detected at ' + time_string)
Tstamp = datetime.datetime.now().strftime('%b-%d-%G_%I%M%S%p-%G')+'.jpg'
CamDir='/home/pi/doorbell/camera/'+Tstamp
camera.capture(CamDir) # basic capture
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."
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(3600)
camera.stop_recording()
except KeyboardInterrupt:
print " Quit"
GPIO.cleanup()
No face detection yet and the config file doesnt do anything yet either.
It sends MQTT message when motion is detected and when it turns passive
And when the doobell is pressed and released.
Not yet, its in an ABS of the shelf box at the moment.
I havent got a 3d printer , but there are a few online services which print for you for a price.
only thing is it is going to extremley lucky to get the box right on the first attempt.
Modifying something like this could be a start http://www.thingiverse.com/thing:1649799 Do you have access to solidworks to do the design? I can help out with the design if your’e interested.
Solidworks is the industry standard, but I am sure there are free ones around too.
In my case I downloaded the .stl files from thingiverse and then just uploaded them to 3D hubs
Interesting project - I am sure there will be much interest in this once completed. So currently you are using the cam motion detection to send a mqtt message as well as by push button?
Whats left to work on:
CV integration?
sending on video / audio feeds to smartphone to allow interaction with visitor?
Both interesting ideas
My plan was to train a classifier to recognise when certain features are present in the images (e.g a person) to reduce the false positive rate of motion detection.I don’t have much experience in this area but a colleague recommended CNN https://www.tensorflow.org/tutorials/deep_cnn
Both of these are a little way off at the moment, still getting used to playing with Python and raspberry Pi.
Not even sure how it would perform yet.
Just trying to get the basics up and running then move on to the next stage.
It now saves a log when a doorbell press has been made and when motion is detected.
Ive tidied the code up a bit also shifted code blocks into functions added remarks etc.
I am now working at getting HA to notify my phone and my wifes phone when either event occurs.
Im also looking at BTLE tag/beacon detection. Maybe as an alternative/addition to face recognition.