Interfacing the CurrentCost meter to an Arduino

After describing how to hook up your CurrentCost meter to your PC, it’s now time to see what else we can hook it up to. An obvious candidate is the Arduino microcontroller. For this project I’m using an Arduino Diecimila, which can be obtained quite cheaply from tinker.it in the UK.

Despite building our TTL->RS232 adapter in the previous post, it turns out that we don’t actually need it to interface with the Arduino - as with most microcontrollers, it expects TTL-level inputs. This makes the wiring trivially simple - we merely need to hook up the ground and data leads from the CurrentCost meter to the ground and one of the digital pins on the Arduino. As a reminder, pin 6 on the RJ45 connector is ground, and pin 7 is our data lead.

The Arduino has one hardware serial port which we could connect the CurrentCost data lead up to, but as the CurrentCost device only runs at 9600 baud, it seems a shame to waste our only high-speed serial port. Instead, we’re going to use the SoftwareSerial library to emulate a serial port on one of the other digital I/O pins - for this example, I chose digital pin 3. And that’s it - just two wires to connect!

Now we have the CurrentCost meter hooked up to the Arduino, it’s time to get it to do something! A good first step it to simply check that the Arduino is getting data from the CurrentCost device - to do this we’re simply going to read data in on the software serial port, and output it on the hardware serial port, which by default will be sent over the USB link to the host PC. The sketch for this follows:

/*
  CurrentCost test sketch

  Example CurrentCost sketch that simply reads in data from the CurrentCost
  device via the software serial port and outputs that data over the hardware
  serial port.

  by Alexis Birkill
  written: 16 June 2008

*/

// Include the SoftwareSerial library so you can use its functions.
// We're using the software serial library as the Arduino only  has one
// hardware serial port, and it's a shame to waste it on a 9600bps device.
#include <SoftwareSerial.h>

// Define the pins used for the software serial port.  Note that we won't
// actually be transmitting anything over the transmit pin.
#define rxPin 3
#define txPin 4

// Set up the serial port
SoftwareSerial softSerial =  SoftwareSerial(rxPin, txPin);

void setup()  {
  // Define pin modes for tx and rx pins:
  pinMode(rxPin, INPUT);
  pinMode(txPin, OUTPUT);
  // Set the data rate for the SoftwareSerial port
  softSerial.begin(9650);

  // Set the data rate for the hardware serial port
  Serial.begin(9600);
}

void loop() {
  // Listen for serial data coming in...
  char someChar = softSerial.read();

  // And send it back out...
  Serial.print(someChar);
}

Simply upload this to your Arduino and then open the Arduino serial port at 9600 baud (the Arduino IDE has this functionality built in - look for the ‘Serial Monitor’ option in the toolbar). If all goes well, you should see XML data output roughly every six seconds.

The more eagle-eyed amongst you will notice that I’m configuring the software serial port at 9650 baud, rather than 9600 baud. When I initially tried 9600 baud, I found that I would get certain characters corrupted. I’m not sure whether the CurrentCost device timing is slightly out, or whether the SoftwareSerial library is slightly off, or a bit of both, but changing it to 9650 baud fixed it. That’s why this simple script is really useful to check that everything is working correctly.

Now we have a simple script working, it’s time to put our Arduino to work. This next script parses out the current wattage figure from the XML data (as most of the time that’s the data you want to see), and also applies some damping - the CurrentCost reading tends to fluctuate slightly, and it’s not worth reporting every minor change. Finally, we’ll also switch one of the digital outputs on if we exceed a certain power figure - this sketch uses pin 13, which on the Diecimila has an LED hooked up to it, but you could use it to drive a bell or buzzer to alert you that you’re using a lot of power - or many other cool things!

/*
  CurrentCost data parser

  Example CurrentCost parser that reads in the serial data from the
  CurrentCost device and outputs the current wattage over the hardware
  serial port.

  by Alexis Birkill
  written: 16 June 2008

*/

// Include the SoftwareSerial library so you can use its functions.
// We're using the software serial library as the Arduino only  has one
// hardware serial port, and it's a shame to waste it on a 9600bps device.
#include <SoftwareSerial.h>

// Define the pins used for the software serial port.  Note that we won't
// actually be transmitting anything over the transmit pin.
#define rxPin 3
#define txPin 4

// Define the pin that will go high when the wattage exceeds a certain limit.
#define alertPin 13

// Set up the serial port
SoftwareSerial softSerial =  SoftwareSerial(rxPin, txPin);

// Local variables
char wattsStr[5];
int watts = 0;
int previousWatts = 0;

// Damping factor to filter out minor fluctuations - a fluctuation up or down
// by less than this value will be ignored.
int dampingFactor = 10;

// Wattage at which to activate alert output
int alertLevel = 800;

void setup()  {
  // Define pin modes for tx and rx pins:
  pinMode(rxPin, INPUT);
  pinMode(txPin, OUTPUT);
  // Set the data rate for the SoftwareSerial port
  softSerial.begin(9650);

  // Set the data rate for the hardware serial port
  Serial.begin(9600);
}

void loop() {
  // Listen for serial data coming in:
  char someChar = softSerial.read();

  // This is a rather horrible but simple way of looking for the correct data
  // without bothering to store any unnecessary data in the Arduino's memory.
  // We could simply store the whole XML string and then parse it, but that
  // would take up a lot of memory unnecessarily.  Instead, we just look for
  // the right character sequence.
  if(someChar == '<') {
    someChar = softSerial.read();
    if(someChar == 'c') {
     someChar = softSerial.read();
     if(someChar == 'h') {
      someChar = softSerial.read();
      if(someChar == '1') {
       someChar = softSerial.read();
       if(someChar == '>') {
        someChar = softSerial.read();
        if(someChar == '<') {
         someChar = softSerial.read();
         if(someChar == 'w') {
          someChar = softSerial.read();
          if(someChar == 'a') {
           someChar = softSerial.read();
           if(someChar == 't') {
            someChar = softSerial.read();
            if(someChar == 't') {
             someChar = softSerial.read();
             if(someChar == 's') {
              someChar = softSerial.read();
              if(someChar == '>') {

               // We got the right sequence - that means that the next five
               // characters are the current wattage.
               wattsStr[0] = softSerial.read();
               wattsStr[1] = softSerial.read();
               wattsStr[2] = softSerial.read();
               wattsStr[3] = softSerial.read();
               wattsStr[4] = softSerial.read();

               // Convert it into a integer.
               watts = atoi(wattsStr);

               // Add some damping so we don't display minor fluctuations
               if(previousWatts + dampingFactor < watts || previousWatts - dampingFactor > watts)
               {
                 // Value has changed by more than the damping factor - output it!
                 Serial.println(watts);
                 previousWatts = watts;
               }

               // Check if we need to switch the alert output on.
               if(watts >= alertLevel)
               {
                 digitalWrite(alertPin, HIGH);
               }
               else
               {
                 digitalWrite(alertPin, LOW);
               }
              }
             }
            }
           }
          }
         }
        }
       }
      }
     }
    }
  }

}

And there we go - the basics of getting an Arduino to process CurrentCost data!

11 Responses to “Interfacing the CurrentCost meter to an Arduino”

  1. I literally did this this morning and then happened upon this post. My code is almost exactly the same as yours too, really quite strange.

    Most of my inspiration came from Roo’s Serial LCD post - http://www.rooreynolds.com/2008/05/20/im-like-totally-serial/

    Just a note; my Current Cost operates at 2400 baud and uses pin 4 for ground and pin 8 for data out. I got mine from ecogadgetshop, for reference.

    Martin.

  2. To make the “XML parsing” easier, you might like to make use of the fact that the XML is always fixed length (except when it’s not… see below) and so you can just pluck the values you want from fixed byte offsets in the message.

    The exception is that sometimes, the CurrentCost meter doesn’t send out the history part of the message, if it’s “too busy”. This is completely unpredictable, but the good news is it does close off the XML properly, so it’s easy to spot if the “fork” happens, and act accordingly.

  3. Any notion on how much energy data could be stored in the 16K of the Arduino ? I’d be interested in an Arduino project that takes a reading every 30 seconds and storing just the watts figure and then is plugged into the USB port for transfer every XYZ days/weeks.
    Good work / Colm

  4. Using Arduino 0015 and a FreeDuino I just get junk from the CurrentCost with the softwareserial implementation.

    If I jack out the processor from the duino and use it as a serial interface , I get the correct data from the CurrentCost on the actual hardware serial pin 1 on the duino.

    Any idea why the software serial isnt working for me?

    The newer http://arduiniana.org/libraries/newsoftserial/
    seems to work okay fwiw.

    Mart.

  5. Hi Mart,

    As mentioned above I had to alter the baud rate slightly to 9650 to get reliable data from the CurrentCost device using the Software Serial library.

    I suspect this is due to slight timing errors in the library, and possibly compounded by the CurrentCost device not working at exactly 9600 baud (something which hardware serial interfaces will cope with happily).

    You may need to play with the 9650 figure to get reliable comms with your CC device, although if NewSoftSerial is working then I’d recommend using that.

  6. Hi

    The first sketch seems to output junk for me:

    ÿÿÿÿÿÿÿÿÿ?ëÍ?ãmÜÿã?Ü)ínÄÿaÿÏ¿ÿyÎÿÿá?áÿ?#ÿ?ÿµÿÿÿÿÿÿÿÿÿÿ?ëÍ?ÿãmÜÿã?Ü)íoÄÿaÿÏ¿ÿyÎÿ?ßÿËÿ?#ÿ?ÿ?ÿÿÿÿÿÿÿÿÿÿüëÍ?ÿãmÜÿã?Ü+íoÄÿaÿO¿ÿyÎÿÿä?áÿÌ#?ÿ?Çÿÿÿÿ

    sort of thing

    I tried a range or software serial rates (how many do I need to try??) and had no luck with NewSoftSerial but probably because I didn’t understand what code I need to change in the sketch other than include newsoftserial.

    Would really like to get this to work.

    Plain English please as I’m new to code and things digital (A level Electronics in 1980!)

    Thanks

    Nick

  7. Hi Nick,

    Do you have the CurrentCost Classic or the CC128? See here to see the different models: http://www.currentcost.com/products.html

    This post was written before the CC128 was launched. The CC128 has altered the serial rate to 57,600 baud, you can see the specs here:

    http://www.currentcost.com/cc128/xml.htm

    I’ve not tried this sketch with the CC128 but hopefully it should just be a matter of updating the baud rate to 57,600.

  8. Thanks for prompt reply Alex

    I tried 57,600 and a few variations of but no luck. Found some other discussion on Pachube forum but no answers.

    Will give up for now!!

    Thanks

    Nick

  9. I’ve also been playing with the CC128 and have finally managed to communicate with the thing.

    /*
    CurrentCost data parser

    Note that this parser requires NewSoftSerial to operate at 57600 baud
    and it is required to increase the receive buffer size (256 seems to work although it could be smaller)
    in order to get things to work in NewSoftSerial.h i.e

    #define _NewSS_MAX_RX_BUFF 256

    Note also that for the CC128 the data is on pin 8 and ground is pin 4

    by Ian Cooper 16/08/09
    */

    #include

    // Set up the serial port - read only (on pin 2) so set write to non-existent pin (300)

    NewSoftSerial currentcost(2, 300);

    void setup() {
    currentcost.begin(57600);
    Serial.begin(9600);
    }

    void loop() {
    // Listen for serial data coming in:
    if ( currentcost.available())
    {
    Serial.print ((char)currentcost.read()); //echo to serial monitor
    }
    }

  10. I was messing with this over and over. John Crouchley explained the pinout to me, which at least got me reading the right thing, but the input was still garbled.

    I upgraded Arduino to 0017 (I was on 0012) and made sure I had the latest NewSoftSerial. Apparently there are some timing problems which have been fixed in 0017, so I was really chuffed to see it finally working and debugging meaningful data over the USB serial.

    I highly recommend hacking this sketch, removing the XPORT stuff if you don’t have one http://john.crouchley.com/blog/archives/404

    Upgrade, people, it’s the future!

  11. If you haven’t found out about this elsewhere or tried it, some models of the energy meter output at a mere 2400 baud, and don’t include the history section (it would take too long to transmit!). Give that a try and see if it cures the gibberish.

    If it’s a 57600 one there’s every chance the timing might be off there as well, scaling up from 9650 gives you 57900… (and for 2400, it’s 2413). That or it’s always 50 baud adrift?

Leave a Reply