Script for theft alarm using HDAPS

From ThinkWiki
Revision as of 17:15, 13 November 2005 by Thinker (Talk | contribs) (needs hdaps module)
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 deterrent. 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 deterrent.

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 with the hdaps kernel module loaded, 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 deterrent.
#
# 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 siren 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.20;   # 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
}

The author of the script disclaims all warranty for this script, and releases it to the public domain.

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).