Posts tagged: currentcost

Current Cost Classic vs CC128

Back in November I bought (well, actually I signed up to a new deal with E.ON which included one) a Current Cost electricity monitor, and hooked it up to my server so I could gather the stats for Cacti. I do this by running a small perl script which looks as follows:

#!/usr/bin/perl
# /usr/local/bin/cc-classic.pl
 
use Device::SerialPort qw( :PARAM :STAT 0.07 );
 
$port = "/dev/currentcost";
 
$ob = Device::SerialPort->new($port)
      or die "Can not open port $port\n";
$ob->baudrate(9600);
$ob->write_settings;
$ob->close;
 
open(SERIAL, "+>$port");
while ($line = <SERIAL>)
{
  if ($line =~ m!<ch1><watts>0*(\d+)</watts></ch1>.*<tmpr>\s*(-*[\d.]+)</tmpr>!)
  {
     $watts = $1;
     $temperature = $2;
     print "watts:$watts temp:$temperature";
     last;
  }
}
close(SERIAL);

This would give me the two values I am interested in; watts and temperature (since it sits in the garage node 0 ;)) in Cacti’s format:

$ /usr/local/bin/cc-classic.pl
watts:761 temp:11.3

But today, I received my new unit, a Current Cost CC128. It’s main benefit is that it supports individual appliance monitors, which makes the output even more useful. So, armed with a draft copy of the CC128 XML output document, I prepared my script to read as follows:

#!/usr/bin/perl
# /usr/local/bin/cc-cc128.pl
 
use Device::SerialPort qw( :PARAM :STAT 0.07 );
 
$port = "/dev/currentcost";
 
$ob = Device::SerialPort->new($port)
      or die "Can not open port $port\n";
$ob->baudrate(57600);
$ob->write_settings;
$ob->close;
 
open(SERIAL, "+>$port");
while ($line = <SERIAL>)
{
  if ($line =~ m!<tmpr>\s*(-*[\d.]+)</tmpr>.*<ch1><watts>0*(\d+)</watts></ch1>!)
  {
     $watts = $2;
     $temperature = $1;
     print "watts:$watts temp:$temperature";
     last;
  }
}
close(SERIAL);

And guess what… that works just fine ;)

For those who read diff:

$ diff /usr/local/bin/cc-classic.pl /usr/local/bin/cc-cc128.pl 
2c2
< # /usr/local/bin/cc-classic.pl
---
> # /usr/local/bin/cc-cc128.pl
10c10
< $ob->baudrate(9600);
---
> $ob->baudrate(57600);
17c17
<   if ($line =~ m!<ch1><watts>0*(\d+)</watts></ch1>.*<tmpr>\s*(-*[\d.]+)</tmpr>!)
---
>   if ($line =~ m!<tmpr>\s*(-*[\d.]+)</tmpr>.*<ch1><watts>0*(\d+)</watts></ch1>!)
19,20c19,20
<      $watts = $1;
<      $temperature = $2;
---
>      $watts = $2;
>      $temperature = $1;

Please note, the above only works with 1 sensor (the main transmitter), so it is likely to change in the future. For now it suits my need.

Serial killers?

Ever since I added the Current Cost to my Ubuntu server, I was running into the problem that upon booting up, the order of my two (one for the Current Cost unit, and one for an APC SmartUPS) Prolific PL2303 serial ports changed. Each boot, the actual device hanging of the /dev/ttyUSB* nodes would be a complete random choice. And that is not good :(

So I investigated writing some udev rules for them, but unfortunately, the PL2303’s are completely identical to the server, except that their position on the USB host would change. And although I tried to find out a consistent way of determining the correct udev rule, I miserably failed. The only way I was able to find out which device was which, was to issue a

$ cat /dev/ttyUSB0

and waiting if some output would appear on the terminal. The Current Cost unit spits out its data every 6 seconds, so if something showed up, that would be the right one to pick for the cacti data source. The UPS would not show anything at all using the above command.

Reading a bit further on udev rules I noticed that you can also use external programs to name devices. This got me thinking. I would need a small program that would listen on the /dev/ttyUSB* node and timeout if nothing was received within a reasonable time.

Let’s start off with the udev rule that invokes the script:

# /etc/udev/rules.d/60-local.rules
# Determine APC UPS and Current Cost USB ports
KERNEL=="ttyUSB*", \
    ATTRS{idVendor}=="067b", ATTRS{idProduct}=="2303", \
    PROGRAM="/usr/local/bin/usb-dev-test.pl %k", \
    SYMLINK+="%c"

The %k parameter will be ttyUSB0, ttyUSB1, etc, and the script usb-dev-test.pl should output a single word, which will be substituted by udev in the %c parameter. With the help of Device::SerialPort it becomes trivial ;)

#!/usr/bin/perl
# /usr/local/bin/usb-dev-test.pl
 
use Device::SerialPort qw( :PARAM :STAT 0.07 );
 
my $argument = $ARGV[$0];
my $port=Device::SerialPort->new("/dev/$argument");
my $STALL_DEFAULT=8; # how many seconds to wait for new input
my $timeout=$STALL_DEFAULT;
 
$port->read_char_time(0);     # don't wait for each character
$port->read_const_time(1000); # 1 second per unfulfilled "read" call
 
my $chars=0;
my $buffer="";
while ($timeout>0) {
  my ($count,$saw)=$port->read(255); # will read _up to_ 255 chars
  if ($count > 0) {
    $chars+=$count;
    $buffer.=$saw;
 
    # Check here to see if what we want is in the $buffer
    # say "last" if we find it
    last;
  }
  else {
    $timeout--;
  }
}
 
if ($timeout==0) {
  print "apcups";
}
else {
  print "currentcost";
}

And look at the result… Magic!

$ ls -la /dev/ttyUSB* /dev/currentcost /dev/apcups
lrwxrwxrwx 1 root root         7 Jan 26 13:10 /dev/apcups -> ttyUSB0
lrwxrwxrwx 1 root root         7 Jan 26 13:10 /dev/currentcost -> ttyUSB1
crw-rw-rw- 1 root dialout 188, 0 Jan 26 14:09 /dev/ttyUSB0
crw-rw-rw- 1 root dialout 188, 1 Jan 26 11:54 /dev/ttyUSB1

Lies, damned lies, and statistics

I’ve been using a 1 wire network for quite some time now, but when I deleted a directory to much on my server, I lost a lot of the stats that I had gathered. A couple of weeks ago I finally got my behind in gear again and rebuild my network, this time making sure it all gets backed up ;)

One day I’ll write something about how it’s all been done, but for now you’ll have to suffice with some pretty graphs.

Here’s the daily graph for the temperatures in our bedrooms for the past 24 hours:

Daily temperatures Bedrooms

And recently I added a Current Cost meter to my network, which gives me the shocking facts about my electricity usage for the past 24 hours:

Daily electricy usage

The above graphs are updated hourly, and I’ve got other graphs too, extending the period of graphing. You can find them here for the time being.

Update 25.1.2009

And now you’re able to follow the stats on twitter: http://twitter.com/awoogadotnl