You can easily create an Internet-connected temperature / humidity sensor, datalogger, and thermostat by combining an EtherTen (XC4216) and a "HUMID" Temperature / Humidity Sensor Module (XC4246). You can even power it over the network cable using a 4-Channel Power-over-Ethernet (PoE) Injector for added convenience if you need to locate it some distance away from a power supply.


a small screenshot of your online data

The HUMID module provides a convenient low-update-rate (one sample every two seconds) reading of both temperature and humidity, using just one digital I/O line.

Readings can also be logged and charted over time, showing trends or measuring the effectiveness of your home heating or cooling systems. By placing sensors outside the house, inside your ceiling cavity, and inside various rooms, you can plot how well your home maintains its temperature when climate conditions change.

The information could also be used as part of the feedback loop for a control system, such as to control active heating or cooling, or to trigger servos or linear actuators to open and close windows and passive ventilation systems.

Parts Required

1 x Freetronics 4-Channel PoE Midspan Injector (Jaycar Cat. XC4254) (if powering from the single network cable)
An Internet connection
A free account on the Cosm web service (formerly known as Pachube)

Instructions

This project can be built up sequentially following a series of steps that allow you to verify the functionality of each section along the way, starting with the Humidity & Temperature Sensor module itself.

HUMID Module Pinout

The HUMID module only requires a single line, but it can't be shared or daisy-chained between multiple modules. A separate I/O line is required for each module you wish to connect.


VIN: Connect to 5V on your Arduino.
DATA: Connect to a digital I/O line on your Arduino.
GND: Connect to GND (0V) on your Arduino.

Connect Humidity / Temperature Sensor Module

Connect GND on the HUMID module to GND on your EtherTen; VIN on the module to 5V on your EtherTen; and DATA on the module to one of the digital I/O pins.

In this example we've used D2 for the data connection, but you can use another pin if you prefer as long as you don't use one of the pins reserved for the Ethernet connection: D10, D11, D12, and D13.


Test Sensor Output

Communicating with the Humidity / Temperature Sensor Module requires a driver for the DHT22 sensor that it's compatible with. The simplest way to install the driver is to download the DHT library from the Freetronics repository on GitHub and install it in your Arduino IDE. Visit the following repository in your browser, and look for the [ZIP] button near the top left of the page to download it as a ZIP archive:

https://github.com/freetronics/DHT-sensor-library

Uncompress the archive and rename the folder to "DHT", then move it into your sketchbook/libraries/ folder. Restart the IDE, and you will now have a new entry in the examples menu at File -> Examples -> DHT -> DHTtester. Open that example in the Arduino IDE, compile it, and upload it to your Arduino. Open the serial console in the IDE and set it to 38400bps to match the setting in the example sketch.

You'll then see a series of readings displayed in the serial console, which demonstrates that the driver library is correctly installed and the HUMID module is connected and functioning.

Create a free Cosm Account

Now that your EtherTen is reading values, the next step is to push those readings up to an online service that will record them and generate online charts for you. There are a number of services available and if you want to keep your data totally private you can even create one yourself, but for this tutorial we'll use an online service called "Cosm". Cosm was formerly known as "Pachube" ("patch-bay"), and is designed to make it easy for anyone to link up data sources such as environmental sensors.

Start by signing up at www.cosm.com to create a free account.

Create Cosm Feed

After your account has been created and you've logged in, click the big blue "+ Device/Feed" button near the top right. You'll be presented with four options for creating a new device or feed, so select the "Arduino" option:


Next, set a title for the device. Something like "My House" is fine:


You don't need to add anything for "Tags" in Step 2, so proceed through to Step 3 and click "Create". You'll then be given a numeric feed ID that will be used by your EtherTen to update the correct feed:


The "Success" page also gives you a handy example sketch that you can use as a test for the new feed. It's even pre-customised to insert the feed ID and an API key generated for you by Cosm.

Click in the example sketch, select it all, and copy it. Then open your Arduino IDE, create a new sketch window if it hasn't already opened one for you, paste in the example sketch, and save it with a sensible name such as "CosmTest":


The example sketch supplied by Cosm says in the comments that it's designed for an Arduino Ethernet shield, which is compatible with the EtherTen you're using, it's functionally identical to an Arduino with a separate Ethernet shield mounted on it.

Look at the settings near the start of the sketch where it sets a network MAC address and default IP address, and change them if necessary. If your network has a DHCP server to assign IP addresses automatically (just about all home networks do, usually built into the broadband router) then you won't need to change anything at all.

Connect your EtherTen to your computer using the supplied USB cable, select the board type as "Arduino Uno", and click the "Upload" button in the IDE. The sketch will then automatically be compiled, then uploaded and executed on your EtherTen.

Leave the EtherTen connected to the network and running with the example sketch, and go back to your web browser to the Cosm window. Click the blue "Finish" button in the feed setup window to return to the list of feeds, and after a few seconds there should be some values visible in the "My House" feed.

Of course the values displayed won't mean anything right now because the example sketch attempts to read analog values from input A0, and we don't even have anything connected to that input! The readings should float somewhere close to the 0 mark, but at least it proves that the EtherTen is successfully sending values to Cosm:


Success! They may not be the temperature and humidity readings that we want to report, but we're getting close now.

Customise Feed Settings

The feed you just created uses default Cosm settings, so now you need to customise it. Move your mouse over the feed and a little "cog" icon will appear in the top right corner, with a menu to allow you to edit or delete the feed. Select "Edit":


The first step is to replace the default datastream, which is simply called "sensor1", with datastreams for temperature and humidity. I prefer to do this as a 2-step process, leaving the default datastream in place and deleting it later after everything else is set up, but if you prefer you can simply delete the "sensor1" datastream now.

Click the blue "+ datastream" button near the right, and fill in the details for temperature. You don't need to include tags, so I've just set the ID and the units. In this example I've given the new datastreams simple, descriptive IDs based on their function, but you can use unique serial numbers or some other identifier if you prefer. Then do the same to add a datastream for humidity:


Scroll further down the page to check the other feed settings. You can set a location for your feed if you like, along with other information such as a description and other attributes.

Most importantly, check the "Feed Status" setting and decide if you want your feed to be publicly visible. The default setting allows anyone to view your Cosm feed and see the values coming from your sensor without having to be logged in. For typical domestic applications it's a good idea to set the Feed Status to "private", otherwise you may be disclosing personal information to the whole world. For example, you may think that displaying temperature and humidity data for anyone to see is harmless, but it could be used to work out if your heating or cooling system is turned on, which could then give people a good idea of whether you're home or not! Think about the implications before leaving a feed set to "public".

Most of the other settings are informational only, and don't change anything about the way the feed works. For example, you can set the "Exposure", "Disposition", and "Domain" settings if you like, but it really doesn't make any functional difference.


Finally, click "Save Changes" to apply the new datastreams and settings.

Your Cosm feed is now ready to accept temperature and humidity values from your EtherTen.


Configure Access Key

If you left your Feed Status set to "public" in the previous step you can skip this section and proceed to "Configure CosmHUMID Sketch".

Cosm uses "access keys" to determine which devices are allowed to update which feeds, and different keys can have different access privileges. The key automatically generated for your new feed will have been set to have "read, update" privileges, but without the right to access your private feeds. That means if you've set your new feed to private, you'll have to also generate a new access key with the necessary privileges to connect to private feeds. Don't worry, it's really easy.

First, click the "Keys" menu in the top right of your Cosm window:



In the keylist you'll see the existing keys. Click the blue "+ Key" button, and fill in the details to create a new key. There are many options for keys including fine-grained control of access privileges, but the simplest approach is to allow the key to use any feed and with all access privileges.


Click "Create", and your new key will be created.

The next screen will show you the key itself. In a moment you'll need to copy and paste that key into a sketch to run on your EtherTen.

Configure the Cosm HUMID Sketch

So far you've tested the Temperature & Humidity Sensor module with one sketch that reads values from it, and tested your Cosm feed with another sketch that publishes simple values taken from an analog input. Next we need to combine those two functions into a single sketch that will publish your sensor readings.

Open the Arduino IDE, create a new sketch, and copy / paste the following source code into it.

Just like the previous sketch, you need to set the MAC address near the top of the sketch so it's unique on your network. Also substitute in the feed ID and your Cosm access key into the appropriate places near the top of the sketch.

 /*
  Cosm DHT22 temperature / humidity sensor client
 
 This sketch connects a DHT22 sensor to Cosm (http://www.cosm.com)
 using the Freetronics EtherTen.
 
 created 15 March 2010
 updated 16 Mar 2012
 by Tom Igoe with input from Usman Haque and Joe Saavedra
 
http://arduino.cc/en/Tutorial/PachubeClient
 This code is in the public domain.
 
 modified 16 May 2012 by Jonathan Oxer
 
 */

#include <SPI.h>
#include <Ethernet.h>
#include <DHT.h>

#define APIKEY         "xxxxxxxx" // your cosm api key
#define FEEDID         00000 // your feed ID
#define USERAGENT      "Cosm Arduino Example (00000)" // user agent is the project name

#define DHTPIN         2      // Data pin for the HUMID module
#define DHTTYPE        DHT22  // Sensor used on the HUMID module

DHT dht(DHTPIN, DHTTYPE);

// 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, 0xAA, 0xBE, 0xEF, 0xFE, 0xED};

// fill in an available IP address on your network here,
// for manual configuration:
IPAddress ip(192,168,1,20);
// initialize the library instance:
EthernetClient client;

// if you don't want to use DNS (and reduce your sketch size)
// use the numeric IP instead of the name for the server:
IPAddress server(216,52,233,121);      // numeric IP for api.cosm.com
//char server[] = "api.cosm.com";   // name address for cosm API

unsigned long lastConnectionTime = 0;          // last time you connected to the server, in milliseconds
boolean lastConnected = false;                 // state of the connection last time through the main loop
const unsigned long postingInterval = 10*1000; //delay between updates to Cosm.com

void setup() {
  // start serial port:
  Serial.begin(38400);
  // start the HUMID module:
  dht.begin();
  // start the Ethernet connection:
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // DHCP failed, so use a fixed IP address:
    Ethernet.begin(mac, ip);
  }
}

void loop() {
  // read the analog sensor:
  int sensorReading = analogRead(A0);   

  // 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)) {
    float temperatureReading = dht.readTemperature();
    Serial.print("Temperature: ");
    Serial.println(temperatureReading);
    float humidityReading    = dht.readHumidity();
    Serial.print("Humidity: ");
    Serial.println(humidityReading);
    sendData(temperatureReading, humidityReading);
  }
  // store the state of the connection for next time through
  // the loop:
  lastConnected = client.connected();
}

// this method makes a HTTP connection to the server:
boolean sendData(float thisTemperature, float thisHumidity) {
  if (client.connected()) client.stop();

  // 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: ");

    /*
     work out the length of the string:
     "temperature," = 12 + 
     digits of temperature value + 
     "humidity," = 9 +
     digits of humidity value + 
     "\r\n" = 2
     */
    int length = 12 + countDigits(thisTemperature,2) + 2 + 9 + countDigits(thisHumidity,2) + 2;

    // calculate the length of the sensor reading in bytes:
    client.println(length);

    // 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("temperature,");
    client.println(thisTemperature);
    client.print("humidity,");
    client.println(thisHumidity);
    client.println();
    client.println();

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

// Counts digits of a floating point number, to calculate content length
// for an HTTP call.
// Based on Arduino's internal printFloat() function.
int countDigits(double number, int digits)  { 
  int n = 0;

  // Handle negative numbers
  if (number < 0.0)
  {
    n++; // "-";
    number = -number;
  }

  // Round correctly so that print(1.999, 2) prints as "2.00"
  double rounding = 0.5;
  for (uint8_t i=0; i<digits; ++i) {
    rounding /= 10.0;
  }
  number += rounding;

  // Extract the integer part of the number and print it
  unsigned long int_part = (unsigned long)number;
  double remainder = number - (double)int_part;

  while (int_part > 0) {
    int_part /= 10;
    n++;
  }
  // Print the decimal point, but only if there are digits beyond
  if (digits > 0) {
    n++; //"."; 
  }

  // Extract digits from the remainder one at a time
  while (digits-- > 0)
  {
    remainder *= 10.0;
    int toPrint = int(remainder);
    n ++; // += String(toPrint);
    remainder -= toPrint; 
  } 
  return n;
}

Save the sketch with some sensible name such as "CosmHUMID", and compile and upload it to your EtherTen.

If everything is working correctly your EtherTen will now periodically read temperature and humidity values from the HUMID module, and push them up to your Cosm feed. You can then load up the feed in your web browser to see the latest readings and also historical charts.

Further Ideas

Once you have your data being published to Cosm, there are all sorts of extra things you can do such as create triggers that happen on certain events. For example, you could set up another EtherTen to control your house heating system, and define a trigger in Cosm that connects back to your heating system to turn it on and off at the appropriate temperatures.

You can also simplify the cabling to your EtherTen and sensor by powering your unit from the same network cable it's already connected with, using a 4-Channel Power-over-Ethernet Midspan Injector (Jaycar Cat. XC4254).

If you'd like to discuss this project or show off your version of it, make sure you visit the Freetronics forum!