From: Tim Pope Date: Fri, 23 Jul 2004 01:33:28 +0000 (+0000) Subject: Added bluetooth phone monitor X-Git-Url: http://git.tpope.net/?p=tpope-extra.git;a=commitdiff_plain;h=deb5077783ff39fea9f1712cbfb3c1380ab0a4c8 Added bluetooth phone monitor --- diff --git a/perl/Device/Nokia.pm b/perl/Device/Nokia.pm new file mode 100755 index 0000000..5a58914 --- /dev/null +++ b/perl/Device/Nokia.pm @@ -0,0 +1,119 @@ +# Device::Nokia +# Author: Tim Pope + +# A Perl class to interface GSM devices as AT modems +# Basically just a few enhancements to Device::Gsm + +package Device::Nokia; +$Device$Revision: 1.1 $ =~ /(\d+)\.(\d+)/; + +use strict; +use Device::Gsm; + +@Device::Nokia::ISA = ('Device::Gsm'); + +# +# Who is the manufacturer of this device? +# +sub manufacturer() { + my $self = shift; + my($ok, $man); + + # Test if manufacturer code command is supported + if( $self->test_command('+CGMI') ) { + + $self->atsend( 'AT+CGMI' . Device::Modem::CR ); + ($ok, $man) = $self->parse_answer(); + + $self->log->write('info', 'manufacturer of this device appears to be ['.$man.']'); + + } + + return $man || $ok; + +} +# +# What is the model of this device? +# +sub model() { + my $self = shift; + my($code, $model); + + # Test if manufacturer code command is supported + if( $self->test_command('+CGMM') ) { + + $self->atsend( 'AT+CGMM' . Device::Modem::CR ); + ($code, $model) = $self->parse_answer(); + + $self->log->write('info', 'model of this device is ['.$model.']'); + + } + + return $model || $code; +} + +# +# Get mobile phone indicators +# +sub indicators() { + my $self = shift; + my($supported,$values,%results); + + # Test if manufacturer code command is supported + if( $self->test_command('+CIND') ) { + $self->atsend( 'AT+CIND=?' . Device::Modem::CR ); + ($_, $supported) = $self->parse_answer(); + $supported =~ s/^\+CIND: //; + $self->atsend( 'AT+CIND?' . Device::Modem::CR ); + ($_, $values) = $self->parse_answer(); + $values =~ s/^\+CIND: //; + #@values = split (/,/, $values); + foreach (split (/,/, $values)) { + $supported =~ s/\("([^"]*)",\([^)]*\)\),?//; + $results{$1} = $_; + } + $self->log->write('info', 'Indicator data retrieved (' . scalar(keys(%results)) . 'values)'); + + } + return %results; +} + +# +# Get mobile phone battery strength +# +sub battery_strength() { + my $self = shift; + # Error code, dBm (signal power), bit error rate + my($code, $strength, $line_power); + + # Test if signal quality command is implemented + if( $self->test_command('+CBC') ) { + + $self->atsend( 'AT+CBC' . Device::Modem::CR ); + ($code, $strength) = $self->parse_answer(); + + if( $strength =~ /\+CBC: (\d+),(\d+)/ ) { + + ($line_power, $strength) = ($1, $2); + + $self->log->write('info', 'battery strength is ['.$strength.'], line power ['.$line_power.']'); + + } else { + + $self->log->write('warn', 'cannot obtain battery strength'); + + } + + } else { + + $self->log->write('warn', 'battery strength command not supported!'); + + } + + return wantarray ? ($line_power, $strength) : $strength; + +} + +1; + +__END__ diff --git a/perl/mobile-phone-monitor b/perl/mobile-phone-monitor new file mode 100755 index 0000000..246cad5 --- /dev/null +++ b/perl/mobile-phone-monitor @@ -0,0 +1,133 @@ +#!/usr/bin/perl +# Author: Tim Pope + +# Monitors a bluetooth mobile phome for calls. You'll need to bind rfcomm1 to +# your mobile phone's SP service. You'll also need my Device::Nokia module +# (the name is misleading, it's not Nokia specific). + +use strict; +use Device::Nokia; +my $number; +my %status; + +my $gsm = new Device::Nokia( port => '/dev/rfcomm1', log => 'file,/dev/null'); + +$SIG{INT} = 'death'; +$SIG{TERM} = 'death'; +$SIG{QUIT} = 'death'; + +sub initialize { + my $gsm=shift; + $gsm->connect() || return 0; + $gsm->atsend( 'AT+CLIP=1' . Device::Modem::CR ); + $gsm->answer(); + return 1; +} + +initialize($gsm) || die "Could not initialize modem: $!"; + +daemonize() if (shift eq "-d"); + +while(1) { +%status=("is_active"=>1); +while($status{"is_active"} ne 0) { + for(my $i=0;$i<8;$i++) { + sleep 1; + $number = wait_for_ring(); + if($number) { + $status{"number"} = $number; + output_status(%status); + ring($number); + last; + } elsif(!defined($number)) { $status{"is_active"}=0; last; }; + } + my %newstatus=gather_data($gsm); + ring() if($newstatus{"call"}!=0 && $status{"call"}!=0); + foreach (keys %newstatus) { + $status{$_} = $newstatus{$_} if(defined ($newstatus{$_})); + } + undef $status{"number"} if (!$number && $status{"callsetup"}==0 && $status{"call"}==0); + output_status(%status); +} +$gsm->disconnect(); +#print "Chillin'...\n"; +output_status(is_active => 0); +do {sleep 60} +until(initialize($gsm)); +} + +sub wait_for_ring { + local $_; + eval { + local $SIG{ALRM} = sub { die "alarm\n" }; + alarm 5; + $_ = $gsm->answer("\\+CLIP: \"[0-9]+\",[0-9]+\$", 30); + alarm 0 + }; + if($@) { + die unless $@ eq "alarm\n"; + return undef; + } else { + m/CLIP: "([0-9]+)",/; + return "$1"; + } +} + +sub ring { + system($ENV{"HOME"} . "/bin/phone-call " . $_[0]); +} + +sub gather_data { + my %data; + my $gsm=shift; + eval { + local $SIG{ALRM} = sub { die "alarm\n" }; + alarm 15; + %data=$gsm->indicators(); + my ($first, $second) = $gsm->battery_strength(); + $data{"source"}=$first; + $data{"battery"}=$second; + ($first, $second) = $gsm->signal_quality(); + $data{"signal"}=$first; + alarm 0; + }; + if($@) { + die unless $@ eq "alarm\n"; + return (is_active => 0); + } else { + $data{"is_active"}=$gsm->is_active() && $data{"signal"} && 1 || 0; + return %data; + } +} + +sub output_status { + my %status = @_; + open STATUS, ">/tmp/.phone-status.new" || die $!; + foreach my $indicator (sort keys %status) { + print STATUS "$indicator=" . $status{$indicator} . "\n"; + }; + close STATUS; + rename "/tmp/.phone-status.new", "/tmp/.phone-status" || die $!; +} + + +sub daemonize { + chdir "/"; + my $pid=fork(); + if($pid) { + exit(0) + } + elsif(defined($pid)) + { + close STDIN; + close STDOUT; + close STDERR; + } + else { exit(1); } +} + +sub death { + $gsm->disconnect() if($gsm); + unlink "/tmp/.phone-status.new", "/tmp/.phone-status"; + exit(0); +}