Saturday, January 16, 2016

Whole House Power Monitoring


I have been tinkering with electronics projects for a long time. I got some Arduino Nano boards in 2012 and started with some silly projects using the stock samples. I wanted to do something more productive and interesting. What could be better than measuring home power consumption?

More research led to an open source web application named Emoncms which seemed to fit my bill.

Data Capture

Now presentation was only half the battle, data capture itself was the other half. I decided to use Arduino Mini for this project which are based on ATmega168, it has plenty of digital and analog pins but only has 16KB of flash memory.

The basic power equation is Power = Voltage x Current. The voltage usually stays around 120V, so I decided to concentrate on measuring the current. So how does one measure current without dealing with live wire, the answer is Current Transformer. They go around the live wire like clamps and generate a safe small voltage corresponding to the current flowing.

US homes usually have two 120 V supply lines, these are out of phase and add up to give 240V used for dryer and cooking ranges. The two lines are spread across the house to all the receptacles.

I got two 100A rated Current Transformers SCT-013-000, they snap around the wire carrying current. They has to be installed in the main breaker panel when the supply for the house came in. This was the difficult part and I installed them very carefully and secured them with zip-ties. The transformers terminate as male mono connectors and I measured a small voltage on my multi-meter. Good, the breaker panel was closed and I was happy that the most critical part was over.

If you are unfamiliar with electrical connections then I strongly suggest getting an electrician to do this part.


The two CTs up close
Breaker panel

Filing Data

I decided to host data on Emoncms itself. Programming the Arduino is a piece of cake. Download the IDE, grab some sample code, flash the Arduino and you are ready to go. But Arduino by itself won't get data anywhere, so I needed something to get it connected.

This brought me to the Ethernet module ENC28J60 which can communicate with Arduino. I used EtherCard library to make the bridge; the ENC28J60 modules takes 4 pins to talk to Arduino. Thankfully, Arduino has plenty and I was not using it for anything else. Armed with some sample code, I was soon pinging google.com. 

My original power equation was insufficient to measure the actual AC power and instead I used a library name EmonLib for doing all the calculations. The power from both power lines was filed as 2 separate input feeds and then added up into a third feed at Emoncms.

The power calculations seemed a bit off but the delta seemed to be correct which could be due to the transformers or something else but I was so excited to see the graph jump when I turned on a lamp. Even a 5-10W consumption was getting registered, I was pretty happy.

Code

Working with EmonLib wasn't a very good experience for me, it felt very cryptic. Atmega168 has just 2KB of RAM and using the library with Serial debugging was sometimes resulted in memory issues. PSTR came to my rescue, it allowed strings to be saved into flash instead of SRAM.

#include <ethercard.h>
#include <emonlib.h>
...
#define    ERROR_NONE    9
#define    ERROR_ETHERNET    2
#define    ERROR_DHCP    3
#define    ERROR_DNS    4

byte mymac[] = { 0x00,0x1C,0xBF,0xB1,0xA0,0x00 }; // ethernet interface mac address, must be unique on the LAN

EnergyMonitor emon1, emon2;
byte Ethernet::buffer[700];
uint32_t nextTime = 0;
Stash stash;
byte errorStatus = 0;

void setup() {  
  delay(2000);  //Delay for allowing serial monitor to be launched
  Serial.begin(9600);

  pinMode(OUTPUT_LED, OUTPUT);     
  digitalWrite(OUTPUT_LED, HIGH);    

  Serial.print("Ethernet: ");
  if (ether.begin(sizeof Ethernet::buffer, mymac) == 0) {
    Serial.println("failed");
    errorStatus = ERROR_ETHERNET;    
    return;
  }
  else{
    Serial.println("ok");
  }

  Serial.print("DHCP: ");
  if (!ether.dhcpSetup()){
    Serial.println("failed");
    errorStatus = ERROR_DHCP;       
    return;
  }
  else{
    ether.printIp("", ether.myip);   
  }

  if (!tryDns()){
    return;
  }

  digitalWrite(OUTPUT_LED, LOW);
  errorStatus = ERROR_NONE;
  emon1.current(CURRENT_PIN1, CURRENT_CALIBRATION);
  emon2.current(CURRENT_PIN2, CURRENT_CALIBRATION);
}

void loop()
{   
  uint32_t currentTime = millis();
  ether.packetLoop(ether.packetReceive());

  if (currentTime > nextTime) {
    switch(errorStatus)
    {
    case ERROR_NONE: 
      break;
    case ERROR_DNS:
      if (!tryDns()){
        blink(ERROR_DNS);
        delay(500);
        return;
      }

      errorStatus = ERROR_NONE;
      break;
    case ERROR_ETHERNET:
      blink(ERROR_ETHERNET);
      delay(500);
      return;
    case ERROR_DHCP:
      blink(ERROR_DHCP);
      delay(500);
      return;
    }

    double Irms1 = emon1.calcIrms(NUMBER_OF_SAMPLES);               
    double Irms2 = emon2.calcIrms(NUMBER_OF_SAMPLES);

    //First reading is incorrect, so skip it
    if (nextTime == 0){
      nextTime = currentTime;
      delay(500);
      return;
    }

    double watt1=Irms1*VOLTAGE;
    double watt2=Irms2*VOLTAGE;    
    update(watt1, watt2);

    nextTime = currentTime + LOGGING_INTERVAL;
    blink(1);
  }
}

const char website[] = "emoncms.org";    //"80.243.190.58"

void update(double watt1, double watt2)
{
  byte sd = stash.create();
  Stash::prepare(PSTR("GET /emoncms/input/post.json?node=9&apikey=$F&json={power1:$D,power2:$D} HTTP/1.1" "\r\n"
    "Host: 80.243.190.58" "\r\n"      
    "User-Agent: EtherCard" "\r\n" 
    "Connection: close" "\r\n"
    "\r\n"
    "$H"),
  PSTR(EMON_APIKEY), (word)watt1, (word)watt2, sd);
  ether.tcpSend();
}

bool tryDns()
{
  Serial.print("Dns: ");
  if (!ether.dnsLookup(website))  {
    Serial.println("failed");
    errorStatus = ERROR_DNS;   
    return false;     
  }
  else{
    Serial.println("ok");
  }
  return true;
}


End Result

And here was the end result, a small box with both the module. The box just had a reset and a LED which blinked on every data write and blinked crazily if things went not good. This setup ran for more than a year non-stop.

I future I might add a small transformer to measure the actual voltage or visualize the data elsewhere instead of Emoncms.

Nothing much inside, power came from a wall adapter.

The project box with an opening for serial programming

No comments :

Post a Comment