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   660991 use 5.006;
  3         26  
4 3     3   19 use strict;
  3         6  
  3         77  
5 3     3   16 use warnings;
  3         5  
  3         110  
6              
7 3     3   28 use Carp;
  3         8  
  3         2211  
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.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 C)
105             unit => $unit?, # Units (default C)
106             lang => $language?, # Language (default C)
107             tzshift => $tz_shift?, # Timezone shift from UTC (hours, default C<0>)
108             ac => $alt_cor?, # Altitude correction (default C<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). West is negative.
126              
127             =item * C : Longitude (-180 to 180). South is negative.
128              
129             =item * C : Choose a forecast product from the available ones:
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              
148             Optional parameters (see the API documentation for further details):
149              
150             =over 4
151              
152             =item * C : Supports C or C, otherwise default is C.
153              
154             =item * C : C (default) or C units.
155              
156             =item * C : Output format, supports C (default) or C, although
157             C will also work, returning png image.
158              
159             =item * C : Timezone offset in hours ( -23 to 23).
160              
161             =item * C : Altitude correction (e.g. temp) for high peaks. Default C<0>, accepts
162             C<2> or C<7> (in km). Only for C product.
163              
164             =back
165              
166             =head2 C
167              
168             my $response = $w7t->get_response(
169             lat => $lat,
170             lon => $lon,
171             product => $product
172             %args?
173             );
174              
175             Same as C except it returns the full L from the API (so you
176             can handle bad requests yourself).
177              
178              
179             =head1 CONVENIENCE FUNCTIONS
180              
181             =head2 C
182              
183             my @products = Weather::Astro7Timer::products();
184              
185             Returns the supported forecast products.
186              
187             =cut
188              
189             sub new {
190 8     8 1 20797 my $class = shift;
191              
192 8         19 my $self = {};
193 8         18 bless($self, $class);
194              
195 8         21 my %args = @_;
196              
197 8         25 $self->{ua} = $args{ua};
198 8   100     38 $self->{scheme} = $args{scheme} || 'https';
199 8   100     30 $self->{timeout} = $args{timeout} || 30;
200 8   66     37 $self->{agent} = $args{agent} || "libwww-perl Weather::Astro7Timer/$VERSION";
201              
202 8         29 return $self;
203             }
204              
205             sub get {
206 13     13 1 9025 my $self = shift;
207 13         41 my %args = @_;
208 13   100     53 $args{lang} ||= 'en';
209 13   100     74 $args{output} ||= 'json';
210              
211 13         64 my $resp = $self->get_response(%args);
212              
213 7 100       506 if ($resp->is_success) {
214 6 100       57 return _output($resp->decoded_content, wantarray ? $args{output} : '');
215             }
216             else {
217 1         15 die $resp->status_line;
218             }
219             }
220              
221             sub products {
222 12     12 1 39 return qw/astro two civil civillight meteo/;
223             }
224              
225             sub get_response {
226 13     13 1 27 my $self = shift;
227 13         33 my %args = @_;
228              
229             croak("product was not defined")
230 13 100       198 unless $args{product};
231              
232             croak("product not supported")
233 12 100       28 unless grep { /^$args{product}$/ } products();
  60         333  
234              
235             croak("lat between -90 and 90 expected")
236 11 100 100     206 unless defined $args{lat} && abs($args{lat}) <= 90;
237              
238             croak("lon between -180 and 180 expected")
239 9 100 100     211 unless defined $args{lon} && abs($args{lon}) <= 180;
240              
241 7         23 my $url = $self->_weather_url(%args);
242              
243 7 100       23 unless ($self->{ua}) {
244 4         25 require LWP::UserAgent;
245 4         24 $self->{ua} = LWP::UserAgent->new();
246             }
247              
248 7         6448 $self->{ua}->agent($self->{agent});
249 7         457 $self->{ua}->timeout($self->{timeout});
250              
251 7         105 return $self->{ua}->get($url);
252             }
253              
254             sub _weather_url {
255 9     9   41 my $self = shift;
256 9         31 my %args = @_;
257 9         19 my $prod = delete $args{product};
258             my $url =
259             $self->{scheme}
260             . "://www.7timer.info/bin/$prod.php?"
261 9         41 . join("&", map {"$_=$args{$_}"} keys %args);
  34         94  
262              
263 9         36 return $url;
264             }
265              
266             sub _output {
267 6     6   927 my $str = shift;
268 6         7 my $format = shift;
269              
270 6 100       33 return $str unless $format;
271              
272 3 100       21 if ($format eq 'json') {
    100          
273 1         910 require JSON;
274 1         8315 return %{JSON::decode_json($str)};
  1         23  
275             } elsif ($format eq 'xml') {
276 1         762 require XML::Simple;
277 1         8511 return %{XML::Simple::XMLin($str)};
  1         4  
278             }
279 1         7 return (data => $str);
280             }
281              
282             =head1 AUTHOR
283              
284             Dimitrios Kechagias, C<< >>
285              
286             =head1 BUGS
287              
288             Please report any bugs or feature requests either on L (preferred), or on RT (via the email
289             C or L).
290              
291             I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
292              
293             =head1 GIT
294              
295             L
296              
297             =head1 LICENSE AND COPYRIGHT
298              
299             This software is copyright (c) 2023 by Dimitrios Kechagias.
300              
301             This is free software; you can redistribute it and/or modify it under
302             the same terms as the Perl 5 programming language system itself.
303              
304             =cut
305              
306             1;