#!/usr/bin/perl -w # Reads data from a Current Cost device via serial port. # Based on code from http://www.jibble.org/currentcost/ # Modified by Ben Smithurst - http://www.bensmithurst.com/currentcost/ use strict; use Time::localtime; use Device::SerialPort qw( :PARAM :STAT 0.07 ); use DBI; use Sys::Syslog; use Time::HiRes qw(time); # You might want to set these my @PORTS = qw(/dev/cuaU0 /dev/ucom0); my $USER = "currentcost"; my $DBFILE = "sqlite.db"; my $RRDFILE = 'powertemp.rrd'; my $DEFINT = 6; my $PORT; my $sqlite; openlog('currentcost', 'pid'); # error handling $SIG{__DIE__} = sub { syslog('notice', "@_"); print STDERR "@_\n"; exit 1; }; $SIG{__WARN__} = sub { syslog('notice', "@_"); print STDERR "@_\n"; }; die "$DBFILE does not exist - maybe you need to run 'initdb.sh'" unless -f $DBFILE; $sqlite = DBI->connect("dbi:SQLite:dbname=$DBFILE", "", "") or die "Cannot open $DBFILE"; foreach my $p (@PORTS) { if (-e $p) { $PORT = $p; last; } } if (!$PORT) { die "Cannot find a valid port"; } my $ob = Device::SerialPort->new($PORT) or die "Cannot create SerialPort for $PORT: $!"; $ob->baudrate(9600); $ob->write_settings; open(SERIAL, "+>$PORT") or die "Cannot open $PORT: $!"; my $uid = getpwnam($USER) or die "Cannot get uid for $USER user"; $< = $> = $uid; my $last; while (my $line = ) { if ($line =~ m!
(\d+)(\d+)(\d+).*(\d+).*([\d.]+)!) { my ($dev_hr, $dev_min, $dev_sec, $watts, $temp) = ($1, $2, $3, $4, $5); my ($real_hr, $real_min, $real_sec); my ($dev_time, $dev_secs, $real_secs, $offset, $delta, $joules); my $now = time; my $tm = localtime $now; $real_hr = $tm->hour; $real_min = $tm->min; $real_sec = $tm->sec; $dev_time = sprintf('%02d:%02d:%02d', $dev_hr, $dev_min, $dev_sec); $real_secs = ($real_hr * 3600) + ($real_min * 60) + $real_sec; $dev_secs = ($dev_hr * 3600) + ($dev_min * 60) + $dev_sec; $offset = $dev_secs - $real_secs; if ($last) { $delta = $now - $last; $joules = $watts * $delta; } else { $delta = "NULL"; $joules = $watts * $DEFINT; } # update RRD system("rrdtool update $RRDFILE N:$watts:$temp"); # store in SQLite $sqlite->do("INSERT INTO readings (ts, watts, temp, device_time, device_offset, ts_delta, joules) VALUES (DATETIME('now', 'localtime'), $watts, $temp, '$dev_time', $offset, $delta, $joules)"); # log to syslog syslog('info', "Power $watts, Temperature $temp"); $last = $now; } }