Low Energy Arduino Electricity Data Logger

This is the second version of the Arduino Energy Monitor based on an updated Seeeduino Stalker V2 data logger.  The biggest change is the move to low power code which allows the logger to run off LIPO batteries for weeks/months - typically a 1000mAh battery will last for 6 weeks under normal conditions so you could get about 9 months or so from a a 6000mAh battery - add a solar cell and you could have a logger self suffcient in power.

We have also added logging for battery voltage so you can see how your battery is performing.  I wouldn't be so difficult to add an Xbee radio to transmit the data to a remote hub - perhaps we will cover this later?

The project uses the pulse from the LED on a modern electricity meter, as this is also an output common to other types of meter you will be able to measure other pulse meter outputs such as water and gas.

This energy data logger project has been built to sense each LED pulse from, in this case, an electricity meter.  The logger records how many pulses occur in the given time frame, say 5 minutes, and then records this count to the on-board SD card along with the current date and time in the CSV file format.  In our case the output is 1 pulse for every watt used which makes life easy.  If your meter pulses to a different, as you might find in a gas meter, then some simple maths would be needed in your spreadsheet to convert from pulses to say kWh.

Picking up the LED pulse can be interesting - we opted for an Infrared sensor which is less sensitive to ambient light but can still pick up the output from out meters red crystal LED - this make screening around the sensor less of an issue - we simply used BlueTack.  If you need to increase your sensitivity to your meters LED then swapping to an ambient light sensor is the way to go with a little more effort required when mounting the sensor.

3 status LEDs are included which let you know that your logging session is going to plan without having to pop the card out and have a look.  The Pulse LED shows you when a pulse from the meter has been successfully counted.  The Write LED shows when the pulse count is written the SD card successfully (every 5 minutes by default) and the Error LED flashes continuously when there is an error writing to the SD card.

Enjoy, and please let us know how you get on via the comments section at the bottom of the page.


The parts list is:

1no. Seeeduino Stalker V2 board.

1no. TAOS TSL261 - IR light to voltage optical sensor.

3 no. LEDs of different colours.

3 no. 100 to 330Ω current limiting resistors for the LED's

1no. microSD card

1no. LIPO Battery

1no. UartSB for programming the Stalker board

1no. Solar panel - optional

 

The wiring is simple enough:


The Sensor:

The TSL261 Light to Voltage sensor looks like this:

TSL261

 

 

Wire Sensor Pin 1 (GND) to Stalker GND

Wire Sensor Pin 2 (VDD) to Stalker 3.3V (can use the I2C header)

Wire Sensor Pin 3 (OUT) to Stalker digital pin 3

 

 

 

 

 


The LEDs:

Use three colours to differentiate between the functions.

Solder a 100Ω resistor to the positive (longer) leg of each LED.

The Pulse LED is on Stalker digital pin 4

The SD Card Write LED is on Stalker digital pin 5

The Write Error LED is on Stalker digital pin 8 (*note - diagram shows this wired to D6 - I will update this to show D8 soon).

Now, in turn, wire the positive LED leg (with resistor attached) to the appropriate digital pin on the Stalker and the negative LED leg (shorter leg adjacent to flat on the LED housing) to the Stalker GND..... you should end up with this:

 Electricity_logger2

Please note: to get the Stalker Board's Real Time Clock to wake the Stalker from sleep you need to solder the INTA-RTC jumper on the bottom of the PCB - see image.

Stalkerv20btm

 

 

 

 

 

 

 

 

 

 

 

 


Mounting the sensor on your meter:

As previously described, the kit uses an Infrared sensor to make screening the sensor easier - if the sensor is not picking up the pulse try the TAOS TSL257 which is sensitive to visible light - it all depends on the output of you meter pulse LED.  Simply use some BlueTack to first position the sensor over the meter LED (you will see your Pulse indicator LED responding when it\'s right) and then screen the sensor from ambient light with more BlueTack to avoid false readings from the surroundings.

meter1

meter2


The Arduino Sketch:

The sketch code is shown below and written for Arduino IDE 022/023 but could easily be converted to 1.0. You can download the sketch along with the two required libraries as a zip file from the link below. Unzip the folder EnergyMKII and paste the two libraries: R8025 & Battery into your Arduino IDE libraries folder before opeing the Arduino IDE.

Top Tip: If you are using the Stalker for the first time and need to set the time and date, insert this line:

RTC.adjust(DateTime(__DATE__, __TIME__));

into the void setup () function to set the time from your computer.  Once this has been doen you can delete or comment the line out.

You can adjust the logging interval using this line in the code:

int sampleRate = 300;

The 300 is the interval, in seconds, at which the data gets written to the SD card.  In this case every 5 minutes.  A microSD card of 256Mb capacity is enough space to store about 8 million time stamped data records which at a 5 minute logging interval equates to about 76 years worth of data - should be enough !

You should now be set - I have assumed you have successfully uploaded the sketch below to your Stalker data logger and inserted your SD card ready to power up for your data logging session.

So, all being well, the Pulse LED will be blinking every time it detects a meter pulse and the Write LED will be blinking every 5 minutes when the data gets written to the microSD card.  Once you have collected your desired data period you can download your CSV file from the microSD card which will be in the following format:

 spreadsheet

 

 

 

 

 

 

 

 

Pretty good - but even better if you graph it out in your spreadsheet (this image needs updating):

log

 

 

 

 

 

 

 

 

 

This graph show electrical watts consumed over a 4 day period

Have fun & do share your experiences via the comments section at the bottom of the page.

The Sketch:

You can also download the PDE directly from the link at the bottom of the page.


// www.airsensor.co.uk 2012
// Last update: 10/4/12

// The low power/battery operated electricity data logger based on the SeeedStudio Stalker V2 board.
// Thanks to Vladimir for feedback and debugging.

#include <avr/sleep.h>
#include <avr/power.h>
#include <Wire.h>
#include <SD.h>
#include "R8025.h" //Download and install from the project zip file
#include "Battery.h" //Download and install from the project zip file

//The following code is taken from sleep.h as Arduino Software v22 (avrgcc) in w32 does not have the latest sleep.h file
#define sleep_bod_disable() \
{ \
  uint8_t tempreg; \
  __asm__ __volatile__("in %[tempreg], %[mcucr]" "\n\t" \
                       "ori %[tempreg], %[bods_bodse]" "\n\t" \
                       "out %[mcucr], %[tempreg]" "\n\t" \
                       "andi %[tempreg], %[not_bodse]" "\n\t" \
                       "out %[mcucr], %[tempreg]" \
                       : [tempreg] "=&d" (tempreg) \
                       : [mcucr] "I" _SFR_IO_ADDR(MCUCR), \
                         [bods_bodse] "i" (_BV(BODS) | _BV(BODSE)), \
                         [not_bodse] "i" (~_BV(BODSE))); \
}

R8025 RTC; //Create the R8025 object
static DateTime interruptTime;
const int chipSelect = 10;
int sampleRate=300; //logging interval in seconds
volatile int alarmFlag = 0;
volatile int pulseFlag = 0;

unsigned long pulseCount = 0;  // Counts power pulses in interrupt, 1 pulse = 1 watt
unsigned long pulseTotal = 0;  // Total power used since the sketch started

// LED pins
const int  dataLedPin    =  4;  // LED indicates pulse counted
const int  logLedPin     =  5;  // LED indicates write to SD card
const int  fileLedPin    =  8;  // LED indicated file error


//Battery values
unsigned int bat_read; //analog read battery voltage
float bat_voltage; //battery voltage
unsigned char charge_status; //battery charge status

void setup ()
{
     /*Initialize INT0 for accepting interrupts */
     PORTD |= 0x04;
     DDRD &=~ 0x04;
  
     Serial.begin(57600);  //for debug - remove to save power
     Wire.begin();
     RTC.begin();
     RTC.adjust(DateTime(__DATE__, __TIME__)); //Set RTC from computer - comment out once RTC is set.
     Battery_init();
     set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    
     pinMode(dataLedPin, OUTPUT);    // LED interrupt indicator initialization
     pinMode(logLedPin, OUTPUT);     // LED file indicator initialization
     pinMode(fileLedPin, OUTPUT);    // LED error indicator initialization
    
     Serial.print("Initializing SD card...");  //for debug - remove to save power
  // make sure that the default chip select pin is set to output, even if you don't use it:
     pinMode(chipSelect, OUTPUT);
    
  // see if the card is present and can be initialized:
    if (!SD.begin(chipSelect)) error();
 
  Serial.println("card initialized.");  //for debug - remove to save power
    
  // write file headers to SD card 
    File dataFile = SD.open("datalog.csv", FILE_WRITE);
    if (dataFile) {
    dataFile.println("Start");
    dataFile.print("Date");
    dataFile.print(',');
    dataFile.print("Time");
    dataFile.print(',');
    dataFile.print("Watts");
    dataFile.print(',');
    dataFile.print("Total Watts");
    dataFile.print(',');
    dataFile.println("Battery");
    dataFile.close();
    }
 
  //Enable interrupt for light sensor on Digital 3
  attachInterrupt(1, Pulse, RISING);
 
  //Set first RTC alarm call @ zero seconds
    setAlarm();
}

void loop ()
{
    printTime();  //for debug - remove to save power
    powerDown(); //go to sleep until next Alarm call
   
    if (pulseFlag == 1) logPulse();  //if interrupt caused by light sensor, count the pulse
    if (alarmFlag == 1) {logData(); setAlarm();}  //if interrupt caused by RTC, log the data & set new RTC alarm
}

void Alarm() // routine called when RTC interrupt is triggered
{
    detachInterrupt(0);
    detachInterrupt(1);
    alarmFlag = 1;
}

void Pulse() // routine called when light sensor interrupt is triggered
{
    detachInterrupt(0);
    pulseFlag = 1;
}

void powerDown()//Power Down routines
{
    cli();
    sleep_enable();      // Set sleep enable bit
    sleep_bod_disable(); // Disable brown out dection during sleep. Saves more power
    sei();
    Serial.println("Sleeping");  //for debug - remove to save power
    delay(10);        //for debug - remove to save power
    sleep_cpu();      // Sleep the CPU as per the mode set earlier(power down) 
    sleep_disable();  // Wakes up sleep and clears enable bit. Before this ISR would have executed
    delay(10);        //This delay is required to allow CPU to stabilize
    Serial.println("Awake from sleep\n");   //for debug - remove to save power
}

void printTime()
{
    DateTime now = RTC.now(); //get the current date-time   
    Serial.print(now.date(), DEC);
    Serial.print('/');
    Serial.print(now.month(), DEC);
    Serial.print('/');
    Serial.print(now.year(), DEC);
    Serial.print(' ');
    Serial.print(now.hour(), DEC);
    Serial.print(':');
    Serial.print(now.minute(), DEC);
    Serial.print(':');
    Serial.print(now.second(), DEC);
    Serial.println(' ');
}

void logPulse() //count a pulse from the light sensor
{
   digitalWrite(dataLedPin, HIGH);
   pulseCount ++;
   pulseFlag = 0;
   Serial.print("Pulse Count: "); Serial.println(pulseCount);  //for debug - remove to save power
   delay(10);
   digitalWrite(dataLedPin, LOW);
   attachInterrupt(0, Alarm, LOW); 
}
 
void logData() //log the data to SD card
{  
    digitalWrite(logLedPin, HIGH);
    Battery_voltage_read();
    pulseTotal = pulseTotal + pulseCount;
    File dataFile = SD.open("datalog.csv", FILE_WRITE);
    if (dataFile) {
    DateTime now = RTC.now();
    if(now.date() < 10) dataFile.print('0');
    dataFile.print(now.date(), DEC);
    dataFile.print('/');
    if(now.month() < 10) dataFile.print('0');
    dataFile.print(now.month(), DEC);
    dataFile.print('/');
    dataFile.print(now.year(), DEC);
    dataFile.print(',');
    if(now.hour() < 10) dataFile.print('0');
    dataFile.print(now.hour(), DEC);
    dataFile.print(':');
    if(now.minute() < 10) dataFile.print('0');
    dataFile.print(now.minute(), DEC);
    dataFile.print(':');
    if(now.second() < 10) dataFile.print('0');
    dataFile.print(now.second(), DEC);
    dataFile.print(',');
    dataFile.print(pulseCount);
    dataFile.print(',');
    dataFile.print(pulseTotal);
    dataFile.print(',');
    dataFile.println(bat_voltage);
    dataFile.close();
    digitalWrite(logLedPin, LOW);
    alarmFlag = 0;
    pulseCount = 0;
   
    // print to the serial port too:
    Serial.println("Data Logged");
    }
    // if the file isn't open, pop up an error:
    else error();
  
}

void setAlarm() //set Alarm for next logging call
{
    DateTime  alarmTime = RTC.now();
    interruptTime = DateTime(alarmTime.get() + sampleRate); //Add sampleRate to start time
    RTC.enableINTA_Interrupts(interruptTime.hour(),interruptTime.minute());    // interrupt at (h,m)
    attachInterrupt(0, Alarm, LOW); 
    Serial.print("Interrupt Time: ");  //for debug - remove to save power
    Serial.print(interruptTime.hour(),DEC);  //for debug - remove to save power
    Serial.print(":");  //for debug - remove to save power
    Serial.println(interruptTime.minute(),DEC);  //for debug - remove to save power
    attachInterrupt(1, Pulse, RISING);
}

void error() //blink File Error LED forever
{
 while(1)
 {
   digitalWrite(fileLedPin, HIGH);
   delay(200);
   digitalWrite(fileLedPin, LOW);
   delay(200); 
 }    
}

4.0/5 rating (2 votes)

Comments (12)

  • P.Wammes
    01 December 2012 at 20:15 |

    Hi Cameron,
    I have a problem with the sketch the energy monitor MK11 and ceeduino stalker v2.1 this sketch is created on the r8025 and not on the SD3231 ship. Now no display of date and time I have changed a bit, the sketch where r8025 stood I have changed in ds3231. now I get an error sketch_dec01a: 209: error: ' class 'DS3231 has no member named ' enableINTA_Interrupts '
    this is de original line
    RTC.enableINTA_Interrupts(interruptTime.hour(),interruptTime.minute()); // interrupt at (h,m)

    can you help me kind regards Peter

    • Administrator
      01 December 2012 at 20:27 |

      Hi Peter, Indeed the RTC changed at Stalker version 2.1 to the much better DS3231 - I will aim to do a code update for you soon. I have the latest Stalker 2.3 in stock and available on eBay if needs be.

  • Denis
    08 November 2012 at 09:01 |

    Hi there,
    I'm Denis and i live in Italy
    Here also the current counter have a led pulse for every watt.
    So i wish to try your MK2, but i want to ask you please
    ...how much time can work using for example 2 X 1.5 V batteries please ?
    If i understand (I'm newbe) this will go to sleep most all time, right ?
    Thanks a lot
    Denis

    • Administrator
      08 November 2012 at 10:23 |

      Hi Denis, The battery run time depends on how many pulses it is receiving - each time a pulse is sensed the Stalker wakes up for a moment, counts the pulse and goes back to sleep. Every 5 minutes (or how often you choose) the Stalker writes the data to an SD card. I would recommend using a LiPo battery such as the one we sell as this plugs right into the stalker - we also do a 6,000mA battery for £30 which would last well - you will need to do tests but I suspect it will last for months if not longer. If you can get to some sunlight nearby you could also plug in one of our solar panels which would most likely keep you going indefinately. Hope that helps - let me know if you need more info.

  • Vladimir
    05 April 2012 at 17:46 |

    Hi. My question concerns to wiring, especially to red LED for "Write Error" connected according to the picture above to pin D6. It doesn't comply to the sketch where "fileLedPin" goes to D8 (which is in fact embedded on Stalker v2 board). Can you clarify it, please ? Cheers

    • Administrator
      05 April 2012 at 18:28 |

      Hi Vladimir, You are right, I need to update the image for this MKII version - please connect fileLedPin to Arduino digital pin 8 which is also the onboard LED so you can also leave it out if you wish.

  • Murray
    02 April 2012 at 06:29 |

    Hi. I don't need a battery, as I can run this from a plug-pack right? Also, can a xbee RF module be used to send data from the meter-box, to an RTU in a nearby building (for transmission of data via telemetry).

    • Administrator
      02 April 2012 at 08:06 |

      Hi Murray, You can provide power via battery or regulated 5V DC, the choice is yours. Indeed, you can set up 2 Stalker boards, with Xbee modules, as NODE and HUB to transmit data via a wireless link. You can then use a Wiznet shiled (1 in stock) or similar on the HUB Stalker to upload your information to the internet. Hope that helps.

  • ALEC DUFFIELD
    12 March 2012 at 16:04 |

    Hi
    now on version 022 and getting the following:-

    In file included from C:\Program Files\arduino\libraries\SD/SD.h:18,
    from EnergyMeterMKII.cpp:8:
    C:\Program Files\arduino\hardware\arduino\cores\arduino/Arduino.h:212:26: error: pins_arduino.h: No such file or directory
    EnergyMeterMKII.cpp:27:22: error: WProgram.h: No such file or directory

    • Administrator
      12 March 2012 at 16:18 |

      Hi Alec, Hmmm might be my memory failing me - I had thought that the SD library came as part of the 022 install but perhaps not - copy the SD library across from 023 and see if that does it? Remember to start the Arduino IDE from scratch after installing a new library or it will not be found. Should work just fine in both 022 & 023.

  • ALEC DUFFIELD
    12 March 2012 at 14:58 |

    Hi Cameron
    Thanks for the listing. looks good and will do everything I need, however.
    Energy meter MKII wont compile.
    Have tried arduino 23 and arduino 1.0 both give various errors.

    • Administrator
      12 March 2012 at 15:12 |

      Hi, I just checked on 022 here and all is well. Have you installed the 2 libraries? Also, make sure the right board is selected in Arduino - should be Arduino Pro or Pro Mini (3.3V, 8 MHz) w/ ATmega328 - perhaps I need to make this clear in the project text.

      Let me know how you get on.

Leave a comment

Please login to leave a comment.