Blog contributor: madryn

Hmmm. Sunday night. 2:30 AM. I woke up with  “There is someone here!”. Two intruders hopped the wall bordering the river bed. They reached into one of the bedroom windows, and rattled the blinds enough to wake my son up. By the time I found a torch, switched on lights and went to look, they had already run off.

Fortunately there was no confrontation.

Unfortunately this was the second time in the last 6 months.

After the previous midnight trespass, the motion sensor flood light was replaced and the electric fence was repaired.

Well, the light didn’t switch on and the fence was “bypassed” with a piece of wood that had been notched carefully to hook the wires so they can be lifted up, just enough, without them touching, creating a gap between the top of the wall and the bottom wire. The improvised implement was left behind in the fence.

I have a beam sensor that was never connected and some Raspberry Pi kit I could repurpose, so it was time to make a system that can monitor the beam, trigger a siren, and act as a camera trap to possibly catch unwelcome visitors in the act. Most importantly this should act as a deterrent and provide some early warning.

If you don’t have a beam sensor you could also use a passive infrared or other sensor normally used on alarm systems.

The most time consuming part was designing and printing a weatherproof housing for the Pi and the camera board. The electronics needed were available as ready made modules so replication will be easy.

The printed parts were designed using OpenSCAD around the components and nuts and bolts that were on hand. When Raspberry Pi availability finally improves, I will consider making a version with mounting options for other Pi models.

The STL files and assembly instructions for the housing have been uploaded to Thingiverse and you can find them here:

Parts and materials:

Hookup diagram:


Most security system sensors have a small relay that is normally closed, so simply connecting a siren via the alarm output is not an option as the signal needs to be inverted.

The beam sensor’s receiver was supplied with power but it was not connected to to an alarm system. It is close to where the camera would be mounted so I decided to directly connect the Alarm contact to the GPIO pins of the Pi.  Ideally you should use an optocoupler or something similar to avoid possible damage to the Pi in case something goes wrong, and especially if the cable between the sensor and the Pi is quite long. The alarm output is just a relay contact, so it acts like a switch.

The normally closed contact opens when the beam is interrupted, and 12V DC is available which can be used to power a 12V piezo siren. The siren is connected to 12V with a relay board which is turned on and off by a GPIO pin.

Take note that putting 5V or more onto the 3.3V GPIO pins will fry the Pi, so always measure to make sure.

The Pi is powered up via the USB power input. The a DC-DC buck converter provides 5V which is stepped down from the 12V that powers the beam units.

Step 1 - Print the 3D parts

The model needs supports when printed, and the objects will need to be rotated sensibly before slicing. The parts are oriented as they would be when assembled, rather than for printing. 

I used SA Filament PLA Plus, but PETG or ABS might be better if you want something more durable.

Step 2 - Flash the SD card with an operating system for the Pi

The intention is to activate a siren for a few seconds, make a log entry, and keep a high resolution still image when the beam is interrupted. It only needs a simple web interface with a live image from the camera so you can take a look if the siren goes off, and provide access to a log file and recorded images.

While there are many existing options for Pi based security cameras, for this project I decided to start from scratch, and keep it simple.

Using Raspberry Pi Imager, download and flash Raspberry Pi OS Lite (32 bit) to the SD card. You should set up a password, enable SSH and preconfigure WiFi network details using the Advanced Options. This will make headless set up easy, as the Pi will boot, connect to your WiFi network, and start an ssh server so you can connect remotely. You can set the host name to whatever you want. I called this one beampi.

Step 3 - Assemble the housing, mount the Pi board, camera and hook up the components

The camera board is connected to the Pi with the standard ribbon cable and mounted to the front plate. The square of perspex is clamped between the two front plates and protects the lens.

It is easiest if you assemble the front end to the bottom shell, and then hook up the components.

The nuts tend to fall out of their slots, so it helps to secure them with a bit of glue.

Please refer to the assembly notes on Thingiverse.

This version has no mounting points for the two additional boards, so they are just tucked inside and the case is closed up. The DC-DC converter and the relay board are inside some shrink sleeve to prevent the possibility of shorting out against the Pi or anything else. All joints in wires are soldered and then covered with shrink sleeve.

There are four cut to length wires leaving the camera housing which go the beam sensor for 12V DC power and the Alarm signal. They are threaded along with the siren’s cables through the hole at the bottom of the housing. The siren is held under the wall bracket with a cable tie.

The cables coming from the alarm loop are connected directly to a GND pin and GPIO24.

The Pi has built in pull up and pull down resistors that can be activated using software, so no additional components are required.

The incoming negative 12V wire is connected to the 12V siren’s negative cable and the negative input on the DC-DC converter.

The incoming positive 12V wire is connected to the COM terminal on the relay board and the positive input of the DC-DC converter.

The siren’s positive wire is connected to the NO terminal on the relay board.

The 5V terminal of the relay board is connected to a 5V pin on the Pi.

The GND terminal of the relay board is connected to a GND pin on the Pi.

The SIGNAL terminal of the relay board is connected to GPIO23 on the Pi.

While the relay board needs a 5V supply, the 3.3V output from the Pi’s GPIO should be sufficient to trigger the optocoupled signal input. Setting the GPIO24 pin High will turn on the relay, and power up the siren. The module should be set to trigger on High. Some modules can be set to trigger on Low. In this mode the signal terminal will have 5V on it and this can damage the 3.3V GPIO on the Pi, so double check.

Female DuPont connectors were used for connections to the GPIO pins of the Pi.

A USB cable was cut in half, and the thicker red and black cables were soldered onto the 5V output of the DC-DC converter to power the Pi via its USB port.

Check everything before you power anything up. Many a Pi did fry by incorrect voltage.

Now would be a good time to insert the SD card if you haven’t already.

Getting the top and back covers on is a bit tricky. The top shell slides over the bottom shell from the back, the front screws are tightened, and then the back cover is screwed on.

If you need to access the SD card, you can just remove the four screws and pull off the back cover.

When the 12V cables are connected to a 12V DC source the Pi should power up.

Step 4 - Set up the Pi

Once the Pi has started up, it should be connected to your WiFi network and you should be able access the device via its host name if your computer supports Avahi / Zeroconf, or log into your WiFi router to check what IP address was assigned to the Pi.

Connect to the Pi using SSH and log in. You should be able do this on the command line in a terminal on most modern MacOS, Linux and Windows systems.

localhost% ssh pi@beampi.local

After logging in, you should see something like this:

Linux beampi 5.10.103+ #1529 Tue Mar 8 12:19:18 GMT 2022 armv6l

The programs included with the Debian GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extentpermitted by applicable law.

pi@beampi:~ $

Next update the OS.

pi@beampi:~ $ sudo apt-get update

pi@beampi:~ $ sudo apt-get upgrade

This may take a while, depending on your internet connection.

We want to use the GPIOs with Python, so install  wiringpi. We also need a web server, so install lighttpd.

pi@beampi:~ $ sudo apt-get install lighttpd wiringpi

After these are installed you should be able to see a default index page at http://beampi.local/ or http://[ip address]/.

The camera module needs to be enabled before we can use it.

pi@beampi:~ $  sudo raspi-config

You will find the camera under 3 - Interface Options.

Enable the camera and exit. You may need to reboot and log back in.

The raspistill command can be used to control and take pictures with the camera. The simplest way to make a live image remotely accessible is to capture frames as quickly as possible to a file and serve that file with a web server. Constantly writing and reading files on the SD card can add unnecessary wear and will be quite slow. A better option is to use a RAM disk. Let’s set one up to mount automatically that is accessible to the raspistill command as well as the web server.

To do this, we need to create a mount point.

For convenience, the mount point is made in the default document path of lighttpd. This way no specific configuration change is needed to serve a file from RAM.

pi@beampi:~ $ sudo mkdir /var/www/html/ramdisk/

To avoid errors, we will use very loose permissions. This is inherently insecure, but for the sake of giving different processes launched by different users access, it is set with global Read Write eXecute permissions.

pi@beampi:~ $ sudo chmod 777 /var/www/html/ramdisk/

Add an entry to the /etc/fstab file to mount a ram disk on the newly created mount point. This will create a small 16Mb temporary filesystem that is held in RAM on startup. The contents is lost on restart.

pi@beampi:~ $ sudo bash

root@beampi:~ $ echo "tmpfs /var/www/html/ramdisk tmpfs nodev,nosuid,size=16M 0 0" >> /etc/fstab

Reboot the Pi.

root@beampi:~ $ reboot

Log back in using ssh.

Now check the camera. The following command will take a picture and store it as a jpeg file on the ram disk.

pi@beampi:~ $ sudo raspistill -o /var/www/html/ramdisk/latest.jpg&

If there were no errors, verify that the image can be retrieved with a web browser from http://beampi.local/ramdisk/latest.jpg. You may need to use just the the IP address your router supplied the Pi.

Now that this works, create a suitable html index page.

pi@beampi:~ $ sudo bash

root@beampi:~ $ echo "<html>






      <img src=\"./ramdisk/latest.jpg\" id=\"reloader\" onLoad=\"setTimeout( () => { document.getElementById('reloader').src='./ramdisk/latest.jpg' + '?' + new Date().getMilliseconds() } ,250)\"><br>

<a href=\"./beam/\">beam logs</a>




</html>" > /var/www/html/index.html

root@beampi:~ $ exit

pi@beampi:~ $

The index file will be at /var/www/html/index.html with the following contents.







      <img src="./ramdisk/latest.jpg" id="reloader" onLoad="setTimeout( () => { document.getElementById('reloader').src='./ramdisk/latest.jpg' + '?' + new Date().getMilliseconds() } ,250)"><br>

<a href="./beam/">beam logs</a>




The image tag has a snippet of javascript that will constantly fetch and display the latest image which will appear as a live stream.

It also adds a link to where the logs and recorded images will be, so lets set this up on the pi.

pi@beampi:~ $ sudo mkdir /var/www/html/beam/

pi@beampi:~ $ sudo chmod 777 /var/www/html/beam

The easiest way to allow access to files in this directory with a web browser is to enable directory listing. It is disabled by default, so add an exception to the configuration file and restart the web server. This needs to be done as a privileged user.

pi@beampi:~ $ sudo bash

root@beampi:~ $ echo "\$HTTP[\"url\"] =~ \"^/beam($|/)\" { dir-listing.activate = \"enable\" }" >> /etc/lighttpd/lighttpd.conf

root@beampi:~ $ systemctl restart lighttpd

root@beampi:~ $ exit

pi@beampi:~ $

The next step is to create a python script for monitoring the beam. A folder “beammonitor” will be the home for this so we create it under /usr/local.

pi@beampi:~ $ sudo mkdir /usr/local/beammonitor

Ownership is changed to make it easier for the pi user to edit the files.

pi@beampi:~ $ sudo chown pi /usr/local/beammonitor

pi@beampi:~ $ sudo chgrp pi /usr/local/beammonitor

Create some empty script files and set permissions to make them executable.

pi@beampi:~ $ cd /usr/local/beammonitor

pi@beampi:/usr/local/beammonitor $ mkdir bin

pi@beampi:/usr/local/beammonitor $ touch bin/

pi@beampi:/usr/local/beammonitor $ chmod +x bin/

Using your favourite text editor, edit the empty file and insert the following:

Eg: vi /usr/local/beammonitor/bin/




import RPi.GPIO as GPIO

import time

import datetime

import shutil


beam = 24

siren = 23

duration = 5

loop = True

logfile = "/var/www/html/beam/beam.log"



GPIO.setup(siren, GPIO.OUT)

GPIO.setup(beam, GPIO.IN, pull_up_down=GPIO.PUD_UP)


while loop:

GPIO.wait_for_edge(beam, GPIO.RISING)

now =

GPIO.output(siren, GPIO.HIGH)

shutil.copyfile("/var/www/html/ramdisk/latest.jpg", "/var/www/html/beam/images/"+now.strftime("%Y-%m-%d_%H-%M-%S")+".jpg")

file = open(logfile, 'a') # Open the file in append mode

file.write('Beam Triggered: '+now.strftime("%Y-%m-%d %H:%M:%S")+"\n")



GPIO.output(siren, GPIO.LOW)



This script will sets up the GPIO’s for the beam input and the siren relay. Then it waits for the beam to be triggered.  When triggered it activates the siren, copies the current image to persistent storage and makes a log entry. It waits for a while and switches off the siren. And then does it all over again.

To make it easier to start and stop we will create some shell scripts.

pi@beampi:/usr/local/beammonitor $ touch

pi@beampi:/usr/local/beammonitor $ touch

pi@beampi:/usr/local/beammonitor $ chmod +x

pi@beampi:/usr/local/beammonitor $ chmod +x

To constantly take images, raspistill is started as a background process in timelapse mode, and then the python script is started to run in the background as well. This way you can log off, and the processes will stay running.

Again, use your favourite text editor to edit the files and insert the following:

Eg: vi /usr/local/beammonitor/


/usr/bin/raspistill -tl 0 -t 9999999999 -drc high -st -mm matrix -w 1296 -h 972 -a "$HOSTNAME" -a 12 -awb greyworld -ex night -o /var/www/html/ramdisk/latest.jpg&


Eg: vi /usr/local/beammonitor/


/usr/bin/killall raspistill


The first script starts raspistill and the script. The second one can be used to stop the background processes.

You can edit the start script to change the raspistill options to suit your requirements. The -tl 0 makes the process capture frames as quickly as possible, and the -a options timestamp the image.

You can now start the camera and alarm by running

pi@beampi:~ $ /usr/local/beammonitor/

Step 5 - Try it

Go to http://beampi.local/ or the Pi’s IP address and you should see a live stream.

The camera settings may still need some tweaking and exposure is not great in pitch darkness, but the picture looks good when the flood light is on and during the day (my back yard not so much). Hopefully the light will be triggered as well.

If you trigger the alarm loop, a log file will be created, and you can access it and a folder containing images taken when the alarm loop was triggered by clicking on the beam logs link.

The objective was to make things as lightweight as possible to run comfortably on the original Pi. Let’s have a look.

pi@beampi:~ $ top

Plenty of memory available. The CPU is 62% idle while the beammonitor script, raspistill processes are running and lighttpd is serving a stream of jpegs. Enough resources available to let the Pi do some more work, but that is for some other day.

If you want the processes to start up on boot, you can add the start script to rc.local or your local crontab. When using crontab you can make it run and stop at specific times.

Time to drill some holes in the wall. :-)

Leave a comment