Added bluetooth phone monitor
[tpope-extra.git] / perl / mobile-phone-monitor
1 #!/usr/bin/perl
2 # Author: Tim Pope
3
4 # Monitors a bluetooth mobile phome for calls.  You'll need to bind rfcomm1 to
5 # your mobile phone's SP service.  You'll also need my Device::Nokia module
6 # (the name is misleading, it's not Nokia specific).
7
8 use strict;
9 use Device::Nokia;
10 my $number;
11 my %status;
12
13 my $gsm = new Device::Nokia( port => '/dev/rfcomm1', log => 'file,/dev/null');
14
15 $SIG{INT}  = 'death';
16 $SIG{TERM} = 'death';
17 $SIG{QUIT} = 'death';
18
19 sub initialize {
20     my $gsm=shift;
21     $gsm->connect() || return 0;
22     $gsm->atsend( 'AT+CLIP=1' . Device::Modem::CR );
23     $gsm->answer();
24     return 1;
25 }
26
27 initialize($gsm) || die "Could not initialize modem: $!";
28
29 daemonize() if (shift eq "-d");
30
31 while(1) {
32 %status=("is_active"=>1);
33 while($status{"is_active"} ne 0) {
34     for(my $i=0;$i<8;$i++) {
35         sleep 1;
36         $number = wait_for_ring();
37         if($number) {
38             $status{"number"} = $number;
39             output_status(%status);
40             ring($number);
41             last;
42         } elsif(!defined($number)) { $status{"is_active"}=0; last; };
43     }
44     my %newstatus=gather_data($gsm);
45     ring() if($newstatus{"call"}!=0 && $status{"call"}!=0);
46     foreach (keys %newstatus) {
47         $status{$_} = $newstatus{$_} if(defined ($newstatus{$_}));
48     }
49     undef $status{"number"} if (!$number && $status{"callsetup"}==0 && $status{"call"}==0);
50     output_status(%status);
51 }
52 $gsm->disconnect();
53 #print "Chillin'...\n";
54 output_status(is_active => 0);
55 do {sleep 60}
56 until(initialize($gsm));
57 }
58
59 sub wait_for_ring {
60     local $_;
61     eval {
62         local $SIG{ALRM} = sub { die "alarm\n" };
63         alarm 5;
64         $_ = $gsm->answer("\\+CLIP: \"[0-9]+\",[0-9]+\$", 30);
65         alarm 0
66     };
67     if($@) {
68         die unless $@ eq "alarm\n";
69         return undef;
70     } else {
71         m/CLIP: "([0-9]+)",/;
72         return "$1";
73     }
74 }
75
76 sub ring {
77     system($ENV{"HOME"} . "/bin/phone-call " . $_[0]);
78 }
79
80 sub gather_data {
81   my %data;
82   my $gsm=shift;
83     eval {
84         local $SIG{ALRM} = sub { die "alarm\n" };
85         alarm 15;
86   %data=$gsm->indicators();
87   my ($first, $second) = $gsm->battery_strength();
88   $data{"source"}=$first;
89   $data{"battery"}=$second;
90   ($first, $second) = $gsm->signal_quality();
91   $data{"signal"}=$first;
92   alarm 0;
93   };
94     if($@) {
95         die unless $@ eq "alarm\n";
96         return (is_active => 0);
97     } else {
98         $data{"is_active"}=$gsm->is_active() && $data{"signal"} && 1 || 0;
99         return %data;
100     }
101 }
102
103 sub output_status {
104     my %status = @_;
105     open STATUS, ">/tmp/.phone-status.new" || die $!;
106     foreach my $indicator (sort keys %status) {
107         print STATUS "$indicator=" . $status{$indicator} . "\n";
108     };
109     close STATUS;
110     rename "/tmp/.phone-status.new", "/tmp/.phone-status" || die $!;
111 }
112
113
114 sub daemonize {
115     chdir "/";
116     my $pid=fork();
117     if($pid) {
118         exit(0)
119     }
120     elsif(defined($pid))
121     {
122         close STDIN;
123         close STDOUT;
124         close STDERR;
125     }
126     else { exit(1); }
127 }
128
129 sub death {
130     $gsm->disconnect() if($gsm);
131     unlink "/tmp/.phone-status.new", "/tmp/.phone-status";
132     exit(0);
133 }