Home Energy Monitoring

Recently, the noise from the multiple servers running in the garage, the enormous energy bills, and my general sense of “I should do more to save the planet” outweighed my procrastination and led me to take action and reduce my energy consumption.

My first step was buying an Energy Monitor. After looking at a few different models, I spotted one with a USB cable that would allow me to “send the readings to a home PC.” Ohh! I could do something with the data instead of just looking at it on a handheld monitor. Interesting…

Getting Started

The first thing to do is install the monitor and the next thing is to install the drivers for the USB cable—these allow the USB connection to present itself as a COM port and make it easy to interact with.

Next, test the basic functionality. To do this (and to see the data transfer in action) you will need a Terminal client. Open your terminal software, set the COM port to whatever the USB Cable driver surfaced as (typically COM 3), set the baud rate to 57600bps, 8 data bits, “none” for parity, 1 stop bit, and no handshaking. When you “open” the COM port you should now see an Xml string being received every six seconds (for example):

HTML

<msg>
   <src>CC128-v0.11</src>
   <dsb>00089</dsb>
   <time>13:02:39</time>
   <tmpr>18.7</tmpr>
   <sensor>1</sensor>
   <id>01234</id>
   <type>1</type>
   <ch1>
      <watts>00345</watts>
   </ch1>
   <ch2>
      <watts>02151</watts>
   </ch2>
   <ch3>
      <watts>00000</watts>
   </ch3>
</msg>

The format of the Xml data can be found in this document, available on the CurrentCost website.

Project Outline / Design

Thinking about the project outline and design, I knew that I wanted to be able to make the received data readings available to multiple applications and websites. I also wanted to be able to tweet my energy usage every couple of hours, upload the data to some data tracking/recording web app, and be able to store the data myself so I could chart it at a later date. I also wanted the ability to see the real-time data when I was away from home, and I wanted to be able to use my phone as a kind of remote monitor.

I sketched out some ideas and came up with a design for a core Windows service that simply grabbed the data from the device, decoded it, and then passed it on to a number of modules/plugins, each of which used the data to complete a specific action. This kind of module/plugin/extension framework is a good candidate for the Managed Extension Framework (MEF) in .NET 4.0:

image

In fact, we'll be targeting the .NET 4.0 framework because we need some of the newer System.Composition namespace elements for the Managed Extension Framework to work.

Step 1 – The Windows Service

The Windows Service is the core of the application and needs a serial port connection to receive the data from the monitor, making it able to alert each of the plugins of the new reading.

Coding the Service

To begin coding the service, you must first create a new “Windows Service” project type. Then, change the class name to EnergyService and the ServiceName to EnergyService, add the serial port, and wire it up. To do this, you'll need a System.IO.Ports.SerialPort member variable in the class:

C#

SerialPort comm;

Create the object in the class constructor, and wire up the ‘DataReceived' event:

C#

comm = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
comm.DataReceived += new SerialDataReceivedEventHandler(SerialDataReceived);

Then, we pull the bytes from the serial port in the ‘SerialDataReceived' event handler and add them to a buffer, immediately checking the buffer to see if the bytes we have stored in there so far make up a full reading. If so, we process it. If we don't have a full reading, however, we simply wait for more bytes.

void SerialDataReceived(object sender, SerialDataReceivedEventArgs e)
{
    rxBuffer += comm.ReadExisting();
    while (IsReading(rxBuffer))
    {
        // we have a reading (or partial reading), so let's process
        EnergyReading rdg = ExtractReading(ref rxBuffer);
        if (rdg.IsValid)
        {
            NotifyPlugins(rdg);
        }
    }
}

private EnergyReading ExtractReading(ref string rxBuffer)
{
    string rdgXml;
    int pos = rxBuffer.IndexOf(Environment.NewLine);
    rdgXml = rxBuffer.Substring(0, pos);
    rxBuffer = rxBuffer.Substring(pos + 2);
    return new EnergyReading(rdgXml);
}

Debug

I also added a debug feature allowing you to inject a reading every six seconds. To enable the debug mode, simply set “debug_enabled” to “true” in the appSettings section of the app.config file.

image

Parsing the Readings

The xml text is passed to the constructor of the EnergyReading class and this parses the xml into the required properties, which gives us an object to pass around as needed. The EnergyReading class only extracts the timestamp, temperature and energy values, though there is scope for parsing much more, especially from the “history” readings (see the Xml definition for more info). Note: we also override the ToString() method so that we have a simple method of debugging the app/values.

C#

class EnergyReading
{
    public DateTime TimeStamp { get; private set; }
    public float Energy { get; private set; }
    public float Temperature { get; private set; }
    public bool IsValid { get; private set; }

    public EnergyReading(string readingData)
    {
        TimeStamp = DateTime.MinValue;
        Energy = float.NaN;
        Temperature = float.NaN;
        IsValid = false;

        try
        {
            // parse the xml based reading
            XmlDocument xDoc = new XmlDocument();
            xDoc.LoadXml(readingData);

            XmlNode xNode = xDoc.SelectSingleNode("/msg/time");
            TimeStamp = DateTime.Parse(xNode.InnerText);
            xNode = xDoc.SelectSingleNode("/msg/tmpr");
            Temperature = float.Parse(xNode.InnerText);
            xNode = xDoc.SelectSingleNode("/msg/ch1/watts");
            Energy = int.Parse(xNode.InnerText);
            IsValid = true;
        }
        catch (Exception ex)
        {
            // invalid reading
            Debug.WriteLine(ex.Message);
        }
    }

    public override string ToString()
    {
        StringBuilder sb = new StringBuilder(TimeStamp.ToLongTimeString());
        sb.Append(" - ");
        sb.Append(Energy.ToString("N"));
        sb.Append(" Watts - ");
        sb.Append(Temperature.ToString("N"));
        sb.Append(" Degrees");

        return sb.ToString();
    }
}

Adding the Plugin Infrastructure

Next up is adding the plumbing for the plugins. As previously mentioned, we will be using MEF, which makes it all incredibly simple.

Basically, we define an interface supported by all of the plugins, create a private variable of type IList<PluginInterface> and tag it with the [ImportMany] attribute (this holds our plugin objects), create a catalog of plugins (loaded from a specific directory), and then add that catalog to a CompositionContainer that automatically wires everything up for us. Sounds complex, but it only takes about 10 lines of code:

C#

using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;

// snip....

CompositionContainer container;

// snip....

[ImportMany]
private IList<IEnergyMonitorPlugin> plugins { get; set; }

// snip....

private void LoadPlugins()
{
    string baseDir = AppDomain.CurrentDomain.BaseDirectory;
    DirectoryCatalog currDirCatalog = new DirectoryCatalog(baseDir);

    container = new CompositionContainer(currDirCatalog);
    container.ComposeParts(this);
}



Now that we have all of the plugins correctly wired up, we need to notify them. For the time being, we'll also leave a few lines of debugging messages in there:

C#

private void NotifyPlugins(EnergyReading rdg)
{
    Debug.WriteLine("Notify : " + rdg.ToString());
    if (null != plugins)
    {
        foreach (IEnergyMonitorPlugin plugin in plugins)
        {
            try
            {
                Debug.WriteLine("Notify : " + plugin.Name);
                plugin.Notify(rdg);
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Plugin '" + plugin.Name + "' : " + ex.Message);
            }
        }
    }
}

Adding an Installer to the Windows Service

Now that we have completed the Windows Service, we need to test it out. To do so, we need to install it, and for that we need to add an Installer Class, as well as adding both a ServiceInstaller and a ServiceProcessInstaller to the designer (set the ServiceProcessInstaller Account property to “Local System” and run the service under this account).

Installing a service is different than installing a normal application. Luckily, we can use .NET framework's InstallUtil.exe to simplify things. I like to set InstallUtil.exe up as an External Tool in Visual Studio when I'm working on Windows Service projects, which makes the whole process as simple as highlighting the Windows Service project and clicking on the Install (or Uninstall) option under the Tools menu:

image

The configuration to set this up as an “external tool” is as follows:

TitleInstall Service (.NET 4)
CommandC:\Windows\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe
Arguments/i "$(ProjectDir)\bin\debug\$(TargetName)$(TargetExt)"
  
TitleUninstall Service (.NET 4)
CommandC:\Windows\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe
Arguments/i "$(ProjectDir)\bin\debug\$(TargetName)$(TargetExt)"

For 32-bit operating systems, change the Framework64 folder name to Framework.

Testing the Windows Service

Once you start the service, if you open the Output windows in Visual Studio and view the output from Debug, you should start seeing the readings come in:

image

 

Step 2 – The Twitter Plugin

The first plugin we'll write is a simple Twitter poster. Every 60 minutes, this plugin will send a tweet with your machine name and the average energy use over the last hour.

image

Next, create a new Class Library project and name it “TwitterPlugin.” Then add a reference to the “EnergyService_CSharp” project and have the class implement the IEnergyMonitorPlugin interface. We will also need to add some class variables to hold the last tweet time, energy total, and reading count.
As Twitter no longer supports Basic Auth for API calls we will need to use oAuth. For this we will use the excellent oAuth class developed by Eran Sandler and extended by Shannon Witley.

C#

[Export(typeof(IEnergyMonitorPlugin))]
public class TwitterPlugin : IEnergyMonitorPlugin
{
    double twInterval;
    double twEnergy = 0;
    int twReadings = 0;
    DateTime twLastTweet = DateTime.MinValue;
    oAuthTwitter _oAuth = new oAuthTwitter();

Next, we give the plugin values for “Name” and “Description” and set the DeInit() function to return true (this is a simple plugin so no deinitialization is needed). For the Init() function, we want to read from the app.config the twitter oAuth parameters, and the interval between tweets—remember, this plugin is loaded into the AppDomain of the service, so we need to add the entries to the app.config file of the service, not the app.config of the twitterplugin project/class.

The code looks like this:

C#

bool IEnergyMonitorPlugin.Init()
{
    _oAuth.Token = GetSetting("twitterplugin_token", "");
    _oAuth.TokenSecret = GetSetting("twitterplugin_tokensecret", "");
    _oAuth.Pin = GetSetting("twitterplugin_pin", "");

    twInterval = double.Parse(GetSetting("twitterplugin_interval", "60"));
    return true;
}

private string GetSetting(string key, string defaultValue)
{
    NameValueCollection appSettings = ConfigurationManager.AppSettings;
    string val = appSettings.Get(key);
    if (null == val)
    {
        val = defaultValue;
    }

    return val;
}

The crux of a plugin is the “Notify” function, and for this one we simply add the energy value to the total energy count and increase the reading count. We then check if more than 60 minutes have passed since the last tweet, and if so we send the tweet:

C#

bool IEnergyMonitorPlugin.Notify(EnergyReading rdg)
{
    bool retVal = false;

    twEnergy += rdg.Energy;
    twReadings++;

    if (twLastTweet.AddMinutes(twInterval) < DateTime.Now)
    {
    // it's time to tweet
        retVal= SendTweet(
            string.Format(
                "In the last {0} mins {1} has used an average of {2} watts", 
                twInterval, 
                Environment.MachineName, 
                (twEnergy/twReadings)));
        twEnergy = 0;
        twReadings = 0;
        twLastTweet = DateTime.Now;
        retVal = true;
    }

    return retVal;
}

Sending the tweet requires that we UrlEncode the message and then call the oAuthWebRequest method of the oAuth class with the post data as a parameter.

private bool SendTweet(string tweet)
{
    bool retVal = false;
    try
    {
        string encTweet = System.Web.HttpUtility.UrlEncode(tweet);
        string xml = _oAuth.oAuthWebRequest(
            oAuthTwitter.Method.POST,
            "http://twitter.com/statuses/update.xml",
            "status=" + tweet);
        retVal = true;
    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.WriteLine("Error : " + ex.ToString());
    }

    return retVal;
}

Now we have the Notify functionality of the TwitterPlugin completed. To get it working, simply copy the plugin to the same folder as the running Windows Service, edit the setting for “twitterplugin_interval” in the service app.config files, and restart the service. The tweets will not yet be accepted by Twitter as we have not yet authorized the application – for this we need user interaction so it is not something we do in the Windows Service. Instead we build a ConfigTool that uses MEF to load in each of the plugins and calls the “Configure” method.
We add a Windows Form to the TwitterPlugin, add a button that takes the user to a Twitter application authorization page, add a textbox that the user enters the PIN displayed on the webpage into and save the resulting oAuth Token and TokenSecret we get back from calling the AccessTokenGet method of the oAuth class. When we have all the oAuth parameters back we simply save them into the app.config file:

imageimage

If all is well, you should see tweets appearing every X minutes (depending on the interval you have set) along with your energy averages.

Now that we have completed our first plugin, it should be easy to see how simple it is to write further plugins. You might consider writing the energy values to a local database, sending Facebook updates, or posting to a dedicated service that uses API to store sensor or energy values, such as http://www.pachube.com or http://www.enio.co.uk.

 

Step 3 – The WebService and Plugin

The next stage we'll develop will give us a little more flexibility. Essentially, this stage consists of a RESTful Windows Communication Framework (WCF) Service and a corresponding WebSvcPlugin that we'll use to update the WCF Service with the latest readings. We'll also build a couple of client applications that will retrieve the reading from the WCF Service (one is a simple webpage using jQuery AJAX to get the reading from the WCF Service, and the other is a Windows Phone 7 application using a HttpWebRequest to get the reading from the WCF Service).

The plugin and clients will need the WCF Service to be in place before they can be written, so we'll tackle the WCF Service first by adding an “ASP.NET Empty Web Application” project to the solution and calling it “EnergyMonitorWs”:image

Then we add a new “AJAX-enabled WCF Service” and name it EnergyMonitor.svc:

image

The WCF Service will expose OperationContracts that allow clients to set the current values and receive each of the values in either JSON or XML format. The current values will be stored in an HttpRuntime.Cache object, so we don't need to worry about persisting the reading data to MSSQL or the FileSystem.

The cache object is in the System.Web.Caching namespace, so we'll need a reference to that. We'll also need to make sure we are working in AspNetCompatibility mode. To do so, we'll add the following attribute to the class:

C#

[AspNetCompatibilityRequirements(
    RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]

Now let's code the “SetCurrentValues” function, which exposes a “/set” endpoint and takes date, time, energy, and temperature as parameters on the HTTP GET querystring and stores them in the cache for an hour (this function should be called every 6 seconds, so caching each reading for up to an hour gives us plenty of room for failed updates).

C#

[OperationContract]
[WebInvoke(
    Method="GET",
    UriTemplate="set?energy={energy}&temp={temp}&date={date}&time={time}")]
public void SetCurrentValues(string energy, string temp, string date, string time)
{
    Cache cache = HttpRuntime.Cache;

    try
    {
        cache.Remove("energy");
        cache.Remove("temp");
        cache.Remove("date");
        cache.Remove("time");
    }
    catch { }

    cache.Add(
        "energy", 
        energy, 
        null, 
        DateTime.Now.AddHours(1), 
        Cache.NoSlidingExpiration, 
        CacheItemPriority.Default, 
        null);
    cache.Add(
        "temp", 
        temp, 
        null, 
        DateTime.Now.AddHours(1), 
        Cache.NoSlidingExpiration, 
        CacheItemPriority.Default, 
        null);
    cache.Add(
        "date", 
        date, 
        null, 
        DateTime.Now.AddHours(1), 
        Cache.NoSlidingExpiration, 
        CacheItemPriority.Default, 
        null);
    cache.Add(
        "time", 
        time, 
        null, 
        DateTime.Now.AddHours(1), 
        Cache.NoSlidingExpiration, 
        CacheItemPriority.Default, 
        null);

    return;
}

We want to make request functions available via a simple HTTP GET and we want to provide the option of JSON or XML as the response. Therefore, we add a “/json/{x}” endpoint and a “/xml/{x}” endpoint where {x} is the reading data we want (energy, temp, date or time):

C#

[OperationContract]
[WebInvoke(
    Method = "GET", 
    UriTemplate = "xml/{value}")]
public string GetValueXml(string value)
{
    WebOperationContext.Current.OutgoingResponse.ContentType = "text/xml";
    return GetValue(value.ToLower());
}

[OperationContract]
[WebInvoke(
    Method = "GET", 
    UriTemplate = "json/{value}", 
    ResponseFormat = WebMessageFormat.Json)]
public string GetValueJson(string value)
{
    return GetValue(value.ToLower());
}

private string GetValue(string key)
{
    Cache cache = HttpRuntime.Cache;

    string retVal = (string)cache.Get(key);
    if (null == retVal)
    {
        retVal = "N/A";
    }

    return retVal;
}

Now that we have the WCF Service in place, we can build the plugin that updates it. This is another Class Library project that we add to the solution (this time naming it WebServicePlugin), again making sure it implements the IEnergyMonitor interface (you'll need to add a reference to the EnergyMonitor_CSharp for this).

Give the plugin a Name and Description and set the Init() and DeInit() functions to return true. Then, simply have the code in the “Notify” function create an HTTP GET request with the values in the querystring to the “/set” endpoint (the SetCurrentValues function). This can be accomplished with a System.Net.WebClient object:

C#

bool IEnergyMonitorPlugin.Notify(EnergyReading rdg)
{
    bool retVal = false;

    DateTime ts = rdg.TimeStamp;

    string getUrl = baseUrl + "/set?";
    getUrl += "energy=" + rdg.Energy.ToString() + "&";
    getUrl += "temp=" + rdg.Temperature.ToString() + "&";
    getUrl += "date=" + ts.ToString("dd/MM/yy") + "&";
    getUrl += "time=" + ts.ToShortTimeString();

    WebClient wc = new WebClient();

    try
    {
        wc.DownloadString(getUrl);
        retVal = true;
    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.WriteLine(
            "Error (Notify) : " + ex.Message);
    }


bool IEnergyMonitorPlugin.Init()
{
    // get the base url from the (Service) app.config
    baseUrl = GetSetting(
        "websvcplugin_baseurl", 
        "http://localhost/EnergyMonWs.svc");
    return true;
}

// snip....


private string GetSetting(string key, string defaultValue)
{
    NameValueCollection appSettings = ConfigurationManager.AppSettings;
    string val = appSettings.Get(key);
    if (null == val)
    {
        val = defaultValue;
    }

    return val;
}

Now that we're done with the WCF Service and WebSvcPlugin, we need to work on the two WCF Service client applications.

Step 4 – The WebService Html Page Client

We'll first tackle the html webpage with jQuery—a simple webpage that uses the jQuery library to make AJAX calls to our WCF Service to get the current values—by adding a new ‘HTML Page' to the EnergyMonitorWs project. To begin, name the page EnergyMonitor.htm.

Next, we'll add some html to the page. This html is linked to some CSS, giving us a simple remote version of the energy monitor:

image

Then we use jQuery to call the WCF Service and update the actual values with real reading data. We also add a JavaScript timer to make the WCF Service calls every 15 seconds. Obviously, we need to reference the jQuery code and the CSS in the head section:

HTML

<head>
    <title>Energy Monitor - Ken Hughes</title>
    <script 
        src="scripts/jquery-1.4.1.js" 
        type="text/javascript"></script>
    <link 
        rel="Stylesheet" href="css/style.css" 
        type="text/css" />
</head>

 

Then, after the main page display elements, we add the javascript code so the values are updated every 15 seconds:

Javascript

function getReading(fname, elementid) {
    ajaxUrl = "EnergyMonWs.svc/json/" + fname;
    $.ajax({
        type: "GET",
        url: ajaxUrl,
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        success: function (msg) {
            // Replace the div's content with the value returned.
            $("#" + elementid).text(msg);
        }
    });
}


function updateReadings() {
    getReading("temp", "tempval");
    getReading("energy", "energyval");
    getReading("time", "timeval");
   
}

$(document).ready(function () {

    updateReadings();
    window.setInterval(function () {
        updateReadings();
    }, 15000);
});

Step 5 – The WebService Windows Phone 7 Client

The purpose of the Windows Phone 7 client is to act as a remote monitor. The client pulls its reading from the web service and updates a monitor-style display. To complete this part of the project, you will need to have the Windows Phone 7 Development tools installed.

image

Begin by adding a new “Windows Phone Application” project and calling it “WinPhoneEnergyMonitor.”

First, in the constructor, add a Timer object, set the interval to 15 seconds, and have it call a function to update the screen values. This function calls the webservice for each value, receiving the latest reading data and updating the relevant TextBlock.

In Windows Phone 7, uses an asynchronous manner to call to things such as the WebClient and HttpWebRequest. Accordingly, we create a new WebClient object, assign a delegate to the “DownloadStringCompleted” event, and then call “DownloadStringAsync” with the relevant uri along with the TextBlock we want to update as the ‘userState' object. All of this allows us to update the correct item in the event handler.

The code looks like this:

C#

private void UpdateScreen(object state)
{
    UpdateValueFromWebService("energy", this.energyValue);
    UpdateValueFromWebService("temp", this.tempValue);
    UpdateValueFromWebService("time", this.timeValue);
    UpdateValueFromWebService("date", this.dateValue);
}

private string UpdateValueFromWebService(string reading, TextBlock tb)
{
    string retVal = "N/A";
    Uri uri = new Uri(baseUri + "/json/" + reading);

    try
    {
        WebClient wc = new WebClient();
        wc.DownloadStringCompleted += 
            new DownloadStringCompletedEventHandler(DownloadStringCompleted);
        wc.DownloadStringAsync(uri, tb);
    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.WriteLine(
            "Error (UpdateValueFromWebService) : " + ex.Message);
    }

    return retVal;
}

void DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
    try
    {
        string val = e.Result.Replace("\"", "").Replace("\\", "");
        System.Diagnostics.Debug.WriteLine(val);
        ((TextBlock)e.UserState).Text = val;
    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.WriteLine(
            "Error (DownloadStringCompleted) : " + ex.Message);
    }
}

Conclusion

This was a really interesting project. Not only did it help me understand how much energy I was using (and help me reduce it), it also presented a software challenge covering a number of areas and technologies: Windows Service, WCF, Windows Phone 7, and javascript/jQuery.

I already have plans for a number of other plugins and new ways to visualize the usage data—keep an eye on the Codeplex site for updates.

If you want to try this out, the download link for the source code is at the top of the article!

About The Author

Ken Hughes is Chief Technical Officer at C2C Systems, a Microsoft Gold Partner ISV. He is passionate about technology, productivity, and automating everything. He stays up-to-date with and keeps his hand in new technologies by working on personal and open source projects such as dasBlog. Contact information may be found on both his blog and Twitter.

Tags:

Follow the Discussion

Comments Closed

Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation, please create a new thread in our Forums,
or Contact Us and let us know.