Air Quality detector code

Below is the messy Arduino Yun test code with API keys removed:


/*
Yun Air Quality sensor and SD card datalogger

*/

#include
#include
#include

//temp holder for reading back from progmem
char buffer[60];

#define runtemperature
#define runparticle
////#define uploaddatainparticlefunction
#define uploadnormally

//moved from password.h for testing

const char APIKEY[] PROGMEM=""; // replace your xively api key here
const char FEEDID[] PROGMEM=""; // replace your feed ID
const char USERAGENT[] PROGMEM=""; // user agent is the project name

//temboo stuff
//const char TEMBOO_ACCOUNT[] PROGMEM= ""; // your Temboo account name
//const char TEMBOO_APP_KEY_NAME[] PROGMEM= "AirQuality"; // your Temboo app key name
//const char TEMBOO_APP_KEY[] PROGMEM= ""; // your Temboo app key

/*** SUBSTITUTE YOUR VALUES BELOW: ***/

// Note that for additional security and reusability, you could
// use #define statements to specify these values in a .h file.
//progmem means the static var is kept in the flash and not moved to the ram at runtime, saves memory.
//const char TWITTER_ACCESS_TOKEN[] PROGMEM = "";
//const char TWITTER_ACCESS_TOKEN_SECRET[] PROGMEM = "";
//const char TWITTER_API_KEY[] PROGMEM = "";
//const char TWITTER_API_SECRET[] PROGMEM = "";

//xively stuff
const unsigned long postingInterval = 60000;
unsigned long lastRequest = 0;
String xdataString = "";
double lastmeasuredtemp = 0;
float lastmeasuredtemp2 = 0.0;
unsigned long lastlowpulseoccupancy =0;
float lastratio =0.0;
float lastconcentration=0.0;
unsigned long lastlowpulseoccupancy2 =0;
float lastratio2 =0.0;
float lastconcentration2=0.0;

//int concentration2average=0;
double sampletime = 0.0;
double sampletime2 = 0.0;

//rolling average code
const int numReadings=20;
float readings[numReadings];
int index = 0;
float total = 0;
float average = 0;
float readings2[numReadings];
int index2 = 0;
float total2 = 0;
float average2 = 0;

//Particle PPD42 detctor
//JST Pin 1 (Black Wire) => Arduino GND
//JST Pin 3 (Red wire) => Arduino 5VDC
//JST Pin 4 (Yellow wire) => Arduino Digital Pin 8
int pin = 8; //digital pin for reading 1um particles.
int pin2 =7; //digital pin for reading 2.5um particles
unsigned long duration;
unsigned long starttime;
unsigned long sampletime_ms = 30000; //should be 30000; but 3 secondsish to process other stuff
unsigned long lowpulseoccupancy = 0;
float ratio = 0;
float concentration = 0;
int counter=0;
unsigned long duration2;
unsigned long starttime2;
unsigned long lowpulseoccupancy2 = 0;
float ratio2 = 0;
float concentration2 = 0;
int counter2=0;
int particleupload=0;
int tweetsent=0;

//when using mac usb port
//float voltin = 4400.0; //4.2v
//float calibrate = 1.0;

//when using charger
float voltin = 4600.0; //4.39v
float calibrate = 2.0;

void setup() {

// Initialize the Bridge and the Serial
Bridge.begin();
Serial.begin(9600);
FileSystem.begin();

//set perticle detector pin for inputs
pinMode(8,INPUT);
starttime = millis();

//initialise rolling average array to 0
for (int thisReading =0; thisReading readings[thisReading]=0.0;

// while(!Serial); // wait for Serial port to connect.
Serial.println(F("Filesystem datalogger\n"));

}

void loop () {
//only bother to check temp and upload every so often
if (counter>30)
{
counter=0;
// make a string that start with a timestamp for assembling the data to log:
String dataString;
dataString += getDate();
dataString += ",";
dataString += getTime();
dataString += ",";

#ifdef runtemperature
// read three sensors and append to the string:
for (int analogPin = 0; analogPin double sensor = analogRead(analogPin);
if(analogPin==0) {
sensor=converttotemp(sensor);
lastmeasuredtemp=sensor;
dataString += String(sensor);
}

if (analogPin ==1) {
dataString += ","; // separate the values with a comma

lastmeasuredtemp2 = readTemp2();
dataString += String(lastmeasuredtemp2);

}
}
#endif

#ifdef runparticle
dataString += ",Concentration:,"; // separate the values with a comma
dataString += String(lastconcentration);
dataString += ",Sampletime:,"; // separate the values with a comma
dataString += String(sampletime);
dataString += ",Concentration2:,"; // separate the values with a comma
dataString += String(lastconcentration2);
dataString += ",Sampletime2:,"; // separate the values with a comma
dataString += String(sampletime2);
dataString += String(",");

//read string from flash progmem
//strcpy_P(buffer, Test1);
//dataString += String(buffer);
#endif

// open the file. note that only one file can be open at a time,
// so you have to close this one before opening another.
// The FileSystem card is mounted at the following "/mnt/FileSystema1"
File dataFile = FileSystem.open("/mnt/sda1/arduino/www/datalog.txt", FILE_APPEND);

// if the file is available, write to it:
if (dataFile) {
dataFile.println(dataString);
dataFile.close();
// print to the serial port too:
Serial.println("\n");
Serial.println(dataString);
}
// if the file isn't open, pop up an error:
else {
Serial.println(F("error opening datalog.txt"));
}

writetotweetfile("/mnt/sda1/concentration2.txt", String(lastconcentration2), getlevel(lastconcentration2,20,45));
writetotweetfile("/mnt/sda1/temperature.txt", String(lastmeasuredtemp), "");
writetotweetfile("/mnt/sda1/concentration.txt", String(lastconcentration), getlevel(lastconcentration,2200,3200));

#ifdef uploadnormally
//send data to xively
updateData();
sendData();
#endif

/*if (tweetsent==0)
{
//sendtweet("Oh-ho...I broke again. What happened while I was gone?...anyone there?");
checkdatetime();
tweetsent=1;
}*/

}

counter++;

#ifdef runparticle
//check the particle sensor
particledetect();
particledetect2();

#ifdef uploaddatainparticlefunction
if (particleupload>1)
{
//send data to xively
updateData();
sendData();
particleupload=0;
}
#endif
#endif

// delay(15000);

}

String getlevel(float value, int low , int high)
{
if (value {
return "low";
}
else if (value {
return "medium";
}
else if (value>high)
{
return "high";
}
return "error";
}

void writetotweetfile(char* path, String value, String level)
{
File dataFile = FileSystem.open(path, FILE_WRITE);

// if the file is available, write to it:
if (dataFile) {
if (level=="")
{
dataFile.println(value);
}
else
{
dataFile.println(level + " (" + value + ") ");
}
dataFile.close();
// print to the serial port too:
// Serial.println("\n");
// Serial.println(dataString);
}
// if the file isn't open, pop up an error:
else {
Serial.println(F("error opening file"));
}
}

/*void sendtweet(String message){
Serial.println(F("Sending a tweet"));
Process p;
p.begin(F("/mnt/sda1/yuntwitter.py"));
p.addParameter(message);
p.run();

}*/

/*void checkdatetime()
{
Process date;
int hours, minutes, seconds;

Serial.println(F("Getting the time"));

if (!date.running()) {
date.begin("date");
date.addParameter("+%T");
date.run();
}

//if there's a result from the date process, parse it:
while (date.available()>0) {
// get the result of the date process (should be hh:mm:ss):
String timeString = date.readString();

// find the colons:
int firstColon = timeString.indexOf(":");
int secondColon= timeString.lastIndexOf(":");

// get the substrings for hour, minute second:
String hourString = timeString.substring(0, firstColon);
String minString = timeString.substring(firstColon+1, secondColon);
String secString = timeString.substring(secondColon+1);

sendtweet("I'm Alive! Time is:" + hourString + ":" + minString + ":" + secString);
}
}*/

//particle sensor stuff
void particledetect() {
duration = pulseIn(pin, LOW);
lowpulseoccupancy = lowpulseoccupancy+duration;

if ((millis()-starttime) > sampletime_ms)
{
sampletime=millis()-starttime;
//subtract the last reading
total=total-readings[index];

ratio = lowpulseoccupancy/(sampletime_ms*10.0); // Integer percentage 0=>100
concentration = 1.1*pow(ratio,3)-3.8*pow(ratio,2)+520*ratio+0.62; // using spec sheet curve. Concentration is the no of particles per 0.1 cubic feet.
Serial.print(F("\nParticle: LPO: "));
Serial.print(lowpulseoccupancy);
lastlowpulseoccupancy=lowpulseoccupancy;
Serial.print(",");
Serial.print(F("Ratio: "));
Serial.print(ratio);
lastratio=ratio;
Serial.print(",");
Serial.println(F("Concentration: "));
Serial.print(concentration);

//add data to the averaging array
readings[index]=concentration;
total=total+readings[index];
index++;

//if at end of averaging array
if(index>=numReadings)
index=0;
average=total/numReadings;
lastconcentration=average;

//lastconcentration=concentration;
lowpulseoccupancy = 0;
starttime = millis();

//comment these out unless testing

particleupload=particleupload+1;
// #ifdef uploaddatainparticlefunction
//send data to xively
// updateData();
// sendData();
//#endif
}
}

//particle sensor stuff
//keeping separate function as the pins are processed at different times due to measuring the LPO. Maybe make this more efficent later?
void particledetect2() {
duration2 = pulseIn(pin2, LOW);
lowpulseoccupancy2 = lowpulseoccupancy2+duration2;

if ((millis()-starttime2) > sampletime_ms)
{
sampletime2=millis()-starttime2;
//subtract the last reading
total2=total2-readings2[index2];

ratio2 = lowpulseoccupancy2/(sampletime_ms*10.0); // Integer percentage 0=>100
concentration2 = 1.1*pow(ratio2,3)-3.8*pow(ratio2,2)+520*ratio2+0.62; // using spec sheet curve. Concentration is the no of particles per 0.1 cubic feet.
Serial.print(F("\nParticle: LPO2: "));
Serial.print(lowpulseoccupancy2);
lastlowpulseoccupancy2=lowpulseoccupancy2;
Serial.print(",");
Serial.print(F("Ratio2: "));
Serial.print(ratio2);
lastratio2=ratio2;
Serial.print(",");
Serial.println(F("Concentration2: "));
Serial.print(concentration2);

//add data to the averaging array
readings2[index2]=concentration2;
total2=total2+readings2[index2];
index2++;

//if at end of averaging array
if(index2>=numReadings)
index2=0;
average2=total2/numReadings;
lastconcentration2=average2;

//lastconcentration=concentration;
lowpulseoccupancy2 = 0;
starttime2 = millis();

//comment these out unless testing

particleupload=particleupload+1;

// #ifdef uploaddatainparticlefunction
//send data to xively
// updateData();
// sendData();
//#endif
}
}

//get an average value for the light detection test
float readTemp2() { // Read analog value n times and avarage over those n times
int KelvinC=273;
float _sensorValue = analogRead(1);
Serial.print(F("\nRAW Temp sensor2: "));
Serial.print(_sensorValue);

//Reads the input and converts it to Kelvin degrees
//float _Kelvin = analogRead(1) * 0.004882812 * 100;
float _Kelvin = (((voltin * _sensorValue)/1024.0)/10.0); //input v =4.18 ~ use 4180, use 4450,1024,4420

//Converts Kelvin to Celsius minus 2.5 degrees error
float _Celsius = _Kelvin - 273.15 + calibrate;
Serial.print(F("\nC Temp sensor2: "));
Serial.print(_Celsius);

//float _Kelvin = (((_sensorValue / 1023.0) * 5.0) * 100.0); // convert
//float _Celsius=_Kelvin-KelvinC;
return _Celsius;
}

//the function convert thermistor value to a temperature in degree c
double converttotemp(double RawADC)
{
double Temp;
Temp = log(10000.0*((1024.0/RawADC-1)));
// =log(10000.0/(1024.0/RawADC-1)) // for pull-up configuration
Temp = 1 / (0.001129148 + (0.000234125 + (0.0000000876741 * Temp * Temp ))* Temp );
Temp = Temp - 273.15+ 1.5; // Convert Kelvin to Celcius + ajust for calibration
//Temp = (Temp * 9.0)/ 5.0 + 32.0; // Convert Celcius to Fahrenheit
//return (int)Temp;
return Temp;
}

// This function return a string with the time stamp
String getDate() {  
String result;
Process time;
// date is a command line utility to get the date and the time
// in different formats depending on the additional parameter
time.begin("date");
time.addParameter("+%Y%m%d"); // parameters: D for the complete date mm/dd/yy
// T for the time hh:mm:ss
time.run(); // run the command

// read the output of the command
while(time.available()>0) {
char c = time.read();
if(c != '\n')
result += c;
}

return result;
}

// This function return a string with the time stamp
String getTime() {
String result;
Process time;
// date is a command line utility to get the date and the time
// in different formats depending on the additional parameter
time.begin("date");
time.addParameter("+%T"); // parameters: D for the complete date mm/dd/yy
// T for the time hh:mm:ss
time.run(); // run the command

// read the output of the command
while(time.available()>0) {
char c = time.read();
if(c != '\n')
result += c;
}

return result;
}

//xively data test

void updateData() {
// convert the readings to a String to send it:
xdataString = "Temperature,";
//xdataString += random(10) + 20;
xdataString += lastmeasuredtemp;
// add pressure:
xdataString += "\nTemperature2,";
xdataString += lastmeasuredtemp2;

//particle sensor stuff
// add low pulse occupancy:
xdataString += "\nLowPulseOccupancy,";
xdataString += lastlowpulseoccupancy;

// add low pulse occupancy:
xdataString += "\nRatio,";
xdataString += lastratio;

// add low pulse occupancy:
xdataString += "\nConcentration,";
//rather than send just no of particles over 1um, send amount between 1um and 2.5um
xdataString += lastconcentration-lastconcentration2;

// add low pulse occupancy2:
xdataString += "\nConcentration2,";
xdataString += lastconcentration2;

}

// this method makes a HTTP connection to the xively server:
void sendData() {
// form the string for the API header parameter:
String apiString = "X-ApiKey: ";
//apiString += APIKEY;

strcpy_P(buffer, APIKEY);
apiString += buffer;

// form the string for the URL parameter:
String url = "https://api.xively.com/v2/feeds/";
//url += FEEDID;
strcpy_P(buffer, FEEDID);
url += buffer;

url += ".csv";

// Send the HTTP PUT request

// Is better to declare the Process here, so when the
// sendData function finishes the resources are immediately
// released. Declaring it global works too, BTW.
Process xively;
Serial.print("\n\nSending data... ");
xively.begin("curl");
xively.addParameter("-k");
xively.addParameter("--request");
xively.addParameter("PUT");
xively.addParameter("--data");
xively.addParameter(xdataString);
xively.addParameter("--header");
xively.addParameter(apiString);
xively.addParameter(url);
xively.run();
Serial.println("done!");

// If there's incoming data from the net connection,
// send it out the Serial:
while (xively.available()>0) {
char c = xively.read();
Serial.write(c);
}

}