Having established how to power my CurrentCost monitor, the next step was to start using an Arduino to upload the data to one of the many Internet of Things (or IoT) data bucket sites out there and – for a first step – Cosm (what used to be called Pachube) seemed like as good a starting point as any.

First power usage and temperature graphs

The above graphs are generated using PachuBlog (which will no doubt get renamed CosmBlog at some point) and should be automatically refreshing every 15 minutes. EDIT: I’ve replaced the dynamic graphs with a static image as the feed is currently falling over and dying after about nine hours resulting in the graphs flatlining, which makes for a pretty dull thing to look at if I’ve gone away for the weekend and not pressed the reset button.

In all, it took longer to compose this post than it did to sort out the code and the graphs, so I can happily chalk this up as one of those things that just works like it’s meant to.

You’ll probably mumble to yourself that the code that performs this minor miracle is far from production ready, being cobbled together as it is from various other postings across the interweb, however, for the sake of anyone who urgently wants to interface their CurrentCost CC128 with an Arduino using the EtherCard library to upload the data to Cosm and doesn’t give a monkey’s about whether the code is pretty or not, here it is;

#include <SoftwareSerial.h>
#include <EtherCard.h>    // https://github.com/jcw/ethercard

#define COSM_FEED            "99999"
#define COSM_APIKEY          "PUT_YOUR_KEY_HERE"

#define PIN_CC128_RX          12   // read only on pin 4 to get data from CC128
#define PIN_CC128_TX          300  // set write to non-existent pin (300)

// CC128
SoftwareSerial currentcost(PIN_CC128_RX, PIN_CC128_TX);

char str[10]; // general char array
char startPwr[] = "<ch1><watts>";
char startTmpr[] = "<tmpr>";
char endChar = '<';
char readChar = 0xFF;
int sizePwr = sizeof(startPwr)-1;
int sizeTmpr = sizeof(startTmpr)-1;
int statePwr = sizePwr;
int stateTmpr = sizeTmpr;
int newstate = 0;
long PwrNum = 0;
double TmprDouble = 0.0;
long TmprNum = 0;
long TmprDecimal = 0;
byte DataAvail = 0;
unsigned int PwrSize = 0;
unsigned int TmprSize = 0;
unsigned int DataSize = 0;
char Pwr[16] = "";
char Tmpr[16] = "";
char TmprBuffer[16] = "";
char PwrBuffer[64] = "";
char DataSizeBuffer[8] = "";

// EtherCard
byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
char website[] PROGMEM = "api.cosm.com";
byte Ethernet::buffer[700];
uint32_t timer;
Stash stash;

void setup () {
  Serial.begin(57600);
  Serial.println("\n[Cosm / CurrentCost interface]");

  currentcost.begin(57600);    // connect to currentcost to get power and temperature data

  if (ether.begin(sizeof Ethernet::buffer, mymac, 10) == 0)
    Serial.println( "Failed to access Ethernet controller");
  if (!ether.dhcpSetup())
    Serial.println("DHCP failed");

  ether.printIp("IP:  ", ether.myip);
  ether.printIp("GW:  ", ether.gwip);
  ether.printIp("DNS: ", ether.dnsip);  

  if (!ether.dnsLookup(website))
    Serial.println("DNS failed");

  ether.printIp("SRV: ", ether.hisip);
}

void loop () {
  ether.packetLoop(ether.packetReceive());

  // read data from CC128
  if (currentcost.available()) {
    cc_read();
  }

  // Keep track of our iterations
  static int count = 0;
  if (DataAvail) {
    cosm_post(count++);
    DataAvail = 0;
  }
}

void cosm_post(int itr) {

  byte sd = stash.create();
  stash.print("Temp,");
  stash.println(TmprDouble);
  stash.print("Power,");
  stash.println(PwrNum);
  stash.save();

  // generate the header with payload - note that the stash size is used,
  // and that a "stash descriptor" is passed in as argument using "$H"
  Stash::prepare(PSTR("PUT http://$F/v2/feeds/$F.csv HTTP/1.0" "\r\n"
                      "Host: $F" "\r\n"
                      "X-ApiKey: $F" "\r\n"
                      "Content-Length: $D" "\r\n"
                      "\r\n"
                      "$H"),
          website, PSTR(COSM_FEED), website, PSTR(COSM_APIKEY), stash.size(), sd);

  // send the packet - this also releases all stash buffers once done
  Serial.print("Sending iteration : ");
  Serial.print(itr);
  Serial.println(" to Cosm");

  ether.tcpSend();

}

int parseDataTmpr(int oldstate, char chr) {
  newstate = oldstate;
  if (newstate > 0) {
    if (chr == startTmpr[sizeTmpr-newstate]) {
      newstate--;
    }
    else {
      newstate = sizeTmpr;
    }
  }
  else if (newstate  0) {
    if (chr == startPwr[sizePwr-newstate]) {
      newstate--;
    }
    else {
      newstate = sizePwr;
    }
  }
  else if (newstate  31) {
    stateTmpr = parseDataTmpr(stateTmpr, readChar);
    if (stateTmpr < 0) {
      Tmpr[abs(stateTmpr)-1] = readChar;
    }
    statePwr = parseDataPwr(statePwr, readChar);
    if (statePwr < 0) {
      Pwr[abs(statePwr)-1] = readChar;
    }
  }

  // finished collecting data from CC128
  else if (readChar == 13) {

    PwrNum = atol(Pwr);
    TmprNum = atol(Tmpr);
    TmprDouble = strtod(Tmpr,NULL);
    TmprDecimal = abs((TmprDouble - (int)TmprDouble) * 100); // convert decimal data to integer
    DataAvail = 1;

    // print debug information
    Serial.flush();
    Serial.println(" ");
    Serial.print("Pwr: ");
    Serial.print(PwrNum);
    Serial.print(" ");
    Serial.print(" Tmpr: ");
    Serial.print(" ");
    Serial.print(TmprDouble);
    Serial.print(" / ");
    Serial.print(TmprNum);
    Serial.print(" ");
    Serial.print(TmprDecimal);
    Serial.println(" ");
    Serial.flush();

  }
}