Ticket #3337: weathercomXML.3.pl

File weathercomXML.3.pl, 11.5 KB (added by simonflood, 13 years ago)

Perl script to pull XML data from weather.com (v0.3)

Line 
1#!/usr/bin/perl -w
2
3use strict;
4
5use Data::Dumper;
6use Getopt::Std;
7use LWP::Simple;
8use XML::Simple;
9
10our($opt_d, $opt_l, $opt_t, $opt_T, $opt_u, $opt_v);
11
12my $name = 'weathercomXML';
13my $version = 0.3;
14my $author = 'Simon Flood';
15my $email = 'simon@floodfamily.info';
16my $updateTimeout = 15*60; # how/where is this used?
17my $retrieveTimeout = 30;  # how/where is this used?
18my @types = ('3dlocation', '6dlocation', 'appt', 'cclocation', 'cclogo',
19             'ccprovider', 'date-0', 'date-1', 'date-2', 'date-3', 'date-4',
20             'date-5', 'desc1', 'desc2', 'desc3', 'dewpoint', 'fclocation',
21             'fclogo', 'fcprovider', 'high-0', 'high-1', 'high-2', 'high-3',
22             'high-4', 'high-5', 'icon-0', 'icon-1', 'icon-2', 'icon-3',
23             'icon-4', 'icon-5', 'latitude', 'longitude', 'low-0', 'low-1',
24             'low-2', 'low-3', 'low-4', 'low-5', 'observation_time',
25             'pressure', 'relative_humidity', 'station_id', 'temp',
26             'updatetime', 'visibility', 'weather', 'weather_icon', 'wind_dir',
27             'wind_gust', 'wind_speed', 'wind_spdgst');
28#my $dir = './';
29my $dir = '.';
30my $unit;
31
32my @months = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
33
34my $base_url = "http://xoap.weather.com/";
35my $weather_url = $base_url . "weather/local/";
36my $query_url = $base_url . "search/search";
37
38my $ccxmlcache = "cc-cache.xml";
39my $fcxmlcache = "fc-cache.xml";
40my $ccrefreshtime = 15*60;   # 15 minutes
41my $fcrefreshtime = 2*60*60; #  2 hours
42
43my($response, $ccxml, $fcxml, $locid);
44
45getopts('d:l:tTu:v');
46
47if (defined $opt_d && ((defined $opt_u) && !(defined $opt_l || defined $opt_t || defined $opt_T || defined $opt_v)))
48{
49    if (-d $opt_d)
50    {
51      ($dir) = ($opt_d =~ /(.*)[^\/]?$/);
52    }
53    else
54    {
55      print "invalid directory ($opt_d)\n";
56      exit 1;
57    }
58}
59
60if (defined $opt_l && !(defined $opt_d || defined $opt_t || defined $opt_T || defined $opt_u || defined $opt_v))
61{
62    my $search = get($query_url . "?where=" . $opt_l);
63    my $searchxml = XMLin($search);
64    if (defined $searchxml->{'loc'}->{'id'})
65    {
66        print $searchxml->{'loc'}->{'id'} . "::" . $searchxml->{'loc'}->{'content'} . "\n";
67    }
68    else
69    {
70        foreach my $locid (sort keys %{$searchxml->{'loc'}})
71        {
72            print $locid . "::" . $searchxml->{'loc'}->{$locid}->{'content'} . "\n";
73        }
74    }
75    exit 0;
76}
77
78if (defined $opt_t && !(defined $opt_d || defined $opt_l || defined $opt_T || defined $opt_u || defined $opt_v))
79{
80    foreach (@types)
81    {
82        print; print "\n";
83    }
84    exit 0;
85}
86
87if (defined $opt_T && !(defined $opt_d || defined $opt_l || defined $opt_t || defined $opt_u || defined $opt_v))
88{
89    print "$updateTimeout,$retrieveTimeout\n"; # do these get used? where/how?
90    exit 0;
91}
92
93if (defined $opt_u && !(defined $opt_l || defined $opt_t || defined $opt_T || defined $opt_v))
94{
95    if ($opt_u eq "ENG")
96    {
97        $unit = "s";
98    }
99    elsif ($opt_u eq "SI")
100    {
101        $unit = "m";
102    }
103}
104
105if (defined $opt_v && !(defined $opt_d || defined $opt_l || defined $opt_t || defined $opt_T || defined $opt_u))
106{
107    print "$name,$version,$author,$email\n";
108    exit 0;
109}
110
111$locid = shift;
112
113if (!(defined $unit && defined $locid))
114{
115    print "Usage: $0 -l <location>\n";
116    print "       $0 -t\n";
117    print "       $0 -T\n";
118    print "       $0 -u <units> [-d <directory>] <location_id>\n";
119    print "       $0 -v\n";
120    print "Options:\n";
121    print "  -d <directory>  use <directory> to store data (must have write permissions!)\n";
122    print "  -l <location>   return list of location ids matching <location>\n";
123    print "  -t              return list of data items supported by script\n";
124    print "  -T              return default timeout values (updateTimeout,retrieveTimeout)\n";
125    print "  -u <units>      specify the units desired in the output, either \"ENG\"\n";
126    print "                  (imperial) or \"SI\" (metric)\n";
127    print "  -v              return information about script (name,version,author,email)\n";
128    exit 0;
129}
130
131sub read_XML_from_cache
132{
133    my($filename) = @_;
134    my($result);
135    open(CACHE, $filename);
136    no strict "vars";
137    $result = eval <CACHE>;
138    close(CACHE);
139    return($result);
140}
141
142sub fetch_XML_and_write_to_cache
143{
144    my($url, $filename) = @_;
145    my($response, $result);
146    $response = get $url;
147    $result = XMLin($response);
148    open(CACHE, ">$filename") ||
149        die "cannot open cache ($filename) for writing";
150    $Data::Dumper::Indent = 0;
151    $Data::Dumper::Purity = 1;
152    $Data::Dumper::Sortkeys = 1;
153    print CACHE Dumper($result);
154    close(CACHE);
155    return($result);   
156}
157
158my $time = time;
159my($lastmod);
160
161if (-e "$dir/$ccxmlcache")
162{
163    $lastmod = (stat("$dir/$ccxmlcache"))[9];
164    if (($time - $lastmod) >= $ccrefreshtime)
165    {
166        $ccxml = &fetch_XML_and_write_to_cache("$weather_url$locid?cc=*&unit=$unit", "$dir/$ccxmlcache");
167    }
168    else
169    {
170        $ccxml = &read_XML_from_cache("$dir/$ccxmlcache");
171    }
172}
173else
174{
175    $ccxml = &fetch_XML_and_write_to_cache("$weather_url$locid?cc=*&unit=$unit", "$dir/$ccxmlcache");
176}
177
178#print Dumper($ccxml); exit;
179
180if (-e "$dir/$fcxmlcache")
181{
182    $lastmod = (stat("$dir/$fcxmlcache"))[9];
183    if (($time - $lastmod) >= $fcrefreshtime)
184    {
185        $fcxml = &fetch_XML_and_write_to_cache("$weather_url$locid?dayf=10&unit=$unit", "$dir/$fcxmlcache");
186    }
187    else
188    {
189        $fcxml = &read_XML_from_cache("$dir/$fcxmlcache");
190    }
191}
192else
193{
194    $fcxml = &fetch_XML_and_write_to_cache("$weather_url$locid?dayf=10&unit=$unit", "$dir/$fcxmlcache");
195}
196
197#print Dumper($fcxml); exit;
198
199my($label, $value);
200
201if (!(defined $ccxml->{'err'} || defined $fcxml->{'err'}))
202{
203    foreach (@types)
204    {
205        $label = $_;
206
207        if (/[36]dlocation/ || /fclocation/)
208        {
209            $value = $fcxml->{'loc'}->{'dnam'};
210        }
211        elsif (/appt/)
212        {
213#            $value = $ccxml->{'cc'}->{'flik'} . chr(176) . $ccxml->{'head'}->{'ut'};
214            $value = $ccxml->{'cc'}->{'flik'} . chr(176);
215        }
216        elsif (/cclocation/)
217        {
218            $value = $ccxml->{'cc'}->{'obst'};
219        }
220        elsif (/[cf]clogo/)
221        {
222            $value = "TWClogo_64px.png";
223        }
224        elsif (/[cf]cprovider/)
225        {
226            $value = "Weather data provided by weather.com" . chr(174);
227        }
228        elsif (/date-0/)
229        {
230            if ($fcxml->{'dayf'}->{'day'}->[0]->{'hi'} eq "N/A")
231            {
232                $value = "Tonight";
233            }
234            else
235            {
236                $value = "Today";
237            }
238        }
239        elsif (/date-1/)
240        {
241            $value = "Tomorrow";
242        }
243        elsif (/date-([2-5])/)
244        {
245            $value = $fcxml->{'dayf'}->{'day'}->[$1]->{'t'};
246        }
247        elsif (/desc1/)
248        {
249            if ($fcxml->{'dayf'}->{'day'}->[0]->{'hi'} eq "N/A")
250            {
251                $value = $fcxml->{'dayf'}->{'day'}->[0]->{'part'}->[1]->{'t'};
252            }
253            else
254            {
255                $value = $fcxml->{'dayf'}->{'day'}->[0]->{'part'}->[0]->{'t'};
256            }
257        }
258        elsif (/desc([23])/)
259        {
260            $value = $fcxml->{'dayf'}->{'day'}->[$1-1]->{'part'}->[0]->{'t'};
261        }
262        elsif (/dewpoint/)
263        {
264#            $value = $ccxml->{'cc'}->{'dewp'} . chr(176) . $ccxml->{'head'}->{'ut'};
265            $value = $ccxml->{'cc'}->{'dewp'} . chr(176);
266        }
267        elsif (/high-([0-5])/) {
268            $value = $fcxml->{'dayf'}->{'day'}->[$1]->{'hi'};
269        }
270        elsif (/icon-0/)
271        {
272            if ($fcxml->{'dayf'}->{'day'}->[0]->{'hi'} eq "N/A")
273            {
274                $value = $fcxml->{'dayf'}->{'day'}->[0]->{'part'}->[1]->{'icon'} . '.png';
275            }
276            else
277            {
278                $value = $fcxml->{'dayf'}->{'day'}->[0]->{'part'}->[0]->{'icon'} . '.png';
279            }
280        }
281        elsif (/icon-([1-5])/)
282        {
283            $value = $fcxml->{'dayf'}->{'day'}->[$1]->{'part'}->[0]->{'icon'} . '.png';
284        }
285        elsif (/latitude/)
286        {
287            $value = $fcxml->{'loc'}->{'lat'};
288        }
289        elsif (/longitude/)
290        {
291            $value = $fcxml->{'loc'}->{'lon'};
292        }
293        elsif (/low-([0-5])/)
294        {
295            $value = $fcxml->{'dayf'}->{'day'}->[$1]->{'low'};
296        }
297        elsif (/observation_time/)
298        {
299            $ccxml->{'cc'}->{'lsup'} =~  /^(\d{1,2})\/(\d{1,2})\/\d{2}\s(\d{1,2})(:\d{2}.*)$/;
300            $value = "$months[$1-1] $2, ";
301            if ($3 < 10)
302            {
303                $value .= "0";
304            }
305            $value .= "$3$4";
306        }
307        elsif (/pressure/)
308        {
309#            $value = $ccxml->{'cc'}->{'bar'}->{'r'} . ' ' . $ccxml->{'head'}->{'up'} . ' (' . $ccxml->{'cc'}->{'bar'}->{'d'} . ')';
310#            $value = $ccxml->{'cc'}->{'bar'}->{'r'} . ' (' . $ccxml->{'cc'}->{'bar'}->{'d'} . ')';
311            $value = $ccxml->{'cc'}->{'bar'}->{'r'} . ' ';
312            if ($ccxml->{'cc'}->{'bar'}->{'d'} =~ /rising/)
313            {
314                $value .= '+';
315            }
316            elsif ($ccxml->{'cc'}->{'bar'}->{'d'} =~ /steady/)
317            {
318                $value .= '=';
319            }
320            elsif ($ccxml->{'cc'}->{'bar'}->{'d'} =~ /falling/)
321            {
322                $value .= '-';
323            }
324            else
325            {
326                $value .= '?';
327            }
328        }
329        elsif (/station_id/)
330        {
331            $value = $locid;
332        }
333        elsif (/temp/)
334        {
335#            $value = $ccxml->{'cc'}->{'tmp'} . chr(176) . $ccxml->{'head'}->{'ut'};
336            $value = $ccxml->{'cc'}->{'tmp'} . chr(176);
337        }
338        elsif (/relative_humidity/)
339        {
340#            $value = $ccxml->{'cc'}->{'hmid'} . "%";
341            $value = $ccxml->{'cc'}->{'hmid'};
342        }
343        elsif (/updatetime/)
344        {
345            $fcxml->{'dayf'}->{'lsup'} =~  /^(\d{1,2})\/(\d{1,2})\/\d{2}\s(\d{1,2})(:\d{2}.*)$/;
346            $value = "$months[$1-1] $2, ";
347            if ($3 < 10)
348            {
349                $value .= "0";
350            }
351            $value .= "$3$4";
352        }
353        elsif (/visibility/)
354        {
355            $value = $ccxml->{'cc'}->{'vis'};
356        }
357        elsif (/wind_dir/)
358        {
359            $value = $ccxml->{'cc'}->{'wind'}->{'t'};
360        }
361        elsif (/weather$/)
362        {
363            $value = $ccxml->{'cc'}->{'t'};
364        }
365        elsif (/weather_icon/)
366        {
367            $value = $ccxml->{'cc'}->{'icon'} . '.png';
368        }
369        elsif (/wind_gust/)
370        {
371            $value = $ccxml->{'cc'}->{'wind'}->{'gust'};
372            if ($value ne "N/A")
373            {
374                $value .= ' ' . $ccxml->{'head'}->{'us'};
375            }
376        }
377        elsif (/wind_spdgst/)
378        {
379            $value = "$ccxml->{'cc'}->{'wind'}->{'s'} ($ccxml->{'cc'}->{'wind'}->{'gust'}) $ccxml->{'head'}->{'us'}";
380        }
381        elsif (/wind_speed/)
382        {
383            $value = $ccxml->{'cc'}->{'wind'}->{'s'} . ' ' . $ccxml->{'head'}->{'us'};
384        }
385
386        print $label . "::" . $value . "\n";
387    }
388
389}
390else
391{
392
393    foreach (@types)
394    {
395        $label = $_;
396        if (/icon/)
397        {
398            $value = "unknown.png";
399        }
400        else
401        {
402            $value = "N/A";
403        }
404        print $_ . "::" . $value . "\n";
405    }
406
407}