See here for unformatted version that you can save.
#!/usr/bin/env perl
# -*- Mode: perl -*-

# $Revision: 1.44 $ $Date: 2005/01/11 03:51:00 $
# $Id: weather,v 1.44 2005/01/11 03:51:00 tconnors Exp $
# $Header: /home/office/tconnors/cvsroot/bin/weather,v 1.44 2005/01/11 03:51:00 tconnors Exp $
# $RCSfile: weather,v $

#displays the weather in an australian city in a small gnuplot window
#at the bottom of your screen. Change the internal URL to point to the
#Bureau of Meteorology webpage for your city, and it displays the last
#72 hours, as well as keeping a permanent history for later perusal -
#see the yearly trends!

#idea initially inspired by Craig West, and he wrote the bad evil
#looking parts of it :)
#Ported to perl and changed a heck of a lot by Tim Connors.
#Copyright Tim Connors 2004, under GPL license

# Patches by:
# Andrew Hood <ajhood  at  fl.net.au.invalid>

#TODO: in the history output, output the full date as well - if date
#      in html file is after now, then it was month=currentmonth--, else
#      currentmonth
#TODO: Allow an average (particularly wind speed and direction -- good
#      for biking, since the wind can change 180 degrees as you go
#      around the bay), over several stations. Furthermore, let you
#      weight stations by different amounts (eg,
#      Chadstone=0.2*Melbourne+0.8*Scoresby)

use warnings;
use strict;

sub min {
  my ($a,$b)=(@_);
  if ($a > $b) {
    return $b;
  }
  return $a;
}

sub max {
  my ($a,$b)=(@_);
  if ($a < $b) {
    return $b;
  }
  return $a;
}

my ($vert,$hor,$VERTSIZE,$HORSIZE,$pidfile,$ofh);
my ($windangle);
my ($date,$time,$temp,$dew,$hum,$dir,$speedkm,$speedknots,$gustkm,$gustknots,$press,$rain);

my (@SAVEARGV)=@ARGV;

sub usageerror {
  my ($error)=(@_);
  if (defined($error)) {
    print STDERR "Usage error: $error\n";
    print STDERR "Usage was: @SAVEARGV\n";
  }
  usage(1);
}

sub usage {
  my ($exit)=(@_);
  print STDERR "Usage: $0 [--proxy <proxy>] <gnuplot args>\n";
  $exit=defined($exit) ? $exit : 0;
  exit $exit;
}

sub parseinput {
  sub setproxy {
    defined ($ENV{http_proxy}=shift (@ARGV)) || usageerror("no proxy supplied");
    return 1;
  }

  while (defined($_= shift (@ARGV))) {
    /^--proxy$/ && setproxy() ||
    /^--help$/ && usage() ||
    last;
  }
  defined($_) && unshift @ARGV, $_;
}

#########################

parseinput();



$ENV{DISPLAY} =~ s/\.0$//;
$pidfile="/tmp/gnuplot.weather.$ENV{USER}$ENV{DISPLAY}";
if (-e $pidfile) {
  my $pid=`cat $pidfile`;
  system ("ps `pidof perl`");
  print "my pid=$$; killing HUP $pid\n";
  kill "HUP", $pid;
}
system("echo $$ > $pidfile");

$VERTSIZE=`xdpyinfo | sed -n 's!.*dimensions: *\\([^x]*\\)x\\([^ ]*\\).*!\\2!p'`;
$HORSIZE=`xdpyinfo | sed -n 's!.*dimensions: *\\([^x]*\\)x\\([^ ]*\\).*!\\1!p'`;

#find a nice place to put the graph. Not relevant when embedded in a FvwmButtons
if ( $HORSIZE >= 1280 ) {
  $hor=768;
} else {
  $hor=820;
}

#where we put our history and working files
if (! -d "$ENV{HOME}/weather" ) {
  mkdir "$ENV{HOME}/weather" or die "can't mkdir \$HOME/weather";
}
chdir "$ENV{HOME}/weather" or die "can't chdir \$HOME/weather";


$SIG{HUP}=\&quit;
$SIG{INT}=\&quit;

$vert=$VERTSIZE-81;
open(GNUPLOT, "|gnuplot -title gnuplot.weather -geometry 80x80+$hor+$vert -noraise @ARGV") or die "Can't open gnuplot pipe: $!";
$ofh = select(GNUPLOT); $| = 1; select ($ofh);
loopdisplay();

#####################
sub quit {
  #I had a problem with excess gnuplots hanging around after the fact. I think I solved this elsewhere though
  print "exiting safely\n";
  print GNUPLOT "\nexit\n";
  close GNUPLOT;
  unlink "$ENV{HOME}/weather/weather.lock";
  exit;
}

sub parentrunning {
   print "Testing if $$ exists\n";
   my $ppid=`ps --no-header -o ppid $$`;
   my $res=kill 0, $ppid;
   print "$$:res=$res\n";
   return $res
}

sub loopdisplay {
  print GNUPLOT<<EO1;
#begin gnuplot code:
    set yr [0:45]
#    set out \"$ENV{HOME}/weather/weather.ps\"
    set nokey
    set noxtics
    set noytics
#end gnuplot code:
EO1
  do {
    if (!parentrunning) {
       quit();
    }
    #you can run this on more than 1 display! Wheee!
    print "making lock\n";
    system("lockfile -l 128 $ENV{HOME}/weather/weather.lock");
    display();
    print "removing lock\n";
    unlink "$ENV{HOME}/weather/weather.lock";
    system("sleep ".30*60);
  } while (1);
}

sub display {
  my ($temp,$time,$url,$code);
# $url="/products/IDN65092/IDN65092.94541.shtml"; # Inverell Research Centre AWS
# $url="/products/IDN65092/IDN65092.94572.shtml"; # Lismore
# $url="/products/IDN65092/IDN65092.94573.shtml"; # Casino
# $url="/products/IDN65092/IDN65092.94588.shtml"; # Glen Innes
# $url="/products/IDN65092/IDN65092.94596.shtml"; # Ballina Airport
# $url="/products/IDN65092/IDN65092.94598.shtml"; # Evans Head
# $url="/products/IDN65092/IDN65092.94599.shtml"; # Cape Byron AWS
# $url="/products/IDN65092/IDN65092.94691.shtml"; # Broken Hill
# $url="/products/IDN65092/IDN65092.94693.shtml"; # Mildura
# $url="/products/IDN65092/IDN65092.94701.shtml"; # Hay
# $url="/products/IDN65092/IDN65092.94703.shtml"; # Bourke Airport
# $url="/products/IDN65092/IDN65092.94710.shtml"; # Cobar Airport
# $url="/products/IDN65092/IDN65092.94711.shtml"; # Cobar
# $url="/products/IDN65092/IDN65092.94712.shtml"; # Young
# $url="/products/IDN65092/IDN65092.94715.shtml"; # Forbes
# $url="/products/IDN65092/IDN65092.94727.shtml"; # Mudgee
# $url="/products/IDN65092/IDN65092.94729.shtml"; # Bathurst
# $url="/products/IDN65092/IDN65092.94743.shtml"; # Mount Boyce
# $url="/products/IDN65092/IDN65092.94746.shtml"; # Moss Vale
# $url="/products/IDN65092/IDN65092.94749.shtml"; # Bellambi
# $url="/products/IDN65092/IDN65092.94750.shtml"; # Nowra
# $url="/products/IDN65092/IDN65092.94752.shtml"; # Badgerys Ck
# $url="/products/IDN65092/IDN65092.94754.shtml"; # Nullo Mountain
# $url="/products/IDN65092/IDN65092.94755.shtml"; # Camden
# $url="/products/IDN65092/IDN65092.94760.shtml"; # Horsley Park
# $url="/products/IDN65092/IDN65092.94762.shtml"; # Holsworthy
# $url="/products/IDN65092/IDN65092.94763.shtml"; # Penrith
# $url="/products/IDN65092/IDN65092.94765.shtml"; # Bankstown
# $url="/products/IDN65092/IDN65092.94766.shtml"; # Canterbury
# $url="/products/IDN65092/IDN65092.94767.shtml"; # Sydney Airport
# $url="/products/IDN65092/IDN65092.94768.shtml"; # Sydney
# $url="/products/IDN65092/IDN65092.94769.shtml"; # Ft Denison
# $url="/products/IDN65092/IDN65092.94774.shtml"; # Nobbys Head
# $url="/products/IDN65092/IDN65092.94775.shtml"; # Tocal AWS
# $url="/products/IDN65092/IDN65092.94776.shtml"; # Williamtown
# $url="/products/IDN65092/IDN65092.94777.shtml"; # Gosford
# $url="/products/IDN65092/IDN65092.94780.shtml"; # Little Bay
# $url="/products/IDN65092/IDN65092.94785.shtml"; # Kempsey Airport
# $url="/products/IDN65092/IDN65092.94786.shtml"; # Port Macquarie Ap AWS
# $url="/products/IDN65092/IDN65092.94791.shtml"; # Coffs Harbour
# $url="/products/IDN65092/IDN65092.94843.shtml"; # Swan Hill
# $url="/products/IDN65092/IDN65092.94862.shtml"; # Yarrawonga
# $url="/products/IDN65092/IDN65092.94910.shtml"; # Wagga Wagga
# $url="/products/IDN65092/IDN65092.94919.shtml"; # Khancoban
# $url="/products/IDN65092/IDN65092.94921.shtml"; # Cooma Airport
# $url="/products/IDN65092/IDN65092.94925.shtml"; # Tuggeranong
# $url="/products/IDN65092/IDN65092.94926.shtml"; # Canberra Airport
# $url="/products/IDN65092/IDN65092.94927.shtml"; # Braidwood
# $url="/products/IDN65092/IDN65092.94929.shtml"; # Bombala
# $url="/products/IDN65092/IDN65092.94934.shtml"; # Green Cape
# $url="/products/IDN65092/IDN65092.94938.shtml"; # Ulladulla
# $url="/products/IDN65092/IDN65092.94939.shtml"; # Montague Island
# $url="/products/IDN65092/IDN65092.94995.shtml"; # Lord Howe Island Airport
# $url="/products/IDN65092/IDN65092.94996.shtml"; # Norfolk Island
# $url="/products/IDN65092/IDN65092.95485.shtml"; # Tibooburra Airport
# $url="/products/IDN65092/IDN65092.95527.shtml"; # Moree Airport
# $url="/products/IDN65092/IDN65092.95571.shtml"; # Grafton
# $url="/products/IDN65092/IDN65092.95695.shtml"; # Wilcannia Airport
# $url="/products/IDN65092/IDN65092.95697.shtml"; # Ivanhoe Airport
# $url="/products/IDN65092/IDN65092.95704.shtml"; # Griffith Airport
# $url="/products/IDN65092/IDN65092.95705.shtml"; # Yanco
# $url="/products/IDN65092/IDN65092.95708.shtml"; # Condobolin
# $url="/products/IDN65092/IDN65092.95709.shtml"; # West Wyalong Airport
# $url="/products/IDN65092/IDN65092.95710.shtml"; # Trangie
# $url="/products/IDN65092/IDN65092.95715.shtml"; # Walgett
# $url="/products/IDN65092/IDN65092.95716.shtml"; # Goulburn
# $url="/products/IDN65092/IDN65092.95717.shtml"; # Parkes Airport
# $url="/products/IDN65092/IDN65092.95718.shtml"; # Coonamble Airport
# $url="/products/IDN65092/IDN65092.95719.shtml"; # Dubbo Airport
# $url="/products/IDN65092/IDN65092.95726.shtml"; # Orange
# $url="/products/IDN65092/IDN65092.95728.shtml"; # Coonabarabran Ap
# $url="/products/IDN65092/IDN65092.95734.shtml"; # Narrabri Airport
# $url="/products/IDN65092/IDN65092.95740.shtml"; # Gunnedah Airport
# $url="/products/IDN65092/IDN65092.95747.shtml"; # Murrurundi Gap
# $url="/products/IDN65092/IDN65092.95748.shtml"; # Wollongong Ap AWS
# $url="/products/IDN65092/IDN65092.95749.shtml"; # Kiama
# $url="/products/IDN65092/IDN65092.95753.shtml"; # Richmond Airport
# $url="/products/IDN65092/IDN65092.95756.shtml"; # Kurnell
# $url="/products/IDN65092/IDN65092.95757.shtml"; # Lucas Heights
# $url="/products/IDN65092/IDN65092.95758.shtml"; # Scone
# $url="/products/IDN65092/IDN65092.95762.shtml"; # Tamworth
# $url="/products/IDN65092/IDN65092.95765.shtml"; # Sydney Olympic Pk
# $url="/products/IDN65092/IDN65092.95766.shtml"; # Sydney Harbour
# $url="/products/IDN65092/IDN65092.95768.shtml"; # North Head
# $url="/products/IDN65092/IDN65092.95770.shtml"; # Norah Head
# $url="/products/IDN65092/IDN65092.95771.shtml"; # Cessnock Airport
# $url="/products/IDN65092/IDN65092.95773.shtml"; # Armidale Airport
# $url="/products/IDN65092/IDN65092.95774.shtml"; # Mangrove Mt
# $url="/products/IDN65092/IDN65092.95784.shtml"; # Taree Airport
# $url="/products/IDN65092/IDN65092.95869.shtml"; # Deniliquin Airport
# $url="/products/IDN65092/IDN65092.95896.shtml"; # Albury Airport
# $url="/products/IDN65092/IDN65092.95909.shtml"; # Thredbo
# $url="/products/IDN65092/IDN65092.95916.shtml"; # Cabramurra
# $url="/products/IDN65092/IDN65092.95929.shtml"; # Merimbula Airport
# $url="/products/IDN65092/IDN65092.95931.shtml"; # Bega
# $url="/products/IDN65092/IDN65092.95937.shtml"; # Moruya Airport
# $url="/products/IDN65092/IDN65092.95940.shtml"; # Pt Perpendicular AWS
  $url="/products/IDV65250/IDV65250.94868.shtml"; # Melbourne
  ($code=$url)=~s/\/products\/(.+)\/.+/$1/;
  unlink <${code}*>;
  int(system("wget http://www.bom.gov.au$url 2> wget.log") / 256) || parsefile($url);

  chomp ($temp=`tail -n 1 72hours.txt | awk '{print \$3}'`);
  chomp ($time=`tail -n 1 72hours.txt | awk '{print \$2\"/\"\$1}'`);
  #     echo "set title 'temp=${temp}{/Symbol \260}C',-3.7"

#  print "windangle=$windangle, speedkm=$speedkm, gustkm=$gustkm\n";
  print GNUPLOT<<EO2
#begin gnuplot code:
    set title 'T=${temp}',-3.7
    set label 2 '${time}' at 7,5
    windgustx(t)=72.0/2-$gustkm* t*sin($windangle*3.1415/180)
#minus, because the wind direction is defined by BOM as coming from, we want going to.
    windgusty(t)=45.0/2-$gustkm* t*cos($windangle*3.1415/180)
    windx(t)=    72.0/2-$speedkm*t*sin($windangle*3.1415/180)
    windy(t)=    45.0/2-$speedkm*t*cos($windangle*3.1415/180)

    #sigh; fscking non-backwards compatible fsking gnu-fscking-plot
    set style line 1 lt 2 lw 2
    set style line 2 lt 3 lw 2
    set style line 3 lt 1
    set style line 4 lt 2
    set style line 5 lt 5
    set style line 6 lt 2 lw 4

    set linestyle 1 lt 2 lw 2
    set linestyle 2 lt 3 lw 2
    set linestyle 3 lt 1
    set linestyle 4 lt 2
    set linestyle 5 lt 5
    set linestyle 6 lt 2 lw 4

    set pointsize 10
    set noarrow
    set arrow from windgustx(0),windgusty(0) to windgustx(1),windgusty(1) ls 2
    set arrow from windx(0),windy(0) to windx(1),windy(1) ls 1
#    print "set arrow from ",windgustx(0),windgusty(0)," to ",windgustx(1),windgusty(1)," ls 2"
#    print "set arrow from ",windx(0),windy(0)," to ",windx(1),windy(1)," ls 1"

    plot '< echo 36 22.5' w points linetype 3, '72hours.txt' u (\$5*45/100) w lines ls 5, '72hours.txt' u (\$13*1) w lines ls 4, '72hours.txt' u 3 w lines ls 3
#end gnuplot code:
EO2
}

sub parsefile {
  my ($url)=shift();
  my (@raw,$raw,$i,$delete,$newtime,$rainrate);
  my %windangle=('N'=>     0.0, 'NNE'=>  22.5, 'NE'=>   45.0, 'ENE'=>  67.5,
                 'E'=>    90.0, 'ESE'=> 112.5, 'SE'=>  135.0, 'SSE'=> 157.5,
                 'S'=>   180.0, 'SSW'=> 202.5, 'SW'=>  225.0, 'WSW'=> 247.5,
                 'W'=>   270.0, 'WNW'=> 292.5, 'NW'=>  315.0, 'NNW'=> 337.5,
                 'CALM'=>  0.0
  );
  $url=~s/.*\///;

  system("cp $url raw.txt");
  system(" > table.txt");
  system("echo '\t\t\t\tRel\tWind\tWind\tWind' >> table.txt");
  system("echo 'Date Time |\tTemp |\tDew |\tHum |\tDir |\tSpeed (km/knots) |\tGust (km/knots) |\tPress |\tRain since 9am |\tRain rate' >> table.txt");
  $raw=`grep -A10 nowrap raw.txt`;
  $raw =~ s/  *<td nowrap align="center">//g;
  $raw =~ s/  *<td align="center">//g;
  $raw =~ s/<\/td>\n/ /g;
  $raw =~ s/&nbsp;/0/g;
  $raw =~ s/--//g;
  @raw=split /\n/, $raw;

  open(OUT, ">72hours.txt") or die "can't write 72.hours.txt $!";
  my ($oldtime,$oldrain);
  my ($first);
  $first=1;
  for ($i=$#raw; $i>=0; $i--) {
#    print "raw=$raw[$i]\n";
    ($date,$time,$temp,$dew,$hum,$dir,$speedkm,$speedknots,$gustkm,$gustknots,$press,$rain) = split / /, $raw[$i];
    $time=~ s/:00//;

#work out wind direction in degrees, and negate result, since wind
#direction is which direction wind comes *from*, and we want to
#display the direction of the wind
    $windangle=-defined($windangle{$dir})?$windangle{$dir}:0.0;
    $gustkm=0    if $gustkm eq '-';
    $gustknots=0 if $gustknots eq '-';

    if ($first) {
      $first=0;

      $oldtime=$time;
      $oldrain=$rain;
    }
    if ($time<$oldtime) {
      $newtime= $time+24;
    } else {
      $newtime= $time;
    }

#    print "oldrain=$oldrain,rain=$rain,newtime=$newtime,oldtime=$oldtime,time=$time,first=$first\n";
    if ($newtime==$oldtime) {
      $rainrate=0;
    } elsif ($rain<$oldrain) {
      $newtime=$time; #revert back to original time
      $oldtime="09";
      $rainrate=$rain/($newtime-$oldtime);
    } else {
      $rainrate = ($rain - $oldrain)/($newtime-$oldtime);
    }
    $oldrain=$rain;
    $oldtime=$newtime;
#    print "rate=$rainrate\n";

    #we want the rain rate to be visible on the graph when you get as
    #low rain as 0.1 mm. You also want to be able to tell when there
    #is 40mm of rain per hour. How do you reconcile both? By taking a
    #fancy log curve - just like charging a capacitor :)

    if ($rainrate>0) {
#      print "rainrate1=$rainrate\n";
      $rainrate=45*(1-exp(-$rainrate/10));
#      print "rainrate2=$rainrate\n";
    } else {
      $rainrate=-999;#make off scale negative, so don't clutter the graph when no rain
    }
    $raw[$i] .= " $rainrate";
    $raw[$i] =~ s/ /\t/g;
#    print "newraw=$raw[$i]\n";
    print OUT "$raw[$i]\n";
  }
  close OUT;


  #now, combine the history file with the current days data, deleting those lines which are common between the 2.
  chomp ($delete=`tail -n 1 history.txt`);
  $delete=~ s/\s/\\W/g;
  system("cp 72hours.txt 72hours.txt.notredund");
  if ($delete ne "") {
    print "delete=$delete\n";
    if (`grep "$delete" 72hours.txt` ne "") {
       print "deleting\n";
       system("sed '1,/$delete/d' 72hours.txt > 72hours.txt.notredund");
    }
    system("cat 72hours.txt.notredund");
  }
  system("cat 72hours.txt.notredund >> history.txt");
  system("cat 72hours.txt >> table.txt");
}

sub log10 {
  my $n = shift;
  return log($n)/log(10);
}