// This #include statement was automatically added by the Particle IDE. //This library is used to push data to the data.sparkfun.com server. #include "SparkFunPhant/SparkFunPhant.h" #include "math.h" //This code was written by Jennifer Fox /* * ---------------------------------------------------------------------------- * "THE Coffee-WARE LICENSE" (Revision 42): * wrote this file. As long as you retain this notice you * can do whatever you want with this stuff. If we meet some day, and you think * this stuff is worth it, you can buy me a coffee in return. * ---------------------------------------------------------------------------- */ //Variables to push data to data.sparkfun.com host -- Change publicKey[] and privateKey[] const char server[] = "data.sparkfun.com"; // Phant destination server const char publicKey[] = "INSERT_PUBLIC_KEY_HERE"; // Phant public key const char privateKey[] = "INSERT_PRIVATE_KEY_HERE"; // Phant private key Phant phant(server, publicKey, privateKey); // Create a Phant object const unsigned long postingRate = 20000; //Post rate to data.sparkfun.com (time in milliseconds) unsigned long lastPost = millis(); //Keeps track of posting rate //Define analog pins on Photon to use for sensors const int LPG = A0; const int NG = A1; const int CO = A2; //Define digital pins on Photon to use for LEDs, buzzer, and MQ7 (CO sensor) heater const int LPGled = D0; const int NGled = D1; const int COled = D2; const int buzzer = D3; const int CORelayPin = D6; const int COVoltPin = D7; //Set up raw signal and PPM variables for each gas sensor int LPGRaw; int NGRaw; int CORaw; int LPGppm; int NGppm; int COppm; //Set safety threshold levels for each hazardous gas const int LPGthresh = 1000; const int NGthresh = 1000; const int COthresh = 50; //Set variables for CO sensor (MQ7) voltage cycle unsigned long startMillis; unsigned long switchTimeMillis; const int CO_5V_Interval = 60000; //60s for 5V interval const int CO_1_5V_Interval = 90000; //90s for 1.5V interval bool heaterInHighPhase; void setup() { Serial.begin(9600); //Initialize LED and buzzer output pins pinMode(LPGled, OUTPUT); pinMode(NGled, OUTPUT); pinMode(COled, OUTPUT); pinMode(buzzer, OUTPUT); //Initialize CO sensor heater pins pinMode(CORelayPin, OUTPUT); pinMode(COVoltPin, OUTPUT); //Set start time (for CO sensor heater voltage) startMillis = millis(); turnHeaterHigh(); } void loop() { //Cycle CO sensor (MQ7) heater voltage if(heaterInHighPhase){ // 5V phase - check to switch if(millis() > switchTimeMillis) { turnHeaterLow(); } } else { // 1.4V phase - check to switch if(millis() > switchTimeMillis) { turnHeaterHigh(); } } //Read in analog value from each gas sensor -- use function defined below to measure CO sensor at end of voltage cycle LPGRaw = analogRead(LPG); NGRaw = analogRead(NG); CORaw = measureCOSensor(); //Caclulate the PPM of each gas sensor using the funtions defined below LPGppm = LPG_ppm(LPGRaw); NGppm = NG_ppm(NGRaw); COppm = CO_ppm(CORaw); //Serial monitor print for debugging and checking data Serial.println(NGRaw); Serial.println(NGppm); delay(1000); //Check gas sensor measurements against safety thresholds checkThreshold(LPGppm, NGppm, COppm); //Wait to post until ~ 20s has lapsed if (lastPost + postingRate < millis()) { Serial.println("Reading!"); postToPhant(LPGppm, NGppm, COppm); //Post gas sensor readings and unit (PPM) to your data stream at data.sparkfun.com lastPost = millis(); } } //Functions to calculate PPM from Photon analog reading //Each equation is determined by visually picking points, plotting PPM v. V_RL, then fitting a trendline to the curve (exponential) //Calculate LPG PPM int LPG_ppm(double rawValue){ double ppm = 26.572*exp(1.2894*(rawValue*3.3/4095)); //Multiply raw analog value by 3.3/4095 to convert to a voltage return ppm; } //Calculate NG PPM int NG_ppm(double rawValue){ double ppm = 10.938*exp(1.7742*(rawValue*3.3/4095)); return ppm; } //Calculate CO PPM int CO_ppm(double rawValue){ double ppm = 3.027*exp(1.0698*(rawValue*3.3/4095)); return ppm; } //Function to check PPM reading with maximum safe PPM threshold //Include a margin of error (currently 10%) void checkThreshold(int lpgppm, int ngppm, int coppm){ int led1; int led2; int led3; if (lpgppm >= LPGthresh*0.9){ digitalWrite(LPGled, HIGH); led1 = TRUE; } else{ digitalWrite(LPGled, LOW); led1 = FALSE; } if (ngppm >= NGthresh*0.9){ digitalWrite(D1, HIGH); led2 = TRUE; } else{ digitalWrite(NGled, LOW); led2 = FALSE; } if (coppm >= COthresh*0.9){ digitalWrite(D2, HIGH); led3 = TRUE; } else{ digitalWrite(COled, LOW); led3 = FALSE; } if(led1 | led2 | led3){ digitalWrite(buzzer, HIGH); } else{digitalWrite(buzzer, LOW);} } //Functions to switch heater voltage on MQ7 (CO) sensor void turnHeaterHigh(){ // 5v phase digitalWrite(COVoltPin, LOW); digitalWrite(CORelayPin, HIGH); heaterInHighPhase = true; switchTimeMillis = millis() + CO_5V_Interval; } void turnHeaterLow(){ // 1.4v phase digitalWrite(COVoltPin, HIGH); digitalWrite(CORelayPin, LOW); heaterInHighPhase = false; switchTimeMillis = millis() + CO_1_5V_Interval; } //Function to read CO sensor voltage (just before switching to 1.5V) int measureCOSensor(){ unsigned int gasLevel = analogRead(CO); unsigned int time = (millis() - startMillis) / 1000; delay(time); return gasLevel; } //Function to post data to data.sparkfun.com host //Many thanks to Jim Lindblom for the sample code and Phant library. int postToPhant(int lpg, int ng, int co){ phant.add("lpg", lpg); //Data stream field name "sensorvalue1" phant.add("ng", ng); //Data stream field name "sensorvalue2" phant.add("co", co); //Data stream field name "sensorvalue3" TCPClient client; char response[512]; int i = 0; int retVal = 0; if (client.connect(server, 80)) // Connect to the server { // Post message to indicate connect success Serial.println("Posting!"); // phant.post() will return a string formatted as an HTTP POST. // It'll include all of the field/data values we added before. // Use client.print() to send that string to the server. client.print(phant.post()); delay(1000); // Now we'll do some simple checking to see what (if any) response // the server gives us. while (client.available()) { char c = client.read(); Serial.print(c); // Print the response for debugging help. if (i < 512) response[i++] = c; // Add character to response string } // Search the response string for "200 OK", if that's found the post // succeeded. if (strstr(response, "200 OK")) { Serial.println("Post success!"); retVal = 1; } else if (strstr(response, "400 Bad Request")) { // "400 Bad Request" means the Phant POST was formatted incorrectly. // This most commonly ocurrs because a field is either missing, // duplicated, or misspelled. Serial.println("Bad request"); retVal = -1; } else { // Otherwise we got a response we weren't looking for. retVal = -2; } } else { // If the connection failed, print a message: Serial.println("connection failed"); retVal = -3; } client.stop(); // Close the connection to server. return retVal; // Return error (or success) code. }