Enerduino (English)



Enerduino has been upgraded: Enerduino 2.0

What's Enerduino? This is a project created to monitor the energy consumption of my house. The reasons behind this monitoring can be more than one: to evaluate offers from energy suppliers, to understand where I'm wasting energy and to save some money. Or just for curiosity.

There are a lot of project out there, very similar to this one. This is my way, a DIY solution based on Arduino controller.

I think everybody can build this: it is very simple and require few electronic knowledge. This project is mainly built on the italian power meter installed by the national company, but it can be easily adapted for any other device, I guess.



HOW IT WORKS

Very simple: thanks to a photoresistor that will be applied on the RA LED of the power meter, we can count the flashes. Every flash should be 1W/H, so by counting these and saving them in a file, we'll be able to do some graphs by using a spreadsheet.

Required components:

  • 1 Arduino controller
  • 1 SD Card shield
  • 1 DS1307 module (a clock with battery, to save date/time)
  • 1 resistor (10Kohm)
  • 1 photoresistor
  • wires

I bought most of these on http://www.seeedstudio.com, but you can choose your own supplier



LET'S BUILD IT

Get the Arduino board. The SD card shield must be placed directly over the controller. PIN D9 must be placed in Arduino PIN 9. The SD power switch must be placed on D9, as the Filelogger library we'll use, requires this mode (http://code.google.com/p/arduino-filelogger/).
Now we have to connect the DS1307 module. Also this one should be placed on top of the Arduino, but since we already have the SD shield, this is not possible. So, we'll place it beside the controller. The two pins shown on top-left of the picture will be connected to analog ports 4 and 5. Power (+ and GND) will come from the ICSP port (please, have a look to the schema at the end of the post).

Then, we have to assemble the photoresistor. It must be used with a resistor in this way

+5V ---PhotoResistor-------.-------Resistor 10K--- GND
|
Pin 0 ------------------------------------------

To connect this, I used a scrap cable: I extracted one pin (this will be connected to analog PIN 0)

This is the picture of the opposite side of the cable: the red wire is placed in the PIN that is connected to port 0 on the other side)

There is shortage of power lines...we need to connect this to ICSP port again...


OK, we mostly completed our work here. Now we need to load the software (see the end of the post), place a SD card (BE CAREFUL: Filelogger works only with FAT16 partitions, with 512 bytes block. You need to create a 64MB partition and then format it with "format f: /fs:fat /a:512". Remember to create a file named data.log in root directory, otherwise nothing will be logged).
I sticked the photoresistor to the power meter LED with Patafix:
Here below a schema to clarify some of the connectionsI tried to use it with a 9V battery, but it last very few hours....it's better to use an external power supply.

Wait some days, then extract the SD card: the data.log file will contain a list of "DATE # OF FLASHES". With a common spreadsheet you can build a graph like this one:



THE CODE

 // 
//  
// Enerduino 
//  
// version 0.2 
//  
// Internal revision: $Id: Enerduino.pde,v 0.22 2009/11/28 16:30:16 cesare Exp cesare $ 
//  
// written by Cesare Pizzi 
//  
// This simple Arduino application allow to monitor power consumpion by checking the flashing  
// light of the power meter. 
// There are 2 lights on italian ENEL power meters: RA (active) and RR (reactive). 
// Only RA led is computed for home contracts 
// One flash should be 1 w/h 
//  
// 

#include <stdlib.h> 

// Include files for Filelogger library 
#include <Spi.h> 
#include <mmc.h> 
#include <nanofat.h> 
#include <FileLogger.h> 

// Include files for clock DS1307 library 
#include <WProgram.h> 
#include <Wire.h> 
#include <DS1307.h> 

// Include files for MsTimer2 library 
#include <MsTimer2.h> 

/// The PIN to power the SD card shield 
#define MEM_PW 9 
// Analog input for photoresistor 
#define PHOTO_IN  0 

unsigned long timer=3600000; // Log file is written every 60 minutes (3600000)  FIXME 
unsigned long flash=0; 
int threshold=450;     // If photoresistor read more than this value, it count a flash 
int writeLog=0; 

// Arduino setup routine 
void setup(void)  
{ 

// This is to power on the SD shield 
pinMode(MEM_PW, OUTPUT); 
digitalWrite(MEM_PW, HIGH); 

// Setup for photoresistor 
pinMode(PHOTO_IN,INPUT); 

// Initialize timer 
MsTimer2::set(timer, flushCounter); 
MsTimer2::start(); 

// Serial.begin(9600);       // FIXME 

// Enable to set up external clock 
// setClock(0,38,17,6,14,11,9); 
} 

// Main 
void loop(void)  
{ 

// Serial.println(analogRead(PHOTO_IN));  // FIXME 

// Read the photo sensor value 
if (analogRead(PHOTO_IN) > threshold) 
{ 
while (analogRead(PHOTO_IN) > threshold) 
{ 
// Just wait the flash to turn off (to avoid multiple counts)    
}  

flash++; 
// Serial.println("Flash");       // FIXME 
} 

// Write the log file if interrupt has been called 
if (writeLog==1) 
{ 
char time[10]; 
char date[15]; 
char logStr[50]; 
char buffer[5]; 

// Write flashes to log file 
strcpy(logStr,getDate(time)); 
strcat(logStr," "); 
strcat(logStr,getClock(date)); 
strcat(logStr,"\t"); 
itoa(flash,buffer,10); 
strcat(logStr,buffer); 
strcat(logStr,"\n"); 

write_log(logStr); 

writeLog=0; 
flash=0;  
} 

delay(10); 
} 

///////////////// 
// Subroutines // 
///////////////// 

// Setup the external clock 
void setClock(int seconds, int minutes, int hour, int dow, 
int day, int month, int year) 
{ 

RTC.stop(); 
RTC.set(DS1307_SEC,seconds);    //set the seconds 
RTC.set(DS1307_MIN,minutes);    //set the minutes 
RTC.set(DS1307_HR,hour);      //set the hours 
RTC.set(DS1307_DOW,dow);      //set the day of the week 
RTC.set(DS1307_DATE,day);     //set the date 
RTC.set(DS1307_MTH,month);     //set the month 
RTC.set(DS1307_YR,year);      //set the year 
RTC.start(); 

} 

// Get the time from the external clock 
char* getClock(char *timeStr) 
{ 
char buffer[5]=" "; 

itoa(RTC.get(DS1307_HR,true),buffer,10); 
strcpy(timeStr,buffer); 
strcat(timeStr,":"); 
itoa(RTC.get(DS1307_MIN,false),buffer,10); 

// Add 0 if a single digit minute has been returned 
if (strlen(buffer)==1) 
{ 
strcat(timeStr,"0");  
}  
strcat(timeStr,buffer); 

// Seconds are not useful at this time. Commented out 
// strcat(timeStr,":"); 
// itoa(RTC.get(DS1307_SEC,false),buffer,10); 
// strcat(timeStr,buffer); 

return timeStr; 
} 

// Get the date from extrenal clock 
char* getDate(char *dateStr) 
{ 
char buffer[5]=" "; 

itoa(RTC.get(DS1307_DATE,true),buffer,10); 
strcpy(dateStr,buffer); 
strcat(dateStr,"/");  
itoa(RTC.get(DS1307_MTH,false),buffer,10); 
strcat(dateStr,buffer); 
strcat(dateStr,"/"); 
itoa(RTC.get(DS1307_YR,false),buffer,10);  
strcat(dateStr,buffer); 

return dateStr; 
} 

// Write data to log file named data.log 
void write_log(char msg[]) 
{ 
int i; 
unsigned int length = (strlen(msg)+1); 
byte buffer[length]; 

for(i=0; i<length;i++) 
{ 
buffer[i] = msg[i]; 
} 

FileLogger::append("data.log", buffer, length-1); 
// We should check for errors here....we'll do it... 
} 

// Routine executed by the timer interrupt. This flush the  
// data to the log file 
void flushCounter(void) 
{ 
writeLog=1; 
}