Jul 09

Cosm and TMP100

All of the devices around us are starting to become data collection points. Every minute of every day many data points are generated. This unwieldy mass of data needs to be logged, processed, stored and displayed in a reasonable way for it to be usable. The question becomes how to do this. One solution for the DIY community is Cosm (formerly Pachub) that allows us to do just that for free. In this article I’ll show you how to setup an account, create a feed and upload temperature readings from an I2C temperature sensor to Cosm via an Arduino Ethernet Shield.

Materials

  • Cosm Account
  • Arduino and Ethernet Shield or Arduino Ethernet
  • Breadboard and jumper wires
  • tmp100 (or other I2C temperature sensor) on a breakout board

Setup a Cosm Account

If you don’t already have one the first thing you need to do is setup a Cosm Account

  1. Go to https://cosm.com
  2. Click the big blue “Get Started” button
  3. Enter an email, username and password then click the “Sign up” button
  4. You’ll get an email with a link to verify your registration
  5. The link will bring you directly into your account
  6. Click on the big plus button
  7. Select Arduino
  8. Give the new feed a title and tags (optional) and press Create
  9. The Cosm Site will give you a sample sketch to upload data. You only need the three lines that start with:
    1. #define APIKEY
    2. #define FEEDID
    3. #define USERAGENT

Arduino wiring

In order to upload the data your Arduino needs to be connected to the internet. If you have an Arduino Ethernet you are ready to go. Otherwise you will need an Ethernet Shield. I already had a couple Arduinos so I decided to go the shield route (Note: the Ethernet Shield will not work with the Arduino Leonard).


Next we need to wire up the TMP100 sensor as shown in the Arduino and TMP100 article.

Sketch

The starter code that Cosm gives you when you create a feed (and the one included in the Arduino IDE) are written to send an analog sensor reading so there are some minor tweaks that need to be done to make it work with an I2C sensor. I’ve included the function to set the accuracy of the TMP100 sensor.
Here is the modified sketch:

/* TMP100 to Cosm
Fork Robotics 2012

Based on: http://arduino.cc/en/Tutorial/CosmClient
*/

#include
#include
#include

#define APIKEY         // your cosm api key
#define FEEDID         // your feed ID
#define USERAGENT      // user agent is the project name

// Set the TMP Address and Resolution here
int tmpAddress = B1001011;
int ResolutionBits = 12;

// assign a MAC address for the ethernet controller.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
// fill in your address here:
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};

// initialize the library instance:
EthernetClient client;

char server[] = "api.cosm.com";   // name address for cosm API

unsigned long lastConnectionTime = 0;
boolean lastConnected = false;
const unsigned long postingInterval = 10*1000; //delay between updates to cosm.com

void setup() {
  // start serial port:
  Wire.begin();
  Serial.begin(9600);
  // start the Ethernet connection:
  Ethernet.begin(mac);
  SetResolution();
}

void loop() {
  // read the analog sensor:
  float sensorReading = getTemperature();
  // if there's incoming data from the net connection.
  // send it out the serial port.  This is for debugging
  // purposes only:
  if (client.available()) {
    char c = client.read();
    Serial.print(c);
  }

  // if there's no net connection, but there was one last time
  // through the loop, then stop the client:
  if (!client.connected() && lastConnected) {
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();
  }

  // if you're not connected, and ten seconds have passed since
  // your last connection, then connect again and send data:
  if(!client.connected() && (millis() - lastConnectionTime > postingInterval)) {
    Serial.print("Sending temperature: ");
    Serial.println(sensorReading);
    sendData(sensorReading);
  }
  // store the state of the connection for next time through
  // the loop:
  lastConnected = client.connected();
}

// this method makes a HTTP connection to the server:
void sendData(float thisData) {
  // if there's a successful connection:
  if (client.connect(server, 80)) {
    Serial.println("connecting...");
    // send the HTTP PUT request:
    client.print("PUT /v2/feeds/");
    client.print(FEEDID);
    client.println(".csv HTTP/1.1");
    client.println("Host: api.cosm.com");
    client.print("X-ApiKey: ");
    client.println(APIKEY);
    client.print("User-Agent: ");
    client.println(USERAGENT);
    client.print("Content-Length: ");

    // calculate the length of the sensor reading in bytes:
    // 8 bytes for "sensor1," + number of digits of the data:
    int thisLength = 8 + getLength(thisData);
    client.println(thisLength);

    // last pieces of the HTTP PUT request:
    client.println("Content-Type: text/csv");
    client.println("Connection: close");
    client.println();

    // here's the actual content of the PUT request:
    client.print("sensor1,");
    client.println(thisData);

  }
  else {
    // if you couldn't make a connection:
    Serial.println("connection failed");
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();
  }
   // note the time that the connection was made or attempted:
  lastConnectionTime = millis();
}

// This method calculates the number of digits in the
// sensor reading.  Since each digit of the ASCII decimal
// representation is a byte, the number of digits equals
// the number of bytes:

int getLength(int someValue) {
  // there's at least one byte:
  int digits = 1;
  // continually divide the value by ten,
  // adding one to the digit count for each
  // time you divide, until you're at 0:
  int dividend = someValue /10;
  while (dividend > 0) {
    dividend = dividend /10;
    digits++;
  }
  // return the number of digits:
  return digits;
}

float getTemperature(){
  Wire.requestFrom(tmpAddress,2);
  byte MSB = Wire.read();
  byte LSB = Wire.read();
  int TemperatureSum = ((MSB << 8) | LSB) >> 4;
  float celsius = TemperatureSum*0.0625;
  float fahrenheit = (1.8 * celsius) + 32;
  return fahrenheit;
}

void SetResolution(){
  if (ResolutionBits < 9 || ResolutionBits > 12) exit;
  Wire.beginTransmission(tmpAddress);
  Wire.write(B00000001); //addresses the configuration register
  Wire.write((ResolutionBits-9) << 5); //writes the resolution bits
  Wire.endTransmission();
  Wire.beginTransmission(tmpAddress); //resets to reading the temperature
  Wire.write((byte)0x00);
  Wire.endTransmission();
}

Using, modifying and troubleshooting

The address for the I2C is configured the same as it was in the previous TMP100 article but it’s possible to use your own TMP100 address and set the resolution to a finer degree.

To view the information that is uploaded to Cosm simply go to the feed at: https://cosm.com/feeds/xxxxx with “xxxxx” in the link replaced with the feed number Cosm gave you when you setup your new feed. You can also just log into Cosm and they will show you all your active feeds. Keep in mind that the feed data is public by default and you will need to modify the settings of the feed if you want to change this.

As written the code uploads the current temperature in Fahrenheit; if you want Celsius then simply change the return line of the GetTemperature function from “return Fahrenheit” to “return Celsius”

The nice thing about this project is that it doesn’t need to be connected to a computer. You just need power and Ethernet. If you do connect it to a computer you can monitor the status of the sketch by using the serial monitor.

Next Steps

This project presents a simple way to monitor and upload digital I2C readings from a single sensor to Cosm. This function can be integrated into a thermostat type project to add historical data for display or analysis. The next step is to be able to upload data from multiple locations in your home labeled for the room they are in or inside and outside temperatures. This also opens the door to more I2C devices being able to upload data. A single internet connected Arduino can upload hundreds of readings.