The FunTechHouse project, a open source home automation system - Electricitymeter with pulse output

Abstract

Reads power consumption from a Electricity meter via the meters puls output, and publishes the results on a MQTT server.

MQTT Interface

Data out

A rising reading of how much has been used since. Every time the device is restarted the reading restarts with 0.

data syntax is "energy=XX.XXX kWh", where XX.XXX is the reading in kWh.

example:

"18:57:12" "FunTechHouse/Energy/meter01" "energy=59.549 kWh"
"19:00:22" "FunTechHouse/Energy/meter01" "energy=59.554 kWh"
"19:03:32" "FunTechHouse/Energy/meter01" "energy=59.558 kWh"

"18:57:12" "FunTechHouse/Energy/meter02" "energy=46.440 kWh"
"19:00:22" "FunTechHouse/Energy/meter02" "energy=46.440 kWh"
"19:03:32" "FunTechHouse/Energy/meter02" "energy=46.501 kWh"

Data in

This project does not subscribe to any data.

Hardware list

Name Link Desc
Arduino Uno arduino.cc - Arduino Uno
Arduino Ethernet Shield arduino.cc - Arduino Ethernet Shield
Iskra WS1102 Datasheet Iskra WS1102 A energy meter with a pulse output, 1000 impl/kWh

Schematics

Software list

Name Desc
github.com - FunTechHouse_ElectricityMeter The main Arduino program
arduino.cc - arduino-1.0.1 The Arduino environment
Arduino Client for MQTT / (github) The mqtt client code included in the main app.

Software description

The setup tells that we would like to connect interrupt function onPulse1 to pin 2 and onPulse2 on pin 3. Also to start ethernet and send a stupid message to the mqtt server that we had a restart, a little hello.

Filename: setup.part.c

void setup()
{
    // KWH interrupt attached to IRQ 0  = pin2
    attachInterrupt(0, onPulse1, FALLING);
    // KWH interrupt attached to IRQ 1  = pin3    
    attachInterrupt(1, onPulse2, FALLING);

    Ethernet.begin(mac, ip);
    if (client.connect(project_name)) 
    {
        client.publish(topic_meter01, "#Hello world");
        client.publish(topic_meter02, "#Hello world");
        //client.subscribe("inTopic");
    }
}

Then every time we get a interrupt from the energy meter we know he has measured 1 Wh, so we add 1Wh to the counter. However to avoid overflow to fast I splitted the counter into two variables, so when we hit 1kWh we increase that one.

Filename: onPulse1.part.c

void onPulse1()
{
    //pulseCounter
    pulseCount1_Wh++;
    if(pulseCount1_Wh == 1000)
    {
        pulseCount1_Wh = 0;
        pulseCount1_kWh++;
    }
}

And every 10s or so we run the loop function. But to avoid to much data, we only send data to the server every 3-4min or so.

Filename: loop.part.c

void loop()
{
    //Talk with the server so he dont forget us.
    if(client.loop() == false)
    {
        client.connect(project_name);
    }

    //But only send data every minute or so
    // 6 ->   6*10s =  60s = 1min
    //12 -> 2*6*10s = 120s = 2min
    //18 -> 3*6*10s = 180s = 3min
    //BUT since the delay is not that accurate, 
    // 18 is more like 3.5 to 4 minutes in real life...
    if(updateCount > 18)
    {
        updateCount = 0;
        char str[30];

        snprintf(str, 30, "energy=%u.%03u kWh", pulseCount1_kWh, pulseCount1_Wh);
        if(client.connected())
        {
            client.publish(topic_meter01, str);
        }

        snprintf(str, 30, "energy=%u.%03u kWh", pulseCount2_kWh, pulseCount2_Wh);
        if(client.connected())
        {
            client.publish(topic_meter02, str);
        }
    }

    updateCount++; 
    delay(10000); // 10*1000ms = 10s
}

And the entire code looks like this.

Filename: FunTechHouse_ElectricityMeter.ino

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

// Update these with values suitable for your network.
byte mac[]    = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0x02 };
byte ip[]     = { 192, 168, 0, 32 };
byte server[] = { 192, 168, 0, 64 };

char project_name[]  = "FunTechHouse_ElectricityMeter";
char topic_meter01[] = "FunTechHouse/Energy/meter01";
char topic_meter02[] = "FunTechHouse/Energy/meter02";

//Number of pulses, used to measure energy.
volatile unsigned int pulseCount1_Wh  = 0;   
volatile unsigned int pulseCount1_kWh = 0;   

volatile unsigned int pulseCount2_Wh  = 0;   
volatile unsigned int pulseCount2_kWh = 0;   

volatile unsigned int updateCount = 0;   

void callback(char* topic, byte* payload,unsigned int length) 
{
    // handle message arrived
}

// The interrupt routine
void onPulse1()
{
    //pulseCounter
    pulseCount1_Wh++;
    if(pulseCount1_Wh == 1000)
    {
        pulseCount1_Wh = 0;
        pulseCount1_kWh++;
    }
}

// The interrupt routine
void onPulse2()
{  
    //pulseCounter
    pulseCount2_Wh++;
    if(pulseCount2_Wh == 1000)
    {
        pulseCount2_Wh = 0;
        pulseCount2_kWh++;
    }
}

PubSubClient client(server, 1883, callback);

void setup()
{
    // KWH interrupt attached to IRQ 0  = pin2
    attachInterrupt(0, onPulse1, FALLING);
    // KWH interrupt attached to IRQ 1  = pin3    
    attachInterrupt(1, onPulse2, FALLING);

    Ethernet.begin(mac, ip);
    if (client.connect(project_name)) 
    {
        client.publish(topic_meter01, "#Hello world");
        client.publish(topic_meter02, "#Hello world");
        //client.subscribe("inTopic");
    }
}

void loop()
{
    //Talk with the server so he dont forget us.
    if(client.loop() == false)
    {
        client.connect(project_name);
    }

    //But only send data every minute or so
    // 6 ->   6*10s =  60s = 1min
    //12 -> 2*6*10s = 120s = 2min
    //18 -> 3*6*10s = 180s = 3min
    //BUT since the delay is not that accurate, 
    // 18 is more like 3.5 to 4 minutes in real life...
    if(updateCount > 18)
    {
        updateCount = 0;
        char str[30];

        snprintf(str, 30, "energy=%u.%03u kWh", pulseCount1_kWh, pulseCount1_Wh);
        if(client.connected())
        {
            client.publish(topic_meter01, str);
        }

        snprintf(str, 30, "energy=%u.%03u kWh", pulseCount2_kWh, pulseCount2_Wh);
        if(client.connected())
        {
            client.publish(topic_meter02, str);
        }
    }

    updateCount++; 
    delay(10000); // 10*1000ms = 10s
}

Build info