Script for theft alarm using HDAPS

From ThinkWiki
Revision as of 20:04, 12 November 2005 by 192.117.108.16 (Talk) (category)
Jump to: navigation, search

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.

The script

This Perl script periodically samples the tilt data reported by the accelerometer, computes the variance over recent samples, and triggers the alarn 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 x.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).
  • Report theft via network (if you get a chance to).