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