Home... Help... Search... Computers... Science...


Reading a CurrentCost CC128 ENVI Power Monitor using Debian Linux

The CC128 ENVI Power Monitor

The CC128 ENVI Power Monitor is cheap and does work pretty well, with its wireless data transmitter connected to the house's main power switchboard. To get data out of it, I use the optional serial cable with its built-in USB convertor, plugged into my Debian Linux server.

Gathering the Data

I adapted the following PERL script from one I found on the Net. It just sits passively waiting for serial data to arrive, ie, it sends nothing to the CC128. I expect the CC128 can receive signals, but my scheme does not use any. At intervals the CC128 dumps out historic data it has stored, and the script filters this into a separate history file, in case I ever have a need for it.

#!/usr/bin/perl -w
# cc6.pl
#
#Original Perl code by Paul Mutton.
#See http://www.jibble.org/currentcost/
#Updated for CC128 by Mark E Taylor. April 2009.
#http://metphoto.homeunix.net/met_current/
#http://metphoto.net
# Reads data from a Current Cost device via USB/serial port.
# modified 2011 by Tardus, to parse the data stream into "current" value and "history" value files.
# modified 2013 by Tardus to pass the serial port as an argument. With 
# multiple USB serial devices, eg, an Arduino as well as the PL2303 used by
# the CC128, we cannot be sure which port gets assigned to the PL2303,
# hence cannot hard code it in this script.

use strict;
use Device::SerialPort qw( :PARAM :STAT 0.07 );
#my $PORT = "/dev/ttyUSB0";
# port now passed via argument to cc6.pl
print $ARGV[0];
my $PORT = "$ARGV[0]";
my $ob = Device::SerialPort->new($PORT);
$ob->baudrate(57600); #For CC Classic use 9600 for CC128 use 56700.
#$ob->databits(8);
#$ob->parity("none");
#$ob->stopbits(1);
$ob->write_settings;
open(SERIAL, "+>$PORT");
while (my $line = <SERIAL>) {
    if ( length($line) > 240 ) {
        print ("HISTORY: $line" );
        open (HISTFILE, '>>powerhist.txt');
        print HISTFILE  "$line\n" ;
        close (HISTFILE);
    } else {
        print ("CURRENT: $line" );
        open (CURRFILE, '>>powercurr.txt');
        print CURRFILE  "$line\n" ;
        close (CURRFILE);
    }
    print "\n";
}

Note: you will need to install the PERL serial module apt-get install libdevice-serialport-perl (as root)

The script logic is to write any files longer than 240 characters to a history file, and shorter ones to a current power file. The history lines the CC128 pumps out at intervals are very long. For now I only use the current power values.

Also, the calling script has to work out what the actual "ttyUSBx" port is and pass it to cc6.pl.

At least with my CC128 the data output is quite dirty, with items dropping out of the xml text stream, and with frequent null characters (ASCII 00) being inserted. The calling script, plotPower1.sh, filters the rubbish out.

Here is a sample:-

powercurr.txt (single line records, wrapped for easier display)
<msg><src>CC128-v1.18</src><dsb>01157</dsb><time>17:24:41</time><tmpr>23.1</tmpr
><sensor>0</sensor><id>02882</id><type>1</type>>c<watts>03152</watts></ch1><ch2>
<watts>00144</watts></ch2></msg>^M

<msg><src>CC128-v1.18</src><dsb>01157</dsb><time>17:24:48</time><tmpr>23.1</tmpr
><sensor>0</sensor><id>02882</id><type>1</type><ch1><watts>03168</watts></ch1>
<ch2><watts>00144</watts></ch2></msg>^M

<msg><src>CC128-v1.18</src><dsb>011b7><time>17:25:50</time><tmpr>23.1</tmpr>
<sensor>0</sensor><id>02882</id><type>1</type><ch1><watts>01274</watts></ch1>
<ch2><watts>00003</watts></ch2></msg>^M

The "^@" characters are nulls that don't belong here. Note to that the third line has lost the closing "</dsb>". The second line is OK.

Processing the data

The following bash shell script runs every 10 minutes, activated by an entry in the crontab scheduler. You might find my brief guide to BASH helpful, if you are not familiar with BASH scripts

#!/bin/sh
# plotPower1.sh
# get the latest house power Kw figures and use it to plot with mrtg
# also add to a history file for any desired later processing (just in case!)
# Tardus 27 Jul 2011
# altered 6 March 2012 to use direct ENVI pickup from this Linux machine
# data is now in the powercurr.txt file
# Revised November 2013 to better handle the dirty data from the CC128

cd ~/monitor

#check to see if the CurrentCost ENVI data receiving script is running
if [ ! $(pidof -x cc6.pl) ]; then
    echo "cc6 is NOT running"
    echo "starting cc6.pl"
    # find what port the CC128's pl2303 usb serial convertor is on
    PORT=`dmesg|grep ttyUSB|awk '/pl2303/ {print $NF}'`
    echo "PORT=$PORT"
    # run cc6.pl in the background, passing it the port to use
    nohup ./cc6.pl "/dev/"$PORT > ./cc6.log 2>&1 &
else
    echo "cc6 is running"
    cp powercurr.txt powercurr.tmp
    rm powercurr.dat
        # parse the xml data and clean it up as much as possible
        # also turning each multi-line record (output by xml2)
        # into a single line record without the "=" signs
        # this is done by the tr command, which translates = and newlines
        # into spaces
    while read LINE
    do
        echo $LINE | xml2 |tr '\n=' ' ' >> powercurr.dat
        echo " "						>> powercurr.dat
    done < powercurr.tmp
        # now we use awk to test for uncorrupted records and average the 
        # data over the approx. 10 minute collection period
    awk -f getAverage.awk powercurr.dat > latestHousePower.txt
        # and get the last line into a separate file
    tail -1 latestHousePower.txt > latestHousePower.dat
    echo `date` "latestHousePower.dat file just written"
        # and add its contents to a history file, in case I ever find a use
        # for it.
    awk '{print strftime(systime()),$0}' latestHousePower.dat >> \
        	latestHousePower.hist

        # reset the input file from the ENVI CC128
    echo "lines in powercurr.txt: " `wc -l powercurr.txt`
    cat powercurr.txt >> powercurr.hist
    cat /dev/null >  powercurr.txt
    cat latestHousePower.txt >> housePower.hist
    echo `date` "===========================" >> housePower.hist
        # plot using MRTG
    env LANG=C mrtg housepower.cfg

    # now send to PVoutput.org
    # get date from Linux
    DATE=`date +"%Y%m%d"`
    TIME=`awk '{print $2}'     		latestHousePower.dat | cut -c1-5`
    TEMPERATURE=`awk '{print $3}'     	latestHousePower.dat`
    CONSUMPTION=`awk '{print $4+$5}'     latestHousePower.dat` 
    echo $DATE $TIME $CONSUMPTION $TEMPERATURE

    
    curl -d "d=$DATE" -d "t=$TIME" -d "v4=$CONSUMPTION" -d "v5=$TEMPERATURE" \
        	-H "X-Pvoutput-Apikey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
        	-H "X-Pvoutput-SystemId: NNNN" \
        	http://pvoutput.org/service/r2/addstatus.jsp 

fi

exit

Here is an example of a cleaned up data file from the CC128:-

powercurr.dat (single line records, wrapped for easier display)
/msg/src CC128-v1.18 /msg/dsb 01157 /msg/time 17:15:17 /msg/tmpr 23.1 
/msg/sensor 0 /msg/id 02882 /msg/type 1 /msg/ch1/watts 00419 
/msg/ch2/watts 00000  
 
/msg/src CC128-v1.18 /msg/dsb 01157 /msg/time 17:16:37 /msg/tmpr 23.1 
/msg/sensor 0 /msg/id 02882  
 
/msg/src CC128-v1.18 /msg/dsb 01157 /msg/time 17:17:26 /msg/tmpr 23.1  
 
/msg/src CC128-v1.18 /msg/dsb 01157 /msg/time 17:18:39 /msg/tmpr 23.1  
 
/msg/src CC128-v1.18 /msg/dsb 01157 /msg/time 17:18:51 /msg/tmpr 23.1 
/msg/sensor 0 /msg/id 02882 /msg/type 1 /msg/ch1/watts 02130 
/msg/ch2/watt /msg/ch2 watts>  
 
/msg/src CC128-v1.18  
 
/msg/src CC128-v1.18 /msg/dsb 01157 /msg/time 17:19:17 /msg/tmpr 23.1 
/msg/sensor 0 /msg/id 02882 /msg/typy pe> /msg/typy/ch1/watts 03252 
/msg/typy/ch2/watts 00144  
 
/msg/src CC128-v1.18 /msg/dsb 01157 /msg/time 17:20:38 /msg/tmpr 23.1 
/msg/sensor 0 /msg/id 02882 /msg/type 1 /msg/ch1/watts 01716 
/msg/ch1/hc2/watts 00008  
 
/msg/src CC128-v1.18 /msg/dsb 01157 /msg/time 17:21:47 /msg/tmpr 23.1
 /msg/sensor 0 /msg/id 02882 /msg/type 1 /msg/ch1/watts 03217  
 
/msg/src CC128-v1.18 /msg/dsb 01157 /msg/time 17:22:12 /msg/tmpr 23.1 
/msg/sensor 0 /msg/id 02882 /msg/type 1 /msg/ch1/watts 03185 
/msg/ch2/watts 00144  

What we want is exactly 18 white-space delimited fields, and exactly 153 characters. Anything else will be rejected by the getAverage.awk script.

# getAverage.awk
BEGIN	{	totalStdWatts=0; totalOffPeakWatts=0; totaltemp=0; count=0
    # 	corr is a correction factor passed by the calling script
    #	if corr is not specified it is forced to "1"
    	if ( corr == "" ) corr=1		}
# find only lines with 18 fields
NF==18	{ 	if ( length ($0) == 153 ) #process only if line has 153 characters
        	{	dsb=$4
        		stamp=substr($6,1,5)
        		temperature=$8
        		stdWatts=$16
        		offPeakWatts=$18
        		totalStdWatts += stdWatts
        		totalOffPeakWatts += offPeakWatts
        		totaltemp += temperature
        		count += 1
        		print dsb,stamp,temperature,stdWatts,offPeakWatts,count,   \
					totaltemp,totalStdWatts,totalOffPeakWatts
        	}
        }	
END	{	avgStdWatts = int (totalStdWatts * corr / count + 0.5 )
        avgOffPeakWatts = int (totalOffPeakWatts / count + 0.5 )
        avgtemp = int (totaltemp / count * 10 + 0.5 ) / 10
        print dsb,stamp,avgtemp,avgStdWatts,avgOffPeakWatts
    }

Here is the latestHousePower.txt file as output by getAverage.awk

01158 15:47 23.2 00769 00002 1 23.2 769 2
01158 15:49 23.1 00760 00003 2 46.3 1529 5
01158 15:49 23.1 00755 00003 3 69.4 2284 8
01158 15:49 23.1 761 3

and the last line which is written to latestHousPower.dat

01158 15:49 23.1 761 3

The 3rd field is the room temperature in degrees Celsius, the 4th is the standard rate power consumption in watts and the 5th is the off-peak power in watts.

Here is the MRTG configuration file I use:-

housepower.cfg

Interval: 10
WorkDir: /home/steve/monitor/mrtg/

Target[single]: `~/monitor/single2mrtg.sh`
Options[single]: growright,integer,gauge,noo
Colours[single]: orange#ffa500,Color2#ff6600,Color3#121212,Color4#191970
MaxBytes[single]: 10000
AbsMax[single]: 15000
WithPeak[single]: ymw
YLegend[single]: Watt
ShortLegend[single]: w
Legend1[single]: w
LegendI[single]: Standard Rate
LegendO[single]: w
Title[single]: Single (Standard) Rate Power Consumed by House 
PageTop[single]: <h1>Single (Standard) Rate Power Consumed by House</h1> 
    Note: time is Australian Eastern Standard Time<br> 

Target[offpeak]: `~/monitor/offpeak2mrtg.sh`
Options[offpeak]: growright,integer,gauge,noo
Colours[offpeak]: black#000000,Color2#ff6600,Color3#001200,Color4#191970
MaxBytes[offpeak]: 10000
AbsMax[offpeak]: 15000
WithPeak[offpeak]: ymw
YLegend[offpeak]: Watt
ShortLegend[offpeak]: w
Legend1[offpeak]: w
LegendI[offpeak]: Offpeak
LegendO[offpeak]: w
Title[offpeak]: Off Peak Rate Power Consumed by House (Water Heating)
PageTop[offpeak]: <h1>Off Peak Rate Power Consumed by House (Water Heating)</h1>
     Note: time is Australian Eastern Standard Time<br> 

Target[housepower]: `~/monitor/housepower2mrtg.sh`
Options[housepower]: growright,integer,gauge
Colours[housepower]: orange#ffa500,black#000000,Color3#121212,Color4#191970
MaxBytes[housepower]: 10000
AbsMax[housepower]: 15000
YLegend[housepower]: Watt
ShortLegend[housepower]: w
Legend1[housepower]: w
LegendI[housepower]: Standard
LegendO[housepower]: Offpeak
Title[housepower]: Total Power Consumed by House 
PageTop[housepower]: <h1>Total Power Consumed by House</h1> 
    Note: time is Australian Eastern Standard Time<br> 

Target[envi-t]: `~/monitor/temperature2mrtg.sh`
Options[envi-t]: growright,integer,gauge
Colours[envi-t]: springgreen#00ee76,color2#000000,Color3#121212,Color4#191970
MaxBytes[envi-t]: 30
AbsMax[envi-t]: 40
WithPeak[envi-t]: ymw
UnScaled[envi-t]: ymwd
YLegend[envi-t]: DegC
ShortLegend[envi-t]: C
Legend1[envi-t]: T 
LegendI[envi-t]: Indoor Temperature
LegendO[envi-t]: Subfloor Temperature
Title[envi-t]: Room Temperature at the CurrentCost ENVI CC128 Monitor Station
PageTop[envi-t]: <h1>Room Temperature at the CurrentCost ENVI CC128  Monitor 
    Station</h1> Note: time is Australian Eastern Standard Time<br>  

And the simple shell scripts that gather the data for mrtg to process:-

#!/bin/sh
# single2mrtg.sh
# extracts data from single rate tariff file and prepares for MRTG

W=`awk '{print int($4)}' ~/monitor/latestHousePower.dat`
UPTIME=0
LABEL="Single (Standard) Rate Power Consumption - Watts"

echo $W
echo $W # MRTG needs 2 variables to plot - we suppress 2nd later
echo $UPTIME
echo $LABEL
#!/bin/sh
# offpeak2mrtg.sh
# extracts data from offpeak rate tariff file and prepares for MRTG

W=`awk '{print int($5)}' ~/monitor/latestHousePower.dat`
UPTIME=0
LABEL="Off Peak Rate Power Consumption (Water Heating) - Watts"

echo $W
echo $W # MRTG needs 2 variables to plot - we suppress 2nd later
echo $UPTIME
echo $LABEL
#!/bin/sh
# housepower2mrtg.sh
# extracts data from single and offpeak rate tariff files and prepares for MRTG

SW=`awk '{print int($4)}' ~/monitor/latestHousePower.dat`
OW=`awk '{print int($5)}' ~/monitor/latestHousePower.dat`
UPTIME=0
LABEL="Total Power Consumption - Watts"

echo $SW
echo $OW
echo $UPTIME
echo $LABEL
#!/bin/sh
# temperature2mrtg.sh
# extracts temperature at the ENVI monitor from single rate tariff file 
# and prepares for MRTG
# added experimental temperature collection of subfloor via digitemp - 10/11/12

TEMP=`awk '{print int($3+0.5)}' ~/monitor/latestHousePower.dat`
UPTIME=0
LABEL="Room Temperature - Degrees C"
SUBTEMP=`fgrep "Sensor 1" ~/monitor/digitemp.log |tail -1 \
        	| awk '{print int($7+0.5)}'` 
echo $TEMP
echo $SUBTEMP
echo $UPTIME
echo $LABEL

Live data display

You can see live data plotted here http://tardus.net/mrtg/


Home... Help... Search... Computers... Science...


This page http://tardus.net/readCC128.html published: 4 Dec 2013

About Tardus

Contact me, "Tardus" Copyright powered by txt2tags

Search tardus.net