#!/usr/local/bin/perl
# tell us the weather
# weather.pl v2011061501
# Copyright 2010-2011 Jeremy Kister
# Released under Perl's Artistic License
# in /etc/asterisk/extensions.conf:
# [weather]
# exten => s,1,Answer
# exten => s,n,AGI(weather.pl,90210);
# exten => s,n,Hangup()
## Note: you may ommit the zip code argument, and the AGI will
## ask you for one.
#sed s/^#// << __EOSQL__ | sqlite3 /var/sql/weather.db
#CREATE TABLE current (
# id INTEGER PRIMARY KEY NOT NULL,
# condition VARCHAR(255),
# temp_f TINYINT NOT NULL,
# wind_condition VARCHAR(255),
# humidity VARCHAR(255),
# zip CHAR(5) NOT NULL,
# location VARCHAR(255),
# time INT NOT NULL
#);
#
#CREATE TABLE forecast (
# id INTEGER PRIMARY KEY NOT NULL,
# condition VARCHAR(255),
# high TINYINT NOT NULL,
# low TINYINT NOT NULL,
# day_of_week VARCHAR(10),
# zip CHAR(5) NOT NULL,
# time INT NOT NULL
#);
#
#create index current01 on current(time);
#create index current02 on current(zip);
#create index forecast01 on forecast(time);
#create index forecast02 on current(zip);
#__EOSQL__
use strict;
use DBI;
use LWP::UserAgent;
use XML::Simple;
use Asterisk::AGI;
my $agi = Asterisk::AGI->new();
my $zip = $ARGV[0];
while($zip !~ /^\d{5}$/){
swift( "Enter zip code,5000,5" );
$zip = $agi->get_variable('SWIFT_DTMF');
}
my ($dbun,$dbpw);
my $dsn = 'DBI:SQLite:dbname=/var/sql/weather.db';
my $dbh = DBI->connect($dsn, $dbun, $dbpw, {RaiseError => 1});
my %f;
my $hourago = ($^T - 3600);
my $sql = 'SELECT condition,temp_f,wind_condition,humidity,location' .
' FROM current' .
" WHERE time > $hourago" .
' AND zip = ' . $dbh->quote($zip);
my $sth = $dbh->prepare($sql);
$sth->execute;
my $c = $sth->fetchrow_hashref;
my $location = $c->{location};
$sql = ' SELECT condition,high,low,day_of_week ' .
' FROM forecast ' .
" WHERE time > $hourago " .
' AND zip = ' . $dbh->quote($zip) .
' ORDER BY id';
$sth = $dbh->prepare($sql);
$sth->execute;
my $i = 0;
while(my $row=$sth->fetchrow_hashref){
foreach my $field (qw/condition high low day_of_week/){
$f{$i}{$field} = $row->{$field};
}
$i++;
}
unless( $c->{condition} && $f{0}{condition} ){
my $ua = LWP::UserAgent->new;
$ua->timeout(10);
my $response = $ua->get("http://www.google.com/ig/api?weather=${zip}&hl=en");
unless($response->is_success){
die $response->status_line;
}
my $xs = XML::Simple->new;
my $href = $xs->XMLin($response->decoded_content);
$location = $href->{weather}{forecast_information}{city}{data};
for my $table (qw/current forecast/){
my $sql = "DELETE FROM $table" .
' WHERE zip = ' . $dbh->quote($zip);
my $sth = $dbh->prepare($sql);
$sth->execute;
}
my $sql = 'INSERT INTO current (temp_f,condition,wind_condition,humidity,zip,location,time) VALUES (';
foreach my $key (qw/temp_f condition wind_condition humidity/){
$c->{$key} = $href->{weather}{current_conditions}{$key}{data};
$sql .= $dbh->quote($c->{$key}) . ',';
}
$sql .= $dbh->quote($zip) . ',' .
$dbh->quote($location) . ',' .
time() . ')';
$sth = $dbh->prepare($sql);
$sth->execute;
foreach my $dow (0..3){
my $sql = 'INSERT INTO forecast (high,low,day_of_week,condition,zip,time) VALUES (';
foreach my $key (qw/high low day_of_week condition/){
$f{$dow}{$key} = $href->{weather}{forecast_conditions}[$dow]{$key}{data};
$sql .= $dbh->quote($f{$dow}{$key}) . ',';
}
$sql .= $dbh->quote($zip) . ',' . time() . ')';
my $sth = $dbh->prepare($sql);
$sth->execute;
}
}
my %eng_dir = (N => 'North', E => 'East', S => 'South', W => 'West');
my %days = (Sun => 'Sunday', Mon => 'Monday', Tue => 'Tuesday', Wed => 'Wednesday',
Thu => 'Thursday', Fri => 'Friday', Sat => 'Saturday' );
my ($dirs) = $c->{wind_condition} =~ /Wind: ([NESW]{1,2})/;
my $eng;
foreach my $dir (split //, $dirs){
$eng .= "$eng_dir{$dir} ";
}
chop($eng); # just because - trailing space.
$c->{wind_condition} =~ s/Wind: $dirs/Wind: $eng/;
unless($ARGV[0]){
$location =~ /(\S+) ([A-Z])([A-Z])$/;
$location = "$1 $2 $3";
swift( "Forecast for $location." );
}
# condition could be: showers, rain, cloudy, mostly cloudy
my $text = "It is currently $c->{temp_f} degrees and $c->{condition} " .
" $c->{wind_condition} and $c->{humidity}. ";
foreach my $dow (sort { $a <=> $b } keys %f){
$text .= "$days{$f{$dow}{day_of_week}}: $f{$dow}{condition} " .
"with a high of $f{$dow}{high} and a low of $f{$dow}{low} " .
". ";
}
swift( $text );
sub swift {
my $msg = join(' ', @_);
$agi->exec('Swift', $msg);
}