#!/usr/bin/perl # # Assemble NOAA current and forecast weather data into an XHTML fragment. # See http://golem.ph.utexas.edu/~distler/blog/archives/000482.html # # Copyright, Jacques Distler, 12/2004-4/2024. # Released under the GPL. use Data::Dumper; use feature "switch"; use XML::Simple; use strict; use POSIX qw/ceil floor/; use DateTime; #### Customize these ##### # my $numDays = 2; # number of days (2 forecast intervals/day) # my $location = 'Austin'; # my location # my $current_file = # the current conditions XML file '/Users/distler/Sites/weather/current.xml'; # my $forecast_file = # the NDFD 12-hour forecast file '/Users/distler/Sites/weather/forecast.xml'; # my $weather_file = # file to save the XHTML fragment '/Users/distler/Sites/weather/weather.html'; # my $icon_path = '/~distler/weather/icons/'; my $unavail_icon = # icon for unavailable Forecasts (don't ask!) $icon_path . 'unavailable.gif'; # my $radar_url = # Doppler radar loop for nearest weather station 'https://weather.gov/radar/loop/DS.p20-r/si.kewx.shtml'; # ########################## my $current = XMLin($current_file); my $forecast = XMLin($forecast_file); my $params = $forecast->{'data'}->{'parameters'}; my $layout = $forecast->{'data'}->{'time-layout'}; my $title = $forecast->{'head'}->{'product'}->{'title'}; my $info_url = $forecast->{'head'}->{'source'}->{'more-information'}; my ($maxperiodkey, $minperiodkey, $condsperiodkey); # arrays of keys for the time-periods in the forecast LAYOUT: for my $i (0 .. $#$layout) { my $period_key = $layout->[$i]->{'start-valid-time'}; my $layout_key = $layout->[$i]->{'layout-key'}; $layout_key =~ /k-p\dd-n\d/ ? do {next LAYOUT;} : $layout_key =~ /k-p24h-n\d+-1/ ? do { $maxperiodkey=$period_key; next LAYOUT;} : $layout_key =~ /k-p24h-n\d+-2/ ? do { $minperiodkey=$period_key; next LAYOUT;} : $layout_key =~ /k-p12h-n\d+-3/ ? do {$condsperiodkey=$period_key; next LAYOUT;} : $layout_key =~ /k-p\d+h-n\d/ ? do {next LAYOUT;} : die "unknown layout key: $layout_key\n"; } # if there's less data in the forecast file than asked for, give only # as much as we've got. if ($numDays > $#$maxperiodkey + 1) { $numDays = $#$maxperiodkey + 1; } my ($conditions, $temperatures, $hilo, $times, $precip, $icons); # When to start? my $dt = DateTime->now; $dt->set_time_zone('local')->add( minutes => 2 ); # ensure the startDate is in the future my $sd = DateTime->now->set_time_zone('local')->add( minutes => 2 )->truncate( to => 'day' ); my $dur = DateTime::Duration->new( hours => 6 ); if ( $dt->is_between($sd, $sd + $dur) ) { $sd->subtract( days => 1); $sd->add( hours => 18); } elsif ( $dt->is_between($sd + $dur, $sd + 3*$dur) ) { $sd->add(hours => 6); } else { $sd->add(hours => 18); } my $startDate = $sd->strftime('%Y-%m-%dT%H:%M:%S%z'); $startDate =~ s/(\d{2})(\d{2})$/$1:$2/; # final format: "2005-01-24-06:00" my $periodoffset = 0; for my $i (0 .. $#$condsperiodkey-1) { if ($startDate eq $condsperiodkey->[$i]->{'content'}) { $periodoffset = $i; last; } } # turn the forecast into hashes, keyed by time-period for my $i (0 .. 2*$numDays-1) { $times->[$i] = $condsperiodkey->[$i + $periodoffset]->{'period-name'}; $conditions->{$times->[$i]} = $params->{'weather'}->{'weather-conditions'}->[$i + $periodoffset]->{'weather-summary'}; $precip->{$times->[$i]} = $params->{'probability-of-precipitation'}->{'value'}->[$i + $periodoffset]; $temperatures->{$times->[$i]} = ($times->[$i] =~ /ight/)? $params->{'temperature'}->{'Daily Minimum Temperature'}->{'value'}->[floor($i/2)+floor($periodoffset/2)] : $params->{'temperature'}->{'Daily Maximum Temperature'}->{'value'}->[floor($i/2)+ceil($periodoffset/2)]; $hilo->{$times->[$i]} = ($times->[$i] =~ /ight/)? 'Low' : 'High'; # towards the end of a 12-hour period, NOAA doesn't deign to "forecast" the # weather for that period. So we hack around them. $icons->{$times->[$i]} = ($params->{'conditions-icon'}->{'icon-link'}->[$i+$periodoffset] =~ /^HASH/ ) ? $unavail_icon : $params->{'conditions-icon'}->{'icon-link'}->[$i+$periodoffset]; $icons->{$times->[$i]} =~ s!http://forecast.weather.gov/images/wtf/!$icon_path!; } #print Dumper($params->{'temperature'}); #print Dumper($conditions, $hilo, $temperatures); # now print out the resulting forecast as an XHTML fragment open(OUT,">$weather_file"); my $abbr_string = " title=\"Probability of Precipitation\""; print OUT "

$location Weather#

\n\n"; for my $i (@$times) { print OUT <


$i

$conditions->{$i}
$hilo->{$i}: $temperatures->{$i}\°F
PoP: $precip->{$i}\% FOO ; $abbr_string = ""; } print OUT <

Currently:

$current->{'weather'}, $current->{'temp_f'}\°F \($current->{'temp_c'}\°C\)
(Doppler Radar) BAR ; close(OUT);