bin/weather

149 lines
3.4 KiB
Perl
Executable File

#!/usr/bin/perl -w
# Inspired by "ansiweather".
use English qw(-no_match_vars);
use strict;
use File::Basename;
use Getopt::Long;
use JSON;
use WWW::Mechanize;
use POSIX qw(strftime);
use Time::Piece;
use utf8;
my $verbose = 0;
sub show_help {
my ($exit_code) = @_;
my $name = basename($PROGRAM_NAME);
print <<EOF;
usage: $name [OPTION] LOCATION
Print a weather report for LOCATION using data from
openweathermap.org.
OPTIONS
--verbose Be verbose and print the data structure returned
by openweathermap.
--help Print this help.
LOCATION
A city name or "city,xx" where xx is the two-letter country code.
Examples
\$ $name --verbose "Paris,FR"
\$ $name "Asunción,PY"
EOF
exit($exit_code);
}
sub tstamp { strftime("%F %T %Z ", localtime); }
sub vprint { print(@_) if ($verbose); }
sub vprintf { printf(@_) if ($verbose); }
sub vtprint { vprint(tstamp()); vprint(@_); }
sub vtprintf { vprint(tstamp()); vprintf(@_); }
STDERR->autoflush(1);
STDOUT->autoflush(1);
binmode(STDOUT, ":utf8");
GetOptions(
"help" => \my $help,
"verbose" => \$verbose,
);
show_help(0) if ($help);
my $location = do {
1 == (scalar @ARGV) or show_help(1);
$ARGV[0];
};
# Return the weather report as a character string.
sub get_response {
vtprint("get_response begins\n");
my $mech = WWW::Mechanize->new();
vprint("Getting weather report...\n");
my $wthr_response = $mech->get(
'http://api.openweathermap.org/data/2.5/weather?q='
. $location . '&units=metric&appid=85a4e3c55b73909f42c6a23ec35b7147'
);
my $wthr_str = $wthr_response->content(raw => 1);
die("Didn't find content in http response.\n") if (! $wthr_str);
utf8::decode($wthr_str) or die("failed to decode response\n");
vprint("get_response returning\n");
return $wthr_str;
}
sub format_time {
my ($r) = @_;
my $t = localtime($r->{dt});
return $t->strftime('%H:%M %Z');
}
sub format_speed {
my ($r) = @_;
return sprintf("%.0fKm/h", 3.6 * $r->{wind}->{speed});
}
my @directions = qw(N NNE NE ENE E ESE SE SSE S SSW SW WSW W WNW NW NNW);
my $point_count = scalar(@directions);
sub format_direction {
my ($r) = @_;
my $deg = $r->{wind}->{deg};
if (0 == $r->{wind}->{speed}) {
return "";
} else {
my $idx = (
($deg + (365 / (2 * $point_count))) / (365 / $point_count)
) % $point_count;
return sprintf(" %s", $directions[$idx]);
}
}
sub format_wind {
my ($r) = @_;
return sprintf("%s%s", format_speed($r), format_direction($r));
}
sub format_temperature {
my ($r) = @_;
return sprintf("%.1f°C", $r->{main}->{temp});
}
sub format_humidity {
my ($r) = @_;
return sprintf("%d%% RH", $r->{main}->{humidity});
}
sub format_sky {
my ($r) = @_;
return sprintf("%s", $r->{weather}->[0]->{main});
}
sub format_response {
my ($r) = @_;
return sprintf(
"Weather at %s ► %s ◆ %s ◆ %s ◆ %s\n",
format_time($r),
format_temperature($r),
format_sky($r),
format_wind($r),
format_humidity($r),
);
}
my $wthr_str = get_response();
vprint("turning the response string into a hashref...\n");
my $json = JSON->new;
my $wthr_hashref = $json->decode($wthr_str);
vprintf("pretty-printing the hashref...\n");
printf("%s\n", $json->pretty->encode($wthr_hashref)) if ($verbose);
vprint("formatting weather report...\n");
print format_response($wthr_hashref);
exit(0);