Go Down

Topic: ds18s20 and pachube (Read 1 time) previous topic - next topic

Evan Cameron

i am wanting to display the data from 3 ds18s20 on pachube feeds, but haven't found nay sample code on how to do this.  do i just replace the analog lines in the code with the digital data?  i also want to graph the status of a digital pins state to track how often it turned on.


arduniomstr

I'm using this example code http://community.pachube.com/files/ethernet_Pachube_input_output_1_1.zip

I adapted the 1-wire sample code to address each sensor directly and generate a String to pass into the pachube_in_out function - grab the sensor readings before calling pachube_in_out() and avoid pin 10 for your bus

Code: [Select]
void readTempHex(byte *addr, byte *data) {
 
 byte i;
 byte present = 0;
 // The DallasTemperature library can do all this work for you!

 ds.reset();
 ds.select(addr);
 ds.write(0x44,1);         // start conversion, with parasite power on at the end
 
 delay(1000);     // maybe 750ms is enough, maybe not
 // we might do a ds.depower() here, but the reset will take care of it.
 
 present = ds.reset();
 ds.select(addr);    
 ds.write(0xBE);         // Read Scratchpad

 for ( i = 0; i < 9; i++) {           // we need 9 bytes
   data[i] = ds.read();
   //Serial.print(data[i], HEX);
   //Serial.print(" ");
 }
 //Serial.println();
}

// Convert Hex temperature reading to Celsius
char *convertReading(byte *hexReading) {
 int HighByte, LowByte, TReading, SignBit, Tc_100, Whole, Fract;
 char reading[20]; // array holding converted temp
 
 LowByte = hexReading[0];
 HighByte = hexReading[1];
 TReading = (HighByte << 8) + LowByte;
 SignBit = TReading & 0x8000;  // test most sig bit
 if (SignBit) // negative
 {
   TReading = (TReading ^ 0xffff) + 1; // 2's comp
 }
 Tc_100 = (TReading*100/2);    

 Whole = Tc_100 / 100;  // separate off the whole and fractional portions
 Fract = Tc_100 % 100;
 if ( !SignBit ) { // positive temp
   sprintf(reading, "%d.%d",Whole, Fract < 10 ? 0 : Fract);
 }
 else { // negative temp
   sprintf(reading, "%c%d.%d",'-', Whole, Fract < 10 ? 0 : Fract);  
 }
 return reading;
}


Here's my feed http://www.pachube.com/feeds/14134

Evan Cameron

#2
Dec 25, 2010, 10:10 pm Last Edit: Dec 25, 2010, 11:14 pm by ecameron Reason: 1
where in the code did you insert this?
any chance you could post your full code?

arduniomstr

This is the main program adapted from the pachube download
You can get the addresses for the sensors by running the 1-wire sample code - I'm only putting data so the get feed stuff is commented out

Code: [Select]
/* ==============================
* This code, which assumes you're using the official Arduino Ethernet shield,
* updates a Pachube feed with your analog-in values and grabs values from a Pachube
* feed - basically it enables you to have both "local" and "remote" sensors.
*
* Tested with Arduino 14
*
* Pachube is www.pachube.com - connect, tag and share real time sensor data
* code by usman (www.haque.co.uk), may 2009
* copy, distribute, whatever, as you like.
*
* v1.1 - added User-Agent & fixed HTTP parser for new Pachube headers
* and check millis() for when it wraps around
*
* =============================== */

#include <SPI.h>
#include <Ethernet.h>
#include <OneWire.h>
#include <stdio.h> // for function sprintf

byte SENSOR_0[] = { 0x10, 0xD2, 0x6E, 0xBB, 0x0, 0x8, 0x0, 0x91 }; //YOUR SENSOR ADDRESSES HERE
byte SENSOR_1[] = { 0x10, 0xA6, 0x3C, 0xEA, 0x1, 0x8, 0x0, 0x3F };

byte temp_0[9];
byte temp_1[9];

OneWire  ds(9);  // bus on pin 9 - problems on pin 10

//#undef int() // needed by arduino 0011 to allow use of stdio


#define SHARE_FEED_ID              XXXXX     // this is your Pachube feed ID that you want to share to
//#define REMOTE_FEED_ID             256      // this is the ID of the remote Pachube feed that you want to connect to
//#define REMOTE_FEED_DATASTREAMS    4        // make sure that remoteSensor array is big enough to fit all the remote data streams
#define UPDATE_INTERVAL            10000    // if the connection is good wait 10 seconds before updating again - should not be less than 5
#define RESET_INTERVAL             10000    // if connection fails/resets wait 10 seconds before trying again - should not be less than 5

#define PACHUBE_API_KEY            "YOUR_KEY_HERE" // fill in your API key

byte mac[] = { YOUR_ARDUINO_MAC_ADD_HERE };
byte ip[] = { YOUR_ARDINO_IP_HERE };
byte gateway[] = { YOUR_ROUTER_IP_HERE };      
byte subnet[] = { 255, 255, 255, 0 };
byte remoteServer[] = { 173, 203, 98, 29 }; // new pachube ip

//float remoteSensor[REMOTE_FEED_DATASTREAMS];        // we know that feed 256 has floats - this might need changing for feeds without floats

void setup()
{
 Serial.begin(9600);
 setupEthernet();

 //pinMode(3, OUTPUT);
 //pinMode(5, OUTPUT);
 //pinMode(6, OUTPUT);
}

void loop()
{

 // call 'pachube_in_out' at the beginning of the loop, handles timing, requesting
 // and reading. use serial monitor to view debug messages
     readTempHex(SENSOR_0, temp_0);
     readTempHex(SENSOR_1, temp_1);

 pachube_in_out();

 // then put your code here, you can access remote sensor values
 // by using the remoteSensor float array, e.g.:

 //analogWrite(3, (int)remoteSensor[3] * 10); // remoteSensor is a float
 //analogWrite(5, (int)remoteSensor[1]);

 // you can have code that is time sensitive (e.g. using 'delay'), but
 // be aware that it will be affected by a short pause during connecting
 // to and reading from ethernet (approx. 0.5 to 1 sec).
 // e.g. this code should carry on flashing regularly, with brief pauses
 // every few seconds during Pachube update.

 //digitalWrite(6, HIGH);
 //delay(100);
 //digitalWrite(6, LOW);
 //delay(100);

}


Here's the 1-wire functions to read each sensor and convert the hex value to a string - this is based on the 1-wire sample code

Code: [Select]
void readTempHex(byte *addr, byte *data) {
 
 byte i;
 byte present = 0;
 // The DallasTemperature library can do all this work for you!

 ds.reset();
 ds.select(addr);
 ds.write(0x44,1);         // start conversion, with parasite power on at the end
 
 delay(1000);     // maybe 750ms is enough, maybe not
 // we might do a ds.depower() here, but the reset will take care of it.
 
 present = ds.reset();
 ds.select(addr);    
 ds.write(0xBE);         // Read Scratchpad

 for ( i = 0; i < 9; i++) {           // we need 9 bytes
   data[i] = ds.read();
   //Serial.print(data[i], HEX);
   //Serial.print(" ");
 }
 //Serial.println();
}

// Convert Hex temperature reading to Celsius
char *convertReading(byte *hexReading) {
 int HighByte, LowByte, TReading, SignBit, Tc_100, Whole, Fract;
 char reading[20]; // array holding converted temp
 
 LowByte = hexReading[0];
 HighByte = hexReading[1];
 TReading = (HighByte << 8) + LowByte;
 SignBit = TReading & 0x8000;  // test most sig bit
 if (SignBit) // negative
 {
   TReading = (TReading ^ 0xffff) + 1; // 2's comp
 }
 Tc_100 = (TReading*100/2);    

 Whole = Tc_100 / 100;  // separate off the whole and fractional portions
 Fract = Tc_100 % 100;
 if ( !SignBit ) { // positive temp
   sprintf(reading, "%d.%d",Whole, Fract < 10 ? 0 : Fract);
 }
 else { // negative temp
   sprintf(reading, "%c%d.%d",'-', Whole, Fract < 10 ? 0 : Fract);  
 }
 return reading;
}


More to follow in next post - max limit!

arduniomstr

Here's the pachube functions that build the string to PUT - I tested this by hard coding a string to make sure I could update before adding the live data

Code: [Select]
String pachube_data;

boolean found_status_200 = false;
boolean found_session_id = false;
boolean found_CSV = false;
char *found;
unsigned int successes = 0;
unsigned int failures = 0;
boolean ready_to_update = true;
boolean reading_pachube = false;

boolean request_pause = false;
boolean found_content = false;

unsigned long last_connect;

int content_length;

void pachube_in_out(){

 if (millis() < last_connect) last_connect = millis();

 if (request_pause){
   if ((millis() - last_connect) > interval){
     ready_to_update = true;
     reading_pachube = false;
     request_pause = false;
     found_status_200 = false;
     found_session_id = false;
     found_CSV = false;

     //Serial.print("Ready to connect: ");
     //Serial.println(millis());
   }
 }

 if (ready_to_update){
   Serial.println("Connecting...");
   if (localClient.connect()) {

     // here we assign comma-separated values to 'data', which will update Pachube datastreams
     // we use all the analog-in values, but could of course use anything else millis(), digital
     // inputs, etc. . i also like to keep track of successful and failed connection
     // attempts, sometimes useful for determining whether there are major problems.
     pachube_data = String(convertReading(temp_0));
     pachube_data += ",";
     pachube_data += String(convertReading(temp_1));
     
     //sprintf(pachube_data,"%d,%d,%d,%d,%d,%d,%d,%d",analogRead(0),analogRead(1),analogRead(2),analogRead(3),analogRead(4),analogRead(5), successes + 1, failures);
     Serial.println(pachube_data);
   
     //content_length = strlen(pachube_data);
     content_length = pachube_data.length();

/*
     Serial.println("GET request to retrieve");

     localClient.print("GET /api/");
     localClient.print(REMOTE_FEED_ID);
     localClient.print(".csv HTTP/1.1\nHost: pachube.com\nX-PachubeApiKey: ");
     localClient.print(PACHUBE_API_KEY);
     localClient.print("\nUser-Agent: Arduino (Pachube In Out v1.1)");
     localClient.println("\n");
*/

     Serial.println("PUT, update");

     localClient.print("PUT /api/");
     localClient.print(SHARE_FEED_ID);
     localClient.print(".csv HTTP/1.1\nHost: pachube.com\nX-PachubeApiKey: ");
     localClient.print(PACHUBE_API_KEY);

     localClient.print("\nUser-Agent: Arduino (Pachube In Out v1.1)");
     localClient.print("\nContent-Type: text/csv\nContent-Length: ");
     localClient.print(content_length);
     localClient.print("\nConnection: close\n\n");
     localClient.print(pachube_data);



     localClient.print("\n");

     ready_to_update = false;
     reading_pachube = true;
     request_pause = false;
     interval = UPDATE_INTERVAL;

     Serial.print("finished PUT: ");
     Serial.println(millis());

   }
   else {
     Serial.print("connection failed!");
     Serial.print(++failures);
     found_status_200 = false;
     found_session_id = false;
     found_CSV = false;
     ready_to_update = false;
     reading_pachube = false;
     request_pause = true;
     last_connect = millis();
     interval = RESET_INTERVAL;
     setupEthernet();
   }
 }

 while (reading_pachube){
   while (localClient.available()) {
     checkForResponse();
   }

   if (!localClient.connected()) {
     disconnect_pachube();
   }
 }
}

void disconnect_pachube(){
 Serial.println("disconnecting.\n=====\n\n");
 localClient.stop();
 ready_to_update = false;
 reading_pachube = false;
 request_pause = true;
 last_connect = millis();
 found_content = false;
 resetEthernetShield();
}


void checkForResponse(){  
 char c = localClient.read();
 //Serial.print(c);
 buff[pointer] = c;
 if (pointer < 64) pointer++;
 if (c == '\n') {
   found = strstr(buff, "200 OK");
   if (found != 0){
     found_status_200 = true;
     //Serial.println("Status 200");
   }
   buff[pointer]=0;
   found_content = true;
   clean_buffer();    
 }

 if ((found_session_id) && (!found_CSV)){
   found = strstr(buff, "HTTP/1.1");
   if (found != 0){
     char csvLine[strlen(buff)-9];
     strncpy (csvLine,buff,strlen(buff)-9);

     //Serial.println("This is the retrieved CSV:");    
     //Serial.println("---");    
     //Serial.println(csvLine);
     //Serial.println("---");  
     Serial.println("\n--- updated: ");
     Serial.println(pachube_data);
     Serial.println("\n--- retrieved: ");
     char delims[] = ",";
     char *result = NULL;
     char * ptr;
     result = strtok_r( buff, delims, &ptr );
     int counter = 0;
/*    
     while( result != NULL ) {
       remoteSensor[counter++] = atof(result);
       result = strtok_r( NULL, delims, &ptr );
     }  
     for (int i = 0; i < REMOTE_FEED_DATASTREAMS; i++){
       Serial.print( (int)remoteSensor[i]); // because we can't print floats
       Serial.print("\t");
     }
*/
     found_CSV = true;

     Serial.print("\nsuccessful updates=");
     Serial.println(++successes);

   }
 }

 if (found_status_200){
   found = strstr(buff, "_id=");
   if (found != 0){
     clean_buffer();
     found_session_id = true;
   }
 }
}


Finally the ethernet function from the pachube example

Code: [Select]
Client localClient(remoteServer, 80);
unsigned int interval;

char buff[64];
int pointer = 0;

void setupEthernet(){
 resetEthernetShield();
 //Client remoteClient(255);
 delay(500);
 interval = UPDATE_INTERVAL;
 Serial.println("setup complete");
}

void clean_buffer() {
 pointer = 0;
 memset(buff,0,sizeof(buff));
}

void resetEthernetShield(){
 Serial.println("reset ethernet");
 Ethernet.begin(mac, ip, gateway, subnet);
}


If you can't get this working I have some separate test sketches that might help you

Evan Cameron

my feed is now updating, but the units don't look right.  the sensor is sitting above my heating register which is set to 68* F.  i would love to go ahead and do the conversion of the feed from C to F, but at this point, i just want it to work.


http://www.pachube.com/feeds/13805


i pasted the code you posted into the sketches and replaced the lines with my info. i also deleted the lines for the second sensor since i only have one attached right now.

arduniomstr

Evan, glad to see you managed to get your feed up and running - unless you're measuring something pretty hot it looks like your reading isn't quite right. I used this test sketch to make sure my sensors where reading correctly - connect your board via USB and check the output on the serial monitor

Code: [Select]
/*

 ReadTempTest

 Sketch to read temperature from Maxim DS18S20 sensors on 1-Wire bus
 and display HEX and DEC readings on serial monitor
 
 Hex values must be supplied for each DS18S20 - these can be obtained
 from OneWireTest sketch
 
 
 Example output
 27 0 4B 46 FF FF 1 10 E0
 28 0 4B 46 FF FF D 10 57
 19.5
 20.0

*/

#include <OneWire.h>

byte SENSOR_0[] = { 0x10, 0xD2, 0x6E, 0xBB, 0x0, 0x8, 0x0, 0x91 }; // sensor 0 address
byte SENSOR_1[] = { 0x10, 0xA6, 0x3C, 0xEA, 0x1, 0x8, 0x0, 0x3F }; // sensor 1 address

byte temp_0[9];
byte temp_1[9];

OneWire  ds(9);  // bus on pin 9 - problems on pin 10

void setup(void) {
 Serial.begin(9600);  
}

void loop(void) {
 readTempHex(SENSOR_0, temp_0);
 readTempHex(SENSOR_1, temp_1);
 Serial.print(convertReading(temp_0));  //problem with println!
 Serial.println();
 Serial.print(convertReading(temp_1));
 Serial.println();
 delay(1000);  
}
 
void readTempHex(byte *addr, byte *data) {
 
 byte i;
 byte present = 0;
 // The DallasTemperature library can do all this work for you!

 ds.reset();
 ds.select(addr);
 ds.write(0x44,1);         // start conversion, with parasite power on at the end
 
 delay(1000);     // maybe 750ms is enough, maybe not
 // we might do a ds.depower() here, but the reset will take care of it.
 
 present = ds.reset();
 ds.select(addr);    
 ds.write(0xBE);         // Read Scratchpad

 for ( i = 0; i < 9; i++) {           // we need 9 bytes
   data[i] = ds.read();
   Serial.print(data[i], HEX);
   Serial.print(" ");
 }
 Serial.println();
}


// Convert Hex temperature reading to Celsius
char *convertReading(byte *hexReading) {
 int HighByte, LowByte, TReading, SignBit, Tc_100, Whole, Fract;
 char reading[20]; // array holding converted temp
 
 LowByte = hexReading[0];
 HighByte = hexReading[1];
 TReading = (HighByte << 8) + LowByte;
 SignBit = TReading & 0x8000;  // test most sig bit
 if (SignBit) // negative
 {
   TReading = (TReading ^ 0xffff) + 1; // 2's comp
 }
 Tc_100 = (TReading*100/2);    

 Whole = Tc_100 / 100;  // separate off the whole and fractional portions
 Fract = Tc_100 % 100;
 if ( !SignBit ) { // positive temp
   sprintf(reading, "%d.%d",Whole, Fract < 10 ? 0 : Fract);
 }
 else { // negative temp
   sprintf(reading, "%c%d.%d",'-', Whole, Fract < 10 ? 0 : Fract);  
 }
 return reading;
}


Have you got a 4.7K pull up resistor? Also this code is configured to work with the sensors in parasitic mode

Go Up