File Coverage

blib/lib/Ham/Resources/Propagation.pm
Criterion Covered Total %
statement 136 162 83.9
branch 49 88 55.6
condition 23 60 38.3
subroutine 17 20 85.0
pod 6 6 100.0
total 231 336 68.7


line stmt bran cond sub pod time code
1             package Ham::Resources::Propagation;
2              
3 1     1   66383 use strict;
  1         3  
  1         41  
4 1     1   5 use warnings;
  1         3  
  1         29  
5 1     1   86940 use LWP::UserAgent;
  1         189572  
  1         104  
6 1     1   29681 use XML::Reader::PP;
  1         134079  
  1         167  
7              
8 1     1   1411 use Data::Dumper;
  1         18651  
  1         1751  
9              
10 1     1   613 use vars qw($VERSION);
  1         4  
  1         23994  
11              
12             our $VERSION = '0.04';
13              
14             my $data_url = 'http://www.hamqsl.com/solarxml.php';
15             my $site_name = 'hamqsl.com';
16             my $default_timeout = 10;
17             my $default_description = 'text'; # maybe 'text' or 'numeric'
18              
19             my @items = ('solar_data', 'hf', 'vhf', 'extended');
20             my @scale = ('Normal', 'Active', 'Minor', 'Moderate', 'Strong', 'Severe', 'Extreme');
21              
22             sub new
23             {
24 1     1 1 286 my $class = shift;
25 1         4 my %args = @_;
26 1         4 my $self = {};
27 1   33     12 $self->{timeout} = $args{timeout} || $default_timeout;
28 1   33     9 $self->{description} = $args{description} || $default_description;
29              
30 1         4 bless $self, $class;
31 1         5 _data_init($self);
32 1         157 return $self;
33             }
34              
35             sub get_groups
36             {
37 0     0 1 0 return \@items;
38             }
39              
40             sub get
41             {
42 2     2 1 2371 my ($self, $item) = @_;
43 2 50 66     52 $self->{solar_data}->{$item} || $self->{hf}->{$item} || $self->{vhf}->{$item} || $self->{extended}->{$item} || return ($self->{error_mesage} = "Don't found this key ".$item);
      66        
      33        
44             }
45              
46             sub all_item_names
47             {
48 1     1 1 3 my ($self, @item_names) = @_;
49 1         10 foreach my $key (sort(@items)){
50 4         6 foreach (sort keys %{$self->{$key}})
  4         34  
51             {
52 36         60 push @item_names, $_;
53             }
54             }
55 1         5 return \@item_names;
56             }
57              
58 0     0 1 0 sub is_error { my $self = shift; $self->{error_message} }
  0         0  
59 0     0 1 0 sub error_message { my $self = shift; $self->{error_message} }
  0         0  
60              
61             # -----------------------
62             # PRIVATE SUBS
63             # -----------------------
64              
65             sub _data_init
66             {
67 1     1   2 my $self = shift;
68 1 50       6 my $content = $self->_get_content($data_url) or return 0;
69 1         72 my $data;
70              
71 1 50       16 my $xml = XML::Reader::PP->new(\$content) or return $self->{error_message} = "Error to read XML of $site_name - ".$!;
72 1         6174 my $p_data;
73              
74 1         9 while ($xml->iterate) {
75             # Solar datas
76 98 100 100     120139 if ($xml->value ne '' && $xml->path !~ /calculated/ && $xml->tag ne '@url' && $xml->tag ne 'source')
      100        
      100        
77             {
78             # Rules for add text to some value items
79 18         539 $data = $xml->value; # data by default, without text
80 18 100       1249 if($xml->tag eq 'xray') { $data = $self->_add_xray_text($xml->value); }
  1         8  
81 18 100       133 if($xml->tag eq 'kindex') { $data = $self->_add_kindex_text($xml->value); }
  1         11  
82 18 100       108 if($xml->tag eq 'aindex') { $data = $self->_add_aindex_text($xml->value); }
  1         7  
83 18 100       102 if($xml->tag eq 'protonflux') { $data = $self->_add_protonflux_text($xml->value); }
  1         8  
84 18 100       1651 if($xml->tag eq 'electonflux') { $data = $self->_add_electronflux_text($xml->value); }
  1         9  
85 18 100       130 if($xml->tag eq 'solarflux') { $data = $self->_add_solarflux_text($xml->value); }
  1         7  
86            
87 18         118 $self->{solar_data}->{$xml->tag} = $data;
88             }
89              
90             # Propagation
91 98 100       6756 if ($xml->path =~ /calculated/) {
92 54         363 $p_data .= $xml->value;
93 54 100       542 if ($xml->tag =~ /\@/) {
94 26         4046 $p_data .= " ";
95             } else {
96             # create a list for HF conditions
97 28 100       1989 if ($p_data =~ m/(\d+)m(\-\d+m) (day|night) (.+)/i) {
98 8         43 my $hf_tag = $1.$2."_".$3;
99 8         79 $self->{hf}->{$hf_tag} = $4;
100             }
101             # create a list for VHF conditions
102 28 100       98 if ($p_data =~ /^(.+)(Band .+)/) {
103 5         1177 $self->{vhf}->{$1} = $2;
104             }
105 28         105 $p_data = undef;
106             }
107             }
108             }
109             }
110              
111             sub _get_content
112             {
113 1     1   4 my ($self, $url) = @_;
114 1         16 my $browser = LWP::UserAgent->new( timeout=>$self->{timeout} );
115 1         22486 $browser->agent("Ham/Resources/Propagation.pm $VERSION");
116 1         105 my $response = $browser->get($url);
117              
118 1 50       1010278 if (!$response->is_success)
119             {
120 0         0 $self->{is_error} = 1;
121 0         0 $self->{error_message} = "Error at $site_name - ".$response->status_line;
122 0         0 return 0;
123             }
124            
125 1         26 return $response->content;
126             }
127              
128             sub _add_aindex_text
129             {
130 1     1   8 my ($self, $num) = @_;
131 1 50       5 return $num if $self->{description} eq 'numeric';
132 1 50       15 return '('.$num.') quiet' if $num <= 7;
133 1 50 33     28 return '('.$num.') unsettled' if $num >= 8 and $num <= 15;
134 0 0 0     0 return '('.$num.') active' if $num >= 16 and $num <= 29;
135 0 0 0     0 return '('.$num.') minor storm' if $num >= 30 and $num <= 49;
136 0 0 0     0 return '('.$num.') major storm' if $num >= 50 and $num <= 99;
137 0 0 0     0 return '('.$num.') severe storm' if $num >= 100 and $num <= 400;
138             }
139              
140             sub _add_kindex_text
141             {
142 1     1   11 my ($self, $num) = @_;
143 1 50       8 return $num if $self->{description} eq 'numeric';
144 1 50       6 return '('.$num.') quiet' if $num <= 2;
145 1 50       5 return '('.$num.') unsettled' if $num == 3;
146 1 50       8 return '('.$num.') active' if $num == 4;
147 0 0       0 return '('.$num.') minor storm' if $num == 5;
148 0 0       0 return '('.$num.') major storm' if $num == 6;
149 0 0 0     0 return '('.$num.') severe storm' if $num >= 7 and $num <= 9;
150             }
151              
152              
153             sub _add_xray_text
154             {
155 1     1   17 my ($self, $num) = @_;
156 1         20 my %xray_defs = (
157             'A|B' => $scale[0].'| No or small flare. No or very minor impact to HF signals.',
158             'C' => $scale[1].'| Moderate flare Low absortion of HF signals.',
159             'M[1-4]' => $scale[2].'| 2000 flares per cycle. Occasional loss of radio contact on sunlit side.',
160             'M[5-9]' => $scale[3].'| 350 flares per cycle. Limited HF blackout on sunlit side for tens of minutes.',
161             'X[1-9?]' => $scale[4].'| 175 flares per cycle. Wide area HF blackout for about an hour on sunlit side.',
162             'X1[0-9]' => $scale[5].'| 8 flares per cycle. HF blackout on most of sunlit side for 1 to 2 hours.',
163             'X2[0-9?]' => $scale[6].'| 1 flare per cycle. Complete HF blackout on entire sunlit side lasting hours.',
164             );
165            
166 1         5 foreach my $xray_key (keys %xray_defs)
167             {
168 6 100       4124 if ($num =~ /$xray_key/i)
169             {
170 1         12 my $xray_complete_data = "(".$num.") ".$xray_defs{$xray_key};
171            
172 1         2 my $radioblackout = $xray_complete_data;
173 1         27 my ($category, $text) = $radioblackout =~ /^\(.+\)(.+)\|(.+)/;
174 1         6 $radioblackout = $category.'.'.$text;
175 1         6 $self->{extended}->{radioblackout} = $radioblackout;
176 1         6 my ($xray_resume_data) = $xray_complete_data =~ /^(.+)\|.+/;
177 1 50       8 $num = $xray_resume_data if $self->{description} ne 'numeric';
178 1         10 return $num;
179             }
180             }
181 0         0 return $num;
182             }
183              
184             sub _add_protonflux_text
185             {
186 1     1   14 my ($self, $num) = @_;
187              
188 1         6 my $exponentation = substr $num, -2;
189              
190 1         20 my %proton_defs = (
191             '00' => $scale[0].'| No impacts on HF.',
192             '01' => $scale[1].'| Very minor impacts on HF in polar regions.',
193             '02' => $scale[2].'| 50 storms per cycle. Minor impacts on HF in polar regions.',
194             '03' => $scale[3].'| 25 storms per cycle. Small effects on HF in polar regions.',
195             '04' => $scale[4].'| 10 storms per cycle. Degraded HF propagation in polar regions.',
196             '05' => $scale[5].'| 3 storms per cycle. Partial HF blackout in polar regions.',
197             '06' => $scale[6].'| 1 storm per cycle. Complete HF blackout in polar regions.',
198             );
199            
200 1         5 my $proton_complete_data = "(".$num.") ".$proton_defs{$exponentation};
201            
202 1         2 my $solarradiotion = $proton_complete_data;
203 1         11 my ($category, $text) = $solarradiotion =~ /^\(.+\)(.+)\|(.+)/;
204 1         4 $solarradiotion = $category.'.'.$text;
205 1         5 $self->{extended}->{solarradiation} = $solarradiotion;
206 1         1362 my ($proton_resume_data) = $proton_complete_data =~ /^(.+)\|.+/;
207 1 50       11 $num = $proton_resume_data if $self->{description} ne 'numeric';
208 1         9 return $num;
209             }
210              
211             sub _add_electronflux_text
212             {
213 1     1   10 my ($self, $num) = @_;
214            
215 1         4 my $electron_def;
216 1 50       12 $electron_def = $scale[0].'| No impacts on HF.' if $num < 1.0e+01;
217 1 50 33     11 $electron_def = $scale[2].'| Minor impacts on HF in polar regions.' if $num > 1.0e+01 && $num < 1.0e+02;
218 1 50 33     32 $electron_def = $scale[2].'| Degraded HF propagation in polar regions.' if $num > 1.0e+02 && $num < 1.0e+03;
219 1 50       5 $electron_def = 'Alert'.'| Partial HF blackout in polar regions.' if $num > 1.0e+03;
220            
221 1         4 my $electron_complete_data = "(".$num.") ".$electron_def;
222            
223 1         3 my $electronalert = $electron_complete_data;
224 1         9 my ($category, $text) = $electronalert =~ /^\(.+\)(.+)\|(.+)/;
225 1         5 $electronalert = $category.'.'.$text;
226 1         11 $self->{extended}->{electronalert} = $electronalert;
227 1         7 my ($electron_resume_data) = $electron_complete_data =~ /^(.+)\|.+/;
228 1 50       6 $num = $electron_resume_data if $self->{description} ne 'numeric';
229 1         3 return $num;
230              
231             }
232              
233             sub _add_solarflux_text
234             {
235 1     1   10 my ($self, $num) = @_;
236            
237 1         5 my @sn_ratio = ('0-10', '10-35', '35-70', '70-105', '105-160', '160-250');
238              
239 1         3 my $solarflux_def;
240 1 50       6 if ($num <= 70)
241             {
242 0         0 $solarflux_def = $scale[0].'| Bands above 40m unusuable.';
243 0         0 $self->{solar_data}->{SN} = $sn_ratio[0];
244             };
245 1 50 33     9 if ($num > 70 && $num <= 90)
246             {
247 0         0 $solarflux_def = $scale[1].'| Poor to fair conditions all bands up through.';
248 0         0 $self->{solar_data}->{SN} = $sn_ratio[1];
249             };
250 1 50 33     9 if ($num > 90 && $num <= 120)
251             {
252 0         0 $solarflux_def = $scale[2].'| Fair conditions all bands up through 15m.';
253 0         0 $self->{solar_data}->{SN} = $sn_ratio[2];
254             };
255 1 50 33     11 if ($num > 120 && $num <= 150)
256             {
257 1         4 $solarflux_def = $scale[3].'| Fair to good conditions all bands up through 10m.';
258 1         4 $self->{solar_data}->{SN} = $sn_ratio[3];
259             };
260 1 50 33     7 if ($num > 150 && $num <= 200)
261             {
262 0         0 $solarflux_def = $scale[4].'| Excelent conditions all bands up through 10m w/6m openings.';
263 0         0 $self->{solar_data}->{SN} = $sn_ratio[4];
264             };
265 1 50       13 if ($num > 200)
266             {
267 0         0 $solarflux_def = $scale[5].'| Reliable communications all bands up through 6m.';
268 0         0 $self->{solar_data}->{SN} = $sn_ratio[5];
269             };
270              
271 1         3 my $solarflux_complete_data = "(".$num.") ".$solarflux_def;
272            
273 1         2 my $bandopenings = $solarflux_complete_data;
274 1         21 my ($category, $text) = $bandopenings =~ /^\(.+\)(.+)\|(.+)/;
275 1         29 $bandopenings = $category.'.'.$text;
276 1         6 $self->{extended}->{bandopenings} = $bandopenings;
277            
278 1         6 my ($solarflux_resume_data) = $solarflux_complete_data =~ /^(.+)\|.+/;
279 1 50       6 $num = $solarflux_resume_data if $self->{description} ne 'numeric';
280 1         3 return $num;
281            
282             }
283              
284              
285             1;
286              
287             __END__