At the weekend, my latest gadgety purchase arrived, a Currentcost EnviR – This smallish device connects to its own wireless transmitter, which uses a current clamp round your live wire at the electricity meter to measure the amount of electricity being used, and display this in realtime on its 4.5″ LCD screen. You have the ability to set the device with the price you pay per kWh, and the device will also give you an estimate of how much the current rate of consumption would cost you should it continue for the month. The fact that this is only an instantaneous reading was a little shocking when we boiled the kettle and momentarily considered whether we’d need to remortgage the house to EDF this month. The total amount of electricity in kWh for the last 7 and 30 days is displayed, and a small bar graph to see at-a-glance what your electricity usage was yesterday, split into proportions of day, night and evening. Temperature at the display unit is also shown.
The crucial part of the device is that it has another socket embedded in the base – an RS232 output, which, using the supplied cable, can be plugged in via USB, and monitored on a PC. I gather there are official applications to read and process this data, but a) a lot of these are windows only (though at least one has a linux executable) and b) where’s the fun in that?
So, with that in mind, and some slightly modified scripts that Alan Pope posted, I got my server reading the serial output from the Envir.
To log this, we use RRDTool, which first needs to be initialised to say what we want to capture. We do this with a bash script:
#!/bin/bash rrdtool create powertemp.rrd --step 5 \ DS:Power:GAUGE:180:0:U \ DS:Temperature:GAUGE:180:U:U \ RRA:AVERAGE:0.5:1:3200 \ RRA:AVERAGE:0.5:6:3200 \ RRA:AVERAGE:0.5:36:3200 \ RRA:AVERAGE:0.5:144:3200 \ RRA:AVERAGE:0.5:1008:3200 \ RRA:AVERAGE:0.5:4320:3200 \ RRA:AVERAGE:0.5:52560:3200 \ RRA:AVERAGE:0.5:525600:3200 \ RRA:MIN:0.5:1:3200 \ RRA:MIN:0.5:6:3200 \ RRA:MIN:0.5:36:3200 \ RRA:MIN:0.5:144:3200 \ RRA:MIN:0.5:1008:3200 \ RRA:MIN:0.5:4320:3200 \ RRA:MIN:0.5:52560:3200 \ RRA:MIN:0.5:525600:3200 \ RRA:MAX:0.5:1:3200 \ RRA:MAX:0.5:6:3200 \ RRA:MAX:0.5:36:3200 \ RRA:MAX:0.5:144:3200 \ RRA:MAX:0.5:1008:3200 \ RRA:MAX:0.5:4320:3200 \ RRA:MAX:0.5:52560:3200 \ RRA:MAX:0.5:525600:3200
Now that’s set up, we need to read data into powertemp.rrd. The following perl script runs in the background, reads /dev/ttyUSB0, and updates RRDTool with power and temperature values:
#!/usr/bin/perl -w # Reads data from a Current Cost device via serial port. BEGIN { push @INC,"/usr/lib/perl5/"; } use strict; use Device::SerialPort qw( :PARAM :STAT 0.07 ); my $PORT = "/dev/ttyUSB0"; my $meas = 0; my $sumW = 0; my $sumT = 0; my $watts; my $temp; my $wget; my $ob = Device::SerialPort->new($PORT) || die "Can't open $PORT: $!\n"; $ob->baudrate(57600); $ob->write_settings; open(SERIAL, "+>$PORT"); while (my $line = <SERIAL>) { #print "$line\n"; if ($line =~ m!<tmpr> *([\-\d.]+)</tmpr>.*<ch1><watts>0*(\d+)</watts></ch1>!) { my $watts = $2; my $temp = $1; print "$watts, $temp\n"; system("rrdtool update powertemp.rrd N:$watts:$temp"); } }
We also run the following script in the background to generate the power and temperature graphs required, every 50 seconds:
#!/bin/sh while [ 1 -lt 2 ] do rrdtool graph ~/cc/power-10min-l.png \ --start end-10m --width 1100 --end now --slope-mode \ --vertical-label Watts --lower-limit 0 \ --alt-autoscale-max \ --title "10 minutes" \ DEF:Power=powertemp.rrd:Power:AVERAGE \ DEF:PowerMin=powertemp.rrd:Power:MIN \ DEF:PowerMax=powertemp.rrd:Power:MAX \ CDEF:PowerRange=PowerMax,PowerMin,- \ LINE1:PowerMin: \ AREA:PowerRange#0000FF11:"Error Range":STACK \ LINE1:PowerMin#0000FF33:"Min" \ LINE1:PowerMax#0000FF33:"Max" \ LINE1:Power#0000FF:"Average" > /dev/null rrdtool graph ~/cc/temp-10min-l.png \ --start end-10m --width 1100 --end now --slope-mode \ --no-legend --vertical-label Temperature --lower-limit 0 \ --alt-autoscale-max \ --title "10 minutes" \ DEF:Temp=powertemp.rrd:Temperature:AVERAGE \ DEF:TempMin=powertemp.rrd:Temperature:MIN \ DEF:TempMax=powertemp.rrd:Temperature:MAX \ CDEF:TempRange=TempMax,TempMin,- \ LINE1:TempMin: \ AREA:TempRange#ff00FF11:"Error Range":STACK \ LINE1:TempMin#ff00FF33:"Min" \ LINE1:TempMax#ff00FF33:"Max" \ LINE1:Temp#ff00FF:"Average" > /dev/null rrdtool graph ~/cc/power-60min-l.png \ --start end-60m --width 1100 --end now --slope-mode \ --no-legend --vertical-label Watts --lower-limit 0 \ --alt-autoscale-max \ --title "60 minutes" \ DEF:Power=powertemp.rrd:Power:AVERAGE \ DEF:PowerMin=powertemp.rrd:Power:MIN \ DEF:PowerMax=powertemp.rrd:Power:MAX \ CDEF:PowerRange=PowerMax,PowerMin,- \ LINE1:PowerMin: \ AREA:PowerRange#0000FF11:"Error Range":STACK \ LINE1:PowerMin#0000FF33:"Min" \ LINE1:PowerMax#0000FF33:"Max" \ LINE1:Power#0000FF:"Average" > /dev/null rrdtool graph ~/cc/temp-60min-l.png \ --start end-60m --width 1100 --end now --slope-mode \ --no-legend --vertical-label Temperature --lower-limit 0 \ --alt-autoscale-max \ --title "60 minutes" \ DEF:Temp=powertemp.rrd:Temperature:AVERAGE \ DEF:TempMin=powertemp.rrd:Temperature:MIN \ DEF:TempMax=powertemp.rrd:Temperature:MAX \ CDEF:TempRange=TempMax,TempMin,- \ LINE1:TempMin: \ AREA:TempRange#ff00FF11:"Error Range":STACK \ LINE1:TempMin#ff00FF33:"Min" \ LINE1:TempMax#ff00FF33:"Max" \ LINE1:Temp#ff00FF:"Average" > /dev/null rrdtool graph ~/cc/power-6h-l.png \ --start end-360m --width 1100 --end now --slope-mode \ --no-legend --vertical-label Watts --lower-limit 0 \ --alt-autoscale-max \ --title "6 Hours" \ DEF:Power=powertemp.rrd:Power:AVERAGE \ DEF:PowerMin=powertemp.rrd:Power:MIN \ DEF:PowerMax=powertemp.rrd:Power:MAX \ CDEF:PowerRange=PowerMax,PowerMin,- \ LINE1:PowerMin: \ AREA:PowerRange#0000FF11:"Error Range":STACK \ LINE1:PowerMin#0000FF33:"Min" \ LINE1:PowerMax#0000FF33:"Max" \ LINE1:Power#0000FF:"Average" > /dev/null rrdtool graph ~/cc/temp-6h-l.png \ --start end-360m --width 1100 --end now --slope-mode \ --no-legend --vertical-label Temperature --lower-limit 0 \ --alt-autoscale-max \ --title "6 Hours" \ DEF:Temp=powertemp.rrd:Temperature:AVERAGE \ DEF:TempMin=powertemp.rrd:Temperature:MIN \ DEF:TempMax=powertemp.rrd:Temperature:MAX \ CDEF:TempRange=TempMax,TempMin,- \ LINE1:TempMin: \ AREA:TempRange#ff00FF11:"Error Range":STACK \ LINE1:TempMin#ff00FF33:"Min" \ LINE1:TempMax#ff00FF33:"Max" \ LINE1:Temp#ff00FF:"Average" > /dev/null rrdtool graph ~/cc/power-1day-l.png \ --start end-1d --width 1100 --end now --slope-mode \ --no-legend --vertical-label Watts --lower-limit 0 \ --alt-autoscale-max \ --title "24 Hours" \ DEF:Power=powertemp.rrd:Power:AVERAGE \ DEF:PowerMin=powertemp.rrd:Power:MIN \ DEF:PowerMax=powertemp.rrd:Power:MAX \ CDEF:PowerRange=PowerMax,PowerMin,- \ LINE1:PowerMin: \ AREA:PowerRange#0000FF11:"Error Range":STACK \ LINE1:PowerMin#0000FF33:"Min" \ LINE1:PowerMax#0000FF33:"Max" \ LINE1:Power#0000FF:"Average" > /dev/null rrdtool graph ~/cc/temp-1day-l.png \ --start end-1d --width 1100 --end now --slope-mode \ --no-legend --vertical-label Temperature --lower-limit 0 \ --alt-autoscale-max \ --title "1 day" \ DEF:Temp=powertemp.rrd:Temperature:AVERAGE \ DEF:TempMin=powertemp.rrd:Temperature:MIN \ DEF:TempMax=powertemp.rrd:Temperature:MAX \ CDEF:TempRange=TempMax,TempMin,- \ LINE1:TempMin: \ AREA:TempRange#ff00FF11:"Error Range":STACK \ LINE1:TempMin#ff00FF33:"Min" \ LINE1:TempMax#ff00FF33:"Max" \ LINE1:Temp#ff00FF:"Average" > /dev/null rrdtool graph ~/cc/power-7day-l.png \ --start end-7d --width 1100 --end now --slope-mode \ --no-legend --vertical-label Watts --lower-limit 0 \ --alt-autoscale-max \ DEF:Power=powertemp.rrd:Power:AVERAGE \ DEF:PowerMin=powertemp.rrd:Power:MIN \ DEF:PowerMax=powertemp.rrd:Power:MAX \ CDEF:PowerRange=PowerMax,PowerMin,- \ LINE1:PowerMin: \ --title "7 Days" \ AREA:PowerRange#0000FF11:"Error Range":STACK \ LINE1:PowerMin#0000FF33:"Min" \ LINE1:PowerMax#0000FF33:"Max" \ LINE1:Power#0000FF:"Average" > /dev/null rrdtool graph ~/cc/temp-7day-l.png \ --start end-7d --width 1100 --end now --slope-mode \ --no-legend --vertical-label Temperature --lower-limit 0 \ --alt-autoscale-max \ --title "7 Days" \ DEF:Temp=powertemp.rrd:Temperature:AVERAGE \ DEF:TempMin=powertemp.rrd:Temperature:MIN \ DEF:TempMax=powertemp.rrd:Temperature:MAX \ CDEF:TempRange=TempMax,TempMin,- \ LINE1:TempMin: \ AREA:TempRange#ff00FF11:"Error Range":STACK \ LINE1:TempMin#ff00FF33:"Min" \ LINE1:TempMax#ff00FF33:"Max" \ LINE1:Temp#ff00FF:"Average" > /dev/null rrdtool graph ~/cc/power-30day-l.png \ --start end-30d --width 1100 --end now --slope-mode \ --no-legend --vertical-label Watts --lower-limit 0 \ --alt-autoscale-max \ --title "30 Days" \ DEF:Power=powertemp.rrd:Power:AVERAGE \ DEF:PowerMin=powertemp.rrd:Power:MIN \ DEF:PowerMax=powertemp.rrd:Power:MAX \ CDEF:PowerRange=PowerMax,PowerMin,- \ LINE1:PowerMin: \ AREA:PowerRange#0000FF11:"Error Range":STACK \ LINE1:PowerMin#0000FF33:"Min" \ LINE1:PowerMax#0000FF33:"Max" \ LINE1:Power#0000FF:"Average" > /dev/null rrdtool graph ~/cc/temp-30day-l.png \ --start end-30d --width 1100 --end now --slope-mode \ --no-legend --vertical-label Temperature --lower-limit 0 \ --alt-autoscale-max \ --title "30 Days" \ DEF:Temp=powertemp.rrd:Temperature:AVERAGE \ DEF:TempMin=powertemp.rrd:Temperature:MIN \ DEF:TempMax=powertemp.rrd:Temperature:MAX \ CDEF:TempRange=TempMax,TempMin,- \ LINE1:TempMin: \ AREA:TempRange#ff00FF11:"Error Range":STACK \ LINE1:TempMin#ff00FF33:"Min" \ LINE1:TempMax#ff00FF33:"Max" \ LINE1:Temp#ff00FF:"Average" > /dev/null rrdtool graph ~/cc/power-365day-l.png \ --start end-365d --width 1100 --end now --slope-mode \ --no-legend --vertical-label Watts --lower-limit 0 \ --alt-autoscale-max \ --title "1 Year" \ DEF:Power=powertemp.rrd:Power:AVERAGE \ DEF:PowerMin=powertemp.rrd:Power:MIN \ DEF:PowerMax=powertemp.rrd:Power:MAX \ CDEF:PowerRange=PowerMax,PowerMin,- \ LINE1:PowerMin: \ AREA:PowerRange#0000FF11:"Error Range":STACK \ LINE1:PowerMin#0000FF33:"Min" \ LINE1:PowerMax#0000FF33:"Max" \ LINE1:Power#0000FF:"Average" > /dev/null rrdtool graph ~/cc/temp-365day-l.png \ --start end-365d --width 1100 --end now --slope-mode \ --no-legend --vertical-label Temperature --lower-limit 0 \ --alt-autoscale-max \ --title "1 Year" \ DEF:Temp=powertemp.rrd:Temperature:AVERAGE \ DEF:TempMin=powertemp.rrd:Temperature:MIN \ DEF:TempMax=powertemp.rrd:Temperature:MAX \ CDEF:TempRange=TempMax,TempMin,- \ LINE1:TempMin: \ AREA:TempRange#ff00FF11:"Error Range":STACK \ LINE1:TempMin#ff00FF33:"Min" \ LINE1:TempMax#ff00FF33:"Max" \ LINE1:Temp#ff00FF:"Average" > /dev/null sleep 50 done
The graphs are then pushed to an internal webserver where they’re added into a page that refreshes every 60 seconds. I have seperate pages for temperature and power, just so I can look at one variable at a time.
Here’s the Power graphs:
All in all, it’s an interesting device, and definitely worth the £30 I spent on eBay!
here’s a script for making an html index file from all the images in a directory
#!/bin/bash
IDX=index.html
(
echo “”
echo “current cost measurements”
echo “”
for X in *png ; do
echo “$X”
echo “”
done
echo “”
echo “”
) > $IDX