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

RCWL-0516 installed

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. Coverage In a larger premisis, with multiple modules, suitably seperated, things might be OK

UPDATE:

HC-SR501 installed

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 root@192.168.1.247 -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:

  1. 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.
  2. 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

extensions.conf

[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

Evidence

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 root@192.168.1.247 -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

Tech used

RCWL-0516 pinout

RCWL-0516 pinout

Disassociating (or not) from the Wireless

This graph shows the seconds since last beacon for a particular MAC sampled regularly over a few days on both 2.4GHz and 5GHz radios. There is a significant fall off at 60s, but I can't find an OpenWRT setting that specifies this - it might be an Android "thing" Graph of seconds since last Beacon I've assumed that if the MAC is associated but the "ms" since last beacon is > 60000 then the device has actually wandered off and can't heartbeat.

OpenWRT doe have this setting:

max_inactivity '3600'

That I'm confident that that explains the max number I saw.