File Coverage

blib/lib/Weather/Astro7Timer.pm
Criterion Covered Total %
statement 60 60 100.0
branch 20 20 100.0
condition 16 17 94.1
subroutine 10 10 100.0
pod 4 4 100.0
total 110 111 99.1


line stmt bran cond sub pod time code
1             package Weather::Astro7Timer;
2              
3 3     3   665613 use 5.006;
  3         27  
4 3     3   21 use strict;
  3         6  
  3         77  
5 3     3   15 use warnings;
  3         8  
  3         93  
6              
7 3     3   28 use Carp;
  3         6  
  3         2309  
8              
9             =head1 NAME
10              
11             Weather::Astro7Timer - Simple client for the 7Timer.info Weather Forecast service
12              
13             =head1 VERSION
14              
15             Version 0.01
16              
17             =cut
18              
19             our $VERSION = '0.1';
20              
21             =head1 SYNOPSIS
22              
23             my $w7t = Weather::Astro7Timer->new();
24              
25             # Get ASTRO weather for the Stonehenge area
26              
27             my %report = $w7t->get(
28             product => 'astro', # Forecast type (astro, civil, civillight, meteo, two)
29             lat => 51.2, # Latitude
30             lon => -1.8, # Longitude
31             );
32              
33             # Dumping the result would give you:
34             %report = {
35             'product' => 'astro',
36             'init' => '2023032606',
37             'dataseries' => [{
38             'temp2m' => 6,
39             'wind10m' => {
40             'speed' => 2,
41             'direction' => 'NE'
42             },
43             'rh2m' => 13,
44             'seeing' => 3,
45             'timepoint' => 3,
46             'lifted_index' => 2,
47             'prec_type' => 'none',
48             'cloudcover' => 9,
49             'transparency' => 6
50             },
51             {...},
52             ...
53             ]
54             };
55              
56             =head1 DESCRIPTION
57              
58             Weather::Astro7Timer provides basic access to the L<7Timer.info|https://7Timer.info>
59             Weather Forecast API.
60             7Timer is a service based on NOAA's GFS and provides various types of forecast products.
61             It is mostly known for its ASTRO product intended for astronomers and stargazers, as
62             it provides an astronomical seeing and transparency forecast.
63              
64             Pease see the L and
65             L for details.
66              
67             The module was made to serve the apps L and
68             L, but if your service
69             requires some extra functionality, feel free to contact the author about it.
70              
71             =head1 CONSTRUCTOR
72              
73             =head2 C
74              
75             my $w7t = Weather::Astro7Timer->new(
76             scheme => $http_scheme?,
77             timeout => $timeout_sec?,
78             agent => $user_agent_string?,
79             ua => $lwp_ua?,
80             );
81            
82             Optional parameters:
83              
84             =over 4
85              
86             =item * C : You can specify C. Default: C.
87              
88             =item * C : Timeout for requests in secs. Default: C<30>.
89              
90             =item * C : Customize the user agent string.
91              
92             =item * C : Pass your own L to customise further.
93              
94             =back
95              
96             =head1 METHODS
97              
98             =head2 C
99              
100             my $report = $w7t->get(
101             product => $product, # Forecast type (astro, civil, civillight, meteo, two)
102             lat => $lat, # Latitude
103             lon => $lon, # Longitude
104             output => $format?, # Output format (default json)
105             unit => $unit?, # Units (default metric)
106             lang => $language?, # Language (default en)
107             tzshift => $tz_shift?, # Timezone shift from UTC (hours, default 0)
108             ac => $alt_cor?, # Altitude correction (default 0)
109             );
110              
111             my %report = $w7t->get( ... );
112              
113              
114             Fetches a forecast report for the requested for the requested location.
115             Returns a string containing the JSON or XML data, except in array context, in which case,
116             as a convenience, it will use L or L to decode it directly to a Perl hash.
117             For an explanation to the returned data, refer to the L.
118              
119             If the request is not successful, it will C throwing the C<< HTTP::Response->status_line >>.
120              
121             Required parameters:
122              
123             =over 4
124            
125             =item * C : Latitude (-90 to 90). South is negative.
126              
127             =item * C : Longitude (-180 to 180). West is negative.
128              
129             =item * C : Choose from the available forecast products:
130              
131             =over 4
132              
133             =item * C : ASTRO 3-day forecast for astronomy/stargazing with 3h step (includes astronomical seeing, transparency).
134              
135             =item * C : CIVIL 8-day forecast that provides a weather type enum (see docs for equivalent icons) with 3h step.
136              
137             =item * C : CIVIL Light simplified per-day forecast for next week.
138              
139             =item * C : A detailed meteorogical forecast including relative humidity and wind profile from 950hPa to 200hPa.
140              
141             =item * C : A two week overview forecast.
142              
143             =back
144              
145             =back
146              
147             Optional parameters (see the API documentation for further details):
148              
149             =over 4
150              
151             =item * C : Supports C or C, otherwise default is C.
152              
153             =item * C : C (default) or C units.
154              
155             =item * C : Output format, supports C (default) or C, although
156             C will also work, returning png image.
157              
158             =item * C : Timezone offset in hours ( -23 to 23).
159              
160             =item * C : Altitude correction (e.g. temp) for high peaks. Default C<0>, accepts
161             C<2> or C<7> (in km). Only for C product.
162              
163             =back
164              
165             =head2 C
166              
167             my $response = $w7t->get_response(
168             lat => $lat,
169             lon => $lon,
170             product => $product
171             %args?
172             );
173              
174             Same as C except it returns the full L from the API (so you
175             can handle bad requests yourself).
176              
177              
178             =head1 CONVENIENCE FUNCTIONS
179              
180             =head2 C
181              
182             my @products = Weather::Astro7Timer::products();
183              
184             Returns the supported forecast products.
185              
186             =cut
187              
188             sub new {
189 8     8 1 20790 my $class = shift;
190              
191 8         17 my $self = {};
192 8         16 bless($self, $class);
193              
194 8         22 my %args = @_;
195              
196 8         22 $self->{ua} = $args{ua};
197 8   100     40 $self->{scheme} = $args{scheme} || 'https';
198 8   100     31 $self->{timeout} = $args{timeout} || 30;
199 8   66     37 $self->{agent} = $args{agent} || "libwww-perl Weather::Astro7Timer/$VERSION";
200              
201 8         37 return $self;
202             }
203              
204             sub get {
205 13     13 1 9031 my $self = shift;
206 13         39 my %args = @_;
207 13   100     56 $args{lang} ||= 'en';
208 13   100     76 $args{output} ||= 'json';
209              
210 13         82 my $resp = $self->get_response(%args);
211              
212 7 100       540 if ($resp->is_success) {
213 6 100       57 return _output($resp->decoded_content, wantarray ? $args{output} : '');
214             }
215             else {
216 1         17 die $resp->status_line;
217             }
218             }
219              
220             sub get_response {
221 13     13 1 24 my $self = shift;
222 13         33 my %args = @_;
223              
224             croak("product was not defined")
225 13 100       206 unless $args{product};
226              
227             croak("product not supported")
228 12 100       39 unless grep { /^$args{product}$/ } products();
  60         325  
229              
230             croak("lat between -90 and 90 expected")
231 11 100 100     225 unless defined $args{lat} && abs($args{lat}) <= 90;
232              
233             croak("lon between -180 and 180 expected")
234 9 100 100     198 unless defined $args{lon} && abs($args{lon}) <= 180;
235              
236 7         22 my $url = $self->_weather_url(%args);
237              
238 7 100       22 unless ($self->{ua}) {
239 4         24 require LWP::UserAgent;
240 4         27 $self->{ua} = LWP::UserAgent->new();
241             }
242              
243 7         6497 $self->{ua}->agent($self->{agent});
244 7         456 $self->{ua}->timeout($self->{timeout});
245              
246 7         102 return $self->{ua}->get($url);
247             }
248              
249             sub _weather_url {
250 9     9   40 my $self = shift;
251 9         29 my %args = @_;
252 9         22 my $prod = delete $args{product};
253             my $url =
254             $self->{scheme}
255             . "://www.7timer.info/bin/$prod.php?"
256 9         41 . join("&", map {"$_=$args{$_}"} keys %args);
  34         97  
257              
258 9         42 return $url;
259             }
260              
261             sub _output {
262 6     6   878 my $str = shift;
263 6         10 my $format = shift;
264              
265 6 100       43 return $str unless $format;
266              
267 3 100       19 if ($format eq 'json') {
    100          
268 1         816 require JSON;
269 1         8513 return %{JSON::decode_json($str)};
  1         26  
270             } elsif ($format eq 'xml') {
271 1         827 require XML::Simple;
272 1         8801 return %{XML::Simple::XMLin($str)};
  1         5  
273             }
274 1         7 return (data => $str);
275             }
276              
277             sub products {
278 12     12 1 43 return qw/astro two civil civillight meteo/;
279             }
280              
281             =head1 AUTHOR
282              
283             Dimitrios Kechagias, C<< >>
284              
285             =head1 BUGS
286              
287             Please report any bugs or feature requests either on L (preferred), or on RT (via the email
288             C or L).
289              
290             I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
291              
292             =head1 GIT
293              
294             L
295              
296             =head1 LICENSE AND COPYRIGHT
297              
298             This software is copyright (c) 2023 by Dimitrios Kechagias.
299              
300             This is free software; you can redistribute it and/or modify it under
301             the same terms as the Perl 5 programming language system itself.
302              
303             =cut
304              
305             1;