File Coverage

blib/lib/Weather/Astro7Timer.pm
Criterion Covered Total %
statement 46 46 100.0
branch 8 8 100.0
condition 4 4 100.0
subroutine 13 13 100.0
pod 5 5 100.0
total 76 76 100.0


line stmt bran cond sub pod time code
1             package Weather::Astro7Timer;
2              
3 3     3   702712 use 5.006;
  3         14  
4 3     3   20 use strict;
  3         8  
  3         120  
5 3     3   19 use warnings;
  3         11  
  3         179  
6              
7 3     3   18 use Carp;
  3         8  
  3         231  
8 3     3   607 use Time::Local;
  3         3332  
  3         277  
9              
10 3     3   23 use parent 'Weather::API::Base';
  3         7  
  3         21  
11 3     3   88124 use Weather::API::Base qw(:all);
  3         13  
  3         2719  
12              
13             =head1 NAME
14              
15             Weather::Astro7Timer - Simple client for the 7Timer.info Weather Forecast service
16              
17             =cut
18              
19             our $VERSION = '0.4';
20              
21             =head1 SYNOPSIS
22              
23             use Weather::Astro7Timer;
24              
25             my $w7t = Weather::Astro7Timer->new();
26              
27             # Get ASTRO weather for the Stonehenge area
28              
29             my %report = $w7t->get(
30             product => 'astro', # Forecast type (astro, civil, civillight, meteo)
31             lat => 51.2, # Latitude
32             lon => -1.8, # Longitude
33             );
34              
35             # Dumping the result would give you:
36             %report = {
37             'product' => 'astro',
38             'init' => '2023032606',
39             'dataseries' => [{
40             'temp2m' => 6,
41             'wind10m' => {
42             'speed' => 2,
43             'direction' => 'NE'
44             },
45             'rh2m' => 13,
46             'seeing' => 3,
47             'timepoint' => 3,
48             'lifted_index' => 2,
49             'prec_type' => 'none',
50             'cloudcover' => 9,
51             'transparency' => 6
52             },
53             {...},
54             ...
55             ]
56             };
57              
58             # You can get a png image instead...
59              
60             my $data = $w7t->get(
61             product => 'civil',
62             lat => 51.2,
63             lon => -1.8,
64             output => 'png'
65             );
66              
67             # ... and write it out to a file
68             open(my $fh, '>', "civil.png") or die $!; print $fh $data; close($fh);
69              
70              
71             =head1 DESCRIPTION
72              
73             Weather::Astro7Timer provides basic access to the L<7Timer.info|https://7Timer.info>
74             Weather Forecast API.
75             7Timer is a service based on NOAA's GFS and provides various types of forecast products.
76             It is mostly known for its ASTRO product intended for astronomers and stargazers, as
77             it provides an astronomical seeing and transparency forecast.
78              
79             Please see the L and
80             L for details.
81              
82             The module was made to serve the apps L and
83             L, but if your service
84             requires some extra functionality, feel free to contact the author about it.
85              
86             =head1 CONSTRUCTOR
87              
88             =head2 C
89              
90             my $w7t = Weather::Astro7Timer->new(
91             scheme => $http_scheme?,
92             timeout => $timeout_sec?,
93             agent => $user_agent_string?,
94             ua => $lwp_ua?,
95             error => $die_or_return?
96             );
97            
98             Optional parameters:
99              
100             =over 4
101              
102             =item * C : You can specify C. Default: C.
103              
104             =item * C : Timeout for requests in secs. Default: C<30>.
105              
106             =item * C : Customize the user agent string.
107              
108             =item * C : Pass your own L to customise further (overrides C).
109              
110             =item * C : Pass C<'die'> to die on error. Default is C<'return'>.
111              
112             =back
113              
114             =head1 METHODS
115              
116             =head2 C
117              
118             my $report = $w7t->get(
119             product => $product, # Forecast type (astro, civil, civillight, meteo, two)
120             lat => $lat, # Latitude
121             lon => $lon, # Longitude
122             output => $format?, # Output format (default json)
123             unit => $unit?, # Units (default metric)
124             lang => $language?, # Language (default en)
125             tzshift => $tz_shift?, # Timezone shift from UTC (hours, default 0)
126             ac => $alt_cor?, # Altitude correction (default 0)
127             );
128              
129             my %report = $w7t->get( ... );
130              
131              
132             Fetches a forecast report for the requested for the requested location.
133             Returns a string containing the JSON or XML data, except in array context, in which case,
134             as a convenience, it will use L or L to decode it directly to a Perl hash
135             (in the case of C output, the hash will containing a single key C with the png data).
136             For an explanation to the returned data, refer to the L.
137              
138             If the request is not successful, it will C throwing the C<< HTTP::Response->status_line >>.
139              
140             Required parameters:
141              
142             =over 4
143            
144             =item * C : Latitude (-90 to 90). South is negative.
145              
146             =item * C : Longitude (-180 to 180). West is negative.
147              
148             =item * C : Choose from the available forecast products:
149              
150             =over 4
151              
152             =item * C : ASTRO 3-day forecast for astronomy/stargazing with 3h step (includes astronomical seeing, transparency).
153              
154             =item * C : CIVIL 8-day forecast that provides a weather type enum (see docs for equivalent icons) with 3h step.
155              
156             =item * C : CIVIL Light simplified per-day forecast for next week.
157              
158             =item * C : A detailed meteorological forecast including relative humidity and wind profile from 950hPa to 200hPa.
159              
160             =item * C : A two week overview forecast (may be unmaintained).
161              
162             =back
163              
164             =back
165              
166             Optional parameters (see the API documentation for further details):
167              
168             =over 4
169              
170             =item * C : Default is C, also supports C or C.
171              
172             =item * C : C (default) or C units.
173              
174             =item * C : Output format, supports C (default), C or C.
175              
176             =item * C : Timezone offset in hours (-23 to 23).
177              
178             =item * C : Altitude correction (e.g. temp) for high peaks. Default C<0>, accepts
179             C<2> or C<7> (in km). Only for C product.
180              
181             =back
182              
183             =head2 C
184              
185             my $response = $w7t->get_response(
186             lat => $lat,
187             lon => $lon,
188             product => $product
189             %args?
190             );
191              
192             Same as C except it returns the full L from the API (so you
193             can handle bad requests yourself).
194              
195              
196             =head1 CONVENIENCE FUNCTIONS
197              
198             =head2 C
199              
200             my @products = Weather::Astro7Timer::products();
201              
202             Returns the supported forecast products.
203              
204             =cut
205              
206             sub new {
207 8     8 1 488014 my ($class, %args) = @_;
208 8         59 return $class->SUPER::new(%args);
209             }
210              
211             sub get {
212 16     16 1 133977 my $self = shift;
213 16         72 my %args = @_;
214 16   100     111 $args{lang} ||= 'en';
215 16   100     81 $args{output} ||= 'json';
216 16 100       53 $args{output} = 'internal' if $args{output} eq 'png';
217 16         37 $self->{output} = $args{output};
218              
219 16         66 return $self->_get_output($self->get_response(%args), wantarray);
220             }
221              
222             sub get_response {
223 16     16 1 34 my $self = shift;
224 16         59 my %args = @_;
225              
226             croak("product was not defined")
227 16 100       320 unless $args{product};
228              
229             croak("product not supported")
230 15 100       43 unless grep { /^$args{product}$/ } products();
  75         2589  
231              
232 14         69 Weather::API::Base::_verify_lat_lon(\%args);
233              
234 10         174 return $self->_get_ua($self->_weather_url(%args));
235             }
236              
237             sub _weather_url {
238 11     11   102 my $self = shift;
239 11         45 my %args = @_;
240 11         41 my $prod = delete $args{product};
241             my $url = "www.7timer.info/bin/$prod.php?"
242 11         43 . join("&", map {"$_=$args{$_}"} keys %args);
  43         141  
243              
244 11         101 return $url;
245             }
246              
247             sub products {
248 15     15 1 57 return qw/astro two civil civillight meteo/;
249             }
250              
251             =head1 HELPER FUNCTIONS
252              
253             =head2 C
254              
255             my $timestamp = Weather::Astro7Timer::init_to_ts($report{init});
256              
257             Returns a unix timestamp from the init date. For the subsequent entries of the
258             timeseries you can add C * 3600 to the timestamp.
259              
260             =cut
261              
262             sub init_to_ts {
263 2     2 1 6013 my $init = shift;
264              
265 2 100       16 return unless $init =~ /^(\d{4})(\d\d)(\d\d)(\d\d)$/;
266 1         12 return timegm(0,0,$4,$3,$2-1,$1)
267             }
268              
269             =head1 HELPER FUNCTIONS FROM Weather::API::Base
270              
271             The parent class L contains some useful functions:
272              
273             use Weather::API::Base qw(:all);
274              
275             # Get time in YYYY-MM-DD HH:mm:ss format, local time zone
276             my $datetime = ts_to_date(time());
277              
278             # Convert 30 degrees Celsius to Fahrenheit
279             my $result = convert_units('C', 'F', 30);
280              
281             See the doc for that module for more details.
282              
283             =head1 OTHER PERL WEATHER MODULES
284              
285             A quick listing of Perl modules for current weather and forecasts from various sources:
286              
287             =head2 L
288              
289             OpenWeatherMap uses various weather sources combined with their own ML and offers
290             a couple of free endpoints (the v2.5 current weather and 5d/3h forecast) with generous
291             request limits. Their newer One Call 3.0 API also offers some free usage (1000 calls/day)
292             and the cost is per call above that. If you want access to history APIs, extended
293             hourly forecasts etc, there are monthly subscriptions. L is from the
294             same author as this module and similar in use.
295              
296             =head2 L
297              
298             An alternative source for multi-source forecasts is Apple's WeatherKit (based on
299             the old Dark Sky weather API). It offers 500k calls/day for free, but requires a
300             paid Apple developer account. You can use L, which is very
301             similar to this module (same author).
302              
303             =head2 L
304              
305             The Norwegian Meteorological Institute offers the free YR.no service (no registration
306             needed), which can be accessed via L. I am not affiliated with that module.
307              
308             =head1 AUTHOR
309              
310             Dimitrios Kechagias, C<< >>
311              
312             =head1 BUGS
313              
314             Please report any bugs or feature requests either on L (preferred), or on RT (via the email
315             C or L).
316              
317             I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
318              
319             =head1 GIT
320              
321             L
322              
323             =head1 LICENSE AND COPYRIGHT
324              
325             This software is copyright (c) 2023 by Dimitrios Kechagias.
326              
327             This is free software; you can redistribute it and/or modify it under
328             the same terms as the Perl 5 programming language system itself.
329              
330             =cut
331              
332             1;