This isn't a project so much as my attempts to remove false positive motion events when trying to use this PIR in a smart doorbell.
The image shows a passive Infrared Sensor (PIR) for detecting motion. There are many different PIR Sensors. This one doesn't allow any sensitivity or timeout adjustments.
The left pin (+) goes to either a 3.3v or 5v pin. The right pin goes to GND. And, the middle pin goes to a GPIO pin.
Male-to-male jumper cables can be used to hookup the PIR Motion sensor directly to any model of a Raspberry Pi.
I thought this was going to be a trivial hook-up and everything would work. And it did. But over time, I noticed that motion was detected every hour, and sometimes more often.
I put the Raspberry Pi and the motion sensor in a box. So, no motion could be detected yet it was being detected.
This page goes through my steps in attempting to eliminate the false positive motion events.
There seem to be three things that trigger motion detection:
High CPU Usage
High Wi-Fi Traffic
Motion
I really only want the last to trigger motion.
I had no idea what was causing the false positives. So, I started googling. Many people seem to have issues with PIR sensors. As expected, many of the most promising fixes were from stackoverflow.com or raspberrypi.org.
My approach with each suggested fix was to add it, reboot the RPi, and let it run for 4-12 hours while collecting all motion detection messages.
If the number of false positives decreased, then I would keep the change. If there was no significant decrease, then it goes into the failed category.
Before looking for a fix, I checked for hourly jobs, such as, cron, systemd and so on. There doesn't seem to be anything running that corresponds with the false positive motion detection except perhaps HRNG, which is hardware random number generator.
Worked
Instead of just detecting motion on the rising edge, the code below waits a few seconds and then checks if the motion pin is still high.
High CPU or Wi-Fi usage still triggers motion detection
Failed
Things that were tried, and failed to make any difference in my system. Failing in my system, doesn't mean it won't work in yours. By failing, I mean running this command every couple of secondsf or about 10 seconds: cat /var/log/syslog
Putting aluminum foil grounded and wrapped in electrical tape around
PIR
Wires from PIR to GPIO pins
I tried grounded and ungrounded. Grounding made false positives more common, which makes no sense
Disable Bluetooth by adding a line to the file:
$ sudo nano /boot/config.txt
dtoverlay=disable-bt
Disable Bluetooth by adding two lines to the file:
$ sudo nano /etc/modprobe.d/raspi-blacklist.conf
blacklist btbcm
blacklist hci_uart
Put 10K Ohm resistor between GND and PIR GPIO pin. I didn't solder this. It seemed to reduce false positives at first and then went back to a false positive once every two hours. It might have slipped loose.
Disabling motion detection after coming out of sleep didn't work
Since the PIR white plastic body extends into the case. I thought the hot glue and PIR body might be picking up heat from either the CPU or the Wi-Fi chip. So, I painted all parts of the hot glue and PIR white case with an opaque black paint. However, this failed.
One suggestion was to put Ferrite beads around or between the PIR wires to the Raspberry Pi
However, on my PIR, the board looks like it has a Ferrite bead (silver horizontal rectangle in photo above, and two on the reverse side)
I could not find small enough snap-on Ferrite beads for AWG 36 gauage wire
I put Ferrite beads in-line, and this prevented all motion from being detected
The following is a simple python script to print a message when motion is detected.
Use the following command to create the script on the Raspberry Pi
$ nano motion.py
and cut-and-paste the following:
#!/usr/bin/env python
# Controls the motion sensor
# run using:
# sudo python motion.py
# modules
import RPi.GPIO as GPIO
import subprocess
import time
# globals
# GPIO Pins
MOTION_PIN = 17
MOTION_WAIT = 1 # 1 minute
lastMotion = datetime.datetime.now()
motionOne = False
# Disable warnings
GPIO.setwarnings(False)
# gpio MOTION pin
GPIO.setmode(GPIO.BCM)
GPIO.setup(MOTION_PIN, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
# this call back occurs when CPU or Wi-Fi usage is high
def motionCallback(self):
# attempting to determine if rising edge is actually a true event
# motion sensor trigger stays high for ~2 seconds
now = datetime.datetime.now()
tn = now.strftime("%H:%M:%S")
logging.debug('motionCallback: now = ('+ tn + ')')
time.sleep(4)
if GPIO.input(MOTION_PIN):
logging.debug('motion detected')
# threading.Timer(MOTION_DELAY, motionTextCallback).start()
sendTextMessage('motion detected')
GPIO.remove_event_detect(MOTION_PIN)
time.sleep(20)
GPIO.add_event_detect(MOTION_PIN, GPIO.RISING, callback=motionCallback, bouncetime=300)
GPIO.add_event_detect(MOTION_PIN, GPIO.RISING, callback=motionCallback, bouncetime=300)
while True:
time.sleep(3600)