Script for theft alarm using HDAPS
Contents
General
Recent ThinkPad models include a built-in two-axis accelerometer, as part of the HDAPS feature. This accelerometer can be put to another use: as a laptop theft deterrant. The following script detects when the laptop is moved and emits a loud audio alarm. Against a casual laptop-snatcher in a populated environment (e.g., typical office space) this can be an effective deterrant.
Note that the alarm cannot work when the laptop is suspended or powered off. You will buy an external motion detector alarm for those cases.
Prerequisites
- hdaps module loaded (comes with kernel 2.6.14 and later)
- sox (SOund eXchange) sound utility
- aumix command line mixer
The latter two should be included with your distribution, but check if they are installed.
The script
This Perl script periodically samples the tilt data reported by the accelerometer, computes the variance over recent samples, and triggers the alarm when the variance exceeds a given threshold.
On an HDAPS-equipped laptop running a modern Linux installation, the script should work as is. Just run it and see (or rather, hear) what happens when you tilt your laptop. The volume and alarm sound can be adjusted at the top of the script. On a ThinkPad T43, the synthetic siren at a volume of 100 is quite ear-splitting.
#!/usr/bin/perl # # This script uses the HDAPS accelerometer found on recent ThinkPad models # to emit an audio alarm when the laptop is tilted. In sufficiently # populated environments, it can be used as a laptop theft deterrant. # # This file is placed in the public domain and may be freely distributed. use strict; use warnings; ############################## # Siren volume and content # Audio volume (0..100) my $volume = 70; # Synthesize a syren for 1.0 seconds: my $play_cmd = "sox -t nul /dev/null -t ossdsp /dev/dsp synth 1.0 sine 2000-4000 sine 4000-2000"; # Play a file: # my $play_cmd = "play keep_your_hands_off_me.wav"; ############################## # Other tweakables my $thresh = 0.15; # tilt threshold (increase value to decrease sensitivity) my $interval = 0.1; # sampling interval in seconds my $depth = 10; # number of recent samples to analyze my $pos_file='/sys/devices/platform/hdaps/position'; my $verbose = 1; ############################## # Code sub get_pos { open(POS,"<",$pos_file) or die "Can't open HDAPS file $pos_file: $!\n"; $_=<POS>; m/^\((\d+),(\d+)\)$/ or die "Can't parse $pos_file content\n"; return ($1,$2); } sub stddev { my $sum=0; my $sumsq=0; my $n=$#_+1; for my $v (@_) { $sum += $v; $sumsq += $v*$v; } return sqrt($n*$sumsq - $sum*$sum)/($n*($n-1)); } my (@XHIST, @YHIST); my ($x,$y) = get_pos; for (1..$depth) { push(@XHIST,$x); push(@YHIST,$y); } my $alarm_file; # flags ongoing alarm (and stores saved mixer settings) while (1) { my ($x,$y) = get_pos; shift(@XHIST); push(@XHIST,$x); shift(@YHIST); push(@YHIST,$y); my $xdev = stddev(@XHIST); my $ydev = stddev(@YHIST); # Print variance and history print "X: v=$xdev (".join(',',@XHIST).") Y: v=$ydev (".join(",",@YHIST).")\n" if $verbose>1; my $tilted = $xdev>$thresh || $ydev>$thresh; if ($tilted && !(defined($alarm_file) && -f $alarm_file)) { print "ALARM\n" if $verbose>0; $alarm_file = `mktemp /tmp/hdaps-tilt.XXXXXXXX` or die "mktemp: $?"; chomp($alarm_file); system('/bin/bash', '-c', <<"EOF")==0 or die "Failed: $?"; ( trap \"aumix -L -f $alarm_file > /dev/null; rm -f $alarm_file" EXIT HUP QUIT TERM aumix -S -f $alarm_file && aumix -v $volume -w 100 && $play_cmd) & EOF } select(undef, undef, undef, $interval); # sleep }
To do
Features awaiting contribution:
- Start out quietly, and increase siren duration and volume if movement persists. Reset after a period of no movement.
- Automatically start and stop with screensaver (especially nifty when integrated with the fingerprint reader). Can probably be done similarly to lightwatch.pl.
- Report theft via network (if you get a chance to).