Lights, camera, action!
25 Jul 2021 - Thomas Lake
For a couple of reasons, I found myself wanting to set up a camera to monitor the area outside the back door of my house. This then became an excuse to play with an ESP32 camera and motion, and extend my home assistant setup.
The camera I’ve used is an ESP32 Cam unit purchased from a convenient online source, running the simple HTTP streaming software provided at Random Nerd Tutorials. This provides a live feed from the camera by pointing a browser at the camera’s IP address - I add an address reservation on my router for the various ESP devices on my network so that the IP remains consistent.
Recording
As I don’t particularly want to rely on me watching the stream in case something happens, I want to record the images onto my home server.
Note that for people living in the UK and EU there are GDPR requirements associated with CCTV, although based on the ICO guidance on the topic for the UK the requirements are easily avoided by ensuring the camera only covers your property and nothing else.
To record the images, I’m using motion - a fairly well established piece of free, open-source software that allows you to record images from cameras (either locally connected to a machine, or over the network as in this case) based on time intervals or detected motion.
Installing motion onto a Debian based machine (in this case, a Raspberry Pi 3B+) is a simple matter of running apt update; apt install motion
. The key bits of my configuration were then to edit /etc/motion/motion.conf
as follows:
- Comment out the
videodevice
line (as we want to use a network camera) - Change
minimum_frame_time
to 5 - Uncomment
netcam_url
line and add the camera IP - e.g.netcam_url http://10.20.30.40/
- Point
mask_file
at a generated mask (see below) post_capture 3
- allow for a little extra after motion triggersoutput_pictures on
- save all the still images while motion is detectedquality 90
- it’s hardly HD to begin with, lets not make it worseffmpeg_output_movies off
- minimise CPU load. You can always stitch the images back together latertext_left Back door
- Just in case I add another cameratext_double on
- To make the date / time big enough to be legibletarget_dir /srv/motion
- Not a standard location, but I have a largish SSD mounted at /srv rather than using the Raspberry Pi memory card- Add ‘%t/%Y/%m/%d/’ to the front of
snapshot_filename
,picture_filename
,movie_filename
andtimelapse_filename
- even though the last two aren’t being used. This gives one folder full of images per day. stream_localhost off
,webcontrol_localhost off
- this server is firewalled and only accessible from the internet on specific ports, so I’m happy to open access here as it will remain confined to the rest of my LAN.lightswitch 30
- In an attempt to avoid some false triggers from changes in overall light level
Masks
Motion provides a couple of options to allow you to mask out areas of an image from motion detection mask_file and from recording mask_privacy. These files need to be the same size as the recorded image and in PGM format - GIMP will happily output these, so I took a snapshot from the camera, created a new white layer and painted over the areas that needed to be excluded in black, and another patch of grey for reduced sensitivity.
Simple, but effective. The alternative would be to remove the weeds that are causing the stray motion in the first place, but this was an easier solution for now.
Notifications
So now the recording is set up, can I use my existing Home Assistant setup to prod me to look at the camera feed or recorded images if something moves? Apparently so!
To set this up, I’m taking advantage of the fact that Home Assistant is running in a virtual environment (not a container) on the same machine as motion. I needed to add these lines to configuration.yaml
:
homeassistant:
allowlist_external_dirs:
- '/srv/motion'
folder_watcher:
- folder: /srv/motion/0
patterns:
- '*-*-00.jpg'
If you already have folder_watcher
or homeassistant
blocks then merge these entries in. I then created a new automation, based on the folder_watcher example :
alias: 'Motion Detected: Back door'
description: ''
trigger:
- platform: event
event_type: folder_watcher
event_data:
event_type: created
condition: []
action:
- service: notify.notify
data:
message: 'New motion capture images found: '
title: 'Motion captured: Back door'
data:
file: ''
- service: logbook.log
data:
name: Back door
message: motion capture detected
mode: single
A couple of quick tests suggest that the time between something moving past the camera and a notification appearing is about 5 seconds - not bad for an afternoon of tinkering about.