Intruder Warning System
Building an intruder warning system use the RCWL-0516 (Microwave Doppler Radar) board (at 10 for £2.30) from AliExpress connected to the GPIO pins of a Raspberry Pi Zero W (at £15.00) [or any other cheap SBC] that doesn't have reliance on software or data in a public (or even private) cloud and is 100% self-contained, but globally accessible.
As well as avoiding external data sources I didn't want a solution that I had to remember to arm and disarm. I needed a way to know whether I was home or not.
I'm also in favour of keeping it simple so this started in BASH and just stayed that way. It's been running for over month without issue.
For anyone considering this for insurance purposes, think again... meet: EN50131 and PD6662... this system does not meet the requirements.
Detecting motion using the RCWL-0516 doppler radar board
I initially configured the hardware for multiple RCWL-0516s (on gpio4 and gpio5) to cover 2 sections of an 'L' - shaped passage, but realised that the 2 modules where within 2m of each other and this caused detection interference.
For my use case one module ended up being sufficient. In a larger premisis, with multiple modules, suitably seperated, things might be OK
I had to do it... I've now also added an HC-SR501 PIR sensor with a detection zone that overlaps the doppler alarm.
Setting up the GPIO ports for access via the /sys filesystem and setting them as INPUT pins.
for gpio in $PORTS; do if [ ! -d /sys/class/gpio/gpio$gpio ]; then echo -n " $gpio" echo $gpio > /sys/class/gpio/export sleep 1 fi echo "in" > /sys/class/gpio/gpio$gpio/direction done
This will read the radar (and PIR) board. The RCWL-0516 pin goes high for 2 seconds, but the HC-SR501 has a POT that can be adjusted. I ensure that both pins are read once per second.
for gpio in $PORTS; do T=`cat /sys/class/gpio/gpio$gpio/value` if [ "$T" == "1" ]; then Alert=true echo `date` $gpio trigger fi done
Presence using mobile MAC association with wireless
My Wireless at home uses OpenWRT giving me direct (ssh) access to associated MACs, so a trivial check is possible to see if I'm at (or near home)
ssh email@example.com -p2222 'for if in `iwinfo | grep ESSID | cut -f1 -d" "`; do iwinfo $if assoclist; done'
There are some complications of using MAC presence on OpenWRT. I discovered these by graphing the triggers along with the last seen beacon:
- Time taken to associate with wireless if the phone is locked: when I enter the sensor was triggered 3 minutes before I was seeing my phone's MAC on the wireless. This is a complication. I chose not to delay triggering the alarm and instead develop the habit of unlocking my phone to "disarm" the alarm before I enter.
- Time taken to disassociate from the wireless if the phone doesn't actively disassociate from OpenWRT the script has a hardpred 120s limit to accept a MAC has "valid". See explaination at right.
The red indicates where there is no beacon - i.e. I was away from home and the system was "armed".
if I zoom the indicated section you can see a trigger (blue) without presence (grey). This should (and did) generate an alarm.
Raising The Alarm
Admission here, I did use a private cloud, but no useful data or personal data is exchanged
I considered using Email for alerting, but decided that I wouldn't want to have been able to ignore an alert about a break-in. I have access to 2 Asterisk installs with multiple trunks, so a phone call is what I did. My house has 2 snom phones I could have used (to dial via a WEB URI) but that added another part to the chain - I also have IP access to the Asterisk Manager (AMI) so I went with:
telnet ipbx.place.local 5038 << EOF Action: login Username: alarm Secret: xxxxyyyyxxxx Action: Originate Channel: SIP/55500001111@sipgate CallerID: 55500001111 Context: housealarm Exten: 25276 Priority: 1 EOF
[housealarm] exten => 25276,1,NoOp(House Alarm) exten => 25276,n,Wait(1) exten => 25276,n,Playback(Alarm) exten => 25276,n,Wait(1) exten => 25276,n,HangUp()
When I was considering multiple radar detectors I'd intended this dialplan to play a zone number Playback(digits/1), but I've not progressed with that
If the alarm is triggered and I'm not at home I want a way to positively know whether there is someone there. I had previously developed the idea of an image ring using RaspiStill so I re-implemented that allowing me to preserve images before and after the trigger. Here:
# wait and then preserve the image ring that exists at the time sleep 25 i=0; folder=`date "+%Y%m%d_%H%M%S"` mkdir ~/$folder for l in `ls -tr $XDG_RUNTIME_DIR/doppler-img-ring-*.jpg`; do cp $l ~/$folder/doppler-img-ring-$i.jpg ((i++)) done
The Pi Zero is does not have sufficient compute / RAM to create a movie file, but if the image ring is copied/scp'd somewhere that can run ImageMagick and FFmpeg this will create a short video that can be preserved:
for file in doppler-img-ring-*.jpg ; do convert $file -font ../font.ttf -pointsize 48 -fill white -annotate +100+100 %[exif:DateTimeOriginal] x-$file; done; ffmpeg -framerate 2 -i x-doppler-img-ring-%d.jpg -vcodec libx264 ../htdocs/output.mp4
Complete BASH source
Source as of 2023-10-11 with private / secret stuff corrupted.
#/bin/bash PORTS="4" MACS="ff:ff:ff:cc:cc:cc ff:ff:ff:dd:dd:dd" # list of MACs that arm / disarm the system echo -n Export ports and set to input for gpio in $PORTS; do if [ ! -d /sys/class/gpio/gpio$gpio ]; then echo -n " $gpio" echo $gpio > /sys/class/gpio/export sleep 1 fi echo "in" > /sys/class/gpio/gpio$gpio/direction done echo " Done!" echo "Starting GPIO Monitoring" SECONDS=0 while [ 1 ] ; do CheckPresence=false Alert=false # delete any images older than 30s find $XDG_RUNTIME_DIR/doppler-img-ring-* -type f -mmin +0.5 -delete 2> /dev/null & # force a presence check every 5 mins, even if no alert if (( $SECONDS > 300 )); then CheckPresence=true SECONDS=0 fi # check for an alert for gpio in $PORTS; do T=`cat /sys/class/gpio/gpio$gpio/value` if [ "$T" == "1" ]; then Alert=true echo `date` $gpio trigger fi done if [ "$CheckPresence" = true ] || [ "$Alert" = true ]; then # connect to the Wifi access point and dump a list of associated MACs ssh firstname.lastname@example.org -p2222 'for if in `iwinfo | grep ESSID | cut -f1 -d" "`; do iwinfo $if assoclist; done' > $XDG_RUNTIME_DIR/presence lastBeacon=999999 fromMac="FF:FF:FF:FF:FF:FF" for mac in $MACS; do T=`grep -i "$mac" $XDG_RUNTIME_DIR/presence` if [ -n "$T" ]; then # if the mac is associated, check for the last beacon for ms in `grep -i "$mac" $XDG_RUNTIME_DIR/presence | cut -f11 -d" "`; do if (( $ms < $lastBeacon )); then lastBeacon=$ms fromMac=$mac fi done fi done echo `date`" Last Beacon $lastBeacon ms from $fromMac" # If the lastBeacon is too long ago, if (( $lastBeacon > 120000 )); then # Activate the camera if not already running T=`ps -e | grep -c raspistill` if (( $T == 0 )); then raspistill -q 10 -o $XDG_RUNTIME_DIR/doppler-img-ring-%1d.jpg --nopreview --timeout 0 --exposure auto --timelapse 1000 & fi # raise the alarm if necessary if [ "$Alert" = true ]; then echo `date` SEND ALERT telnet ipbx.nowhere.com 5038 << EOF Action: login Username: alarm Secret: qwer1234qwer Action: Originate Channel: SIP/5552719271@sipgate CallerID: 5552719271 Context: housealarm Exten: 25276 Priority: 1 EOF # wait and then preserve the image ring that exists at the time sleep 25 i=0; folder=`date "+%Y%m%d_%H%M%S"` mkdir ~/$folder for l in `ls -tr $XDG_RUNTIME_DIR/doppler-img-ring-*.jpg`; do cp $l ~/$folder/doppler-img-ring-$i.jpg ((i++)) done # wait a little longer to ensure we can't retrigger too soon sleep 30 fi else # ensure recording is turned off if I'm home killall -9 raspistill fi fi sleep 1 done