00001 #!/usr/bin/perl -w
00002 use strict;
00003 use NDFDParser;
00004 use NWSLocation;
00005 use Data::Dumper;
00006 use Getopt::Std;
00007 use Date::Manip;
00008
00009 our ($opt_v, $opt_t, $opt_T, $opt_l, $opt_u, $opt_d);
00010
00011 my $name = 'NDFD-18_Hour';
00012 my $version = 0.1;
00013 my $author = 'Lucien Dunning';
00014 my $email = 'ldunning@gmail.com';
00015 my $updateTimeout = 15*60;
00016 my $retrieveTimeout = 30;
00017 my @types = ('18hrlocation', 'updatetime',
00018 'temp-0', 'temp-1', 'temp-2', 'temp-3', 'temp-4', 'temp-5',
00019 '18icon-0', '18icon-1', '18icon-2', '18icon-3', '18icon-4', '18icon-5',
00020 'pop-0', 'pop-1', 'pop-2', 'pop-3', 'pop-4', 'pop-5',
00021 'time-0', 'time-1', 'time-2', 'time-3', 'time-4', 'time-5');
00022 my $dir = './';
00023
00024 getopts('Tvtlu:d:');
00025
00026 if (defined $opt_v) {
00027 print "$name,$version,$author,$email\n";
00028 exit 0;
00029 }
00030
00031 if (defined $opt_T) {
00032 print "$updateTimeout,$retrieveTimeout\n";
00033 exit 0;
00034 }
00035 if (defined $opt_l) {
00036 my $search = shift;
00037 NWSLocation::AddLocSearch($search);
00038 NWSLocation::AddStateSearch($search);
00039 NWSLocation::AddStationIdSearch($search);
00040 my $results = doSearch();
00041 my $result;
00042 while($result = shift @$results) {
00043 if ($result->{latitude} ne "NA" && $result->{longitude} ne "NA") {
00044 print "$result->{latitude},$result->{longitude}::";
00045 print "$result->{station_name}, $result->{state}\n";
00046 }
00047 }
00048 exit 0;
00049 }
00050
00051 if (defined $opt_t) {
00052 foreach (@types) {print; print "\n";}
00053 exit 0;
00054 }
00055
00056 if (defined $opt_d) {
00057 $dir = $opt_d;
00058 }
00059
00060 my $locstr = shift;
00061 my $units = $opt_u;
00062 my ($latitude, $longitude) = getLocation($locstr);
00063 if (!(defined $opt_u && defined $latitude && defined $longitude
00064 && $latitude ne "" && $longitude ne "")) {
00065 die "Invalid Usage";
00066 }
00067
00068 my $param = { maxt => 0,
00069 mint =>0,
00070 temp =>1,
00071 dew=>0,
00072 pop12=>1,
00073 qpf=>0,
00074 sky=>0,
00075 snow=>0,
00076 wspd=>0,
00077 wdir=>0,
00078 wx=>0,
00079 waveh=>0,
00080 icons=>1,
00081 rh=>0,
00082 appt=>0 };
00083
00084 my $d1 = UnixDate("now", "%O");
00085 my $d2 = UnixDate(DateCalc($d1, "+ 18 hours"), "%O");
00086 my $result;
00087 my $creationdate;
00088 my $nextupdate;
00089 my $getData = 1;
00090
00091 if (open (CACHE, "$dir/ndfd18_cache_${latitude}_${longitude}")) {
00092 ($nextupdate, $creationdate) = split / /, <CACHE>;
00093 # We don't have to check the start/end dates, since we get the same chunk
00094 # every time, and we update the cache atleast every hour, which is how often the
00095 # data is updated by the NWS.
00096 if (Date_Cmp($nextupdate, "today") > 0) { # use cache
00097 no strict "vars"; # because eval doesn't scope var correctly
00098 $result = eval <CACHE>;
00099 if ($result) {
00100 $getData = 0;
00101 } else {
00102 print STDERR "Error parsing cache $@\n";
00103 };
00104 }
00105
00106 }
00107
00108 if ($getData) {
00109 ($result, $creationdate) = NDFDParser::doParse($latitude, $longitude, $d1, $d2, $param);
00110 # output cache
00111 open(CACHE, ">$dir/ndfd18_cache_${latitude}_${longitude}") or
00112 die "cannot open cache ($dir/ndfd18_cache_${latitude}_${longitude}) for writing";
00113 $Data::Dumper::Purity = 1;
00114 $Data::Dumper::Sortkeys = 1;
00115 $Data::Dumper::Indent = 0;
00116 # NDFD is updated by 45 minutes after the hour, we'll give them until 50 to
00117 # make sure
00118 my $min = UnixDate("today", "%M");
00119 my $newmin;
00120 if ($min < 50) {
00121 $newmin = 50-$min;
00122 } else {
00123 $newmin = 60-($min-50);
00124 }
00125 $nextupdate = DateCalc("today", "+ $newmin minutes");
00126 print CACHE UnixDate($nextupdate, "%O ") . UnixDate("today", "%O\n");
00127 print CACHE Dumper($result);
00128 }
00129 my $index = 0;
00130 my $icon;
00131 printf "updatetime::Last Updated on %s\n",
00132 UnixDate($creationdate, "%b %d, %I:%M %p %Z");
00133 my $pop12;
00134 foreach my $time (sort keys %$result) {
00135 if (defined $result->{$time}->{'probability-of-precipitation_12 hour'}) {
00136 $pop12 = $result->{$time}->{'probability-of-precipitation_12 hour'};
00137 next;
00138 }
00139
00140 print "time-${index}::" . UnixDate($time, "%i %p\n");
00141 if ($units eq 'SI') {
00142 $result->{$time}->{temperature_hourly} =
00143 int( (5/9) * ($result->{$time}->{temperature_hourly}-32));
00144 }
00145 print "temp-${index}::$result->{$time}->{temperature_hourly}\n";
00146 print "pop-${index}::$pop12 %\n";
00147 $icon = $result->{$time}->{'conditions-icon_forecast-NWS'};
00148 $icon =~ s/.*\/([a-z0-9_]+[.][j][p][g])/$1/;
00149 local *FH;
00150 open(FH, "icons") or die "Cannot open icons";
00151 while(my $line = <FH>) {
00152 if ($line =~ /${icon}::/) {
00153 $line =~ s/.*::
00154 print "18icon-${index}::$line";
00155 last;
00156 }
00157 }
00158 ++$index > 5 && last;
00159
00160 }
00161
00162 # This script will accept locations that are either station ids, or latitude
00163 # longitude. This is because I haven't decided which to use yet :)
00164 sub getLocation {
00165 my $str = shift;
00166
00167 $str =~ tr/[a-z]/[A-Z]/;
00168 my $lat;
00169 my $lon;
00170
00171 if ($str =~ m/[A-Z]{4,4}/) { # station id form
00172 NWSLocation::AddStationIdSearch($str);
00173
00174 } else { # hopefully lat/lon
00175 ($lat, $lon) = split /,/, $str;
00176 $lat =~ s/(\d{1,3}([.]\d{1,3})?)([.]\d{1,3})?[N]/+$1/ or
00177 $lat =~ s/(\d{1,3}([.]\d{1,3})?)([.]\d{1,3})?[S]/-$1/;
00178 $lon =~ s/(\d{1,3}[.](\d{1,3})?)([.]\d{1,3})?[E]/+$1/ or
00179 $lon =~ s/(\d{1,3}([.]\d{1,3})?)([.]\d{1,3})?[W]/-$1/;
00180 NWSLocation::AddLatLonSearch($lat, $lon);
00181 }
00182
00183 my $results = NWSLocation::doSearch($str);
00184 if ($lat && $lon && !$results) {
00185 # didn't find a matching station
00186 print "18hrlocation::$lat,$lon\n";
00187 return ($lat, $lon);
00188 }
00189
00190 # Should be one result in array
00191 my $location = $results->[0];
00192 $lat = $location->{latitude};
00193 $lon = $location->{longitude};
00194 if ($lat eq 'NA' || $lon eq 'NA') {
00195 # maybe scrape them from website, since they are there, annoying that
00196 # they aren't all in the XML file, gotta love the U.S. Gov :)
00197 die "Latitude and Longitude do not exist for $str";
00198 }
00199 print "18hrlocation::$location->{station_name}, $location->{state}\n";
00200
00201 return ($lat, $lon);
00202 }