Information wants to be free...

Temperature Monitor in Perl/Tk

This is a simple script that fetches the current temperature for a geographical location and displays it. It is similar to the alarm clock script I made earlier.

I attempted to see if I could get the weather information from Storm Weather Center, but I was disappointed to see that they want money to provide this information. It is even more disappointing that they actually threaten to sue anyone who gets their information without approval.

Luckily, we have weather.com that provides weather information for free, if it is for personal use. This information can be fetched with RSS, if you know the weather.com specific location code.

Note that you need the Perk/Tk module and the XML-RSS-Parser module to use the script.

#!/usr/bin/perl -w
use strict;
use LWP::Simple;
use XML::RSS::Parser;
use Tk;

# Location code examples: NOXX0035 (Stavanger), NOXX0029 (Oslo).
# Find more at: http://www.weather.com/weather/rss/subscription

my ($update_rate, $location);
$location    = shift @ARGV or die "Usage: $0 <location code> [update rate]\n";
$update_rate = shift @ARGV or $update_rate = 15; # Default is 15 minutes.

my $url = "http://rss.weather.com/weather/rss/local/". $location . 
          "?cm_ven=LWO&cm_cat=rss&par=LWO_rss";

my $parser = XML::RSS::Parser->new;
my $window = new Tk::MainWindow;
$window->repeat($update_rate * 1000 * 60, \&get_temperature);
my $label = $window->Label(-foreground => "black",
                           -background => "white",
                           -font => 'Helvetica 36 bold')->pack();

$label->configure(-text => "Regex error!"); # If regex fails, this is displayed.
&get_temperature;
Tk::MainLoop;

sub get_temperature {
  my $data = get($url);
  unless (defined $data) {
    $label->configure(-text => "No contact!");
    return;
  }

  my $feed = $parser->parse_string($data);
  unless (defined $feed) {
    $label->configure(-text => "Parse error!");
    return;
  }

  for ($feed->query("/channel/item")) {
    my $node = $_->query("title");
    if ($node->text_content =~ m/current/i) {
      $node = $_->query("description");
      if ($node->text_content =~ m/(\d+)\s*&deg/) {
        my $deg = (($1 - 32) / 9) * 5; # Fahrenheit to Celsius.
        $label->configure(-text => sprintf("%.1f\x{B0}C", $deg));
      }
    }
  }
}
          


Topic: Scripts and Code, by Kjetil @ 10/08-2008, Article Link