2013-08-25 12:48:39 -04:00
|
|
|
#!/usr/bin/perl
|
|
|
|
# conky-mythtv-weather-build.plx
|
|
|
|
#
|
|
|
|
# Copyright (C) 2013, Bradley M. Kuhn
|
|
|
|
#
|
|
|
|
# This program gives you software freedom; you can copy, modify, convey,
|
|
|
|
# and/or redistribute it under the terms of the GNU General Public License
|
|
|
|
# as published by the Free Software Foundation; either version 3 of the
|
|
|
|
# License, or (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful, but
|
|
|
|
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
# General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License along
|
|
|
|
# with this program in a file called 'GPLv3'. If not, write to the:
|
|
|
|
# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor
|
|
|
|
# Boston, MA 02110-1301, USA.
|
|
|
|
#
|
|
|
|
# Quick hack to use mythtv scripts.
|
|
|
|
|
2013-08-27 07:19:05 -04:00
|
|
|
# Get listing of stations with:
|
|
|
|
# /home/bkuhn/hacks/mythtv/mythplugins/mythweather/mythweather/scripts/us_nws/nwsxml.pl -l
|
|
|
|
|
2013-08-25 12:48:39 -04:00
|
|
|
use strict;
|
|
|
|
use warnings;
|
2013-08-25 13:13:18 -04:00
|
|
|
use Date::Manip;
|
2013-08-25 16:13:10 -04:00
|
|
|
use utf8;
|
|
|
|
use feature 'unicode_strings';
|
|
|
|
use Encode qw(encode decode);
|
2013-08-25 12:48:39 -04:00
|
|
|
|
2013-08-26 21:05:09 -04:00
|
|
|
use File::Temp qw/tempdir/;
|
2013-12-31 16:50:11 -05:00
|
|
|
use File::Spec;
|
2013-08-26 21:05:09 -04:00
|
|
|
|
2013-12-31 16:50:11 -05:00
|
|
|
my $DIR = File::Spec->catdir("$ENV{HOME}", 'tmp', '.conky-mythtv-weather');
|
|
|
|
my $VOFFSET_FILE = File::Spec->catfile($DIR, 'conky-weather-voffset-last');
|
|
|
|
|
|
|
|
chdir($DIR) or die "unable to go to $DIR";
|
2013-08-26 21:05:09 -04:00
|
|
|
|
2013-08-25 16:17:38 -04:00
|
|
|
if (@ARGV != 6 and @ARGV != 7) {
|
|
|
|
print STDERR "usage: $0 /path/to/mythtv/git/checkout <units> <location> <text_voffset> <img_voffset> <fontsize_pixels> [hour-format]\n";
|
2013-08-25 12:48:39 -04:00
|
|
|
exit 1;
|
|
|
|
}
|
2013-08-25 16:17:38 -04:00
|
|
|
my($MYTH_PATH, $UNITS, $LOCATION, $VOFFSET_TEXT, $VOFFSET_IMAGE, $FONT_SIZE, $HOUR_FORMAT) = @ARGV;
|
2013-08-25 16:13:10 -04:00
|
|
|
$HOUR_FORMAT = "%a %H:%M" unless defined $HOUR_FORMAT;
|
2013-12-31 16:50:11 -05:00
|
|
|
my $TEXT_LINE_OFFSET_VPOS_AMOUNT = 1.59;
|
|
|
|
my $VOFFSET_TOP_DEFAULT_OFFSET = 11;
|
|
|
|
|
|
|
|
if ($VOFFSET_IMAGE eq 'READ') {
|
|
|
|
open(VOFFSET, "<", $VOFFSET_FILE) or die "unable to read $VOFFSET_FILE: $!";
|
|
|
|
while (my $line = <VOFFSET>) {
|
|
|
|
chomp $line;
|
|
|
|
$VOFFSET_IMAGE = $line if $line =~ /^\s*[\d\.]+\s*$/;
|
|
|
|
}
|
|
|
|
close VOFFSET;
|
|
|
|
die "unable to read voffset from $VOFFSET_FILE: $!"
|
|
|
|
if ($VOFFSET_IMAGE eq 'READ');
|
|
|
|
}
|
|
|
|
$VOFFSET_IMAGE += $VOFFSET_TOP_DEFAULT_OFFSET;
|
|
|
|
|
2013-08-25 16:13:10 -04:00
|
|
|
my $degree;
|
|
|
|
if ($UNITS eq "SI") {
|
|
|
|
$degree = encode('utf8', "°C");
|
|
|
|
} elsif ($UNITS eq 'ENG') {
|
|
|
|
$degree = encode('utf8', "°F");
|
|
|
|
} else {
|
|
|
|
die "invalid units, $UNITS";
|
|
|
|
}
|
2013-08-25 12:48:39 -04:00
|
|
|
|
2013-08-25 16:23:07 -04:00
|
|
|
my($mythIconPath) = $MYTH_PATH . "/mythplugins/mythweather/theme/default/icons";
|
|
|
|
my(%commands) = ('forecast' => $MYTH_PATH .
|
|
|
|
"/mythplugins/mythweather/mythweather/scripts/us_nws/ndfd18.pl",
|
|
|
|
'extended' => $MYTH_PATH .
|
2013-08-25 17:00:11 -04:00
|
|
|
"/mythplugins/mythweather/mythweather/scripts/us_nws/ndfd.pl",
|
|
|
|
'current' => $MYTH_PATH .
|
2013-12-29 16:22:07 -05:00
|
|
|
"/mythplugins/mythweather/mythweather/scripts/us_nws/nwsxml.pl",
|
|
|
|
'accuweather' => $MYTH_PATH .
|
|
|
|
"/mythplugins/mythweather/mythweather/scripts/accuweather/accuweather.pl");
|
2013-08-25 13:13:18 -04:00
|
|
|
|
2013-08-25 16:23:07 -04:00
|
|
|
my %data;
|
2013-12-29 16:22:07 -05:00
|
|
|
|
|
|
|
my($location1) = $LOCATION;
|
|
|
|
my($location2) = $LOCATION;
|
|
|
|
if ($LOCATION =~ /^([^|]+)\|([^|]+)/) {
|
|
|
|
($location1, $location2) = ($1, $2);
|
|
|
|
}
|
|
|
|
if ($location1 eq "FORCE_ACCUWEATHER") {
|
|
|
|
foreach my $key (qw/forecast extended current/) { delete $commands{$key}; }
|
|
|
|
}
|
2013-08-25 16:23:07 -04:00
|
|
|
foreach my $type (keys %commands) {
|
2013-12-29 16:22:07 -05:00
|
|
|
my $location = $location1;
|
|
|
|
$location = $location2 if $type eq "accuweather";
|
|
|
|
open(DATA, "-|", $commands{$type}, '-u', $UNITS, $location)
|
2013-08-25 16:23:07 -04:00
|
|
|
or die "unable to run: $commands{$type} -u $UNITS $LOCATION: $!";
|
2013-08-25 13:13:18 -04:00
|
|
|
|
2013-08-25 16:23:07 -04:00
|
|
|
while (my $line = <DATA>) {
|
|
|
|
die "bad line output in data: $line"
|
2013-12-29 16:22:07 -05:00
|
|
|
unless $line =~ /^\s*(\S+)\s*:\s*:\s*(.*)$/;
|
2013-08-25 16:23:07 -04:00
|
|
|
$data{$type}{$1} = $2;
|
|
|
|
}
|
|
|
|
close DATA;
|
|
|
|
die "error($?) running: $commands{$type} -u $UNITS $LOCATION: $!"
|
|
|
|
unless $? == 0;
|
2013-08-25 13:13:18 -04:00
|
|
|
}
|
2013-12-29 16:53:29 -05:00
|
|
|
if (not defined $data{current}{observation_time}) {
|
|
|
|
foreach my $key (%{$data{accuweather}}) {
|
|
|
|
$data{current}{$key} = $data{accuweather}{$key};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (not defined $data{forecast}{updatetime}
|
|
|
|
and defined $data{accuweather}{'time-1'}) {
|
2013-12-29 16:22:07 -05:00
|
|
|
foreach my $key (%{$data{accuweather}}) {
|
|
|
|
$data{forecast}{$key} = $data{accuweather}{$key};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (not defined $data{extended}{updatetime}) {
|
|
|
|
foreach my $key (%{$data{accuweather}}) {
|
|
|
|
$data{extended}{$key} = $data{accuweather}{$key};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-29 17:55:47 -05:00
|
|
|
my $updateTime = $data{forecast}{updatetime};
|
|
|
|
$updateTime = $data{extended}{updatetime} if not defined $updateTime;
|
|
|
|
|
|
|
|
$updateTime =~ s/\s*(?:Last\s*)?Updated\s*(?:on|:)?\s*//;
|
2013-08-25 13:13:18 -04:00
|
|
|
my $now = ParseDate("now");
|
2013-12-29 17:55:47 -05:00
|
|
|
$updateTime = ParseDate($updateTime);
|
2013-08-26 21:06:04 -04:00
|
|
|
my $x = Delta_Format(DateCalc($updateTime, $now), 0, "%mt minutes ago");
|
2013-08-25 13:13:18 -04:00
|
|
|
|
2013-08-25 16:23:07 -04:00
|
|
|
$data{forecast}{updatetime} = $x if defined $x;
|
|
|
|
$data{forecast}{updatetime} = "as of $data{forecast}{updatetime}";
|
2013-08-26 21:06:04 -04:00
|
|
|
$data{forecast}{"maxLength"} = 0;
|
2013-08-25 16:34:57 -04:00
|
|
|
my %doneDays;
|
2013-08-25 16:13:10 -04:00
|
|
|
foreach my $ii (qw/0 1 2 3 4 5/) {
|
2013-08-25 17:46:28 -04:00
|
|
|
next if not defined $data{forecast}{"time-${ii}"};
|
2013-08-25 16:23:07 -04:00
|
|
|
my $time = ParseDate($data{forecast}{"time-${ii}"});
|
2013-08-25 17:46:28 -04:00
|
|
|
next if not defined $time;
|
2013-08-25 16:13:10 -04:00
|
|
|
if (defined $time) {
|
2013-08-26 21:06:04 -04:00
|
|
|
$time = DateCalc($time, "+ 1 day") if ($time lt $updateTime);
|
|
|
|
if ($time lt $now) {
|
|
|
|
delete $data{forecast}{"time-${ii}"};
|
|
|
|
next;
|
|
|
|
}
|
2013-08-25 17:46:28 -04:00
|
|
|
my $day = UnixDate($time, '%A');
|
2013-08-25 16:23:07 -04:00
|
|
|
$data{forecast}{"time-${ii}"} = UnixDate($time, $HOUR_FORMAT);
|
2013-08-26 21:06:04 -04:00
|
|
|
my $ll = length($data{forecast}{"time-${ii}"});
|
|
|
|
$data{forecast}{"maxLength"} = $ll
|
|
|
|
unless $data{forecast}{"maxLength"} > $ll;
|
2013-08-25 17:46:28 -04:00
|
|
|
$doneDays{$day} = 'forecast';
|
2013-08-25 16:13:10 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
my $f = $FONT_SIZE + 5;
|
2013-12-31 16:50:11 -05:00
|
|
|
|
|
|
|
my($xpos, $vpos) = (340, $VOFFSET_IMAGE);
|
|
|
|
|
|
|
|
my $place = $data{current}{'cclocation'};
|
|
|
|
$place .= " $location2" if ($location1 eq "FORCE_ACCUWEATHER");
|
|
|
|
|
|
|
|
print '${voffset ', $VOFFSET_TEXT , '} ${font :size=', $f, '}${alignc}Weather:${font}', " $place\n";
|
|
|
|
|
|
|
|
$vpos += ($TEXT_LINE_OFFSET_VPOS_AMOUNT * $f);
|
|
|
|
|
2013-12-29 16:22:07 -05:00
|
|
|
if (not defined $data{current}{observation_time_rfc822}) {
|
2013-12-29 16:26:48 -05:00
|
|
|
$data{current}{observation_time_rfc822} = $data{current}{observation_time};
|
|
|
|
$data{current}{observation_time_rfc822} =~ s/^\s*(?:Observation\s*of\s*:?|Last\s*Updated\s*(?:on)?)\s*//;
|
2013-12-29 16:22:07 -05:00
|
|
|
}
|
2013-12-29 16:53:29 -05:00
|
|
|
my($temp, $feelsLike, $humidity, $windSpeed, $windGust, $icon, $datetime, $weatherConditions) =
|
2013-08-25 17:25:47 -04:00
|
|
|
($data{current}{temp}, $data{current}{heat_index},
|
|
|
|
$data{current}{relative_humidity}, $data{current}{wind_speed},
|
|
|
|
$data{current}{wind_gust}, $data{current}{weather_icon},
|
2013-12-29 16:53:29 -05:00
|
|
|
$data{current}{observation_time_rfc822}, $data{current}{weather});
|
2013-08-25 17:25:47 -04:00
|
|
|
|
2013-12-31 16:50:19 -05:00
|
|
|
if (defined $data{current}{wind_spdgst} and
|
|
|
|
(not defined $data{current}{wind_speed})) {
|
|
|
|
$data{current}{wind_spdgst} =~ /^\s*([\d\.]+)\s*\(?\s*([\d\.]+)\s*\)?\s*$/;
|
|
|
|
($data{current}{wind_speed}, $data{current}{wind_gust}) = ($1, $2);
|
|
|
|
}
|
2013-08-26 21:06:04 -04:00
|
|
|
my $date = ParseDate($datetime);
|
2013-08-25 17:00:11 -04:00
|
|
|
|
2013-08-26 21:06:04 -04:00
|
|
|
my $howOld = DateCalc($date, $now);
|
|
|
|
my $ago = Delta_Format($howOld, 0, "%mt min ago");
|
|
|
|
my $hourFormat = $HOUR_FORMAT;
|
|
|
|
if ($howOld ge DateCalc($now, "+ 1 day")) {
|
|
|
|
$ago = Delta_Format($howOld, 0, "\${color5}%dt day(s) ago\${color}");
|
|
|
|
} elsif (UnixDate($date, "%Y-%m-%d") ne UnixDate($now, "%Y-%m-%d")) {
|
|
|
|
$hourFormat = "%a at $hourFormat" unless $hourFormat =~ /%[aA]/g;
|
|
|
|
$ago = UnixDate($date, $hourFormat);
|
|
|
|
} else {
|
|
|
|
$hourFormat =~ s/\s*%[aA]\s*//;
|
|
|
|
$ago = UnixDate($date, $hourFormat);
|
|
|
|
}
|
|
|
|
$ago = Delta_Format(DateCalc($date, $now), 0, "%st sec ago")
|
|
|
|
if ($ago =~ /0 min ago/);
|
2013-08-25 17:00:11 -04:00
|
|
|
$feelsLike = $data{current}{windchill}
|
|
|
|
if (not defined $feelsLike) or $feelsLike =~ /^\s*N[\s\/]*A\s*$/i;
|
2013-12-29 16:03:09 -05:00
|
|
|
undef $feelsLike if defined $feelsLike and $feelsLike =~ /^\s*(N[\s\/]*A)?\s*$/i;
|
|
|
|
undef $windGust if defined $windGust and $windGust =~ /^\s*(N[\s\/]*A)?\s*$/i;
|
|
|
|
undef $windSpeed if defined $windSpeed and $windSpeed =~ /^\s*(N[\s\/]*A)?\s*$/i;
|
2013-12-29 16:53:43 -05:00
|
|
|
undef $weatherConditions
|
|
|
|
if defined $weatherConditions and $weatherConditions =~ /^\s*(N[\s\/]*A|unknown)?\s*$/i;
|
2013-08-25 17:00:11 -04:00
|
|
|
|
2013-08-27 07:18:55 -04:00
|
|
|
$icon = $data{extended}{"icon-0"}
|
|
|
|
if ($icon =~ /unknown/i and $data{extended}{"date-0"} eq UnixDate($now, "%A"));
|
|
|
|
|
2013-08-26 21:06:04 -04:00
|
|
|
my $smallFontSize = $FONT_SIZE - 5;
|
|
|
|
$smallFontSize = 7 if $smallFontSize < 7;
|
|
|
|
(defined $ago) ?
|
|
|
|
print "\${alignr}\${font :size=${smallFontSize}px}(as of $ago)\n" :
|
|
|
|
print "\n";
|
2013-12-31 16:50:11 -05:00
|
|
|
$vpos += ($TEXT_LINE_OFFSET_VPOS_AMOUNT * $smallFontSize);
|
2013-08-25 17:00:11 -04:00
|
|
|
print "\${font :size=${FONT_SIZE}px} Current: $temp $degree";
|
2013-08-25 17:04:39 -04:00
|
|
|
print " (feels like: $feelsLike $degree)" if defined $feelsLike;
|
2013-08-25 17:25:47 -04:00
|
|
|
print "\${image $mythIconPath/$icon -p $xpos,$vpos -s 50x37}"
|
|
|
|
unless $icon =~ /unknown/i;
|
2013-12-31 16:50:11 -05:00
|
|
|
$vpos += ($TEXT_LINE_OFFSET_VPOS_AMOUNT * $FONT_SIZE);
|
2013-12-29 16:53:43 -05:00
|
|
|
print "\n\${goto 82}Humidity: $humidity\%";
|
|
|
|
print " Wind: " if defined $windSpeed or defined $windGust;
|
|
|
|
print "$windSpeed kph" if defined $windSpeed;
|
2013-08-25 17:00:11 -04:00
|
|
|
print " ($windGust kph)" if defined $windGust;
|
2013-12-31 16:50:11 -05:00
|
|
|
$vpos += ($TEXT_LINE_OFFSET_VPOS_AMOUNT * $FONT_SIZE);
|
|
|
|
if (defined $weatherConditions) {
|
|
|
|
print "\n\${goto 82}Conditions: $weatherConditions\n";
|
|
|
|
$vpos += ($TEXT_LINE_OFFSET_VPOS_AMOUNT * $FONT_SIZE);
|
|
|
|
}
|
|
|
|
$vpos += ($TEXT_LINE_OFFSET_VPOS_AMOUNT * $FONT_SIZE);
|
2013-08-26 21:06:04 -04:00
|
|
|
print "\n";
|
2013-08-25 17:00:11 -04:00
|
|
|
|
2013-12-31 16:50:11 -05:00
|
|
|
$xpos = $FONT_SIZE * (4 + $data{forecast}{maxLength});
|
|
|
|
|
2013-08-25 16:13:10 -04:00
|
|
|
foreach my $ii (qw/0 1 2 3 4 5/) {
|
2013-08-25 17:46:28 -04:00
|
|
|
next if not defined $data{forecast}{"time-${ii}"};
|
2013-08-25 16:13:10 -04:00
|
|
|
my($time, $temp, $pop, $icon) =
|
2013-08-25 16:23:07 -04:00
|
|
|
($data{forecast}{"time-${ii}"}, $data{forecast}{"temp-${ii}"},
|
|
|
|
$data{forecast}{"pop-${ii}"}, $data{forecast}{"18icon-${ii}"});
|
2013-08-25 16:13:10 -04:00
|
|
|
$pop =~ s/\s+//g;
|
|
|
|
$pop = " $pop" if length($pop) eq 2;
|
|
|
|
$pop = " $pop" if length($pop) eq 3;
|
2013-08-26 21:06:04 -04:00
|
|
|
print "\${font :size=${FONT_SIZE}px} $time:\${goto 120}$temp $degree \${image $mythIconPath/$icon -p $xpos,$vpos -s 20x15} $pop chance\n";
|
2013-12-31 16:50:11 -05:00
|
|
|
$vpos += ($TEXT_LINE_OFFSET_VPOS_AMOUNT * $FONT_SIZE);
|
2013-08-25 16:13:10 -04:00
|
|
|
}
|
2013-12-31 16:50:11 -05:00
|
|
|
$xpos = $FONT_SIZE * 26;
|
|
|
|
|
2013-08-25 16:34:57 -04:00
|
|
|
foreach my $ii (qw/0 1 2 3 4 5/) {
|
2013-08-25 17:03:54 -04:00
|
|
|
# You can also use "%doneDays" here, as in:
|
|
|
|
# next if defined $doneDays{$data{extended}{"date-${ii}"}};
|
2013-08-25 17:46:28 -04:00
|
|
|
next if not defined $data{extended}{"date-${ii}"};
|
2013-08-25 17:03:54 -04:00
|
|
|
next if $data{extended}{"date-${ii}"} eq UnixDate($now, "%A");
|
2013-08-25 16:34:57 -04:00
|
|
|
my($day, $high, $low, $icon) =
|
|
|
|
($data{extended}{"date-${ii}"}, $data{extended}{"high-${ii}"},
|
|
|
|
$data{extended}{"low-${ii}"}, $data{extended}{"icon-${ii}"});
|
2013-08-26 21:06:04 -04:00
|
|
|
print "\${font :size=${FONT_SIZE}px} $day:\${goto 120}High: $high $degree Low: $low $degree \${image $mythIconPath/$icon -p $xpos,$vpos -s 20x15}\n";
|
2013-12-31 16:50:11 -05:00
|
|
|
$vpos += ($TEXT_LINE_OFFSET_VPOS_AMOUNT * $FONT_SIZE);
|
2013-08-25 16:34:57 -04:00
|
|
|
}
|
2013-12-31 16:50:11 -05:00
|
|
|
print "\$hr\n";
|
|
|
|
$vpos += ($TEXT_LINE_OFFSET_VPOS_AMOUNT * $FONT_SIZE);
|
|
|
|
$vpos -= $VOFFSET_TOP_DEFAULT_OFFSET;
|
|
|
|
open(VOFFSET, ">", $VOFFSET_FILE);
|
|
|
|
print VOFFSET "$vpos\n";
|
|
|
|
close VOFFSET;
|
2013-08-25 12:48:39 -04:00
|
|
|
###############################################################################
|
|
|
|
#
|
|
|
|
# Local variables:
|
|
|
|
# compile-command: "perl -c conky-mythtv-weather-build.plx"
|
|
|
|
# End:
|
|
|
|
|