Error messages when uploading multiple datastreams
danolson1 opened this issue · 0 comments
When I try to upload multiple data streams to Xively, I frequently get errors. About 50-60% of the time I get return values of 200, the rest of the time I get values of 3 and 411. Occasionally this causes the Arduino to freeze. Any idea what's going on? Is there any way to see the server response from unsuccessful HTTP requests?
I'm using an Arduino Mega 2560 with WiFi shield. I have updated the WiFi shield firmware to the latest version. I'm using the Arduino IDE 1.0.5-r2.
Here's the code I'm using.
/*
Internet OD reader (IODR) program
Version 8
Dan Olson
9-8-2014
For use with v2 of the IODR, using an Arduino Mega 2560, Arduino WiFi shield and IODR v2 shield circuit board (designed by me)
Detect growth of bacterial cultures by measuring the absorbtion of a light
Pin assignments:
0: used by ethernet shield
1: used by ethernet shield
2: yellow LED
3: RX for lcd display (unused)
5: for entering calibration mode
7: handshake communication between wifi shield and arduino (can't be used for other things)
9: transistor that controls all 8 LEDs (note, this was previously pin 7, but moved to pin 9 since the wifi shield needs to use pin 7)
8: temperature sensor
10: ethernet shield enable
18: TX for lcd display
50, 51, 52: SPI bus for WiFi shield communication with arduino
53: necessary to set this pin as output to allow ethernet shield to work
20-34 (even numbered pins): blank reset buttons
A8: pin 89, light sensor for tube 8
A9: pin 88, light sensor for tube 7
A10: pin 87, light sensor for tube 6
A11: pin 86, light sensor for tube 5
A12: pin 85, light sensor for tube 4
A13: pin 84, light sensor for tube 3
A14: pin 83, light sensor for tube 2
A15: pin 82, light sensor for tube 1
*/
include <OneWire.h>
include <SPI.h>
//#include <Ethernet.h> //not needed since we're using wifi
include <HttpClient.h>
//#include <Cosm.h> // not needed since we're using new xively library
include <Math.h>
include <SoftwareSerial.h>
include <WiFi.h>
include <Xively.h>
define VERSION 8
define API_KEY "ykoxrQb5UKnebVGoBH5Vl1XZQQITCV7nAFnXy5dEAuxkStef" // my Xively API key
char xivelyKey[] = "ykoxrQb5UKnebVGoBH5Vl1XZQQITCV7nAFnXy5dEAuxkStef";
define FEED_ID 641819840 // my Cosm feed ID
// initialize variables
// no longer needed // MAC address for your Ethernet shield
// no longer needed //byte mac[] = { 0x90, 0xA2, 0xDA, 0x0D, 0xA7, 0x42 }; // for ethernet shield attached to mega
// define login details for wifi shield
// currently set up for use with home network, need to change for Dartmouth network
// IODR #2 wifi shield mac address is 78:C4:0E:02:10:F9. Note that the sticker on the back says 90:A2:DA:0F:0C:64 but this is not correct. Run the WiFi "ConnectNoEncryption" file to see the correct MAC address.
char ssid[] = "Dartmouth Public"; // your network SSID (name)
//char pass[] = "celebration!"; // your network password
int status = WL_IDLE_STATUS; // status of wireless connection
//define strings for datastream IDs
char tube1Stream[] = "tube1";
char tube2Stream[] = "tube2";
char tube3Stream[] = "tube3";
char tube4Stream[] = "tube4";
char tube5Stream[] = "tube5";
char tube6Stream[] = "tube6";
char tube7Stream[] = "tube7";
char tube8Stream[] = "tube8";
char temperatureStream[] = "temperature";
// create datastreams
XivelyDatastream datastreams[] = {
XivelyDatastream(tube1Stream, strlen(tube1Stream), DATASTREAM_FLOAT),
XivelyDatastream(tube2Stream, strlen(tube2Stream), DATASTREAM_FLOAT),
XivelyDatastream(tube3Stream, strlen(tube3Stream), DATASTREAM_FLOAT),
XivelyDatastream(tube4Stream, strlen(tube4Stream), DATASTREAM_FLOAT),
XivelyDatastream(tube5Stream, strlen(tube5Stream), DATASTREAM_FLOAT),
XivelyDatastream(tube6Stream, strlen(tube6Stream), DATASTREAM_FLOAT),
XivelyDatastream(tube7Stream, strlen(tube7Stream), DATASTREAM_FLOAT),
XivelyDatastream(tube8Stream, strlen(tube8Stream), DATASTREAM_FLOAT),
XivelyDatastream(temperatureStream, strlen(temperatureStream), DATASTREAM_FLOAT),
};
// Wrap all 9 datastream into a feed
XivelyFeed feed(FEED_ID, datastreams, 9);
unsigned long lastConnectionTime = 0; // last time we connected to Xively
const unsigned long connectionInterval = 60000; // delay between connecting to Xively in milliseconds
// network setup
WiFiClient client;
XivelyClient xivelyclient(client);
boolean connectedToInternet = false;
// digital temperature sensor
int DS18S20_Pin = 8; //DS18S20 temp sensor signal pin on digital 8
OneWire ds(DS18S20_Pin); // on digital pin 8
float temperature;
// LEDs and light sensors
int ledPin = 9;
int yellowLED = 2;
int numTubes = 8;
int calibrationPin = 5;
int lightInPin[] = {A15, A14, A13, A12, A11, A10, A9, A8}; //pins for analog inputs for light sensor
float lightIn[] = {0,0,0,0,0,0,0,0}; //value of light sensor
float ODvalue[] = {0,0,0,0,0,0,0,0};
int LEDoffReading[] = {0,0,0,0,0,0,0,0};
int LEDonReading[] = {0,0,0,0,0,0,0,0};
int pointsToAverage = 30; //number of light readings to average in each data point sent to Cosm
int blankButtonState[] = {0,0,0,0,0,0,0,0}; // status of buttons for blanking individual tubes
//int newBlankButtonState[] = {0,0,0,0,0,0,0,0};
int blankButtonPin[] = {20, 22, 24, 26, 28, 30, 32, 34};
int lastButtonPressed = 0; // keep track of which reset button was pressed most recently
// calibration data from 3-17-2013
// float blankValue[] = {598.8,980.7,564.0,847.7,988.9,505.6,638.2,622.6}; //from 3/16/2013 calibration
float blankValue[] = {1000.0, 1000.0, 1000.0, 1000.0, 1000.0, 1000.0, 1000.0, 1000.0}; //from 3/25/2013 calibration
//float slopeValue[] = {1.13805, 1.10954, 1.10806, 1.11424, 1.08111, 1.18568, 1.15645, 1.05881};
//float iceptValue[] = {0.07818, 0.0152, 0.00991, 0.01595, -0.02349, -0.03377, -0.02151, -0.05815};
int calibrationMode = 1; // 1 is for no calibration, 0 is for calibration mode. in calibration mode, one reading is taken every time the button is pressed
int calibrationCount = 0; // keeps track of how many times the calibration button was pressed
// for lcd serial display
SoftwareSerial mySerial (3,18);
void setup() {
mySerial.begin(9600); //start lcd display
delay(500); // wait for lcd display to boot up
Serial.begin(9600);
pinMode(ledPin, OUTPUT);
pinMode(yellowLED, OUTPUT);
analogReference(EXTERNAL);
pinMode(calibrationPin, INPUT);
pinMode(53, OUTPUT); //necessary for WiFi shield function
// calibration mode is for calibrating the analog channels
// see description in main loop
// needs to be rewritten as its own subroutine to make program flow clearer
calibrationMode = digitalRead(calibrationPin); // decide whether or not to enter calibration mode
if (calibrationMode == 0){ // enter calibration mode
Serial.println();
Serial.println("Entering calibration mode...");
calibrationCount = 0;
}
// connect to internet with wifi adapter
Serial.print("Internet OD reader v");
Serial.println(VERSION);
Serial.println("==========================");
Serial.println("Initializing network");
// send message to LCD display
mySerial.write(254); // move cursor to beginning of first line
mySerial.write(128);
mySerial.write("Trying to connect to internet ");
// attempt to connect to Wifi network:
while ( status != WL_CONNECTED) {
Serial.print("Attempting to connect to SSID: ");
Serial.println(ssid);
status = WiFi.begin(ssid); //use for an SSID that doesn't require a password
//status = WiFi.begin(ssid, pass); //use for an SSID that requires a password
// wait 10 seconds for connection:
delay(10000);
}
Serial.println("Connected to wifi");
connectedToInternet = true;
printWifiStatus();
// temporarily disabled for testing
/*
// make 4 attempts to connect to internet
for (int i=1; i<4; i++){
status = WiFi.begin(ssid, pass); //try to connect to internet
Serial.print("Attempting to connect to SSID: ");
Serial.println(ssid);
Serial.print("using password: ");
Serial.println(pass);
Serial.print("status: ");
Serial.println(status);
if (status != WL_CONNECTED) {
Serial.print("Error connecting to network, trying again...");
Serial.print("attempt ");
Serial.print(i);
Serial.println(" of 3");
delay(10000);
}
else {
i=4; //jump out of for loop
connectedToInternet = true;
Serial.println("Network initialized");
Serial.println();
printWifiStatus();
// send message to LCD display
//mySerial.write(254); // move cursor to beginning of first line
//mySerial.write(128);
//mySerial.write("Connected to internet ");
delay(1000);
}
}
*/
}
// main program loop
void loop() {
// infinite loop in calibration mode
// calibration mode can only be entered during setup, so controller needs to be reset
// it allows you to step through the analog readings and adjust the trim potentiometers
// once you've entered the calibration mode, each press of the CAL-MODE button takes one reading
while (calibrationMode == 0){
Serial.println("_CALIBRATION MODE_");
readLightSensors();
calibrationDisplay();
//checkBlankButtons();
//blankButtonStatusDisplay();
while(digitalRead(calibrationPin) == 1){ //button is pressed
}
delay(100); // debounce
while(digitalRead(calibrationPin) == 0){ //button is released
}
delay(100); // debounce
}
// normal mode (i.e. not calibration mode)
temperature = getTemp(); //read temperature sensor (deg. C)
//Serial.println(" ***** readLightSensors() ****");
readLightSensors(); // read light sensor values
//Serial.println(" **** serialPrintState() ****");
//serialPrintState(); // display the raw data from the sensors
//Serial.println(" **** checkBlankButtons() ****");
checkBlankButtons();
//Serial.println(" **** displayTubeStatus() *****");
displayTubeStatus(); // display the status of the current tube on the lcd display
delay(300);
// send data to Xively
if (connectedToInternet){
if (millis() - lastConnectionTime > connectionInterval) {
digitalWrite(yellowLED, HIGH); // turn on yellow LED when sending data to Xively
sendData();
// update connection time so we wait before connecting again
lastConnectionTime = millis();
//serialPrintHeaders();
digitalWrite(yellowLED, LOW); // turn off yellow LED
}
}
}
// end of main program loop
//display a message on the LCD saying that one tube blank value was reset
void displayTubeReset(int tubeNum){
char resetTopLine[] = "Tube: ";
char resetBotLine[] = "Was reset ";
// set tube number
resetTopLine[5] = tubeNum + 49; //convert integer to ascii by adding 48, add one more to shift index by 1
mySerial.write(254); // move cursor to beginning of first line
mySerial.write(128);
mySerial.write(resetTopLine);
mySerial.write(254); // move cursor to beginning of second line
mySerial.write(192);
mySerial.write(resetBotLine);
Serial.print("displayTubeReset:");
Serial.println(resetTopLine);
delay(3000); //show the message for 3 seconds
}
// display current OD, raw light sensor value and blank value on serial LCD
void displayTubeStatus(){
char bval[60];
char odval[60];
char ltin[60];
char topLine[] = "Tube: Blk= ";
char botLine[] = "OD= Raw= ";
dtostrf(blankValue[lastButtonPressed], 4, 0, bval);
dtostrf(LEDonReading[lastButtonPressed], 4, 0, ltin);
dtostrf(ODvalue[lastButtonPressed], 3, 2, odval);
//if the OD value gave a "NaN" or "inf" value, this will add in blank spaces to make things display properly
// if (sizeof(odval)<4){
// odval += " ";
// }
//set tube number
topLine[5] = lastButtonPressed + 49; //convert integer to ascii by adding 48, add one more to shift index by 1
//set blank, OD and raw numbers
for (int i=0; i < 4; i++){
topLine[12+i] = bval[i]; //set blank value
botLine[3+i] = odval[i]; //set OD value
botLine[12+i] = ltin[i]; //set raw value
}
/*
Serial.print("___topLine->");
Serial.print(topLine);
Serial.println("");
Serial.print("___botLine->");
Serial.print(botLine);
Serial.println("");
*/
mySerial.write(254); // move cursor to beginning of first line
mySerial.write(128);
mySerial.write(topLine);
mySerial.write(254); // move cursor to beginning of second line
mySerial.write(192);
mySerial.write(botLine);
}
// check the state of the reset buttons. keep track of which button was most recently pressed.
// if a button is pressed and held for a certain amount of time (>2 seconds), then reset the blank value for that well
void checkBlankButtons(){
for (int i=0; i<numTubes; i++){
//in v2 of the IODR shield, I accidentally wired the reset buttons to give digital 0 when pressed instead of
//digital 1 (as in previous version). So I added a "!" before the all 3 digitalRead commands to fix this
blankButtonState[i] += !digitalRead(blankButtonPin[i]);
// if a button was pressed, keep track of which one
// if multiple buttons were pressed, remember the highest numbered one
if (!digitalRead(blankButtonPin[i]) == 1){
lastButtonPressed = i;
}
// if a button was not held down during this cycle, reset it's counter
// i.e. reset button 2 was held down for 2 cycles, then it was released
// now it's held down for 2 cycles again. it shouldn't reset the blank value
if (!digitalRead(blankButtonPin[i]) == 0){
blankButtonState[i] = 0;
}
// if a button has been held down for 4 cycles, reset that tube
if (blankButtonState[i] > 4) {
// reset blankValue for tube i
blankValue[i] = LEDonReading[i];
displayTubeReset(i); // write a message to the serial LCD saying the tube was reset
// reset the blank button state
blankButtonState[i] = 0;
}
}
//blankButtonStatusDisplay();
}
// display the state of each pushbutton used to blank the tube reader
void blankButtonStatusDisplay(){
Serial.print("Blank Button State: ");
for (int i=0; i<numTubes; i++){
Serial.print(blankButtonState[i]);
Serial.print(" ");
}
Serial.print(" lastButtonPressed=");
Serial.print(lastButtonPressed);
Serial.println();
}
void calibrationDisplay(){
// write raw values of light sensor to serial port
for (int i=0; i<numTubes; i++){
Serial.print(lightIn[i]);
Serial.print(" ");
}
Serial.println();
}
void serialPrintHeaders(){
// write column names
Serial.println("(lightIn, ODvalue)");
for (int i=0; i<numTubes; i++){
Serial.print("T");
Serial.print(i+1);
Serial.print(" ");
}
Serial.println();
}
void serialPrintState(){
// write values
//Serial.print(" ");
for (int i=0; i<numTubes; i++){
//Serial.print(LEDoffReading[i]);
//Serial.print(" ");
//Serial.print(LEDonReading[i]);
//Serial.print(" ");
Serial.print(lightIn[i]); //raw value of light sensor
Serial.print(" ");
//Serial.print(ODvalue[i]); //calculated OD value
//Serial.print(" ");
}
// display temperature
Serial.print("Temp: ");
Serial.print(temperature);
Serial.println();
}
void readLightSensors(){
// clear the lightIn value
for (int i = 0; i<numTubes; i++){
lightIn[i] = 0;
ODvalue[i] = 0;
}
// start accumulating lightIn values
for (int j = 0; j<pointsToAverage; j++){
// read light sensor values with the LED off
// this measures ambient light levels, which will later get subtracted from the reading
digitalWrite(ledPin, LOW); //turn off LEDs
delay(10); //it takes ~1ms for the light senor reading to stabilize after the LED has been turned off
for (int i = 0; i < numTubes; i++){
LEDoffReading[i] = analogRead(lightInPin[i]);
}
// read light sensor values with the LED on
digitalWrite(ledPin, HIGH); //turn on LEDs
delay(10); //it takes ~1ms for the light senor reading to stabilize after the LED has been turned on
for (int i = 0; i < numTubes; i++){
LEDonReading[i] = analogRead(lightInPin[i]);
}
// calculate the difference and add it to lightIn
for (int i = 0; i < numTubes; i++){
lightIn[i] += (LEDonReading[i] - LEDoffReading[i]);
}
}
// divide lightIn by pointsToAverage to get the average value
for (int i = 0; i < numTubes; i++){
lightIn[i] = lightIn[i]/pointsToAverage;
//ODvalue[i] = -(log10(lightIn[i]/blankValue[i])-iceptValue[i])/slopeValue[i];
ODvalue[i] = -(log10(lightIn[i]/blankValue[i]));
}
// turn the lights off when you're done
digitalWrite(ledPin, LOW); //turn off LEDs
}
float getTemp(){
//returns the temperature from one DS18S20 in DEG Celsius
byte data[12];
byte addr[8];
if ( !ds.search(addr)) {
//no more sensors on chain, reset search
ds.reset_search();
return -1000;
}
if ( OneWire::crc8( addr, 7) != addr[7]) {
Serial.println("CRC is not valid!");
return -1000;
}
if ( addr[0] != 0x10 && addr[0] != 0x28) {
Serial.print("Device is not recognized");
return -1000;
}
ds.reset();
ds.select(addr);
ds.write(0x44,1); // start conversion, with parasite power on at the end
byte present = ds.reset();
ds.select(addr);
ds.write(0xBE); // Read Scratchpad
for (int i = 0; i < 9; i++) { // we need 9 bytes
data[i] = ds.read();
}
ds.reset_search();
byte MSB = data[1];
byte LSB = data[0];
float tempRead = ((MSB << 8) | LSB); //using two's compliment
float TemperatureSum = tempRead / 16;
return TemperatureSum;
}
// send the supplied value to Xively, printing some debug information as we go
void sendData() {
Serial.println ("Data being sent to Xively");
for (int i=0; i<numTubes; i++){
datastreams[i].setFloat(ODvalue[i]);
Serial.print("Tube ");
Serial.print(i);
Serial.print(" = ");
Serial.println(datastreams[i].getFloat());
}
datastreams[numTubes].setFloat(temperature);
Serial.println("Uploading to Xively");
int ret = xivelyclient.put(feed, xivelyKey);
Serial.print("xivelyclient.put returned ");
Serial.println(ret);
Serial.println();
}
// print status of the wifi adapter to the serial port
// need to have the serial port enabled
void printWifiStatus() {
// print the SSID of the network you're attached to:
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
// print your WiFi shield's IP address:
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: ");
Serial.println(ip);
// print the received signal strength:
long rssi = WiFi.RSSI();
Serial.print("signal strength (RSSI):");
Serial.print(rssi);
Serial.println(" dBm");
}