Sunday, February 27, 2011

Two ways to log temperatures.

With an Arduno, Adafruit's XPort Ethernet shield, and an Internet connection, parameters such a temperature can be logged to the cloud.

When I assembled the Ethernet shield I only connected power, TX and RX. Setup of PPP on the XPort was a little tedious, as a fixed IP address, mask, gateway, and other parameters had to be entered through the Arduino with a terminal app. I connected the output of an LM335 temperature sensor to analog port 0 using the recommended calibration circuit from the data sheet.

Since Arduino can be powered over USB, I used the USB port on the router for power only. This was a neat solution because it needed no additional power supply for the Arduino. The drawback was that power from a USB port isn't always stable or equal to exactly five volts. Measure the voltage of VREF after connecting it to the port. Analog read should be equal to VREF/1023. Hopefully it is stable. One option may be to make a stable 3.75 volt reference circuit, and that would enable any USB port to be use. This would also improve resolution of the A/D reading. With any spare op-amps, the LM335 could be level-shifter and amplified.

For now, I'm just using an external power supply.














The first solution used and HTTP GET to some PHP running on our hosting server. Getting this to send a properly formatted HTTP packet was a little tricky. I ended up using Wireshark and comparing the output of a browser to the output of the XPort. For this I needed a true Ethernet hub, but now switches seem to be replacing hubs, even in the consumer space. In the future I may need a second NIC on my pc, bridged to the main NIC, just so I can solve this kind of problem.


#include
#include
#include
//#define IPADDR "207.58.139.246" //www.ladyada.net
//#define IPADDR "157.166.226.25" //cnn.com
#define IPADDR "---.---.---.---" //www.---.net

#define PORT 80

char linebuffer[256]; // large buffer for storing data
unsigned int value = 77; //fake temperature
int indoorPin = 0;
float fpVal = 0;
int i = 0;
boolean debug = false;

#define XPORT_RXPIN 2
#define XPORT_TXPIN 3
#define XPORT_RESETPIN 4
#define XPORT_DTRPIN 5
#define XPORT_CTSPIN 6
#define XPORT_RTSPIN 7

AF_XPort xport = AF_XPort(XPORT_RXPIN, XPORT_TXPIN, XPORT_RESETPIN, XPORT_DTRPIN, XPORT_RTSPIN, XPORT_CTSPIN);

void setup() {

Serial.begin(9600);
xport.begin(9600);
xport.reset();
delay(1000);
if(debug){
Serial.println("Finished Setup...");
}

}

void loop()
{
byte ret;

while(true)
{

if(debug){
Serial.println("Reading Temperature...");
}
value = analogRead(indoorPin);
fpVal = float(value);
fpVal = fpVal-52.0;
fpVal = fpVal*500.0/1023.0;
fpVal = fpVal-273.15;
fpVal = fpVal*9.0/5.0+32.0;
value = ((int)fpVal);
if(debug){
Serial.println((int)fpVal);
Serial.println((int)fpVal);
Serial.println((int)fpVal);
Serial.println((int)fpVal);
Serial.println(value);

Serial.print("Temperature = ");
Serial.println(value);
Serial.print("GET /php/add_temperature.php?temperature=");
Serial.print(value);
Serial.println(" HTTP/1.1");
}

//while(true){}


if(debug){
Serial.println("Connecting...");
}
xport.connect(IPADDR, PORT);
//xport.flush(300);

if(debug){
Serial.println("Getting...");
}
//xport.println("GET /index.html");




//xport.print("GET /savedb.php?value=");
//xport.print("GET /php/add_temperature.php?temperature=12.6 HTTP/1.1");

xport.print("GET /php/add_temperature.php?temperature=");
xport.print(value);
xport.println(" HTTP/1.1");
xport.println("Host: www.---.net");
xport.println("Connection: keep-alive");
xport.println("User-Agent: Arduino/xport\r\n");
//xport.println("User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.125 Safari/533.4");
//xport.println("Accept: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5");
//xport.println("Accept-Encoding: gzip,deflate,sdch");
//xport.println("Accept-Language: en-US,en;q=0.8");
//xport.println("Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3\r\n");
//note that this has got to end with and extra crlf.

//delay(1000);
//delay(1000);
//delay(1000);

ret=xport.readline_timeout(linebuffer, 255, 3000); // get first line
while(ret!=0){
if(debug){
Serial.print(linebuffer);
}
ret=xport.readline_timeout(linebuffer,255,4000);
}

if(debug){
Serial.print("Readline returned: ");Serial.println(ret,HEX);
}

for (int i=0; i <= 300; i++) { delay(1000);} } }


The PHP code stored the temperatures to a SQL data base, and an app was written to display the latest ten readings.

After we changes hosting services, we didn't have time to reinstall all our PHP application. However, I found and interesting service called pachube. When you sign up, they give you an API key which lets you post data to their site. This site requires an HTTP PUT to post data. The code is slightly different


#include
#include
#include
//#define IPADDR "207.58.139.246" //www.ladyada.net
//#define IPADDR "157.166.226.25" //cnn.com
#define IPADDR "173.203.98.29" //www.pachube.com

#define PORT 80

char linebuffer[256]; // large buffer for storing data
unsigned int value = 77; //fake temperature
int indoorPin = 0;
float fpVal = 0;
int i = 0;
boolean debug = true;
int vref = 500;//fully regulated
//int vref = 469;//cisco
//int vref = 465;//pc

#define XPORT_RXPIN 2
#define XPORT_TXPIN 3
#define XPORT_RESETPIN 4
#define XPORT_DTRPIN 5
#define XPORT_CTSPIN 6
#define XPORT_RTSPIN 7

AF_XPort xport = AF_XPort(XPORT_RXPIN, XPORT_TXPIN, XPORT_RESETPIN, XPORT_DTRPIN, XPORT_RTSPIN, XPORT_CTSPIN);

void setup() {

Serial.begin(9600);
xport.begin(9600);
xport.reset();
delay(1000);
if(debug){
Serial.println("Finished Setup...");
}

}

void loop()
{
byte ret;

while(true)
{
//reset before each reading - see if that stops it from getting hung up every five days.
xport.reset();
delay(1000);
delay(1000);
delay(1000);
delay(1000);
delay(1000);
if(debug){
Serial.println("Finished Setup...");
}


if(debug){
Serial.println("Reading Temperature...");
}
value = analogRead(indoorPin);
fpVal = float(value);
//if(debug)Serial.println((int)fpVal);
//fpVal = fpVal-52.0;
if(debug)Serial.println((int)fpVal);
fpVal = fpVal*(float)vref/1023.0;
if(debug)Serial.println((int)fpVal);
fpVal = fpVal-273.15;
if(debug)Serial.println((int)fpVal);
fpVal = fpVal*9.0/5.0+32.0;
if(debug)Serial.println((int)fpVal);
value = ((int)fpVal);
if(debug){
Serial.println(value);

Serial.print("Temperature = ");
Serial.println(value);
Serial.print("GET /php/add_temperature.php?temperature=");
Serial.print(value);
Serial.println(" HTTP/1.1");
}

//while(true){}


if(debug){
Serial.println("Connecting...");
}
xport.connect(IPADDR, PORT);
//xport.flush(300);

if(debug){
Serial.println("Getting...");
}
//xport.println("GET /index.html");


xport.print("PUT /v2/feeds/19356.csv HTTP/1.1\n");
xport.print("Host: api.pachube.com\n");
// fill in your Pachube API key here:
xport.print("X-PachubeApiKey: --------------------------------\n");
xport.print("Content-Length: ");

// calculate the length of the sensor reading in bytes:
int thisLength = getLength(value);
//+ id and comma
xport.println(thisLength + 2, DEC);

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

// here's the actual content of the PUT request:
// this wored when I send the value,input1 but it appeared backwards!
// ok, this time it looked like it worked.

xport.print("0,");
xport.println(value, DEC);
xport.println("\n");
/*
xport.print("GET /php/add_temperature.php?temperature=");
xport.print(value);
xport.println(" HTTP/1.1");
xport.println("Host: www.---.net");
xport.println("Connection: keep-alive");
xport.println("User-Agent: Arduino/xport\r\n");
*/
ret=xport.readline_timeout(linebuffer, 255, 3000); // get first line
while(ret!=0){
if(debug){
Serial.print(linebuffer);
}
ret=xport.readline_timeout(linebuffer,255,4000);
}

if(debug){
Serial.print("Readline returned: ");Serial.println(ret,HEX);
}

for (int i=0; i <= 300; i++) { delay(1000);} } } // 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;
}


Pachube's API for displaying data is a little tricky, and I haven't been able to retrieve nice-looking data, but here's their standard API plot showing my indoor temperature data over a 24 hour period.

No comments:

Post a Comment