html/weather.pl
1 # Irssi weather as statusbar item and forecast command
2
3 # Fixes in this version
4 #
5 # 1. Fixed issue with N/A°F in the windchill/feelslike variable.
6 # 2. Added more information in the /forecast command.
7 # 3. Added an extended function for three day forecasts.
8 # 4. Moved the extended function info /forecast -e (yippie! FLAGS!)
9 # 5. Added a /forecast -o option to print the info to the active window
10 # 6. 2.0 has a TOTAL rewrite on how to get the data. We no longer use weather.com its now Geo::Weather data
11 # 7. Removed the three day extended forecast for the 2.0 version, will rewrite it later.
12 # 8. 2.1 now has 10 day extended forecast, takes slightly longer to load
13 # 9. 2.2 has returned to writing statusbar info to a file to save time in window switching
14 # 10. 2.3 allows theme customization of weather in statusbar (written for ardya)
15
16
17 # Use the following format in your theme file
18 # weather_display = "$0%R>%n%_$2%_%G>%n$4";
19 #
20 # $0 is temperature
21 # $2 is feelslike (windchill/headindex)
22 # $4 is current conditions (windy or partly cloudy)
23
24 # - You have to modify this line to the path of your LWP-dir
25 use lib '/usr/lib/perl5/vendor_perl/5.6.1';
26 use Irssi;
27 use Irssi::TextUI;
28 use Geo::Weather;
29 use 5.6.0;
30
31 use vars qw($VERSION %IRSSI $zipcode $refresh $show_type $last_refresh $refresh_tag);
32
33 $VERSION = '2.3';
34 %IRSSI = (
35 authors => 'GrayWolf',
36 contact => 'graywolf@i-differ.net',
37 name => 'Weather.pl',
38 description => 'Put local weather information in your statusbar as well as add a forecast command',
39 license => 'Public Domain'
40 );
41
42 #
43 ## Variable defaults, can be changed with /set in Irssi, to save trouble I recommend setting your zipcode here
44 #
45 if (!$zipcode) {
46 $zipcode = "46260";
47 }
48 $zip = $zipcode;
49 $country = "us";
50 $refresh = "900";
51 $show_type = "yes";
52 $in_celsius = "no";
53
54 #
55 ## Bind our commands
56 #
57 Irssi::command_bind("weather", "show_usage");
58 Irssi::command_bind("forecast", "show_weather");
59 Irssi::command_bind("weathsecret", "get_weather_for_status");
60
61 #
62 ## Usage information
63 #
64 sub show_usage {
65 Irssi::print("[Usage] Forecast Statusbar script v$VERSION");
66 Irssi::print("/weather : shows usage info");
67 Irssi::print("/forecast <zipcode> : Show current forecast for <zipcode>");
68 Irssi::print("/forecast -o <zipcode> : Show current forecast for <zipcode> in the active window \(print to channel\)");
69 Irssi::print("/forecast -e <zipcode> : Show extended ten day forecast for <zipcode>");
70 Irssi::print("/set weather_refresh : Sets how often the statusbar is updated");
71 Irssi::print("/set weather_zip : The zipcode of the area you want displayed in the statusbar");
72 Irssi::print("/set weather_show_type (yes/no) : Choose if you want to see F/C in the statusbar");
73 Irssi::print("/set weather_in_celsius (yes/no) : Choose if you want to see the temperature in celsius");
74 Irssi::print("/statusbar <bar> add weather : see /help statusbar for more information.");
75 }
76
77 #
78 ## First thing run the status grab
79 #
80 get_weather_for_status();
81
82 #
83 ## Get down to work
84 #
85 sub weather_us {
86 my $winfo = new Geo::Weather;
87 $winfo->{timeout} = 5; # set timeout to 5 seconds instead of the default of 10
88
89 # Get the $zip from a /forecast command
90 $zip = $_[0];
91
92 # Currently only the US is supported, hope to add more countries later
93 if ( $country == "us" ) {
94 # Lets go get the information
95 my $current = $winfo->get_weather($zip);
96 my $forecast = $winfo->report_forecast();
97
98 $temperature = $current->{temp};
99 $feelslike = $current->{heat};
100 $description = $current->{cond};
101 $wind = $current->{wind};
102 $wind =~ s/\<br\>/\n/g;
103 $wind =~ s/\<.+?\>//sg;
104 $wind =~ s/ //g;
105 $dewp = $current->{dewp};
106 $humi = $current->{humi};
107 $visb = $current->{visb};
108 $visb =~ s/\<br\>/\n/g;
109 $visb =~ s/\<.+?\>//sg;
110 $baro = $current->{baro};
111 $baro =~ s/\<br\>/\n/g;
112 $baro =~ s/\<.+?\>//sg;
113 return($temperature,$feelslike,$description,$wind,$dewp,$humi,$visb,$baro,$forecast);
114 } else {
115 Irssi::print("Unable to get weather for $country");
116 return(0,0,0);
117 }
118 }
119
120 # Statusbar formatting
121 sub get_weather_for_status {
122
123 ($temperature,$feelslike,$description,$therest) = weather_us($zipcode);
124
125 # If the user doesn't want to see F in the statusbar lets strip that out
126 if ( $show_type eq 'yes' ) {
127 $temperature .= 'F';
128 $feelslike .= 'F';
129 }
130 # If the user wants his temp in celsius lets convert it here
131 if ($in_celsius eq 'yes') {
132 $convert = $temperature;
133 $convert =~ s/F//g;
134 $temperature = ((5 / 9) * ($convert - 32));
135 $temperature = sprintf('%d', $temperature);
136 $feelcon = $feelslike;
137 $feelcon =~ s/F//g;
138 $feelslike = ((5 / 9) * ($feelcon - 32));
139 $feelslike = sprintf('%d', $feelslike);
140 # Now we have the temp in celsius, do they want to see the C?
141 if ($show_type eq 'yes') {
142 $temperature .= 'C';
143 $feelslike .= 'C';
144 }
145 }
146 chomp($temperature);
147 chomp($feelslike);
148 chomp($description);
149 open STATUS_FILE, ">.irssi/weather.status" or die "Can't write to status file: $!";
150 print STATUS_FILE "$temperature,$feelslike,$description";
151 close STATUS_FILE;
152 }
153
154 # Status bar information
155
156 sub theme_format {
157 open GET_STATUS, "<.irssi/weather.status" or die "Can't open status file: $!";
158
159 my $themed = "";
160 my $themecmd = "";
161
162 while ($line = <GET_STATUS>) {
163 ($temperature,$feelslike,$description) = split(/,/, $line);
164 }
165 chomp($description);
166 $description =~ s/ /\_\_/g;
167 $themed = Irssi::current_theme->format_expand("{weather_display $temperature $feelslike $description}",Irssi::EXPAND_FLAG_IGNORE_REPLACES);
168
169 $statusbar_output = $themed;
170 return $statusbar_output;
171 Irssi::statusbar_items_redraw('weather');
172 close GET_STATUS;
173 }
174
175 sub weather {
176 my ($item, $get_size_only) = @_;
177
178 $sbar_out = theme_format();
179 $sbar_out =~ s/ /\//g;
180 $sbar_out =~ s/\_\_/ /g;
181 chomp($sbar_out);
182 $item->default_handler($get_size_only, "{sb $sbar_out}", undef, 1 );
183 }
184
185 sub show_weather {
186 my ($commands, $item, $witem) = @_;
187 ($flag, $thezip) = split(/ /, $commands);
188 if ($flag =~ /^\s*$/) {
189 $thezip = $zipcode if $thezip < 1;
190 ($temperature,$feelslike,$description,$wind,$dewp,$humi,$visb,$baro) = weather_us($thezip);
191 Irssi::active_win()->print("Information for $thezip - Temp: $temperature, Feels Like: $feelslike, Currently: $description, Dew Point: $dewp, Humidity: $humi, Visibility: $visb, Pressure: $baro, Wind: $wind");
192 } elsif ($flag =~ /^\d*$/) {
193 $flag = $zipcode if $flag < 1;
194 ($temperature,$feelslike,$description,$wind,$dewp,$humi,$visb,$baro) = weather_us($flag);
195 Irssi::active_win()->print("Information for $flag - Temp: $temperature, Feels Like: $feelslike, Currently: $description, Dew Point: $dewp, Humidity: $humi, Visibility: $visb, Pressure: $baro, Wind: $wind");
196 $flag = $zipcode;
197 weather_us($flag);
198 } elsif ($flag =~ /\-o/) {
199 if ($witem) {
200 $thezip = $zipcode if $thezip < 1;
201 ($temperature,$feelslike,$description,$wind,$dewp,$humi,$visb,$baro) = weather_us($thezip);
202 $witem->command("MSG ".$witem->{name}." Information for $thezip - Temp: $temperature, Feels Like: $feelslike, Currently: $description, Dew Point: $dewp, Humidity: $humi, Visibility: $visb, Pressure: $baro, Wind: $wind");
203 $thezip = $zipcode;
204 weather_us($thezip);
205 }
206 } elsif ($flag =~ /\-e/) {
207 if ($witem) {
208 $thezip = $zipcode if $thezip < 1;
209 ($temperature,$feelslike,$description,$wind,$dewp,$humi,$visb,$baro,$forecast) = weather_us($thezip);
210 my $count = 0;
211 my $active = 0;
212 my $day = 0;
213 my @days = ();
214
215 $forecast =~ s/\<.+?\>//sg;
216 $forecast =~ s/ //g;
217 $forecast =~ s/°/F/g;
218 $forecast =~ s/FF/F/g;
219 $forecast =~ s/^\s+//gm;
220
221 @fore = split(/\n/, $forecast);
222 $endres = undef;
223
224 foreach $line (@fore) {
225 if ($count > 3) {
226 if ($active <= 4) {
227 if ($active eq 0) {
228 # This is necessary to prevent wrapping into the next call of /forecast -e
229 $endres .= "\n";
230 }
231 chomp($line);
232 $line =~ s/ \/ /\//g;
233 $line =~ s/ \%/\% chance of precipitation/g;
234 $endres .= "$line ";
235 $active ++;
236 } else {
237 $active = 1;
238 $day ++;
239 if ($day < 11) {
240 chomp($line);
241 $line =~ s/ \/ /\//g;
242 $line =~ s/ \%/\% chance of precipitation/g;
243 $endres .= "\n$line";
244 }
245 }
246 }
247 $count ++;
248 }
249
250 @days = split(/\n/, $endres);
251 Irssi::active_win()->print("Extended Ten Day Forecast for $thezip");
252 Irssi::active_win()->print("$days[1]");
253 Irssi::active_win()->print("$days[2]");
254 Irssi::active_win()->print("$days[3]");
255 Irssi::active_win()->print("$days[4]");
256 Irssi::active_win()->print("$days[5]");
257 Irssi::active_win()->print("$days[6]");
258 Irssi::active_win()->print("$days[7]");
259 Irssi::active_win()->print("$days[8]");
260 Irssi::active_win()->print("$days[9]");
261 Irssi::active_win()->print("$days[10]");
262 }
263 } else {
264 Irssi::active_win()->print("Cannot print to the active window");
265 }
266 }
267
268
269 sub refresh_weather {
270 Irssi::statusbar_items_redraw('weather');
271 }
272
273 sub read_settings {
274 $zipcode = Irssi::settings_get_str('weather_zip');
275 $show_type = Irssi::settings_get_str('weather_show_type');
276 $in_celsius = Irssi::settings_get_str('weather_in_celsius');
277 $refresh = Irssi::settings_get_int('weather_refresh');
278 $refresh = 1 if $refresh < 1;
279 return if $refresh == $last_refresh;
280 $last_refresh = $refresh;
281 Irssi::timeout_remove($refresh_tag) if $refresh_tag;
282 $refresh_tag = Irssi::timeout_add($refresh * 1000, 'get_weather_for_status', undef);
283 $refresh_tag = Irssi::timeout_add($refresh * 1000, 'refresh_weather', undef);
284 }
285
286 Irssi::settings_add_int('misc', 'weather_refresh', $refresh);
287 Irssi::settings_add_str('misc', 'weather_zip', $zipcode);
288 Irssi::settings_add_str('misc', 'weather_show_type', $show_type);
289 Irssi::settings_add_str('misc', 'weather_in_celsius', $in_celsius);
290
291 Irssi::statusbar_item_register('weather', undef, 'weather');
292 Irssi::statusbars_recreate_items();
293
294 read_settings();
295 Irssi::signal_add('setup changed', 'read_settings');
296
297 #
298 ## TODO
299 #
300 # 1. Add other countries -- (not sure if this will ever happen, feel free....)
301 # 2. Fix the read_settings so that changes are immediate -- (just update your zipcode at the top of the script and don't bug me)
302 # 3. Allow the extended function to show temps in C (currently only F) -- (I don't want to)
303 # 4. I want to add some type of error check for the zipcodes, so that you can't enter an invalid one
304 # 5. Make the lookup background or async so it doesn't tie up the irssi session -- (all I can find is fork() which requires a major rewrite.
305 # Wait the 10 damn seconds you lazy gits.)