Monitor home energy with AMEE

Create an energy monitor using XML, Ruby, Rails, and Ajax

Electricity is invisible. To understand how people use it, you need to make it visible. This tutorial will show you how easy it is to build a Web-based energy monitoring system yourself, using a Current Cost real-time energy monitor and AMEE, a neutral Web-based API for energy data, combined with some XML, Ruby, Rails, and Ajax.

James Smith, Development Manager, AMEE

James Smith is Development Manager at AMEE. He has a background in software engineering, having spent over 10 years in C++ software development, on projects ranging from biometrics to flight simulation, as well as a PhD in 3D animation algorithms. James has also carried out substantial work in the environmental software sector, working on Web-based projects such as The Carbon Diet and Green Thing before joining AMEE.



29 September 2009

Also available in Portuguese

Before you start

This tutorial is for any developer interested in working with energy data on the Web, with a particular focus on electricity data. You will use a number of technologies, including XML, Ruby, HTTP, Atom, Rails, Google Charts, and a little bit of Ajax thrown in for good measure.

About this tutorial

Frequently used acronyms

  • Ajax: Asynchronous JavaScript + XML
  • AMEE: Avoiding Mass Extinctions Engine
  • API: Application program interface
  • HTML: Hypertext Markup Language
  • HTTP: Hypertext Transfer Protocol
  • MVC: Model-View-Controller
  • PC: Personal computer
  • REXML: Ruby Electric XML
  • UID: User identifier
  • URL: Uniform Resource Locator
  • USB: Universal Serial Bus
  • XML: Extensible Markup Language
  • YAML: YAML Ain't Markup Language

Electricity is invisible. You use it all the time, but you rarely know how much you use. To understand your energy use (and hopefully reduce it), you need to re-engage with energy in a way which is currently impossible. Smart metering and real-time monitoring can help, by making it easy to see just how much energy you use. Forthcoming systems such as Google Powermeter and Microsoft® Hohm offer to make your energy usage available over the Web, but, in this tutorial, I will show you how to build a similar system from scratch using readily-accessible tools.

To effectively reduce energy usage, you need to understand how much you use, and yearly or monthly figures just aren't good enough. For proper understanding, you need instant feedback. With the AMEE API, you will build a system in this tutorial that lets you visualise your energy usage from minute to minute and see changes instantly, connecting you with your energy use like never before.

A number of devices on the market allow you to monitor your home energy usage. In this tutorial, you learn to hook up those devices to AMEE, a neutral energy management API, and then create a simple Ruby on Rails Web site to visualize the results, so you can see your carbon emissions from electricity in real time over the Web.

Prerequisites

Join the green groups on My developerWorks

Discuss topics and share resources about energy, efficiency, and the environment on the GReen IT Report space and the Green computing group on My developerWorks.

If you are unfamiliar with AMEE, I suggest you read my introductory article, "Introduction to AMEE," before you start this tutorial. See the link to this article in Resources.

The following tools are needed to follow along with this tutorial:

  • A Linux™ PC; I assume you are working in a Linux environment, though most things should be easily adaptable to other platforms.
  • Ruby 1.8.6 or greater. Most modern UNIX®-based operating systems will have this installed already. Windows® users can download a simple installer. See Resources for a link to the download site.
  • Rubygems 1.3.1 or greater. Rubygems is a package management system for Ruby code (or "gems"). Once you have Rubygems installed, you will need to add GitHub to your sources list as shown in Listing 1. You will also need the rb232 gem for accessing serial ports from Ruby. Note that this is currently only available on Linux platforms—Mac and Windows versions are in the pipeline, however. For the display side of things, you will also need the rails gem installed. See Resources for a link to the download site for Rubygems.
    Listing 1. Installing required Ruby gems
    sudo gem sources -a http://gems.github.com
    sudo gem install Floppy-rb232 rails

Overview

In this tutorial, you will build an energy monitor from scratch using a Current Cost meter and the AMEE API. Take a look at both of these items, before you get into the creation of the energy monitor.

The Current Cost meter

The Current Cost meter is a real-time display unit for electricity monitoring. You connect it to your electricity supply, and it tells you how much power you use at any one time, as well as other stats like how much the energy costs you. The great thing about the Current Cost meter, however, is that it has a serial data output on it, so you can hook it up to your PC and get all the same data in your own code.

AMEE

AMEE, which is an acronym for Avoiding Mass Extinctions Engine, is a Web-based API that allows you to store and retrieve energy and consumption data, while also applying carbon calculations to work out emissions related to that consumption. By storing your energy information in an AMEE profile, you can build up a history of energy use and calculate a carbon footprint for it.

The finished app

This tutorial will step through the entire process of measuring your energy usage, sending it to AMEE over the Web, and then show the results. You will build a simplified version of the AMEE real-time energy monitoring demo in Figure 1, which graphs the last hour of energy usage for a Current Cost meter connected to it through AMEE. The version you will create will have most of the same functionality, but you just won't deal with the graphic design—you can do that part yourself!

Figure 1. AMEE's realtime energy monitoring demonstration
Screen capture of AMEE's realtime energy monitoring demonstration

Measuring energy use with a Current Cost device

Before you can produce and analyze the energy data, you must first gather this data with an energy monitor. As mentioned, you will use the Current Cost meter, which can connect to a PC, uses a public data format, and produces data in XML, which is, of course, easy to parse and make use of in your application.

Real-time energy monitors

Many people use electricity, but they seldom know how much. Real-time energy monitors aim to solve that problem by displaying your current usage at all times. You attach a special clamp around your incoming electricity supply, which is connected to a transmitter. This clamp measures the flow of energy through the wire, and transmits it to a display unit inside your home, so that you can get a live view of how much energy your home is using. These sort of systems are not 100% accurate—and can often a discrepancy of up to 10%—but they are good enough to get a rough idea of what is going on.

Of the many different makes and models on the market, the CC128 Envi made by Current Cost (see Figure 2) is particular interest to you. This is one of the few that can connect to a PC (using a special USB cable), and the only one with a public data format. This makes it a very attractive device if you like to play around with data, especially your own energy data.

Figure 2. The Current Cost CC128 "Envi" energy monitor
Photo of the Current Cost CC128 Envi energy monitor

Data output

Data is produced from the Current Cost meter in a simple XML format, which is sent as text over the serial output. If you hook up a PC to the meter using the correct cable and settings (57600 baud, 8 data bits, 1 stop bit, no parity) you can read this XML and do interesting things with it. Listing 2 shows the format.

Listing 2. Current Cost XML output
<msg>
  <src>CC128-v0.11</src>
  <dsb>00175</dsb>
  <time>20:57:01</time>
  <tmpr>24.9</tmpr>
  <sensor>0</sensor>
  <id>00077</id>
  <type>1</type>
  <ch1>
    <watts>00280</watts>
  </ch1>
</msg>

The meter sends an XML data packet every six seconds. The fields in the XML represent different bits of data. src identifies the type of meter and software version. dsb is "days since birth", that is, since the meter was first turned on. time is self-explanatory, and tmpr gives the current temperature as measured by the sensor in the meter. sensor and id identify which sensor is connected and how, and type tells you what type of sensor it is (1 is electricity). The most useful information is in the ch* tags. Each input channel on the meter (that is, each sensor) will have one of these, containing a watts tag that shows the current power usage measured by that sensor. You can get the total power by adding up all of the ch* sections.

The meter also stores and sends historical data. While you won't use it for this project, it's very useful data. It is also sent in XML packets, but is only sent every two hours in a stream of smaller packets, rather than one large packet. If you are interested, see Resources for a link to the XML format for this data.

Parsing the XML

Once you know you can get useful data from the meter, you need to get it into your code. The first step is to grab the data from the serial port that the meter connects to. To do that, you will build a Ruby script that reads data from the port, separates it into individual packets, and converts the XML into something you can use.

First, look at grabbing data from the serial port (see Listing 3).

Listing 3. A Ruby class to represent a Current Cost meter
require 'rb232'
require 'rb232/text_protocol'
require 'currentcost/reading'
require 'observer'

module CurrentCost

  class Meter

    include Observable

    def initialize(port = '/dev/ttyS0')
      @port = RB232::Port.new(port, :baud_rate => 57600, :data_bits => 8, 
:stop_bits => 1, :parity => false)
      @protocol = RB232::TextProtocol.new(@port, "\n")
      @protocol.add_observer(self)
      @protocol.start
    end

    def update(message)
      unless message.nil?
        # Parse reading from message
        @latest_reading = Reading.from_xml(message)
        # Inform observers
        changed
        notify_observers(@latest_reading)
      end
    end

    def latest_reading
      @latest_reading
    end

    def close
      @protocol.stop
    end

  end  
end

Listing 3 shows a Ruby class that represents the Current Cost meter. Let's step through what's going on, function by function.

The initialize function takes an argument, which tells the object which serial port to connect to. The Current Cost meter has a fixed set of connection parameters, so these are hardcoded in the line that creates the serial port object using the RB232 gem installed earlier. The next few lines deal with higher level handling of the protocol. The XML messages are just text, and are separated by newlines, so you can make use of a handy utility class in RB232 called TextProtocol. This class wraps the serial port up, and only passes on complete messages. It hides all of the details of having to read individual bytes and detect packet separators, making your life easier.

To set up the text protocol, create a new instance of the class, giving it the pre-initialized serial port as an argument. Also specify the separator character for the protocol, in this case a newline. But how do you get the messages when they arrive? Well, TextProtocol implements the Observer pattern, an implementation of which is included in Ruby's standard library. Basically, any object interested in receiving messages from a TextProtocol instance can do so by registering itself with that instance. The class which is observing must have an update function, which receives the updated data as an argument.

So, when the meter is created, register it with TextProtocol to receive the messages when they arrive. You then tell the protocol object to start monitoring the port.

To get the data, you need an update function; when a message is received, Meter::update is called, with an argument that is the text of the received message. In this case, the function needs to just do one thing: Take that message and convert it into something of use. Since the message is an XML representation of a reading, you will define a class called Reading, which can be created directly from an XML string. You can then pass on the reading to someone else who will decide what to do with it. To do this, make the Meter object itself implement the Observer pattern. By putting include Observer in the class definition, you pull in the required functionality.

Then, when you want to say that something has changed, just call changed, followed by notify_observers, with the data you want to send. In this case, you want to send on the Reading object that you just created. Don't worry about where it goes for now; I will come back to that later on!

Let's deal with the actual XML parsing now. See Listing 4 for the implementation of the Reading class.

Listing 4. A Ruby class for parsing Current Cost XML data
require 'rexml/document'

module CurrentCost

  class Reading

    def self.from_xml(xml)
      # Parse XML
      doc = REXML::Document.new(xml)
      # Create reading object
      r = Reading.new
      # Extract basic data
      r.software_version = REXML::XPath.first(doc, "/msg/src").text
      r.days_since_birth = REXML::XPath.first(doc, "/msg/dsb").text.to_i
      r.hour, r.minute, r.second = REXML::XPath.first(doc, "/msg/time").
text.split(':').map{|x| x.to_i}
      r.id = REXML::XPath.first(doc, "/msg/id").text rescue nil
      r.type = REXML::XPath.first(doc, "/msg/type").text rescue nil
      r.temperature = REXML::XPath.first(doc, "/msg/tmpr").text.to_f rescue nil
      r.sensor = REXML::XPath.first(doc, "/msg/sensor").text rescue nil
      # Channels
      r.channels = []
      REXML::XPath.each(doc, "/msg/*/watts") do |node|
        r.channels << { :watts => node.text.to_i }
      end
      # Done
      return r
    end

    attr_accessor :days_since_birth
    attr_accessor :hour
    attr_accessor :minute
    attr_accessor :second
    attr_accessor :id
    attr_accessor :type
    attr_accessor :software_version
    attr_accessor :temperature
    attr_accessor :sensor

    # An array of channels. channels[x][:watts] contains the current power for 
    # that channel in watts. 
    # The figure shown on the meter is the sum of the wattage for all channels.
    attr_accessor :channels

    # The sum of the current wattage for all channels, as shown on the meter
    def total_watts
      watts = 0
      channels.each { |c| watts += c[:watts] }
      return watts
    rescue
      0
    end

  end
end

The Reading class is very straightforward. It has a number of attributes that can be accessed that store various parts of the message from the meter, and it has a factory method to create an instance from an XML string. Look inside that.

You will parse the XML using Ruby's built-in REXML library (see Resources for information on using this parser). REXML is a nice easy-to-use parser, with full support for advanced features like XPath (which you will get to in a moment). The first step is to create a document object from the XML string. As the message is short, I use REXML's tree mode, where it parses the entire document into memory, after which point you can access any part of it. Once you parse the document fully, proceed to extract the information that you want. Use XPath queries to grab the parts of the document to put into each attribute of the Reading object. This might be overkill for the simple data at the start of the function, but it's useful at the end where you have to parse an unknown number of channels into an array. Because the code looks for any tag containing a watts tag, you can grab all the data without knowing how many are there. These readings are stored into an array of channels.

The value shown on the meter is the combined total of all channels, so you also write a helper function to give that total by simply adding up all of the channel data.

The Current Cost gem

At this point, you have a nice set of classes that can read Current Cost readings from a serial port, parse them into a simple Ruby structure, and notify arbitrary observers that something has changed.

All the functionality above has actually been wrapped up as a gem, so that you don't have to manually add it to every application where you want to use a Current Cost meter. The full source code is on GitHub (see Resources), and you can get it by installing the Floppy-currentcost gem. Simply create a CurrentCost::Meter object, make sure you have a class that conforms to Observer's requirements, register one with the other, and sit back and watch the readings drop neatly into your application. You can also get all of the source code used in this tutorial in Download.

Next, look at what you can do with these readings now that you have them.


Processing energy data with AMEE

The next step for this data is to store it somewhere so you can access it later on. You will also do some carbon calculations on the stored information, so you can see live emissions from the energy monitor. You will store the energy data in AMEE and let it work out carbon emissions. This section of the tutorial will show you how to take the readings from the meter and store them in the AMEE platform. Before moving on, you will need to sign up for an AMEE API key.

Creating a profile

First, create a profile, which is an area in which to store energy information for an individual (or a company, or anything that can be thought of as a single unit). You can create profiles using API calls, or manually through the AMEE Web interface, details of which are in the signup mail you will get from AMEE. For this project, as you want to use the same profile every time, you will create one manually and pass the profile identifier as a parameter.

Within a profile, AMEE arranges data into categories, each of which contain items. To store a piece of data, simply create the right sort of item inside the right category. By looking at the AMEE documentation (see Resources), you can see that the right place to store electricity information is in the /home/energy/quantity category, using the electricity data item. This will, by default, use United Kingdom (UK) electricity emission factors, but you can change the country code in the /metadata category.

Publishing meter data to AMEE

You will need to create some sort of publisher class to do the job of taking readings and putting them in AMEE. This publisher will have to receive a reading, decide whether or not to store it, and create an AMEE request that will store that data if appropriate. Listing 5 shows the code for such a class.

Listing 5. Storing Current Cost readings in AMEE
require 'net/http'

class AMEEPublisher

  def initialize(config)
    @profile_uid = config['amee']['profile_uid']
    @last_minute = Time.now.min - 1
    # Store AMEE connection details
    @server = config['amee']['server']
    @username = config['amee']['username']
    @password = config['amee']['password']
    # Get electricity UID for later
    req = Net::HTTP::Get.new("/data/home/energy/quantity/drill?type=electricity")
    req.basic_auth @username, @password
    req['Accept'] = "application/xml"
    http = Net::HTTP.new(@server)
    http.start do
      response = http.request(req)
      raise response.body if (response.code != "200")
      @uid = response.body.match("<Choices><Name>uid</Name><
Choices><Choice><Name>.*?</Name><Value>(.*?)<
/Value></Choice></Choices></Choices>")[1]
    end
  end

  def update(reading)
    # Let's put data into AMEE every minute.
    if Time.now.min != @last_minute
      @last_minute = Time.now.min
      # Create POST options
      options = {
        :dataItemUid => @uid,
        :startDate => Time.now.xmlschema,
        :endDate => (Time.now + 60).xmlschema,
        :energyConsumption => (reading.total_watts / 1000.0),
        :energyConsumptionUnit => "kWh",
        :energyConsumptionPerUnit => "h",
        :name => "currentcost"
      }
      # Post data to AMEE
      req = Net::HTTP::Post.new("/profiles/#{@profile_uid}/home/energy/quantity")
      req.basic_auth @username, @password
      req['Accept'] = "application/xml"
      req.set_form_data(options)
      http = Net::HTTP.new(@server)
      http.start do
        response = http.request(req)
        raise response.body if response.code != "201"
      end
    end
  end

end

In Listing 5, first look at the update function. As you must realize by now, this function is intended to be part of an Observer pattern. Having this function means that you can just register an instance of this class with a Meter object and everything will flow nicely.

Inside the update function, you have a few jobs to do. First of all, do you want to store this reading? The Current Cost meter will produce a reading every six seconds, but AMEE can only store data with a maximum time resolution of one minute. So, you ignore any data if it comes within a minute of the last time you stored anything. Save the current time when you send, and check it when you get a reading. A more intelligent approach might be to take an average of the readings received over a minute for a more accurate result, but that is left as an exercise for the reader!

As discussed above, storing data in AMEE involves creating profile items. To do this, send an HTTP POST request to the category where you want to store the data. The body of the POST should contain the item values that you want to store, along with any other required parameters. Start by building that parameter list.

The options hash in Listing 5 contains the parameter list. First, set the dataItemUid parameter. This is a 12-digit hex string (UID) that tells AMEE which type of profile item you want to create. I'll come back to how to get that UID in a moment. For now, just assume you already have it. The next two parameters are the startDate and endDate. These parameters define the time period that your item will be valid for. Use the current time as the start, and the end is set to be in 60 seconds. AMEE will round the times down to the minute automatically.

The next few options are the actual data you want to store. For this data item, the value that you want to store is called energyConsumption. As this is an energy (not power) figure, you will send it in kilowatt-hours (kWh). You have watts, so divide by 1000 to get a figure in kilowatts. AMEE actually wants a rate of energy—it has a time dimension to it as well as just "energy used". If you send energy into AMEE in kilowatt-hours per hour, you can just use the kilowatt figure without any further conversion. The energyConsumptionUnit and energyConsumptionPerUnit specify the energy and time units that you want to use respectively. You also set a name for this item. This isn't required, but it is necessary if you ever want to store more than one data series of the same type in the same category, so add it now.

Once you create the parameter list, storing it in AMEE is simple. Use Ruby's built-in Net::HTTP library to create a POST request. The path for the POST includes the profile UID and the category path. Provide the AMEE login credentials using the standard HTTP Basic authentication method, and set the Accept header in the request to application/xml. This will make sure that any responses you get are in the right format. JSON is also available. You then send the request, and expect to get a 201 response, which means that AMEE has created the item you asked it to.

The other function in Listing 5 is the initialize function. This is run when the object is created, so you can do any one-time setup here. Earlier on, I assumed you knew the UID of the data item you wanted to store. This is the place to actually fetch it. Make a GET request to a drilldown resource. This takes a human-readable name like "electricity" and converts it into an AMEE UID for later use. The path for the drill is the data category corresponding to the profile category you are using, and the UID is easily obtained from the XML response by using a regular expression. You do it this way because UIDs are not stable across different AMEE platforms—if you hardcoded the right UID for the development (stage) platform, it wouldn't work when it was time to transfer over to the live (production) platform.

Hooking it all together

As mentioned, the code above is designed to hook directly into a CurrentCost::Meter object and receive readings directly. You need something around it to initialize that connection, and then to run on our system continuously processing the data and publishing it to the right places. Listing 6 shows a simplified version of such a script.

Listing 6. System daemon wrapper
require 'rubygems'
require 'daemons'
require 'currentcost/meter'
require 'yaml'
require 'amee_publisher' 
# Load config
config = YAML.load_file('currentcostd.yml')
Daemons.run_proc('currentcostd', :dir_mode => :system) do
 
  # Create meter object
  meter = CurrentCost::Meter.new config['currentcost']['port'], :cc128 => true 
  meter.add_observer(AMEEPublisher.new(config))
  # Just let it run
  while (true)
    sleep(30)
  end
 
end

This script uses the daemons ruby gem to run as a background process. Simply load the configuration from a YAML file, create the Meter object, hook it up to an AMEE publisher, then just let it run indefinitely—the daemons gem can take care of stopping it if you want to.

The Currentcost-daemon project on GitHub includes the AMEE publisher, along with a few similar publishers for different systems. You can set it up to run in the background and publish Current Cost readings to many different targets (including Twitter!). See Resources for details.


Displaying the data with Rails

Now that you have regular readings of your electricity usage and have stored them in AMEE, it's time to do some visualization of this data. While you might do that many ways, I will go for the obvious choice and build something that can display the carbon emissions of energy use over time as a graph. For this, you will build a Web site that can take the data from AMEE and present it in a useful way.

Getting carbon data out of AMEE

The first step is to get the data back out of AMEE. Also, you don't just want one reading but a series of them—let's say the last hour's worth. Fortunately, AMEE provides access to this information in a standard way, by providing an Atom feed for every category in a profile. This feed has an entry for every item stored, starting with the most recent and going back in order. You could put this straight into a feed reader if you wanted to, or run it through feed processors like Yahoo! Pipes, but you will make your own site to consume it and produce some results.

Fetching the feed for a category is as simple as sending an authenticated GET request to the profile category, with an Accept header of "application/atom+xml". I'll show you the code to do that in a while, but first look at the feed itself, in Listing 7.

Listing 7. A typical Atom feed for an AMEE profile category
<feed xmlns="http://www.w3.org/2005/Atom" 
xmlns:amee="http://schemas.amee.cc/2.0" xml:lang="en-US" xml:base=
"http://stage.amee.com/profiles/A2C16CB5BE98/home/energy/quantity">
  <title type="text">Profile A2C16CB5BE98, Category Quantity</title>
  <id>urn:dataCategory:A92693A99BAD</id>
  <generator version="2.0" uri="http://www.amee.cc">AMEE</generator>
  <link href="" type="application/atom+xml" rel="edit" />
  <link href="" type="application/json" rel="alternate" />
  <link href="" type="application/xml" rel="alternate" />
  <author>
    <name>A2C16CB5BE98</name>
  </author>
  <amee:name>Quantity</amee:name>
  <amee:categories />
  <updated>2009-08-11T20:49:04.000Z</updated>
  <entry>
    <title type="text">currentcost</title>
    <subtitle type="text">Tue, 11 Aug 2009 21:49:00 BST - Tue, 11 Aug 2009 
21:50:00 BST</subtitle>
    <link href="02D07ECC41CB" type="application/atom+xml" rel="edit" />
    <link href="02D07ECC41CB" type="application/json" rel="alternate" />
    <link href="02D07ECC41CB" type="application/xml" rel="alternate" />
    <id>urn:item:02D07ECC41CB</id>
    <published>2009-08-11T20:49:00.000Z</published>
    <updated>2009-08-11T20:49:00.000Z</updated>
    <amee:dataItem uid="CDC2A0BA8DF3" />
    <amee:startDate>2009-08-11T21:49:00+01:00</amee:startDate>
    <amee:endDate>2009-08-11T21:50:00+01:00</amee:endDate>
    <amee:amount unit="kg/year">2686.900900</amee:amount>
    <amee:itemValue>
      <amee:name>Energy Consumption</amee:name>
      <amee:value>0.21</amee:value>
      <link href="02D07ECC41CB/currentReading" rel="http://schemas.
amee.cc/2.0#itemValue" />
      <amee:unit>kWh</amee:unit>
      <amee:perUnit>hour<amee:perUnit>
    </amee:itemValue>
    <amee:name>currentcost</amee:name>
    <content type="html"><div class="vevent"><div 
class="summary">2686.900900 kg/year</div><abbr class="dtstart" 
title="2009-08-11T21:49:00+01:00"> Tue, 11 Aug 2009 21:49:00 BST</abbr> - <abbr 
class="dtend" title="2009-08-11T21:50:00+01:00"> Tue, 11 Aug 2009 21:50:00
 BST</abbr></div></content>
    <category scheme="http://schemas.amee.cc/2.0#item" term="CDC2A0BA8DF3" 
label="Energy Quantity" />
  </entry>
</feed>

The feed in Listing 7 is just standard Atom with a few custom extensions for AMEE-specific data. Each item in the category is an entry, though I only show one in Listing 7 for brevity. Different parts of this feed will be useful to you depending on your interests, but the useful parts for this tutorial are the amee:amount and amee:itemValue tags. The amount tag in each entry shows the carbon footprint of that item, in kg/year by default (you can change this with parameters to the GET). This is the value you want to plot. Also included in the feed are the individual item values, such as Energy Consumption, which you set earlier. Listing 7 only shows one, again for brevity, but will a series of them in a real feed. If you want to plot the actual energy used over time, you can use the amee:value tag for the Energy Consumption value to get the value for each entry.

Creating the display application

The feed is useful, but you need to display it, so let's built a Web site that can do exactly that. You will use the Ruby on Rails framework for this tutorial, though you can just as easily build the same thing in PHP, Django, Java™, or any other Web technologies.

The first step is to create the Rails application and do some basic setup, as in Listing 8.

Listing 8. Creating and configuring your Rails app
rails realtime_display
cd realtime_display
script/generate controller Main

config/routes.rb
map.root :controller => "main"

config/initializers/load_config.rb
$AMEE_CONFIG = YAML.load_file("#{RAILS_ROOT}/config/config.yml")

config/config.yml
username: your_amee_username
password: your_amee_password
server: stage.amee.com
profile: your_amee_profile_uid

app/views/layouts/application.html.erb
<html>
  <head><%= javascript_include_tag :defaults %></head>
  <body><%= yield %></body>
</html>

The first few commands create the application and a controller for the application called MainController. Rails is an MVC-oriented framework. Requests are handled by controllers, which manipulate data from models, and render views to create the actual HTML output that is sent back to the browser.

The subsequent lines in Listing 8 are some basics to get the application set up. You set the MainController to handle the root URL of the site. You load a YAML configuration file, which will contain AMEE connection and profile details, and you set up a basic application layout template that includes a set of standard JavaScript libraries, including Prototype and script.aculo.us.

Before writing code, you should decide how the page will be structured. Since the Atom feed can take a short while to retrieve from AMEE, you will load it through a bit of Ajax. The main index page will do very little except set up a container for the results and then call the Ajax action once the page is loaded. To get a live view of energy use, you will also make it load the latest data once a minute. Listing 9 shows the code for this index page.

Listing 9. app/views/main/index.html.erb: Main view, calls Ajax action to get data
<div class="data" id="data">
  <%= image_tag "ajax-loader.gif" %>
</div>
<% javascript_tag do -%>
  new Ajax.Request("<%= url_for :controller => 'main', :action => 
'update_data' %>", { method:'get'});
<% end -%>
<%= periodically_call_remote(:url => {:controller => 'main', 
:action => 'update_data'}, :frequency => '60', :method => :get) %>

Note that the only displayed content here is an image with an Ajax-style loading icon on it. The rest of the page is JavaScript. The first part does an immediate Ajax GET request to an action in our MainController called update_data. The result of that action will be inserted into the page later on. You also use Rails' periodically_call_remote helper function to set up the same call to happen once a minute after the page is loaded. You need both, unfortunately, as periodically_call_remote will not do its first call until a minute after the page is loaded.

Now you can start to write the controller code. This will do all the heavy lifting to fetch the feed from AMEE, parse it, and convert it into a chart image (see Listing 10).

Listing 10. app/controllers/main_controller.rb: parses AMEE Atom feed and converts to Google Chart
require 'net/http'

class MainController < ApplicationController

  def update_data

    # Grab AMEE feed
    http = Net::HTTP.new($AMEE_CONFIG['server'])
    http.read_timeout = 20
    http.start
    items = []
    req = Net::HTTP::Get.new("/profiles/#{$AMEE_CONFIG['profile']}
/home/energy/quantity?itemsPerPage=60")
    req.basic_auth $AMEE_CONFIG['username'], $AMEE_CONFIG['password']
    req['Accept'] = "application/atom+xml"
    feed = http.request(req)

    # Parse data and find max value while we're at it
    max = 0
    doc = REXML::Document.new(feed.body)
    REXML::XPath.each(doc, '/feed/entry') do |entry|
      item = entry.elements['amee:amount'].text.to_f
      max = item if item > max
      items << item
    end
    items.reverse!

    # Get current value
    @current = items.last.to_i

    # Create image URL
    params = []
    params << "cht=lc"
    params << "chs=600x200"
    params << "chd=t:#{items.join(',')}"
    params << "chds=0,#{max}"
    params << "chxt=x,y"
    params <<"chxl=0:|#{(Time.now-items.count.minutes).strftime("%H:%M")}|#
{(Time.now-(items.count/2).minutes).strftime("%H:%M")}|#{Time.now.strftime("%H:%M")}"
    params << "chxr=1,0,#{max.to_i}"
    @image = "http://chart.apis.google.com/chart?#{params.join('&')}"

    respond_to do |format|
      format.js {
        render :update do |page| 
          page.replace_html 'data', :partial => 'data' 
        end
      }
    end

  end
end

Note that there is only one function in this controller: update_data. Because the index action is very simple (it's pure HTML and JavaScript), you can let the Rails framework render it automatically using the file in Listing 9.

When the update_data action is called, you need to do a series of things. First, grab the Atom feed from AMEE. Again, use the Net::HTTP library to do the request. Set up a simple GET to the same URL as you POSTed to earlier, with an Accept header of "application/atom+xml". By default, you will only get the latest 10 items in the feed, so use the itemsPerPage parameter on the end of the GET URL to force AMEE to give you 60, enough for the last hour of energy use. Note that this request is still authenticated with HTTP Basic.

Once you have the Atom feed, you need to turn it into something we can put in a chart. All you need is an array of carbon values, so simply parse the Atom feed into a REXML document and use XPath to loop through each entry fetching the contents of the amee:amount tag. Add each amount to the array, keeping track of the highest value as you go for use later on. Once you've done this, reverse the array so that the oldest values are at the start rather than the end, which makes more sense when graphing. You also store the latest value as @current to display later on.

Now you need to create an image from the data. The Google Charts API is perfect for this; by simply creating the right URL, you can graph any data without having to deal with actually creating image files. The charts API consists of creating a URL with a series of query parameters on the end. The first parameter you add is cht, which specified the chart type; in this case, a line chart (lc). Next is chs, the size in pixels. Now you come to the actual data, in the chd parameter. This is a simple comma-delimited list of values, so creating it is as simple as using Array#join on the data. You also need to tell Google Charts what the highest value is so that it can scale the graph appropriately. Use the chds parameter, setting the highest and lowest values. That's all you really need to make a chart; the remaining parameters just add axis labels. For more details on these, see the Google Charts documentation link in Resources. Now, you only need to paste that URL into an image tag in your page and we will have a graph.

The final stage in the update_data action is to actually render the data. In this case, since it is an Ajax action, use Rails' helpers once again to render some JavaScript, which replaces the content of the data element in the index page (the DIV surrounding the Ajax loader image) with content rendered by a Rails partial view called, once again, data. Listing 11 shows the partial code (see Downloads for the full source code).

Listing 11. app/views/main/_data.html.erb: Data view partial, renders results
<div id="date">
  <%= Date.today.strftime("%A, %d %B %Y") %>
</div>
<% if @current %>
  <div id="total">
    Live CO2 emitted: <span class="current-power"><%= number_with_
delimiter @current %></span> kg/year (equiv.)
  </div>
<% end %>
<div id="graph">
  <%= image_tag @image, :width => 600, :height => 200 %>
</div>

This is just generating simple HTML. Add the date, some text for the current carbon value, and then just create an image tag that uses the URL you created in the update_data action. Once the Ajax call is complete, your page looks something like Figure 3, with a date, a current total, and a history graph.

Figure 3. Your energy usage displayed in your browser
History graph of energy usage displayed in your browser

Because of the periodical Ajax load, this graph will update once a minute to show the latest data from your Current Cost meter! Note that at no point does the Web site talk to the meter directly. By using AMEE in the middle, you have decoupled the collection and display of the data completely, allowing you to change either one without affecting the other.


Summary

In this tutorial, you created a complete Web-based, real-time energy monitoring solution. This shows every stage of using AMEE for data aggregation and storage, including history and Atom feed output. The display you created here is very simple, but you now have all the knowledge necessary to create something that can connect people to their energy use in new and innovative ways!


Download

DescriptionNameSize
Energy monitor source codetutorial.monitor.zip128KB

Resources

Learn

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into XML on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=XML, Web development, Open source, Linux, Industries
ArticleID=431094
ArticleTitle=Monitor home energy with AMEE
publish-date=09292009