Arduino Electricity Monitor

I’ve had my eye on some of the commercially available home energy monitors for a while. They all utilise a current transducer that clips or clamps around the main cable coming into the house. I wasn’t too keen on these, as in order to correctly, and accurately, measure the current flowing, you need to accurately know the voltage too. Without making serious modifications to the supply cabling, this isn’t possible. Making changes to the supply cabling is pretty dangerous and not to mention, very illegal.

However, those of us lucky enough to have a modern, digital electricity meter, may have spotted an LED on the front that flashes whenever a certain amount of electricity has been consumed. In my case, it flashes 1000 times per kWh, which is once per Wh.

I found an excellent Arduino sketch over at that counts these pulses from the meter. There’s a very simple circuit feeding 5v to an LDR which is sitting in one half of a voltage divider. The output of this voltage divider is then wired to pin1 on the Arduino. Of course, pin1 supports interrupts, so we can get the Arduino to do something whenever that interrupt happens.

As it’s a ‘normal’ LDR and not limited to infra-red or anything, I needed to shield it from ambient light. If someone switched the light on, we’d probably get an errant pulse being recorded. The first thing that sprung to mind when I saw the size of the disc surrounding the LED on the meter was the small canisters 35mm photographic film comes in (remember that lovely stuff?!) So i dug one out and cut a hole in the base for the cable. Perfect fit. I need to fashion some kind of more robust bracket, probably involving velcro and strips of aluminium at some point. For now Blu-Tack will just about do.


I’ve modified the code to include parts of the standard ‘web client repeating’ sample sketch. I want to be able to log the data in a mySQL database so that I can graph it and do further analysis on it later. So the Arduino posts the measurements whenever there is a pulse to a PHP script that then inserts everything into a database.

There are a number of issues with this script as it stands. If I change the value in the ‘power’ equation (towards the bottom of the code), it breaks the script. With the numbers as they are, I get figures in the region of 600kWh, which is more like a small factory, rather than a domestic dwelling! For now, I’ve done a division in the PHP script to get this number to something more realistic. I need to get my maths head on, and do some thinking.

The other problem is that the Arduino seems to stop after a few hours. I can’t wok out what’s causing it. It’s powered up and the network lights flash in unison on the Ethernet Shield, network switch and Raspberry Pi (that’s where the PHP script is). But nothing is appearing in the database…

Anyway, feel free to use this code, but please let me know of any improvements or changes you make.


#include <SPI.h>
#include <Ethernet.h>

//Adapted from a sample Arduino sketch and, by chris at

// assign a MAC address for the ethernet controller.
// fill in your address here:
byte mac[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
// fill in an available IP address on your network here,
// for manual configuration:
IPAddress ip(192,168,xx,xx);

// fill in your Domain Name Server address here:
IPAddress myDns(8,8,8,8);

// initialize the library instance:
EthernetClient client;

char server[] = "192.168.xx.xx";

unsigned long lastConnectionTime = 0;          // last time you connected to the server, in milliseconds
boolean lastConnected = false;                 // state of the connection last time through the main loop
const unsigned long postingInterval = 60*1000;  // delay between updates, in milliseconds

//Number of pulses, used to measure energy.
long pulseCount = 0;   

//Used to measure power.
unsigned long pulseTime,lastTime;

//power and energy
double power, elapsedkWh;

//Number of pulses per wh - found or set on the meter.
int ppwh = 1; //1000 pulses/kwh = 1 pulse per wh

void setup()

  // give the ethernet module time to boot up:
  // start the Ethernet connection using a fixed IP address and DNS server:
  Ethernet.begin(mac, ip, myDns);
  // print the Ethernet board/shield's IP address:
  Serial.print("My IP address: ");

  // KWH interrupt attached to IRQ 1 = pin3
  attachInterrupt(1, onPulse, RISING);

void loop() {
  // if there's incoming data from the net connection.
  // send it out the serial port.  This is for debugging
  // purposes only:
  if (client.available()) {
    char c =;

  // if there's no net connection, but there was one last time
  // through the loop, then stop the client:
  if (!client.connected() && lastConnected) {

  // if you're not connected, and ten seconds have passed since
  // your last connection, then connect again and send data:
  if(!client.connected() && (millis() - lastConnectionTime > postingInterval)) {
  // store the state of the connection for next time through
  // the loop:
  lastConnected = client.connected();

// this method makes a HTTP connection to the server:
void httpRequest() {
  // if there's a successful connection:
  if (client.connect(server, 80)) {

// prepare the variables  
  char powerString[8] = "";
  char elapsedString[8] = "";
  //convert to strings  
  dtostrf(power, 7, 4, powerString);
  dtostrf(elapsedkWh, 4, 3, elapsedString);
  String valueOne = powerString;
  String valueTwo = elapsedString;
  //assemble query  
  String stringOne = "GET /energymonitorscript.php/?power=";
  String stringTwo = "&elapsed=";
  String stringThree = " HTTP/1.0 \r\n";
  String stringOut = stringOne + valueOne + stringTwo + valueTwo + stringThree; 

    // send the HTTP PUT request:
    client.println("User-Agent: arduino-ethernet \r\n");
    client.println("Connection: close \r\n");

    // note the time that the connection was made:
    lastConnectionTime = millis();
  else {
    // if you couldn't make a connection:
    Serial.println("connection failed");

// The interrupt routine
void onPulse()

//used to measure time between pulses.
lastTime = pulseTime;
pulseTime = micros();


//Calculate power
power = (3600000000.0 / (pulseTime - lastTime))/ppwh;

//Find kwh elapsed
elapsedkWh = (1.0*pulseCount/(ppwh*1000)); //multiply by 1000 to pulses per wh to kwh convert wh to kwh

//Print the values.
Serial.print(" ");

//make the http request


  1. Dave Stowe
    April 15

    Have a look at mine, it might help :-

    Name :- Meter Pulse Counter and Clock Reader

    Purpose :- Counts the pulses in one day from midnight, and sends the data on request, normally every 5 seconds to my XRF net.
    Uses the LLAP protocol to send and recive data on my Ciseco XRF network see for more info.
    My network communicates serially at 115200 baud so we dont miss a meter pulse.
    Answers to “aMRALIVE—-” to see if the unit is alive.
    Answers to “aMRSENDDATA-” to send the watts used, average, minimum and maximum values.
    Answers to “aMRRESETT—” to re-align the clock module, done by the master unit at 23:00 if master read the
    NTP time okay over the WWW before this, so we can accurately reset the unit at midnight. If no sync, runs on DS1307.
    Replies to the commands, mimicing aMRALIVE—- and RESETT—. On reqesting data sends the data blocks and then

    Protocol :- See full expination at above web site. It uses data in 12 byte blocks, a sync letter, ‘a’, 2 byte ident, ‘MR’ in
    my unit and then 9 bytes for data. You can set the frequencies, baud rates and security through their software. FREE!
    Datastream sent to master unit is :-
    LLAP Strings aMRWA0000025aMRAV0001800aMRCU0001800aMRMI0001798aMRMA0001802aMRSENDDATA- ‘6 Packets of 12 byte data’
    Description —-Watts——Average——Current—-Minimum—-Maximum——Reply—-

    Pysical :- Fitted in a large matchbox size box, and flashes a RGB LED red with a mimic pulse, blue with data on the network and
    green on the rest for power. An Xino RF Arduino from Ciseco is the main unit, with a DS1307 attached by double sided tape.
    You can use what ever type of Arduino you want. An LDR reads the meter pulse, LDR connects 1 pin to 5v, the other to pin D2.
    You also need a 10k resistor from pin D2 to 0volts. I attached my LDR to the meter with Blue Tack. Make sure no external
    light gets to the sensor. The darker it is aound the LDR the better, but not touching, glare. I use the falling edge for
    the interrupt, got a better accuracy as the LDR increases its resistance quicker, than rising edge. I attached the box to the
    side of the meter with double sided tape. Runs off a cheap everday mini USB plug 5v wall 240vAC PSU. Consumption is about 50ma!

    Testing :- Good accurate reads upto 30kwh, i.e great on domestic UK 240vac 80amp supply. Tested with lots of electric storage heaters,
    electric cooker, shower, ect all on! Got upto 18Kwh. Reading exactly the same as meter. Accuracy measured over 1 week was 0.2%.
    It could do with the LDR changing to a photo-transistor to get the timing perfect. On a pulse tester, I was getting +- 3.
    Never had a problem with any of the excellent Ciseco XRF modules, but beware the older ones being sold on Ebay, by ex-users,
    they are NOT all 5v tolerant! The easiest module is XBEE shaped and pinouts are similar. RTFM please! I have damaged
    units in my earlier days by not reading up on them. Various firmwares are available. All free.

    Further :- A master unit in my lounge works out and dislays and stores the data, the costs and other stuff using a Gameduino screen, with
    info speech for errors and warnings on an Emic sound unit. It also, on another secure other frequency XRF net work,
    controls the central heating, alarm system, reading temperatures int and ext, light level, motion detection devices, door
    and window sensors and RFID tag access to master. Later on, house access. All done through the excellent LLAP protocol
    and XRF variants. I might publish the master soon.

    Program :- Programmed using IDE 1.0.5-r2, size of program only 10,860 bytes, so can be done in smaller memory devices.

    Wriitten by:- Dave Stowe April 2014
    Copyright :- Dave Stowe, a disabled ex-industrial multiskilled engineer/programmer enjoying programming in C (well close enough) on Arduino’s.
    License :- This software is released under the DWYWWIIINRC License (Do Whatever You Want With It, It Is Not Rocket Science).
    Thanks to :- Jesper Eklunds, modified his program a lot! and to my super partner Leanda, who looks after and puts up with me.

    // Variables used for stats, see program for information
    int count = 0;
    int errors = 0;
    float wCurrent;
    float wAvg;
    float wTotal;
    unsigned long timeNow;
    unsigned long timeOld = 0.0;
    unsigned long timeStart = 0.0;
    float wMin = 10000.0;
    float wMax = 0.0;
    float sec = 0.0;
    float timeInterval = 0.0;
    boolean doFirst = true;
    boolean flash = true;
    boolean alive = true;
    boolean answerMaster = false;

    // Pin Assignments
    // Inputs
    const int LDRPin = 2; // Our LDR input triggers Int0

    // Outputs
    const int pulseledPin = 11; // Red LED
    const int powerledPin = 9; // Green LED
    const int CommsledPin = 10; // Blue LED
    const int SRFPower = 8; // Pin used to power up SRF
    const int error = 13; // Error LED

    // DS1307: SDA pin -> Arduino Digital 4, SCL pin -> Arduino Digital 5
    DS1307 rtc(4,5); // Initialise the DS1307 rtc board
    Time t; // t is name a struction to hold Time

    // Storage variables for the incoming data
    String XRF_id = “”; // the XRF id we recieved store
    String XRF_data = “”; // the XRF data we recieved store

    void setup() {
    rtc.halt(false); // Turn on the clock
    attachInterrupt(0, Calculate, FALLING); // LDR on Pin 2(int0), used to get pulses, fires interrupt, goes to function Calculate

    pinMode(pulseledPin, OUTPUT); //Set Red LED pin as an output
    pinMode(powerledPin, OUTPUT); // Set Green LED pin as output
    pinMode(CommsledPin, OUTPUT); // Set Blue LED pin as output
    pinMode(error , OUTPUT); // Set pin 13 as OUTPUT
    pinMode(SRFPower , OUTPUT); // Set Pin 8(SRF Power) as output
    digitalWrite(SRFPower, HIGH); // Turn on the SRF Power

    Serial.begin(115200); // Start the serial port for the SRF Communications, only active when pin 8 high

    digitalWrite(pulseledPin, LOW); // Turn off the red led
    digitalWrite(powerledPin,HIGH); // Turn on the green led
    digitalWrite(CommsledPin, LOW); // Turn off the blue led
    digitalWrite(error , LOW); // Turn off the error led
    // Send a start message with my time
    t = rtc.getTime(); // Get the time data into t
    String s = “aMRS”;
    if(t.hour < 10) s=s+"0";
    s = s + t.hour;
    if(t.min < 10) s=s+"0";
    if(t.sec = 12) { // Have we got twelve bytes?
    if ( == ‘a’) { // is the first one an ‘a’?
    // Yes so read in the ID string 2 bytes
    digitalWrite(pulseledPin, LOW); // Turn off the red led
    digitalWrite(powerledPin, LOW); // Turn off the green led
    digitalWrite(CommsledPin,HIGH); // Turn on the blue led
    for (byte i = 0; i < 2; i++) XRF_id += char(; // Read in to get the XRF_id
    // Read in the data string 9 bytes
    for (byte i = 0; i = 0 && val 9 && val 99 && val 999 && val 9999 && val 99999 && val 0.1 ) { // If its greater than 0.1secs since last pulse, its a pulse
    timeOld = timeNow; // and store the time now for the next pulse check
    count++; // add the pulse to our count
    sec = ( timeNow – timeStart ) / 1000.0; // convert to seconds
    wTotal = count; // our total used is the pulse count. 1000 pulses = 1 Kw
    wAvg = 3600.0 * count / sec; // work out the average watts
    wCurrent = 3600.00 / timeInterval; // work out the current watts
    if ( wCurrent > wMax ) { wMax = wCurrent; }// store the maximum watts used if greater than before
    if ( wCurrent < wMin ) { wMin = wCurrent; }// store the mimimum watts used if lower than before
    flash = true;
    else { // the pulse is to short, so its an error
    digitalWrite(error, HIGH); // debug led on
    errors++; // increase the error count

    This has worked well for some time

Leave a Reply

Your email address will not be published. Required fields are marked *