PIR motion-activated recording
By Patrick Wigmore, , published: , updated
Having established that the only way the Hedgehog Home Hub was going to record usable video footage was locally, onto flash storage; and having established that it wasn’t powerful enough to run motion
and detect movement in software, I realised I was going to need a PIR sensor.
Besides needing almost no computing power, a passive infrared motion detector can be set up so that it detects a hedgehog before it walks into view of the camera, so there is less chance of missing some of the action.
I decided to wire the PIR sensor to the Home Hub’s “WPS” button input, so that, from a software point of view, it looks like someone is pressing the WPS button when a hedgehog appears. (Actually, it ended up being the inverse; the button is pressed all the time and released when a hedgehog appears.)
Automating the recording process
To make the PIR sensor useful, I first needed an automated recording process.
The function of the WPS button is defined by the script in /etc/rc.button/wps. However, repeated button press events are queued up for processing by the script, so the script needs to be one that runs quickly and then exits. It can’t carry out the full recording itself.
Therefore, I wrote a hhcam-record
script, which records video, and a hhcam-trigger
script to be called by the button script. hhcam-trigger
starts hhcam-record
and schedules the termination of hhcam-record
for 60 seconds later. (The length of time is configurable.)
It’s worth mentioning that OpenWRT runs BusyBox, so the shell isn’t as full-featured as a typical Bash shell, which did affect the way I wrote some of the scripts.
/etc/rc.button/wps
:
#!/bin/sh
if [ "$ACTION" = "released" ] && [ "$BUTTON" = "wps" ]; then
/sbin/hhcam-trigger
fi
return 0
A basic implementation of /sbin/hhcam-trigger
:
#!/bin/sh
# Script to trigger or re-trigger a recording using the hedgehog camera
source /sbin/hhcam-parameters
function schedule_recording_end {
/sbin/hhcam-timer "$RECORDING_PID_FILE" "$1s" "$TIMER_PID_FILE" &
echo $! > "$TIMER_PID_FILE"
}
if [ -f "$RECORDING_PID_FILE" ]; then
# Reschedule recording end (retrigger)
previous_timer_pid=$(cat "$TIMER_PID_FILE")
schedule_recording_end $RECORDING_TIME
kill -SIGTERM "$previous_timer_pid"
else
# Start a new recording and schedule it to end after $RECORDING_TIME seconds
/sbin/hhcam-record &
echo $! > $RECORDING_PID_FILE
schedule_recording_end $RECORDING_TIME
fi
Initially I wanted to use at
to schedule the end of the recording, but at
will only schedule events to occur at the start of the minute on the clock. This means it might limit the recording to 2 seconds if the recording started 2 seconds before the start of the next minute! So, I instead wrote a third script, hhcam-timer
, which just uses sleep
to time the required number of seconds.
A basic implementation of /sbin/hhcam-timer
:
#!/bin/sh
# Script to end a hedgehog camera recording after a certain time
# The first argument should be the path to a file containing the PID of the
# recording process that will be stopped after the time.
# The second argument should be the time after which to end the recording
# It should be formatted suitably for use as an argument for 'sleep'
# The third argument should be the path to a file containing the PID of this
# timer script once it is running. The script will remove it when it is done.
# Although the time may be specified in minutes, it needs to be timed to the
# nearest second or better.
# Timer
sleep "$2"
# Stop recording
kill -SIGTERM $(cat "$1")
killall -q -SIGTERM v4l2-ctl
# Remove PID files
rm "$1"
rm "$3"
It was around about this point that I realised there might be an issue with the webcam hardware ‘crashing’. After being powered up for a while, the webcam would seem to lock up and stop responding. Unplugging it and plugging it in again would get it working again, but that’s no good for an automated system.
I hoped I might be able to programmatically reset the camera by fiddling with the USB subsystem in some way. Or that the issue might be thermal and might go away once the camera was outdoors in the cold. But, it seemed conceivable that I might have to rig up some means of power-cycling the camera, either based on a software control, at regular intervals on a timer, or triggered via the PIR sensor in some way, being careful to make sure the camera got reset before each recording, but not during the recordings.
Adding the PIR sensor
To attach the PIR sensor to the WPS button input, I used the wire from an old pair of headphones to carry the power, ground and signal for the PIR, plugging it into a 3.5mm TRS jack, which I fitted to the rear of the Home Hub. I put a 1k resistor in line with the signal input, to provide some amount of input protection.
It turned out that the PIR was active high, while the WPS button was active low, so the button would appear pressed until motion was detected, when it would be released. This is not an issue so far as triggering the video recording is concerned, because the “release” event of the button can trigger a recording. However, it is a problem during boot-up, because holding down the WPS button causes the router to boot into OpenWRT’s “failsafe mode”. It is therefore impossible to successfully boot or reboot the Home Hub with the PIR connected directly to the button input.
If I could guarantee that I’d always be physically present to reboot the Home Hub, then I could just unplug the PIR beforehand, wait for the boot to finish, and then plug it back in again. In theory that might be sufficient, but what if there was a mains power failure or someone accidentally unplugged the power supply? And being able to reboot the system remotely is a nice feature.
The only way I could think of getting around this, other than buying a different PIR sensor with an active low output, was to build a timer circuit to keep the button input high until the router was safely booted.
(Hindsight note, July 2023: Re-reading this, it has just occurred to me that, rather than building a timer circuit, I could have just inverted the signal from the PIR! Ah well.
Hindsight note, September 2023: But, actually, a hold-off timer is required regardless, in case an animal is walking past the PIR sensor during boot-up.)
Building a delay circuit
After experimenting with some circuitry, I realised that the problem with adding a timer circuit for the PIR is that it will only function on first boot after power-on. After that, the 5V rail is unlikely to de-energise during reboots, and certainly not for long enough to allow the timer to reset. Since the entire point of having a timer is to enable the device to be rebooted remotely, without having to physically access it and unplug the PIR, such a timer would be a fairly useless feature.
During boot, the green power LED flashes. So, I built a circuit to keep the PIR switched off for a short period after the green power LED has gone out.
I’m not an electronics engineer, and I designed the circuit to use components I already had to hand, so it’s pretty basic. It worked in simulation, when tested on a breadboard, and when tested out-of-system.
However, once installed in the Hub, the PIR module did not receive enough voltage to send logic high outputs.
I was stuck on this for a while. Eventually I realised that the problem was the fact that the 3.3V LED signal was less than the supply voltage to my transistor, so that when the input was high, current still flowed because the input was “low” relative to the supply. I solved this by supplying the transistor from a potential divider formed from a 3V Zener diode and a 100k resistor.
After tweaking and simulating the circuit in circuitjs, it looked looked like it was going to work.
But the circuit still failed to work! The router stubbornly booted into failsafe mode as though the WPS button had been held down.
At first I thought the PIR sensor might not be consuming enough power to drain the capacitor, and set about trying to add a resistor to load the output down further, before realising that that was nonsense; the load current is irrelevant to the successful draining of the capacitor, and besides that the circuit was already tested as working with the PIR.
Fearing I may have damaged the LED GPIO line, I disconnected my circuit from the GPIO line and measured voltages. Then it dawned on me: I had connected it to the wrong line; the one for the blue LED. Testing the delay circuit’s behaviour in response to lighting the blue LED showed that the circuit was behaving as designed.
I’d been lulled into a false sense of correctness because the power-on delay side-effect of the circuit was enough to prevent the router booting into failsafe mode at first power-on even if the green LED did not further inhibit the PIR, and to start with I’d only tested it with initial power-ons, not reboots.
Connecting it to the line for the green LED was slightly challenging, since that was the most inaccessible solder pad out of of the three different colours, but a piece of fine, enamelled copper wire made it possible. After correcting this misconnection, the circuit functioned properly.
With the PIR motion sensor working, the Hedgehog Home Hub was ready to be put into service! This enabled me leave it running long enough to discover the webcam reliability issues!