Greg and ChiefRobot, thank you for all of your help on here. Your code definitely saved me.
I just wanted to share my results. I combined code from Greg and ChiefRobot for a sketch that POSTs and GETs data from Pachube. The CSV data returned is parsed to individual variables. I thought people might appreciate seeing it all in one place.
- Code: Select all
/*
* A simple sketch that uses WiServer to PUT (via POST) to Pachube
*
* Sends and receives two variables to Pachube.
* The data received is parsed; storing the CSV values in the appropriate variables.
* Sketch does not make WiFi connection after upload. The ardunio must be reset.
*
* Many thanks to GregEigsti and ChiefRobot for writing most of this code.
*/
//#include <MsTimer2.h> //For easy and accurate timing. 210bytes
#include <WiServer.h>
//#define maxLength 30
//Wireless configuration defines ----------------------------------------
#define WIRELESS_MODE_INFRA 1
#define WIRELESS_MODE_ADHOC 2
//Wireless configuration parameters ----------------------------------------
unsigned char local_ip[] = {192,168,1,108}; // IP address of WiShield
unsigned char gateway_ip[] = {192,168,1,254}; // router or gateway IP address
unsigned char subnet_mask[] = {255,255,255,0}; // subnet mask for the local network
const prog_char ssid[] PROGMEM = {"2WIRE814"}; // max 32 bytes
unsigned char security_type = 1; // 0 - open; 1 - WEP; 2 - WPA; 3 - WPA2
// WPA/WPA2 passphrase
const prog_char security_passphrase[] PROGMEM = {"xxx"}; // max 64 characters
// WEP 64-bit keys
//Change the length on line 337 in the g2100.c file: cmd->keyLen = 5; // Key length: 5 bytes (64-bit WEP); 13 bytes (128-bit WEP)
prog_uchar wep_keys[] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, // Key 0 Shortened the keys to match my router settings.
0x00, 0x00, 0x00, 0x00, 0x00, // Key 1
0x00, 0x00, 0x00, 0x00, 0x00, // Key 2
0x00, 0x00, 0x00, 0x00, 0x00 // Key 3
};
// setup the wireless mode
// infrastructure - connect to AP
// adhoc - connect to another WiFi device
unsigned char wireless_mode = WIRELESS_MODE_INFRA;
unsigned char ssid_len;
unsigned char security_passphrase_len;
// End of wireless configuration parameters
//--------------------------------------------------------------
//non WiShield defines
#define DEBUG_PRINT
#define TEMPERATURE_PIN 5
#define LIGHT_PIN 0
//global variables.
boolean inValidPacket;
char recvData[256];
long updateTime = 0;
boolean firstPass = false;
//boolean intTimer;
//Sensor Data Variables:
//--------------------------------------------------------------
int temperature;
int light;
//Incoming Data Variables: Use an appopriate number of variables for your CSV values.
//--------------------------------------------------------------
int var1;
int var2;
//int var3;
//Pachube
//--------------------------------------------------------------
// IP Address for Pachube.com
uint8 ip[] = {209,40,205,190};
char hostName[] = "www.pachube.com\nX-PachubeApiKey: [YOUR KEY HERE]\nConnection: close";
char url[] = "/api/XXXX.csv?_method=put";
// A request that POSTS data to Pachube
POSTrequest postPachube(ip, 80, hostName, url, feedData);
//char url2[] = "/api/feeds/XXXX.xml"; //For retreiving XML if necessary. Needs a different parser.
char url2[] = "/api/feeds/XXXX.csv";
GETrequest getPachube(ip, 80, hostName, url2);
/*
//MsTimer2 one minute timer ISR
//--------------------------------------------------------------
void timerISR() {
intTimer = true;
}
*/
//body data function, provides data for the POST command in comma separated values (CSV)
//currently POSTs one value but more can be added by separating with comma (no spaces)
//Your program will not want to use the hardcoded values below, rather it would read the
//sensor(s) and build the data string shown below.
//--------------------------------------------------------------
void feedData()
{
char buf[16];
sprintf(buf, "%d,%d", temperature, light);
WiServer.print(buf);
}
// Function that prints data from the server during POSTrequests
//--------------------------------------------------------------
void printData(char* data, int len) {
// Print the data returned by the server
// Note that the data is not null-terminated, may be broken up into smaller packets, and
// includes the HTTP header.
while (len-- > 0) {
Serial.print(*(data++));
}
}
// Function that prints data from the server during GETrequests
//Parsing the data takes three stages:
//1. Data is received in chunks. The last chunk is stored in recvData.
//2. recvData is split into individual lines.
//3. The last line, which always contains the csv data, is split into individual values.
//--------------------------------------------------------------
void printGetData(char* data, int len) {
//if we are not in the middle of a packet AND we find the OK token
if(false == inValidPacket && NULL != strstr(data, "HTTP/1.1 200 OK")) {
//mark that we are in a valid packet
inValidPacket = true;
//temporary for debugging purposes
Serial.println("Data reception has started");
}
//if we were in a valid packet AND we get the ending 0 == len call
//This is executed once after receiving the last chunck of data.
if(true == inValidPacket && 0 == len) {
//mark that we are no longer in a valid packet
inValidPacket = false;
//grab out the values with something like sscanf()
parseData();
//temporary for debugging purposes
Serial.println("Data reception has ended");
//Serial.println(data);
//reset firstPass variable for parsing data
firstPass = true;
}
else {
//insures that the data in recvData is clean and doesn't have leftovers from before
memset(recvData, 0, 256 * sizeof(char));
//stash away the last bit of data received
memcpy(recvData, data, len);
#ifdef DEBUG_PRINT //temporary for debugging purposes
Serial.println("-------- Received a chunk of data: --------");
Serial.println(recvData);
//inString = recvData;
//Serial.println(data);
//Serial.println("Last chunk of data:");
//Serial.print("Length: ");
//Serial.println(len);
Serial.println("-------- End of Chunk --------");
#endif //DEBUG_PRINT
}
}
void setup() {
//initialize sensor variables
temperature = 0;
light = 0;
//setup the analog pins as input, probly redundant
pinMode(TEMPERATURE_PIN, INPUT);
pinMode(LIGHT_PIN, INPUT);
// Initialize WiServer (we'll pass NULL for the page serving function since we don't need to serve web pages)
WiServer.init(NULL);
// Enable Serial output and ask WiServer to generate log messages (optional)
#ifdef DEBUG_PRINT
Serial.begin(57600);
//WiServer.enableVerboseMode(true); //optional
#endif //DEBUG_PRINT
// Have the printData function called when data is returned by the server during POSTrequests
//postPachube.setReturnFunc(printData);
// Have the printGetData function called when data is returned by the server during GETrequests
getPachube.setReturnFunc(printGetData);
//set up global state data
//intTimer = false;
inValidPacket = false;
memset(recvData, 0, 256 * sizeof(char));
//setup the timerISR to be called every minute
//MsTimer2::set(20000, timerISR); // 60000ms/1min period
//MsTimer2::start();
}
void loop() {
if(millis() >= updateTime) {
//time inverval has passed
updateTime += 30000;
//intTimer = false;
//For now just increment the variables. In the future connect them to actual sensors.
temperature++;
light++;
//temperature = convertTemp(analogRead(TEMPERATURE_PIN));
//light = 1024 - analogRead(LIGHT_PIN);
#ifdef DEBUG_PRINT
Serial.println("===== Timer Fired =====");
Serial.print("Temp: ");
Serial.print(temperature, DEC);
Serial.print("F, Light: ");
Serial.println(light, DEC);
#endif //DEBUG_PRINT
//submit tasks for WiServer
postPachube.submit();
getPachube.submit();
}
// Run WiServer
WiServer.server_task();
delay(10);
}
//Function that parses the last chunk of data received.---------------------------------
void parseData() {
const char *ptr = recvData;
char field [ 64 ];
int n;
int x;
//steps through the recvData saving the last line in 'field' and the number of characters read in 'n'.
while ( sscanf(ptr, "%64[^\n]%n", field, &n) == 1 )
{
#ifdef DEBUG_PRINT
//printf("field = \"%s\"\n", field);
//Serial.print ("Field = ");
//Serial.println(field);
#endif //DEBUG_PRINT
ptr += n; /* advance the pointer by the number of characters read */
if ( *ptr != '\n' )
{
break; /* didn't find an expected delimiter, done? */
}
while ( *ptr == '\n' )
{
++ptr; /* skip the delimiter */
}
}
//Store each comma separated value (CSV) in the associated variable
//To use more variable just follow the pattern.
//sscanf looks for comma separated integers (%d , %d). For longer numbers or floats use a different data type.
//Don't forget to change the data type of your variables to match.
//---------------------------
sscanf(field, "%d,%d" , &var1, &var2 );
//sscanf(field, "%d,%d,%d," , &var1, &var2, &var3 );
#ifdef DEBUG_PRINT
Serial.print ("Var1 = "); //print results
Serial.println(var1);
Serial.print ("Var2 = ");
Serial.println(var2);
//Serial.print ("Var3 = ");
//Serial.println(var3);
#endif //DEBUG_PRINT
}
/*
http://www.arduino.cc/playground/ComponentLib/Thermistor2
(Ground) ---- (10k-Resistor) -------|------- (Thermistor) ---- (+5v)
|
Analog Pin 0
*/
/*
int convertTemp(int value)
{
double temp;
temp = log(((10240000 / value) - 10000));
temp = 1 / (0.001129148 + (0.000234125 * temp) + (0.0000000876741 * temp * temp * temp));
temp = temp - 273.15; // Convert Kelvin to Celcius
temp = (temp * 9.0) / 5.0 + 32.0; // Convert Celcius to Fahrenheit
return (int)temp;
}
*/
/*
http://www.libelium.com/squidbee/index.php?title=Adding_a_light_sensor
(Ground) ---- (Light Sensor) -------|------- (1k-Resistor) ---- (+5v)
|
Analog Pin 0
*/
The output looks something like this:
===== Timer Fired =====
Temp: 47F, Light: 47
Data reception has started
-------- Received a chunk of data: --------
HTTP/1.1 200 OK
Server: nginx/0.6.34
Date: Fri, 28 May 2010 06:02:44 GMT
Content-Type: text/plain; charset=utf-8
Connection: close
Last-Modified: Fri, 28 May 2
-------- End of Chunk --------
-------- Received a chunk of data: --------
010 06:02:13 GMT
X-Runtime: 5
Cache-Control: private, max-age=0, must-revalidate
Content-Length: 5
Set-Cookie: _pachube_app_session=ef383e1ba7d4a0e50a14578fc488
-------- End of Chunk --------
-------- Received a chunk of data: --------
f36f; path=/; expires=Fri, 28 May 2010 07:02:43 GMT; HttpOnly
Vary: Accept-Encoding
Vary: Accept-Encoding
46,46
-------- End of Chunk --------
Var1 = 46
Var2 = 46
Data reception has ended