Last active
February 11, 2017 09:37
-
-
Save jacoby/9dc5b7baf2f068a7aa2d to your computer and use it in GitHub Desktop.
Perl program to search Forecast.IO API for current weather conditions, based upon latitude and longitude, and display them in Linux using notify-send
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env perl | |
# forecast.pl is Copyright (C) 2014, by Dave Jacoby. | |
# It is free software; you can redistribute it and/or modify it under the terms of either: | |
# | |
# a) the GNU General Public License as published by the Free Software Foundation; either external linkversion 1, or (at your option) any later versionexternal link, or | |
# | |
# b) the "Artistic License". | |
# interface to forecast.io which uses Linux notify-send to | |
# send a variety of weather information to the user's awareness | |
# Usage: | |
# --current , -c cureent conditions | |
# --alerts, -a alerts; current weather alerts if any | |
# --hourly, -h hourly forecasts for the next four hours | |
# --daily, -d forecast for the next two days | |
# You can use all the flags at once. No flags defaults to current conditions | |
use feature qw{ say state } ; | |
use strict ; | |
use warnings ; | |
use utf8 ; | |
use Carp ; | |
use Data::Dumper ; | |
use DateTime ; | |
use Getopt::Long ; | |
use JSON ; | |
use LWP::UserAgent ; | |
use YAML qw{ LoadFile } ; | |
my $config = config() ; | |
my $url = | |
'https://api.forecast.io/forecast/' | |
. $config->{ apikey } . '/' | |
. ( join ',', map { $config->{ $_ } } qw{ latitude longitude } ) ; | |
my $agent = LWP::UserAgent->new( ssl_opts => { verify_hostname => 0 } ) ; | |
my $response = $agent->get( $url ) ; | |
if ( $response->is_success ) { | |
my $content = $response->content ; | |
my $forecast = decode_json $content ; | |
my $current = $forecast->{ currently } ; | |
my $alerts = $forecast->{ alerts } ; | |
my $hourly = $forecast->{ hourly } ; | |
my $daily = $forecast->{ daily } ; | |
say join "\n", | |
( map { join "\t", '+', $_, ref $forecast->{ $_ } } sort keys %$forecast ), '' | |
if $config->{ verbose } ; | |
current_conditions( $current ) if $config->{ current } ; | |
daily_forecasts( $daily ) if $config->{ daily } ; | |
hourly_forecasts( $hourly ) if $config->{ hourly } ; | |
handle_alerts( $alerts ) if $config->{ alerts } ; | |
} | |
exit ; | |
sub current_conditions { | |
my $current = shift ; | |
my $temp = int $current->{ temperature } ; | |
my $summary = $current->{ summary } ; | |
my $liketemp = int $current->{ apparentTemperature } ; | |
my $icon = $current->{ icon } ; | |
my $title = qq{Currently ${temp}°F} ; | |
my $body = qq{$summary. Feels like ${liketemp}°F.\nPowered by Forecast.} ; | |
say $icon if $config->{ verbose } ; | |
my $png = get_icons( $icon ) ; | |
notify( $title, $body , $png ) ; | |
} | |
sub handle_alerts { | |
my $alerts = shift ; | |
my $body = qq{Powered by Forecast.} ; | |
for my $alert ( @$alerts ) { | |
my $title = $alert->{ title } ; | |
my $warning = 0 ; | |
$warning = 1 if $title =~ /warning/i ; | |
notify( $title, $body ) ; | |
} | |
} | |
sub hourly_forecasts { | |
my $hourly = shift ; | |
my $icon = $hourly->{ icon } ; | |
my $summary = $hourly->{ summary } ; | |
my $data = $hourly->{ data } ; | |
my $body = $summary . "\n\n" ; | |
for my $hour ( @$data[ 0 .. 3 ] ) { | |
my $summary = $hour->{ summary } ; | |
my $dt = DateTime->from_epoch( epoch => $hour->{ time } ) ; | |
$body .= join " ", $dt->hour_12(), $dt->am_or_pm(), '-', $summary, "\n" ; | |
} | |
$body .= qq{Powered by Forecast.} ; | |
my $title = 'Four-Hour Forecast' ; | |
my $png = get_icons( $icon ) ; | |
notify( $title, $body , $png ) ; | |
} | |
sub daily_forecasts { | |
my ( $daily, $f ) = @_ ; | |
my $icon = $daily->{ icon } ; | |
my $summary = $daily->{ summary } ; | |
my $data = $daily->{ data } ; | |
my $body ; | |
for my $day ( @$data[ 1 .. 2 ] ) { | |
my $summary = $day->{ summary } ; | |
my $dt = DateTime->from_epoch( epoch => $day->{ time } ) ; | |
my $max = int $day->{ temperatureMax } ; | |
my $min = int $day->{ temperatureMin } ; | |
my $icon = $day->{ icon } ; | |
$body .= join ' ', | |
$dt->day_name() . ':', | |
$summary, "\n\t" , | |
'H:', | |
$max . '°F', | |
'- L:', | |
$min . '°F', | |
"\n" ; | |
} | |
$body .= qq{Powered by Forecast.} ; | |
my $title = 'Two-Day Forecast' ; | |
my $png = get_icons( $icon ) ; | |
notify( $title, $body , $png ) ; | |
} | |
# Handles the actual notification, using Linux's notify-send | |
sub notify { | |
my $title = shift ; | |
my $body = shift ; | |
my $icon = shift ; | |
$body = $body || '' ; | |
$icon = $icon || $ENV{HOME} . '/Pictures/Icons/icon_black_muffin.jpg' ; | |
`notify-send "$title" "$body" -i $icon ` ; | |
} | |
# show the icons | |
sub get_icons { | |
my $icon = shift ; | |
my $path = $ENV{ HOME } . '/Pictures/forecast.io/' ; | |
# these are the icon names that forecast.io will use. | |
my @icons = qw{ | |
clear-day | |
clear-night | |
cloudy | |
fog | |
partly-cloudy-day | |
partly-cloudy-night | |
rain | |
sleet | |
snow | |
wind | |
} ; | |
# I found my weather icon set online, which had vastly | |
# different icons. I cannot distribute them, as they aren't mine | |
# and I don't hold the copyright, but you can find/make your own. | |
# Coming soon? | |
# hail | |
# thunderstorm | |
# tornado | |
if ( grep m{$icon} , @icons ) { | |
return $path . $icon . '.png' ; | |
} | |
return $path . 'default' . '.png' ; | |
} | |
# Reads configuration data from YAML file. Dies if no valid config file | |
# if no other value is given, it will choose current | |
sub config { | |
my $config_file = $ENV{ HOME } . '/.forecast.yaml' ; | |
my $output = {} ; | |
if ( defined $config_file && -f $config_file ) { | |
my $output = LoadFile( $config_file ) ; | |
GetOptions( | |
'verbose' => \$output->{ verbose }, | |
'alerts' => \$output->{ alerts }, | |
'current' => \$output->{ current }, | |
'daily' => \$output->{ daily }, | |
'hourly' => \$output->{ hourly }, | |
) ; | |
$output->{ current } = 1 | |
if !$output->{ alerts } | |
and !$output->{ hourly } | |
and !$output->{ daily } ; | |
say Dumper $output if $output->{ verbose } ; | |
return $output ; | |
} | |
croak( 'No Config File' ) ; | |
} | |
__DATA__ | |
What ~/.forecast.yaml should look like, set for Lafayette | |
--- | |
apikey: You can't have my API key | |
latitude: 40.422778 | |
longitude: -86.915278 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment