Home power Monitoring
About | Current power usage | Summary by hour | Summary by weekday
Note: The charts haven’t been updated in a while since I’m in the process of moving

This is a DIY project using current transducers, an arduino, and some custom software to monitor power consumption for an entire house. The power measurements are graphed and made public on a webserver.
The end result is a slightly cheaper hack of the The Energy Detective.
This data shared online is currently represented as both current power consumption as well as as summary charts.
- What this can do is visualize when appliances, lights, computers, etc are using home power.
- What this cannot do is detect smaller devices like cellphone chargers, dangling wallwarts or anything else that consumes less than 10Watts.
If you have questions or comment feel free to send me mail or leave a message on the hack-a-day comment thread.
Similar projects
There are a number of similar projects already out there for home power monitoring. If you have a project similar to this one not listed here I would love to hear about it.
- Jason Winters’ Pico-Projects – Similar project using CTs with an IO bridge
- ladyada’s tweet-a-watt – Uses a Kill-a-Watt for monitoring power usage on one outlet
- Pluggy is a geek – amazing “let’s monitor everything possible” project. This is very interesting because he compares power usage monitored by CTs vs monitoring power at the meter.
Overview Diagram

Materials
- Current Transducers – $46.00 for 2
- Arduino Diecimilia Microcontroller ~ $20
- Arduino Ethernet Shield ~ $45
- Small sheet plexiglass with mounting screws and standoffs ~ $5
- Router capable of running openwrt or something can serve a cgi script (optional) ~ $40
- Web server to host the power charts (optional) ~ $5/month
Total cost ~ $110 (not counting what I already had lying around) If money is tight there are a few things that can make this cheaper by about fifty bucks:
- Adding a serial port to a router running openwrt or using a dedicated computer connected to the arduino serial. This will elimate the need for the ethernet shield which is a very expensive component
- Hosting the charts locally or on a server with a dedicated, static ip address will eliminate the need for the openwrt router as well as the ethernet shield (more details on that later)
- Web hosting is optional if you only want to view the data locally and you have a machine that’s always on at home. A cheap netbook would be sufficient for the task.
Accuracy
Here are some factors that will influence accuracy for all current transducer monitoring systems like this one.
Power Factor
Power factor is a number between 0 and 1 and is the ratio of real power to the product of the rms current times the rms voltage. Power factor differs from device to device and will need to be approximated to caculate over all power usage. A power factor of .60 will be used as an approximation for the overall power calculation. In order to calculate power factor the voltage would need to be monitored as well as the current for each phase.
Voltage
Voltage can vary depending on what is connected to the home. For calculating power the voltage will be approximated to be 120V(rms).
Accuracy of the ADC
Measuring the voltage from the CT is done using an Arduino microcontroller. With 3.3V as the analog reference the resolution of the ADC is .0032mV. This voltage on the CT is 213mA of current which corresponds to an apparent power resolution of ~ 25Watts. This means the apparent power calculations on the arduino will only be as accurate as the resolution.
RMS vs Peak Approximations
In the first version of this project a very simple peak voltage calculation was being used with a fudge factor to make a guess at the scaling factor for overall power.
To improve this slightly the arduino is now making an RMS caluculation instead of using the peak value.
Because the signal from the CT is not level shifted the arduino only sees the signal when it is above zero volts. Instead of applying a DC bias to the signal only half the samples will be used for the RMS calculation. Assuming the signal is symetrical on the X-axis the following code calculates an approximate RMS value for a specified number of evenly spaced samples.
float rms_val1 = 0;
float rms_val2 = 0;
for (int cnt=0; cnt
val1 = analogRead(S1_PIN);
val2 = analogRead(S2_PIN);
rms_val1 = rms_val1 + sq( (float)val1 );
rms_val2 = rms_val2 + sq( (float)val2 );
}
rms_val1 = sqrt(rms_val1 / (SAMPLES/2) );
rms_val2 = sqrt(rms_val2 / (SAMPLES/2) );
A 100W spotlight, a fan, a toaster oven and a computer were used as devices to test the accuracy of the home power monitor.

For each device the CT was hooked up to an oscilliscope as well as a DMM to measure the RMS voltage of the CT. During the testing one of the power phases was shut completely off with the exception of the device being tested. (the scope and arduino were on the other phase, isolated from the device being tested) The toaster oven also makes a good firestarter.
Kill-a-watt measuremnts
- Voltage = voltage measurement on the Kill-a-Watt
- Current = current measurement on the Kill-a-Watt
- Power = power measurement on the Kill-a-Watt
- Power factor = ratio of voltage x current to the measured power
Arduino measurements
- RMS measurement = The value recorded by the ADC from the CT
- Voltage = ADC value converted to voltage ( value * .0032 )
- CT Voltage Accuracy = The ratio of the measured voltage to the voltage measu red on the CT with a DMM
- Calculated Current = (Voltage) * 200 / 3
- Current Accuracy = The ratio of the calculated current to the measurement ma de by the Kill-a-Watt
| Device / Measurements | Measurements on the Kill-a-Watt | Measurements on the Arduino |
|---|---|---|
| Spotlight
CT DMM measurement = .015Vrms |
|
|
| Fan
CT DMM measurement = .022Vrms |
|
|
| Toaster Oven
CT DMM measurement = .166Vrms |
|
|
| Computer
CT DMM measurement = .032Vrms |
|
|
Hardware

The analog to digital converter on the Arduino has a 10bit resolution. This means it can measure 2^10 or 1024 distinct states. A spec sheet wasn’t available from the CT which makes it difficult to calculate the power conversion. The output of the CT is 0-3V and since the default range of the ADC is 0-5V the analog reference was tied to 3.3V through a 5k resistory (pictured below). For a 0-3.3V input on the ADC / 1024 bits the arduino will measure 3.2mv for every bit.
Installation of the clamp-on current transducers and mounting the arduino was the easiest part of this project. Using plexiglass, screws and stand-offs the arduino was mounted next to the breaker box. The CTs were clamped on the mains and fed through the side down to the arduino analog inputs.
The waveforms that come off the CTs are pictured on the right below. (right click for higher resolution). Between the two phases there 180degree difference as expected.
![]() |
![]() |
![]() |
Software
Arduino Sketch
The arduino samples the the input from the ADC and posts it to a cgi sitting on the linksys router using the ethernet shield. The input is sinusoidal so the rms value is calculated for 10k samples. Once the sampling is complete the arduino takes NUM_READINGS and averages them together which is posted to the cgi.
The rate at which the arduino sends data to the webserver tobe recorded in the database is about 1 measurement every 20 seconds.
#include
#define S1_PIN 0 // input pin for first inductive sensor
#define S2_PIN 5 // input pin for second inductive sensor
#define SAMPLES 10000 // number of samples to take
#define NUM_READINGS 10 // number of readings to average
int val1 = 0;
int val2 = 0;
int reading_cnt = 0; // counter for 1 second samples
float total_rms1 = 0;
float total_rms2 = 0;
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192, 168, 0, 177 };
byte gateway[] = { 192, 168, 0, 1 };
byte subnet[] = { 255, 255, 255, 0 };
byte server[] = { 192, 168, 0, 1 }; // router.springfield
Client client(server, 80);
void setup() {
Ethernet.begin(mac, ip, gateway, subnet);
analogReference(EXTERNAL);
Serial.begin(9600);
delay(1000);
Serial.println("Connecting...");
}
void loop() {
int max_val1 = 0;
int max_val2 = 0;
float rms_val1 = 0;
float rms_val2 = 0;
for (int cnt=0; cnt < SAMPLES; cnt++) { val1 = analogRead(S1_PIN); val2 = analogRead(S2_PIN); rms_val1 = rms_val1 + sq((float)val1); rms_val2 = rms_val2 + sq((float)val2); } rms_val1 = sqrt(rms_val1 / (SAMPLES/2) ); rms_val2 = sqrt(rms_val2 / (SAMPLES/2) ); total_rms1 = total_rms1 + rms_val1; total_rms2 = total_rms2 + rms_val2; reading_cnt++; if (reading_cnt >= NUM_READINGS) {
float average_rms1 = total_rms1 / NUM_READINGS;
float average_rms2 = total_rms2 / NUM_READINGS;
Serial.print("AVG VALUES *RMS* - ");
Serial.print(average_rms1);
Serial.print(" ");
Serial.println(average_rms2);
if (client.connect()) {
Serial.println("Sending data");
client.print("GET /cgi-bin/relay.pl?value1=");
client.print(average_rms1);
Serial.print(" ");
Serial.println(average_rms2);
if (client.connect()) {
Serial.println("Sending data");
client.print("GET /cgi-bin/relay.pl?value1=");
client.print(average_rms1);
client.print("&value2=");
client.print(average_rms2);
client.println(" HTTP/1.1");
client.println();
client.stop();
} else {
Serial.println("Failed to connect to client");
}
total_rms1 = 0;
total_rms2 = 0;
reading_cnt = 0;
}
}
Moving the data from the arduino to shared web hosting
Router on the local network
The arduino ethernet shield is not capable of DNS lookups which means it needs to talk to something that has a static ip address. Most shared web hosting consist of multiple servers that use the dns name to route http requests. To work around this issue a linksys router running the openwrt linux operating system was used to host a cgi that relays the data from the arduino to my web hosting.
use Socket;
use strict;
print "Content-Type: text/html; charset=ISO-8859-1nn";
# Read the reading from the GET request
my @qstring = split ('&', $ENV{'QUERY_STRING'});
die "wrong number of values" unless (scalar @qstring == 2);
# Relay the readings to power.jarv.org
socket(SH, PF_INET, SOCK_STREAM, getprotobyname('tcp')) or die $!;
my $dest = sockaddr_in (80, inet_aton('power.jarv.org'));
connect (SH, $dest) or die $!;
print SH "nGET /post.pl?$qstring[0]&$qstring[1] HTTP/1.1n" .
"Host: power.jarv.orgn" .
# BASE64 encoded username:password
"Authorization: Basic ************************nn";
close SH;
The base64 encoded username-password is for minimal security on the shared web hosting server.
Storing the data in an sqlite db
For the purpose of posting the power readings on my shared web hosting a subdomain was created called power.jarv.org. This is just a paranoid step as it keeps it isolated from my main web directory.
This is the database schema. There is one table that stores the epoch time and the two values recorded for each power phase.
CREATE TABLE data (
timestamp INTEGER UNIQUE,
value1 INTEGER,
value2 INTEGER
);
Very simple, one table and one row per entry. If you can think of better ways to store this data and report please let me know, I considered using rrdtool but thought this offered the most flixibility.
#!/usr/bin/perl -w
use strict;
use Data::Dumper;
use CGI qw/:standard/;
use DBI;
use constant DBNAME => [path to sqlite database]
print header;
my $ts = time();
my $v1 = param('value1') or die "Value1 not in parameter list";
my $v2 = param('value2') or die "Value2 not in parameter list";
my $dbargs = {AutoCommit =>1, PrintError =>1};
my $dbh = DBI->connect("dbi:SQLite:dbname=" . DBNAME, "", "",$dbargs)
or die "Unable to connect to the db";
$dbh->do(
"insert or ignore into data values ($ts, $v1, $v2)");
$dbh->disconnect;
This simple script will take the data which is encoded in the http query string sent from the arduino ethernet shield and relay it to another cgi sitting on power.jarv.org.
Generating the Flash Charts
Finally once the data is collected into the sqlite database the charts are periodically generated. To do this a perl script is run in a cron job that connects to the database and outputs json files for open flash charts.
I have two types of charts that are created, one is a regular line chart and the other is a summary chart that averages data over time and presents it as a bar graph.
The perl script is set up as a cron job that runs on the shared web hosting server every 10 minutes or so. Runtime statistics are presented at the top of each page.
Filed under: Uncategorized | 2 Comments







2 Responses to “Home power Monitoring”