Logging and graphing data from Eco-Eye Smart energy meter.

Energy monitor Linux

I have an Eco-Eye Smart energy meter, and they provide software for Windows, but nothing for Linux.

When I purchased the meter, I also bought the optional USB cable, which emulates a serial port.

This made it quite trivial to connect and read within Linux.

On my Linux server, the device appeared as /dev/ttyUSB0

So I wrote the following bash and Perl scripts to extract the data.

This Perl script runs in the background and reads the amps from the meter, converts them to watts and writes the data to a log file in the form of two columns, time and watts. The log file name is the current date – so the script is killed each night at midnight, and restarted which creates a new log file with the current date.
This script also updates an rrd file which creates a daily graph of energy usage.

Help for the maths (my weak point!) came from contributors on the Science section of the Pistonheads Forums

UPDATE: July 2023 – the old version of the code no longer works with newer versions of Perl – see the new version directly below.

I switched from RRDTool to gnuplot some time ago – so my graphing is done by gnuplot – however I have added a section where the script can be updated to use RRDTool.

New version:

#!/usr/bin/perl
use strict;
use warnings;
use Device::SerialPort qw( :PARAM :STAT 0.07 );
use POSIX qw(strftime);

my $PORT = "/dev/ttyUSB0";
my $mains_voltage = 240;
my $date = strftime "%d-%m-%Y", localtime;
my $logfile = "/usr/local/etc/energy_meter_logs/$date.log"; # file name and path for daily logfile

my $ob = Device::SerialPort->new($PORT) || die "Can't Open $PORT: $!";
$ob->baudrate(19200) || die "failed setting baudrate";
$ob->parity("none") || die "failed setting parity";
$ob->databits(8) || die "failed setting databits";
$ob->stty_icrnl(1) || die "failed setting convert cr to new line";
$ob->handshake("none") || die "failed setting handshake";
$ob->write_settings || die "no settings";
$ob->write_settings;

# open the log file
open(my $f1, '>>', $logfile) or die "Unable to open $logfile [$!]\n";

open(SERIAL, "+>$PORT");
while (my $amps = ) {
my $watts = $amps * $mains_voltage;
my $datestring = strftime "%H:%M:%S", localtime;
# write to log file
print $f1 "$datestring,$watts\n";
$f1->flush;
}

$f1->close();
$ob->close();

If you want to use RRDTool

Remove these two lines:

# open the log file
open(my $f1, '>>', $logfile) or die "Unable to open $logfile [$!]\n";

Remove this line:

my $logfile = "/usr/local/etc/energy_meter_logs/$date.log"; # file name and path for daily logfile

And add this line:

my $rrd_file = "/energy.rrd"; # rrd file

Remove these three lines:

my $datestring = strftime "%H:%M:%S", localtime;
print $f1 "$datestring,$watts\n";
$f1->flush;

Replace with these two lines:

my $cmd = ("/usr/bin/rrdtool update $rrd_file -t energy N:$watts");
system($cmd);

Old version:

#!/usr/bin/perl
#
# The serial IO needs to be terminated with a new line and not a carriage return.
# A line has been added (stty_icrnl) to the line in the tty setup below that converts CR to NL
# Requires: Device::SerialPort
use Device::SerialPort;
use POSIX qw(strftime);
$date = strftime "%d-%m-%Y", localtime;
$PORT = "/dev/ttyUSB0"; # port to watch
#
# Serial Settings
#
# note the need to convert carriage returns to new lines to terminate each read. (stty_icrnl)
$ob = Device::SerialPort->new($PORT) || die "Can't Open $PORT: $!";
$ob->baudrate(19200) || die "failed setting baudrate";
$ob->parity("none") || die "failed setting parity";
$ob->databits(8) || die "failed setting databits";
$ob->stty_icrnl(1) || die "failed setting convert cr to new line";
$ob->handshake("none") || die "failed setting handshake";
$ob->write_settings || die "no settings";
#
# edit these settings after selecting the correct serial port parameters.
#
my $logfile = "/usr/local/etc/energy_meter_logs/$date.log"; # file name and path for daily log file
my $rrd_file = "/var/www/eluna/html/rrd/13_energy/energy.rrd"; # rrd file
my $mains_voltage = "243";
#
# open the logfile, and Port
#
open(my $fh, '>>', $logfile) or die "Unable to open $logfile $!\n";
open( DEV, "<$PORT" ) || die "Cannot open $PORT: $_";
#
# Loop forever, logging data to the log file
#
while ( $_ =  ) { # print input device to file
my $amps = $_;
my $watts = ($amps * $mains_voltage) ;
$datestring = strftime "%H:%M:%S", localtime;
my $cmd = ("/usr/bin/rrdtool update $rrd_file -t energy N:$watts");
system($cmd);
print $fh "$datestring,$watts\n";
$fh->flush;
}
close $fh;
undef $ob;
#
# eof
#

The following bash script reads the log file and drops the first column (we’re only interested in watts which is the second column) and then using a Perl command it computes the overall daily usage, and then sends an email with said usage on a daily basis.
This script is also run from cron, and runs a few minutes after the job that kills the above Perl script.

#!/bin/bash
#
date=$(date +%d-%m-%Y --date='1 days ago')
#
logfile="/usr/local/etc/energy_meter_logs/${date}.log"
tmpfile="/tmp/energyout.txt"
#
cat $logfile |awk -F "," '{print $2}' > $tmpfile
#
kwday=$(perl -nle' $s += $_; END { printf "%.2f", $s*4/3600000 } ' $tmpfile)
#
echo "${kwday} kWh" | mail -s "Power usage for $date" [your email address here]
#
rm -f $tmpfile
#
# eof
#

My daily graph, which is produced by the Eluna graph system.