Archives

Categories

Weather and Boinc

I just wrote a Perl script to look at the Australian Bureau of Meteorology pages to find the current temperature in an area and then adjust BOINC settings accordingly. The Perl script (in this post after the break, which shouldn’t be in the RSS feed) takes the URL of a Bureau of Meteorology observation point as ARGV[0] and parses that to find the current (within the last hour) temperature. Then successive command line arguments are of the form “24:100” and “30:50” which indicate that at below 24C 100% of CPU cores should be used and below 30C 50% of CPU cores should be used. In warm weather having a couple of workstations in a room running BOINC (or any other CPU intensive task) will increase the temperature and also make excessive noise from cooling fans.

To change the number of CPU cores used the script changes /etc/boinc-client/global_prefs_override.xml and then tells BOINC to reload that config file. This code is a little ugly (it doesn’t properly parse XML, it just replaces a line of text) and could fail on a valid configuration file that wasn’t produced by the current BOINC code.

The parsing of the BoM page is a little ugly too, it relies on the HTML code in the BoM page – they could make a page that looks identical which breaks the parsing or even a page that contains the same data that looks different. It would be nice if the BoM published some APIs for getting the weather. One thing that would be good is TXT records in the DNS. DNS supports caching with specified lifetime and is designed for high throughput in aggregate. If you had a million IOT devices polling the current temperature and forecasts every minute via DNS the people running the servers wouldn’t even notice the load, while a million devices polling a web based API would be a significant load. As an aside I recommend playing nice and only running such a script every 30 minutes, the BoM page seems to be updated on the half hour so I have my cron jobs running at 5 and 35 minutes past the hour.

If this code works for you then that’s great. If it merely acts as an inspiration for developing your own code then that’s great too! BOINC users outside Australia could replace the code for getting meteorological data (or even interface to a digital thermometer). Australians who use other CPU intensive batch jobs could take the BoM parsing code and replace the BOINC related code. If you write scripts inspired by this please blog about it and comment here with a link to your blog post.

#!/usr/bin/perl
use strict;
use Sys::Syslog;

# St Kilda Harbour RMYS
# http://www.bom.gov.au/products/IDV60901/IDV60901.95864.shtml

my $URL = $ARGV[0];

open(IN, "wget -o /dev/null -O - $URL|") or die "Can't get $URL";
while(<IN>)
{
  if($_ =~ /tr class=.rowleftcolumn/)
  {
    last;
  }
}

sub get_data
{
  if(not $_[0] =~ /headers=.t1-$_[1]/)
  {
    return undef;
  }
  $_[0] =~ s/^.*headers=.t1-$_[1]..//;
  $_[0] =~ s/<.td.*$//;
  return $_[0];
}

my @datetime;
my $cur_temp -100;

while(<IN>)
{
  chomp;
  if($_ =~ /^<.tr>$/)
  {
    last;
  }
  my $res;
  if($res = get_data($_, "datetime"))
  {
    @datetime = split(/\//, $res)
  }
  elsif($res = get_data($_, "tmp"))
  {
    $cur_temp = $res;
  }
}
close(IN);
if($#datetime != 1 or $cur_temp == -100)
{
  die "Can't parse BOM data";
}

my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();

if($mday - $datetime[0] > 1 or ($datetime[0] > $mday and $mday != 1))
{
  die "Date wrong\n";
}

my $mins;
my @timearr = split(/:/, $datetime[1]);
$mins = $timearr[0] * 60 + $timearr [1];
if($timearr[1] =~ /pm/)
{
  $mins += 720;
}
if($mday != $datetime[0])
{
  $mins += 1440;
}

if($mins + 60 < $hour * 60 + $min)
{
  die "page outdated\n";
}

my %temp_hash;
foreach ( @ARGV[1..$#ARGV] )
{
  my @tmparr = split(/:/, $_);
  $temp_hash{$tmparr[0]} = $tmparr[1];
}
my @temp_list = sort(keys(%temp_hash));
my $percent = 0;
my $i;
for($i = $#temp_list; $i >= 0 and $temp_list[$i] > $cur_temp; $i--)
{
  $percent = $temp_hash{$temp_list[$i]}
}

my $prefs = "/etc/boinc-client/global_prefs_override.xml";
open(IN, "<$prefs") or die "Can't read $prefs";
my @prefs_contents;
while(<IN>)
{
  push(@prefs_contents, $_);
}
close(IN);

openlog("boincmgr-cron", "", "daemon");

my @cpus_pct = grep(/max_ncpus_pct/, @prefs_contents);
my $cpus_line = $cpus_pct[0];
$cpus_line =~ s/..max_ncpus_pct.$//;
$cpus_line =~ s/^.*max_ncpus_pct.//;
if($cpus_line == $percent)
{
  syslog("info", "Temp $cur_temp" . "C, already set to $percent");
  exit 0;
}
open(OUT, ">$prefs.new") or die "Can't read $prefs.new";
for($i = 0; $i <= $#prefs_contents; $i++)
{
  if($prefs_contents[$i] =~ /max_ncpus_pct/)
  {
    print OUT "   <max_ncpus_pct>$percent.000000</max_ncpus_pct>\n";
  }
  else
  {
    print OUT $prefs_contents[$i];
  }
}
close(OUT);
rename "$prefs.new", "$prefs" or die "can't rename";
system("boinccmd --read_global_prefs_override");
syslog("info", "Temp $cur_temp" . "C, set percentage to $percent");

1 comment to Weather and Boinc

  • as

    i’m a happy user of https://openweathermap.org/current . you have to sign up to get an api key, but usage is free for a reasonable amount of requests (no payment data required). has served me stable for several years now. and i would know, as my heating-control relies on that data.