MythTV  master
ndfd18.pl
Go to the documentation of this file.
1 #!/usr/bin/perl
2 use strict;
3 use warnings;
4 
5 use English;
6 use File::Basename;
7 use Cwd 'abs_path';
8 use lib dirname(abs_path($0 or $PROGRAM_NAME)),
9  '/usr/share/mythtv/mythweather/scripts/us_nws',
10  '/usr/local/share/mythtv/mythweather/scripts/us_nws';
11 
12 use NDFDParser;
13 use NWSLocation;
14 use Data::Dumper;
15 use Getopt::Std;
16 use Date::Manip;
17 
18 our ($opt_v, $opt_t, $opt_T, $opt_l, $opt_u, $opt_d);
19 
20 my $name = 'NDFD-18_Hour';
21 my $version = 0.5;
22 my $author = 'Gavin Hurlbut / Lucien Dunning';
23 my $email = 'gjhurlbu@gmail.com / ldunning@gmail.com';
24 my $updateTimeout = 15*60;
25 my $retrieveTimeout = 30;
26 my @types = ('18hrlocation', 'updatetime',
27  'temp-0', 'temp-1', 'temp-2', 'temp-3', 'temp-4', 'temp-5',
28  '18icon-0', '18icon-1', '18icon-2', '18icon-3', '18icon-4', '18icon-5',
29  'pop-0', 'pop-1', 'pop-2', 'pop-3', 'pop-4', 'pop-5',
30  'time-0', 'time-1', 'time-2', 'time-3', 'time-4', 'time-5',
31  'copyright', 'copyrightlogo');
32 my $dir = './';
33 my $icon_file = dirname(abs_path($0 or $PROGRAM_NAME)) . "/icons";
34 
35 getopts('Tvtlu:d:');
36 
37 if (defined $opt_v) {
38  print "$name,$version,$author,$email\n";
39  exit 0;
40 }
41 
42 if (defined $opt_T) {
43  print "$updateTimeout,$retrieveTimeout\n";
44  exit 0;
45 }
46 if (defined $opt_l) {
47  my $search = shift;
48  NWSLocation::AddLocSearch($search);
49  NWSLocation::AddStateSearch($search);
50  NWSLocation::AddStationIdSearch($search);
51  my $results = doSearch();
52  my $result;
53  while($result = shift @$results) {
54  if ($result->{latitude} ne "NA" && $result->{longitude} ne "NA") {
55  print "$result->{latitude},$result->{longitude}::";
56  print "$result->{station_name}, $result->{state}\n";
57  }
58  }
59  exit 0;
60 }
61 
62 if (defined $opt_t) {
63  foreach (@types) {print; print "\n";}
64  exit 0;
65 }
66 
67 if (defined $opt_d) {
68  $dir = $opt_d;
69 }
70 
71 my $locstr = shift;
72 my $units = $opt_u;
73 my ($latitude, $longitude) = getLocation($locstr);
74 if (!(defined $opt_u && defined $latitude && defined $longitude
75  && $latitude ne "" && $longitude ne "")) {
76  die "Invalid Usage";
77 }
78 
79 my $param = { maxt => 0,
80  mint =>0,
81  temp =>1,
82  dew=>0,
83  pop12=>1,
84  qpf=>0,
85  sky=>0,
86  snow=>0,
87  wspd=>0,
88  wdir=>0,
89  wx=>0,
90  waveh=>0,
91  icons=>1,
92  rh=>0,
93  appt=>0 };
94 
95 my $d1 = UnixDate("now", "%O");
96 my $d2 = UnixDate(DateCalc($d1, "+ 18 hours"), "%O");
97 my $result;
98 my $creationdate;
99 my $nextupdate;
100 my $getData = 1;
101 
102 if (open (CACHE, "$dir/ndfd18_cache_${latitude}_${longitude}")) {
103  ($nextupdate, $creationdate) = split / /, <CACHE>;
104  # We don't have to check the start/end dates, since we get the same chunk
105  # every time, and we update the cache atleast every hour, which is how often the
106  # data is updated by the NWS.
107  if (Date_Cmp($nextupdate, "now") > 0) { # use cache
108  no strict "vars"; # because eval doesn't scope var correctly
109  $result = eval <CACHE>;
110  if ($result) {
111  $getData = 0;
112  } else {
113  print STDERR "Error parsing cache $@\n";
114  };
115  }
116 
117 }
118 
119 if ($getData) {
120  my $unit = ($units eq "SI" ? "m" : "e");
121  ($result, $creationdate) = NDFDParser::doParse($latitude, $longitude, $d1, $d2, $unit, $param);
122  # output cache
123  open(CACHE, ">$dir/ndfd18_cache_${latitude}_${longitude}") or
124  die "cannot open cache ($dir/ndfd18_cache_${latitude}_${longitude}) for writing";
125  $Data::Dumper::Purity = 1;
126  $Data::Dumper::Sortkeys = 1;
127  $Data::Dumper::Indent = 0;
128  # NDFD is updated by 45 minutes after the hour, we'll give them until 50 to
129  # make sure
130  my $min = UnixDate("now", "%M");
131  my $newmin;
132  if ($min < 50) {
133  $newmin = 50-$min;
134  } else {
135  $newmin = 60-($min-50);
136  }
137  $nextupdate = DateCalc("now", "+ $newmin minutes");
138  print CACHE UnixDate($nextupdate, "%O ") . UnixDate("now", "%O\n");
139  print CACHE Dumper($result);
140 }
141 my $index = 0;
142 my $icon;
143 printf "updatetime::Last Updated on %s\n",
144  UnixDate($creationdate, "%b %d, %I:%M %p %Z");
145 print "copyright::National Digital Forecast Database\n";
146 print "copyrightlogo::none\n";
147 my $pop12;
148 foreach my $time (sort keys %$result) {
149  if (defined $result->{$time}->{'probability-of-precipitation_12 hour'}) {
150  $pop12 = $result->{$time}->{'probability-of-precipitation_12 hour'};
151  next;
152  }
153 
154  print "time-${index}::" . UnixDate($time, "%i %p\n");
155  print "temp-${index}::$result->{$time}->{temperature_hourly}\n";
156  print "pop-${index}::$pop12 %\n";
157  $icon = $result->{$time}->{'conditions-icon_forecast-NWS'};
158  $icon =~ s/.*\/([a-z0-9_]+[.][j][p][g])/$1/;
159  local *FH;
160  open(FH, $icon_file) or die "Cannot open icons";
161  while(my $line = <FH>) {
162  if ($line =~ /${icon}::/) {
163  $line =~ s/.*:://;
164  print "18icon-${index}::$line";
165  last;
166  }
167  }
168  ++$index > 5 && last;
169 
170 }
171 
172 # This script will accept locations that are either station ids, or latitude
173 # longitude. This is because I haven't decided which to use yet :)
174 sub getLocation {
175  my $str = shift;
176 
177  $str =~ tr/[a-z]/[A-Z]/;
178  my $lat;
179  my $lon;
180 
181  if ($str =~ m/[A-Z]{4,4}/) { # station id form
182  NWSLocation::AddStationIdSearch($str);
183 
184  } else { # hopefully lat/lon
185  ($lat, $lon) = split /,/, $str;
186  $lat =~ s/(\d{1,3}([.]\d{1,3})?)([.]\d{1,3})?[N]/+$1/ or
187  $lat =~ s/(\d{1,3}([.]\d{1,3})?)([.]\d{1,3})?[S]/-$1/;
188  $lon =~ s/(\d{1,3}[.](\d{1,3})?)([.]\d{1,3})?[E]/+$1/ or
189  $lon =~ s/(\d{1,3}([.]\d{1,3})?)([.]\d{1,3})?[W]/-$1/;
190  NWSLocation::AddLatLonSearch($lat, $lon);
191  }
192 
193  my $results = NWSLocation::doSearch($str);
194  if ($lat && $lon && !$results) {
195  # didn't find a matching station
196  print "18hrlocation::$lat,$lon\n";
197  return ($lat, $lon);
198  }
199 
200  # Should be one result in array
201  my $location = $results->[0];
202  $lat = $location->{latitude};
203  $lon = $location->{longitude};
204  if ($lat eq 'NA' || $lon eq 'NA') {
205  # maybe scrape them from website, since they are there, annoying that
206  # they aren't all in the XML file, gotta love the U.S. Gov :)
207  die "Latitude and Longitude do not exist for $str";
208  }
209  print "18hrlocation::$location->{station_name}, $location->{state}\n";
210 
211  return ($lat, $lon);
212 }