00001 #!/usr/bin/perl
00002 use strict;
00003 use warnings;
00004
00005 use English;
00006 use File::Basename;
00007 use Cwd 'abs_path';
00008 use lib dirname(abs_path($0 or $PROGRAM_NAME)),
00009 '/usr/share/mythtv/mythweather/scripts/us_nws',
00010 '/usr/local/share/mythtv/mythweather/scripts/us_nws';
00011
00012 use XML::Parser;
00013 use base qw(XML::SAX::Base);
00014 use Date::Manip;
00015 use Date::Manip::TZ;
00016 use Data::Dumper;
00017 use Getopt::Std;
00018 use LWP::Simple;
00019
00020 my $alerts;
00021 my $currAlert;
00022 my $currInfo;
00023 my $loc_file = dirname(abs_path($0 or $PROGRAM_NAME)) . "/bp16mr06.dbx";
00024
00025 sub StartDocument {
00026 $alerts = [];
00027 }
00028
00029 sub StartTag {
00030 my ($expat, $name, %atts) = @_;
00031 if ($name eq "feed"){
00032 $currAlert = {};
00033 }
00034
00035 if ($name eq "entry") {
00036 $currInfo = {};
00037 }
00038
00039 }
00040
00041
00042 sub EndTag {
00043 my ($expat, $name, %atts) = @_;
00044
00045 if ($name eq "feed") {
00046 push @$alerts, $currAlert;
00047 }
00048 if ($name eq "entry") {
00049 push (@{$currAlert->{'entry'}}, $currInfo);
00050 }
00051 }
00052
00053 sub Text {
00054 my ($expat, $text) = @_;
00055
00056 if ($expat->within_element('cap:geocode') && $expat->within_element('value')) {
00057 if($expat->{Text}) {
00058 my %geocodes;
00059 foreach my $geocode ($expat->{Text} =~ m/(\d+)/g) {
00060 $geocodes{int $geocode} = 1;
00061 }
00062 $currInfo->{'cap:geocode'} = \%geocodes;
00063 }
00064
00065 } elsif ($expat->within_element('entry')) {
00066 $currInfo->{$expat->current_element} = $expat->{Text} if ($expat->{Text}
00067 =~ /\w+/);
00068
00069 } elsif ($expat->within_element('feed')) {
00070 $currAlert->{$expat->current_element} = $expat->{Text} if ($expat->{Text} =~
00071 /\w+/);
00072 }
00073
00074 }
00075
00076 ############################################
00077 sub getWarnings {
00078
00079 my $state = shift;
00080 my $cache_dir = shift;
00081 $state =~ tr/[A-Z]/[a-z]/;
00082 my $parser = new XML::Parser(Style => 'Stream');
00083 my $capfile = '';
00084 my $url = "http://alerts.weather.gov/cap/$state.php?x=0";
00085 if($cache_dir && -d $cache_dir)
00086 {
00087 my $cache_file = "$cache_dir/$state.cap";
00088 my $rc = mirror($url, $cache_file);
00089 if(is_error($rc)) {
00090 die "cannot retrieve alert data";
00091 }
00092 open(CAP, $cache_file);
00093 undef($/);
00094 $capfile = <CAP>;
00095 close(CAP);
00096 }
00097 else
00098 {
00099 $capfile = get $url
00100 or die "cannot retrieve alert data";
00101 }
00102 $parser->parse($capfile);
00103 return $alerts;
00104 }
00105
00106 sub getEffectiveWarnings {
00107 my $date = shift;
00108 my $state = shift;
00109 my $geo = shift;
00110 my $cache_dir = shift;
00111 my @results;
00112 if (!$alerts) {
00113 getWarnings($state, $cache_dir);
00114 }
00115 my $alert;
00116 my $info;
00117
00118 $date = ParseDate($date);
00119 my $tz = new Date::Manip::TZ;
00120
00121 my @dates;
00122 while ($alert = shift @$alerts) {
00123 push @dates, $alert->{'updated'};
00124 while ($info = shift @{$alert->{'entry'}}) {
00125 if ($info->{'cap:effective'} &&
00126 Date_Cmp($date, $info->{'cap:effective'}) >= 0 &&
00127 Date_Cmp($date, $info->{'cap:expires'}) < 0 &&
00128 (!$geo || $info->{'cap:geocode'}{int $geo})) {
00129 push @results, $info;
00130 }
00131 }
00132 }
00133 if (scalar(@dates) > 1) {
00134 return @dates, @results;
00135 } else {
00136 return $dates[0], @results;
00137 }
00138 return @results;
00139 }
00140
00141 our ($opt_v, $opt_t, $opt_T, $opt_l, $opt_u, $opt_d);
00142
00143 my $name = 'NWS-Alerts';
00144 my $version = 0.3;
00145 my $author = 'Lucien Dunning';
00146 my $email = 'ldunning@gmail.com';
00147 my $updateTimeout = 10*60;
00148 my $retrieveTimeout = 30;
00149 my @types = ('swlocation', 'updatetime', 'alerts', 'copyright');
00150 my $dir = "./";
00151
00152 getopts('Tvtlu:d:');
00153
00154 if (defined $opt_v) {
00155 print "$name,$version,$author,$email\n";
00156 exit 0;
00157 }
00158
00159 if (defined $opt_T) {
00160 print "$updateTimeout,$retrieveTimeout\n";
00161 exit 0;
00162 }
00163 if (defined $opt_l) {
00164 open(LOCS, $loc_file) or die "couldn't open bp16mr06.dbx";
00165 my $search = shift;
00166 while(<LOCS>) {
00167 if (m/$search/i) {
00168 my @entry = split /[|]/;
00169 print "$entry[6]::$entry[3], $entry[0]\n";
00170 }
00171 }
00172 exit 0;
00173 }
00174
00175 if (defined $opt_t) {
00176 foreach (@types) {print; print "\n";}
00177 exit 0;
00178 }
00179
00180 if (defined $opt_d) {
00181 $dir = $opt_d;
00182 }
00183
00184 my $loc = shift;
00185
00186 if (!(defined $loc && !$loc eq "")) {
00187 die "Invalid usage";
00188 }
00189
00190 my $state;
00191 my $locstr;
00192 # its a big file that we have to search linearly, so we keep a simple cache
00193 if (open(CACHE, "$dir/NWSAlert_$loc")) {
00194 ($state, $locstr) = split /::/, <CACHE>;
00195 chomp $locstr;
00196 close(CACHE);
00197 }
00198
00199 if (!$state || !$locstr) {
00200 ($state, $locstr) = doLocation($loc);
00201 if ($state && $locstr) {
00202 my $file = "$dir/NWSAlert_$loc";
00203 open(CACHE, ">$file") and
00204 print CACHE "${state}::${locstr}\n";
00205 } else { die "cannot find location"; }
00206 }
00207
00208 my ($updatetime, @warnings) = getEffectiveWarnings("now", $state, $loc, $dir);
00209
00210 foreach my $warning (@warnings) {
00211 my $txt = $warning->{'summary'};
00212 for my $line (split /\n/, $txt) {
00213 print "alerts::$line\n" if ($line =~ m/\w+/);
00214 }
00215 }
00216 if (!@warnings) {
00217 print "alerts::No Warnings\n";
00218 }
00219
00220 print "swlocation::$locstr,$state\n";
00221
00222 $updatetime = ParseDate($updatetime);
00223 $updatetime = UnixDate($updatetime, "%b %d, %I:%M %p %Z");
00224
00225 print "updatetime::Last Updated at $updatetime\n";
00226 print "copyright::NOAA,National Weather Service\n";
00227
00228 sub doLocation {
00229 my $code = shift;
00230 open(LOCS, $loc_file) or die "couldn't open bp16mr06.dbx";
00231 while(<LOCS>) {
00232 if (m/$code/) {
00233 my @entry = split /[|]/;
00234 return ($entry[0], $entry[3]);
00235 }
00236 }
00237 }