Energy Monitoring the with Raspberry Pi (part 1)

When I received my (first) Raspberry Pi a couple of weeks ago, I knew exactly what I wanted to do with it. I’ve looked at devices for monitoring energy usage such as the Owl, but I wanted to build one myself, so when the Raspberry Pi came out, with it’s £30 price tag, low power consumption and GPIO, I knew it was exactly what I was looking for.

First, setting up the Pi. This turned out to be extremely simple. I downloaded the latest Raspbian “wheezy” image from the website, then issued the following commands on a Macbook to write the image to disk:

sudo diskutil unmount /dev/disk2s1
sudo dd -if=2012-07-15-wheezy-raspbian.img of=/dev/rdisk2 bs=1M

where disk2s1 and rdisk2 are the SD card. The card was then ready to use.

Due to the location of my electricity meter, I couldn’t run an Ethernet cable from the router, so I had to use wireless. I had some trouble with the wireless which I’ve now resolved and I’ll detail how I fixed it in another post.

Once the Pi was set up I just needed a way of measuring consumption. Normally, you would use a current transformer to measure the load. However, the Pi doesn’t have any analogue inputs, meaning I would need some additional circuitry for this. Also, a current transformer is good for measuring the load at any one point in time, but for me, being able to accurately measure the usage over time is far more useful. This would require high sample rates and the ability to perform accurate integral calculations, which would be difficult without a real-time operating system, or an external micro-controller to do the calculations and push consumption values back to the Pi. Thankfully, this is built in to modern digital meters in the form of an LED that flashes at a rate proportional to consumption. The LED on my meter flashes at a rate of 1000/kWh.

To read this LED, all that is needed is an SFH300 photo-transistor connected to one of the GPIOs. No additional components are required. Here is the circuit I used:

SFH300 circuit

The Pi has internal pull-down resistors on all GPIOs. I initially used pin 3 on the GPIO header, but it seemed like the pull-down resistor on this pin wasn’t working. As it turns out, pins 3 and 4 have on-board 1k8 pull-ups for SPI which where causing the pin to always sit at around 3.1V with the pull-down enabled. Moving to pin 15 solved this issue.

After the photo-transistor was connected, I created a short C program to read the pin and write to a MySQL database. A database table called readings contains 2 INT columns – secs and tics. The program polls the pin every 10ms and whenever a flash is detected, the current unix timestamp (seconds since 1970) is stored in secs and the current microsecond time is stored in tics. A 10ms resolution is accurate enough for my purposes.

The program is run as a daemon and is started at boot time. Here is the code in its entirety:

#include <bcm2835.h>
#include <my_global.h>
#include <mysql.h>
#include <sys/time.h>
 
// Input on pin 15
#define PIN RPI_GPIO_P1_07
 
MYSQL * conn;
 
void cleanup(int signum)
{
    printf("Quitting...\n");
    mysql_close(conn);
    exit(signum);
}
 
int main (int argc, char **argv)
{
    char query[1000];
 
    if (daemon(0, 0) == -1)
        return 1;
 
    signal(SIGINT, cleanup);
 
    conn = mysql_init(NULL);
    // If cannot connect, wait 1 second
    while (conn == NULL)
        delay(1000);
 
    while (mysql_real_connect(conn, "SERVER", "USERNAME", "PASSWORD", "DB_NAME", 0, NULL, 0) == NULL)
        delay(1000);
 
    if (!bcm2835_init())
        return 1;
 
    // Setup pin as input
    bcm2835_gpio_fsel(PIN, BCM2835_GPIO_FSEL_INPT);
    // With pullup
    bcm2835_gpio_set_pud(PIN, BCM2835_GPIO_PUD_DOWN);
 
    while (1)
    {
        if (bcm2835_gpio_lev(PIN) == HIGH)
        {
            // Flash detected
            struct timeval tv;
            long secs;
            long tics;
            gettimeofday(&tv, NULL);
            secs = tv.tv_sec;
            tics = tv.tv_usec;
            sprintf(query, "INSERT INTO readings VALUES(%ld, %ld)", secs, tics);
            if (mysql_query(conn, query))
                return 1;
 
            // Wait for flash to clear
            while(bcm2835_gpio_lev(PIN) == HIGH);
        }
        // Delay 10ms
        delay(10);
    }
    return 0;
}

Next it was simply a case of displaying the data. For this, my chosen language was PHP for a web interface, using Google Chart Tools to display the data. The code for this will follow in another post. The live reading is calculated from the time between the last two flashes and updates every 5 seconds. On the graph, the spikes from my electric heating throughout the day can be clearly seen, as well as the fridge compressor turning on and off through the night.

This is all that was needed to get the raw data in to the Pi – making sense of the data was another matter entirely, with details to come later.