Harry Rose

Home » Perl » CurrentCost

Current Cost

Recently I bought a Current Cost CC128 so I could monitor my electricity usage (it also monitors the temperature of the room in which you place the base station). In order to gather data from the base station I also bought an RJ45-USB cable, which is also available from the same company. When plugged in, the current cost spams a load of XML to you every 6 seconds, which you must then parse (or do as I did below and just use regex) in order to get the data you want.

The script is heavily based on the one from Paul Mutton, but I've modified it slightly to fit my needs.

The machine I currently use for logging the data is my laptop (which is running Linux) and unfortunately I need to use it away from the flat occasionally, which means I need to unplug it from the current cost, and then remember to start the logging script when I returned. I'm a forgetful person, so I decided to see if I could automate this step (and it turns out you can with udev).

Below is the udev rule that I created, which creates a symlink /dev/currentCost to the current cost device, which for me was usually /dev/ttyUSB0 (but as far as I'm aware, that isn't guaranteed to be constant, so by telling udev to symlink /dev/currentCost to it we can be sure that the value we place in the script later is pointing to the correct device). As well as creating the symlinks, it also runs /usr/bin/currentCost, which is described below.

SUBSYSTEMS=="usb",ATTRS{idVendor}=="067b",ATTRS{idProduct}=="2303",SYMLINK+="currentCost",RUN+="/usr/bin/currentCost"

Below is the code that does the actual logging. Hopefully the comments explain most of the script. If you want more information on RRD tool there is some more information on the Paul Mutton link above, or here.

#!/usr/bin/perl -w
#
# Reads data from a Current Cost device via serial port.
#
 
use strict;
use Device::SerialPort qw( :PARAM :STAT 0.07 );
use Data::Dumper;
 
$| = 1;
 
 
#
# Configuration
#
 
my $pathToRRDDB = "/home/harry/electricity/power.rrd";
my $PORT = "/dev/currentCost";
 
#
# End Configuration
#
 
# Since this forks off, we should check that there aren't already instances
# of the script running.  There is probably a better way of doing this...
my $noRunning = `ps aux | grep "/usr/bin/currentCost" | grep "perl" | grep -v "grep" | wc -l`;
 
chomp($noRunning);
 
if($noRunning > 1) #There is already an instance running in the background somewhere.
{
    print "CurrentCost Already Running ($noRunning instances). Exiting";
    exit;
}
 
# Fork off, this is so we can detach from the terminal (if we don't do this
# udev will become blocked)
if(!fork())
{
    print "Daemonising\n";
    &main;
}
else
{
    exit;
}
 
sub main
{
    my $ob = Device::SerialPort->new($PORT);
 
    $ob->baudrate(57600);
    $ob->write_settings;
 
    open(SERIAL, "+>$PORT");
    while (my $line = <SERIAL>) {
        if ($line =~ m!<time>([\d:]+)</time>.*<tmpr>(-?[\d.]+)</tmpr>.*<ch1><watts>0*(\d+)</watts></ch1>!) {
        my $watts = $3;
        my $temp = $2;
        my $time = $1;
        
        # Put the data into the databse. 
        system("rrdtool update $pathToRRDDB N:$watts:$temp");
        }
    }
}

OK, so we have the data being logged (yay), how do we draw graphs with it? Well, here's another script that I have cron run every so often.

#!/bin/bash
 
GRAPHPATH=/home/harry/electricity/graphs/
RRDPATH=/home/harry/electricity/power.rrd
 
if [[ ! -d $GRAPHPATH ]];
then
    mkdir $GRAPHPATH;
fi;
 
function makegraph {    
    #TYPE=$1
    #LENGTH=$2
    #YAXIS=$3
    #ADDITIONALARGS=$4
    rrdtool graph $GRAPHPATH$1-$2.png \
    --start end-$2 --width 700 --end now --slope-mode \
    --no-legend --vertical-label $3 $4 \
    --alt-autoscale-max \
    DEF:$1=$RRDPATH:$1:AVERAGE \
    DEF:${1}Min=$RRDPATH:$1:MIN \
    DEF:${1}Max=$RRDPATH:$1:MAX \
    CDEF:${1}Range=${1}Max,${1}Min,- \
    LINE1:${1}Min: \
    AREA:${1}Range#0000FF11:"Error Range":STACK \
    LINE1:${1}Min#0000FF33:"Min" \
    LINE1:${1}Max#0000FF33:"Max" \
    LINE1:$1#0000FF:"Average"
}
 
function makepowergraph {
    makegraph Power $1 Watts "--lower-limit 0"
}
 
function maketempgraph {
    makegraph Temperature $1 Celcius -Y
}
 
makepowergraph $1
maketempgraph $1

Basically just run that script with a length of time as the parameter (e.g 4h for a graph of the past four hours), and it'll generate an electricity usage graph and a temperature graph for that time period. Fun.

Extensions

In the future I plan on using the history information provided by the Current Cost device to fill in the gaps from when I've disconnected my laptop from the current cost, so watch this space for future versions.

Example Output

Here are some graphs of the past day that I have generated (I have a cron job that uploads the graphs to the web every 5 minutes provided the current cost is plugged in).

Power consumption

Power consumption over the past 24h

Temperature

Temperature of my flat over the past 24h