Project

Basic Arduino Temperature Web Monitor

This Arduino code reads a Dallas Semiconductor One-Wire temperature sensor and reports to an Exosite Portal via the Ethernet Shield.

What is this?

Hook-up information and code for a simple network connected temperature monitoring device based on the Arduino platform that sends temperature data to my Exosite portal with Exosite’s basic HTTP API. On Exosite Portals, I have set up events on certain conditions (Temp less than 40 degrees for example) to alert me (via Email and SMS text) that the event condition exists. (SMS: Your Pipes are going to freeze!)

What is Arduino?

An open-source prototyping platform … for all you ever need to know on Arduino, check out the Arduino website. The version of the platform used here has an Atmel ATmega328 microcontroller.

Hardware:

- Arduino Uno – Link
- Arduino Ethernet Shield – Link
- Dallas Semiconductor DS18B20 One-Wire Temperature Sensor – Datasheet
- A 4.7k ohm resistor
- A little wire and heat-shrink tubing (optional).

The Arduino Uno, Ethernet Shield, and temp sensor were all purchased from SparkFun.

Set-up

The Arduino Uno and Ethernet Shield are simple to connect, the Ethernet Shield plugs into the top of the Uno board and by plugging in the USB cable, both are powered and ready to go. The temp sensor requires a little breadboard work or soldering. I choose to create a little cable (~6 inches) to keep the temp sensor away from the heat coming off the boards. This DS18B20 sensor is great because it can be powered with the data signal using parasite power. I recommend reading up on the data-sheet on this option, but essentially the sensor grabs a little power off the signal line when it is a high logic level. So two-wires can be used, a ground and the signal with a 4.7k pull-up resistor on it to 5V. I chose the Arduino Uno’s signal pin 7, since it is not being used for anything on the Ethernet Shield. I used enough wire for about 6 inches of length and once connected, used heat-shrink tubing to wrap it all up. (Note: I’ve tried putting these temp sensors right on the main board, but the heat from the power regulators and chips affects it greatly.)

Software

Note: This project page was updated in July, 2012 to include updated code for Arduino 1.0x and a Exosite library.
The Arduino IDE is easy to install and use, check out the installers here. It runs on Mac, Windows, and Linux. Once installed, create a new “sketch” and use the included code below. It uses a five libraries, two of the five are included in the Arduino install (assumption Arduino 21 version Updated July, 2012 to use Arduino 1.0). Those two are ‘SPI’ and ‘Ethernet’. The third library required is for the one-wire interface. This library can be found on on the Arduino “Playground” section , specifically version 2.0. The Dallas Temperature Control library can be found here. (Thanks to all that have contributed to these existing libraries!). The fifth library is the Exosite library, which can be found here.

The actual code is easy to understand. It uses the Exosite library to set up a connection to the Exosite One Platform over Ethernet, reads the temperature over the one-wire interface, and sends the value to the platform every 120 seconds with the Basic HTTP API from Exosite.  I left a lot of comments and debug serial messages in the code, taking these out would show there  are very few lines of code.

The New Code – July 2012

/*
 Exosite Arduino Basic Temp Monitor 2 (updated to use Exosite library)
 
 This sketch shows an example of sending data from a connected
 sensor to Exosite. (http://exosite.com) Code was used from various
 public examples including the Arduino Ethernet examples and the OneWire
 Library examples found on the Arduino playground. 
 (OneWire Lib credits to Jim Studt, Tom Pollard, Robin James, and Paul Stoffregen)
 
 This code keeps track of how many milliseconds have passed
 and after the user defined REPORT_TIMEOUT (default 60 seconds)
 reports the temperature from a Dallas Semi DS18B20 1-wire temp sensor.
 The code sets up the Ethernet client connection and connects / disconnects 
 to the Exosite server when sending data.
 
 Assumptions:
 - Tested with Aruduino 1.0
 - Arduino included Ethernet Library
 - Arduino included SPI Library
 - Using Exosite library (2011-06-05) https://github.com/exosite-garage/arduino_exosite_library
 - Using OneWire Library Version 2.0 - http://www.arduino.cc/playground/Learning/OneWire
 - Using Dallas Temperature Control Library - http://download.milesburton.com/Arduino/MaximTemperature/DallasTemperature_372Beta.zip
 - User has an Exosite account and created a device (CIK needed / https://portals.exosite.com -> Add Device)
 - Uses Exosite's basic HTTP API, revision 1.0
 
 Hardware:
 - Arduino Duemilanove
 - Arduino Ethernet Shield
 - Dallas Semiconductor DS18B20 1-Wire Temp sensor used in parasite power mode (on data line, 4.7k pull-up)

 Version:
 1.0 - Novemeber 8, 2010 - by M. Aanenson
 2.0 - July 6, 2012 - by M. Aanenson
 
 */
 
 
#include <SPI.h>
#include <Ethernet.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Exosite.h>

// User defined variables for Exosite reporting period and averaging samples
#define REPORT_TIMEOUT 120000 //milliseconds period for reporting to Exosite.com
#define SENSOR_READ_TIMEOUT 30000 //milliseconds period for reading sensors in loop
// Pin use
#define ONEWIRE 7 //pin to use for One Wire interface

// Set up which Arduino pin will be used for the 1-wire interface to the sensor
OneWire oneWire(ONEWIRE);
DallasTemperature sensors(&oneWire);

//global variables
byte macData[] = { "PUTYOURMACHERE"  }; // <-- Fill in your MAC here! (e.g. {0x90, 0xA2, 0xDA, 0x00, 0x22, 0x33}) 
String cikData = "PUTYOURCIKHERE";      // <-- Fill in your CIK here! (https://portals.exosite.com -> Add Device)
Exosite exosite(&Ethernet, macData, cikData);


//
// The 'setup()' function is the first function that runs on the Arduino.
// It runs completely and when complete jumps to 'loop()' 
//
void setup() {
  Serial.begin(9600);

  // Start up the OneWire Sensors library
  sensors.begin();
  delay(1000);
  Serial.println("Starting Exosite Temp Monitor");
  Serial.println();
  
  exosite.init();
  delay(2000); 

}

//
// The 'loop()' function is the 'main' function for Arduino 
// and is essentially a constant while loop. 
//
void loop() {
  static unsigned long sendPrevTime = 0;
  static unsigned long sensorPrevTime = 0; 
  static float tempF;
  
  Serial.print("."); // print to show running

 // Read sensor every defined timeout period
  if (millis() - sensorPrevTime > SENSOR_READ_TIMEOUT)
  {
    Serial.println();
    Serial.print("Requesting temperature...Temp: ");
    sensors.requestTemperatures(); // Send the command to get temperatures
    float tempC = sensors.getTempCByIndex(0);
    tempF = DallasTemperature::toFahrenheit(tempC);
    Serial.print(tempF);
    Serial.println(" F ..........DONE");
    
    sensorPrevTime = millis();
  }

  // Send to Exosite every defined timeout period
  if (millis() - sendPrevTime > REPORT_TIMEOUT)
  {
    Serial.println(); //start fresh debug line
    Serial.println("Sending data to Exosite...");
    
    exosite.sendToCloud("temp",tempF);

    sendPrevTime = millis(); //reset report period timer
    Serial.println("done sending.");
  }
  delay(5000); //slow down loop
}


The Original Code


/*
Exosite Arduino Basic Temp Monitor

This sketch shows an example of sending data from a connected
sensor to Exosite. (http://exosite.com) Code was used from various
<div id="_mcePaste">public examples including the Arduino Ethernet examples and the OneWire</div>
<div id="_mcePaste">Library examples found on the Arduino playground.</div>
<div id="_mcePaste">(OneWire Library credits to Jim Studt, Tom Pollard, Robin James, and Paul Stoffregen)</div>
This code keeps track of how many milliseconds have passed
and after the user defined REPORT_TIMEOUT (default 60 seconds)
reports the temperature from a Dallas Semi DS18B20 1-wire temp sensor.
The code sets up the Ethernet client connection and connects / disconnects
to the Exosite server when sending data.

Code for reading the 1-wire interface was adapted from the OneWire library
example code.

Assumptions:
- Tested with Aruduino 0021
- Arduino included Ethernet Library
- Arduino included SPI Library
- Using OneWire Library Version 2.0 - http://www.arduino.cc/playground/Learning/OneWire
- User has an Exosite account and created a device (CIK needed)
- Uses Exosite's basic HTTP API, revision 1.0

Hardware:
- Arduino Duemilanove
- Arduino Ethernet Shield
- Dallas Semiconductor DS18B20 1-Wire Temp sensor used in parasite power mode (on data line, 4.7k pull-up)

Version:
1.0 - Novemeber 8, 2010 - by M. Aanenson

*/

#include <SPI.h>
#include <Ethernet.h>
#include <OneWire.h> //Version 2.0 -  http://www.arduino.cc/playground/Learning/OneWire

//
// Set up which Arduino pin will be used for the 1-wire interface to the sensor
//
OneWire oWire(7); //on pin7 which is not used by Ethernet shields for SPI or selects

//
// Exosite Device CIK is required, add a new device on your portal - www.exosite.com (~~~~ Fill in your CIK here! ~~~~)
//
#define DeviceCIK "cd7fa801fae264c0e70f82f4325df38d1d861220"

//
// Assign a MAC address to the ethernet controller (~~~~ Fill in your MAC address here! ~~~~)
//
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};

//
// Assign a static IP address and network information (~~~~ Fill in you network info! ~~~~)
//
byte ip[] = { 192,168,2,2 };
byte gateway[] = { 192,168,2,1 };
byte subnet[] = { 255, 255, 255, 0 };
// User could use DHCP by finding an appropriate library instead of static address.

//
// Host address for sever connection (m2.exosite.com)
//
byte server[] = { 173, 255, 209, 28 }; // m2.exosite.com

//
// Initialize the Ethernet client library with IP Address and port of the server
//
Client client(server, 80); // Port 80 is default for HTTP

//
// User defined variables for Exosite reporting period and averaging samples
//
#define REPORT_TIMEOUT 60000 //milliseconds period for reporting to Exosite.com


//
// The 'setup()' function is the first function that runs on the Arduino.
// It runs completely and when complete jumps to 'loop()' 
//
void setup() {

  //
  // Start serial port for debuging
  //
  Serial.begin(9600);
  //
  // Start Ethernet connection
  //
  Ethernet.begin(mac, ip);
  //
  // Small delay to give Ethernet time to boot:
  //
  delay(1000); 
  
  // done, go to loop()
}

//
// The 'loop()' function is the 'main' function for Arduino 
// and is essentially a constant while loop. 
//
void loop() {
  static unsigned long sendPrevTime = 0;
  String myDataString; //allocate for actual data sent
  byte i;
  byte present = 0;
  byte data[12];
  byte addr[8];  
  int HighByte, LowByte, TReading, SignBit, Tc_100, Tf_100, Whole, Fract;
  
  //
  // Find devices on the 1-wire, validate CRC, and check the family code
  //
  Serial.println();
  if ( !oWire.search(addr)) 
  {
    //Serial.print("No more addresses.\n");
    oWire.reset_search();
    delay(250);
    return;
  }
 
  //Serial.print("R=");
  //for( i = 0; i < 8; i++) 
  //{
    //Serial.print(addr[i], HEX);
    //Serial.print(" ");
  //}

  if ( OneWire::crc8( addr, 7) != addr[7]) 
  {
    Serial.print("CRC is not valid!\n");
    return;
  }

  if ( addr[0] == 0x10) 
  {
    Serial.print("Sensor is a DS18S20 family device.");
    //not doing anything different for now.
  }
  else if (addr[0] == 0x28) 
  {
    Serial.print("Sensor is a DS18B20 family device");
    //not doing anything different for now.
  }
  else 
  {
    Serial.print("Sensor is family code unknown, code is not set up for this, returning...");
    return;
  }
  
  //
  // Perform the read
  //
  oWire.reset();
  oWire.select(addr);
  oWire.write(0x44,1);         // start conversion, with parasite power on at the end
  
  delay(1000);     // maybe 750ms is enough, maybe not
  
  present = oWire.reset();
  oWire.select(addr);    
  oWire.write(0xBE);         // Read Scratchpad

  //Serial.print("P=");
  //Serial.print(present,HEX);
  //Serial.print(" ");
  for ( i = 0; i < 9; i++) // we need 9 bytes
  {           
    data[i] = oWire.read();
    //Serial.print(data[i], HEX);
    //Serial.print(" ");
  }
  //Serial.print(" CRC=");
  //Serial.print( OneWire::crc8( data, 8), HEX);
  //Serial.println();
  
  //
  // Convert value to degrees Celcius, then conver to Farenheit.
  //
  LowByte = data[0];
  HighByte = data[1];
  TReading = (HighByte << 8) + LowByte;
  SignBit = TReading & 0x8000;  // test most sig bit
  if (SignBit) // negative
  {
    TReading = (TReading ^ 0xffff) + 1; // 2's comp
  }
  Tc_100 = (6 * TReading) + TReading / 4;    // multiply by (100 * 0.0625) or 6.25
  Tf_100 = ((1.8)*Tc_100) + (32*100); // Farenheit
  
  Whole = Tf_100 / 100;  // separate off the whole and fractional portions
  Fract = Tf_100 % 100;
  
  Serial.println();
  Serial.print("Measured Temp: ");
  if (SignBit) // If its negative
  {
     Serial.print("-");
  }
  Serial.print(Whole);
  Serial.print(".");
  if (Fract < 10)
  {
     Serial.print("0");
  }
  Serial.print(Fract);
  Serial.print(" F");
  Serial.println();
  
  Serial.print("."); // print to show running
  delay(2000); // slow the loop down since the reporting period is likely in seconds
  
  //
  // Run every defined timeout period
  //
  if (millis() - sendPrevTime > REPORT_TIMEOUT)
  {
    sendPrevTime = millis(); //reset report period timer
    Serial.println(); //start fresh debug line
    
    Serial.print("connecting to Exosite...");
    
    //
    // Try to connect
    // 
    if (client.connect()) 
    {
      if (client.connected())
      {
        Serial.println("connected");
        Serial.print("Sending data to Exosite...");
        
        myDataString = ""; //erase current string, start new
        
        //
        // Take data and create a string to include in HTTP request body
        // Exosite basic HTTP API format looks like: 'resourceid#=value&resourceid#2=value2&....'
        // 
        myDataString += "1="; //put into resource 1 for this device
        myDataString += "1"; //just send a '1' for now. 
        
        //
        // Send Temperature to device resource register 2
        //
        myDataString += "&2="; //put into resource 2 for this device, note the '&'
        if (SignBit) // If its negative
        {
          myDataString += "-"; //add negative sign
        }
        myDataString += Whole; //first part of value
        myDataString += ".";   //decimal place
        myDataString += Fract; //fraction
        
        //
        // Send request using Exosite basic HTTP API
        // (Don't forget to change the CIK
        //
        client.println("POST /api:v1/stack/alias HTTP/1.1");
        client.println("Host: m2.exosite.com");
        client.print("X-Exosite-CIK: ");
        client.println(DeviceCIK);
        client.println("Content-Type: application/x-www-form-urlencoded; charset=utf-8");
        client.println("Accept: application/xhtml+xml");
        client.print("Content-Length: ");
        client.println(myDataString.length()); //calculate length
        client.println();
        client.println(myDataString);

        //
        // Read from the nic or the IC buffer overflows with no warning and goes out to lunch
        //
        while (client.available()) {
          char c = client.read();
          Serial.print("Response: "); //for debugging
          Serial.println(c); //for debugging
        }      
        
        //
        // Done sending
        //
        Serial.println("done sending.");
        //Serial.print("Sent Data String: "); //for debugging
        //Serial.println(myDataString); //for debugging
        Serial.println("disconnecting.");
        client.stop();
      }
      else
      {
       //
       // For some reason connection failed
       // 
        Serial.println("no connection");
        Serial.println();
      }
    }
    else 
    {
      //
      // Connection failed
      //
      Serial.println("connection failed");
      Serial.println();
    }  
  } 
}

What it looks like