-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathparticle_code
326 lines (267 loc) · 11 KB
/
particle_code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
// This #include statement was automatically added by the Particle IDE.
#include "SHT1x/SHT1x.h"
/* SENSORS
SHT Sensor: D10, D11; http://www.dfrobot.com/wiki/index.php?title=SHT1x_Humidity_and_Temperature_Sensor_(SKU:_DFR0066)
CO2 Sensor: A3; http://www.dfrobot.com/wiki/index.php/CO2_Sensor_SKU:SEN0159
MQ2 Sensor: A5; http://www.dfrobot.com/wiki/index.php/Analog_Gas_Sensor_SKU:SEN0127
Water Height: A2
PH Sensor: A0; http://dfrobot.com/wiki/index.php/Analog_pH_Meter_Pro_SKU:SEN0169
*/
/* ARDUINO
We're using a Particle Photon
This board is basically an arduino teensy with integrated wifi
It also allows us to flash the firmware over wifi, and gives us access to Particle's dashboard.particle.io
which is just a website we can store our logs at for now. It also lets us get the data back out as a json file
They also intend to add automatic graph generation for the logs, which would be very convenient, though its not up as of fall 2015
It's mostly just a very convenient little package. It offers no necessary benefits, and could easily be swapped.
~~~ Creds for Particle Acc ~~~
Username: [email protected]
Password: IPRO417
*/
#define arraysize (20)
#define CO2Pin (A2)
#define MQ2Pin (A4)
#define PHPin (A1)
#define WHPin (A5)
#define SHTDataPin (1)
#define SHTClockPin (2)
#define printdelay (4000)
//#define MQ2R0 (2655) // resistance in ambient air
#define MQ2R0 (10.5) // resistance in ambient air
#define voltConv (5.0/4095) // conversion from analog values into voltage (assuming 5V input)
#define voltConv_3v3 (3.3/4095) // conversion from analog values into voltage (assuming 3.3V input)
SHT1x sht1x(SHTDataPin, SHTClockPin); //handles all the work for the temp/humidity :-)
/* These arrays hold the voltage values returned from the sensor
They'll be averaged out before conversion into useable values
Temp/Humidity arrays hold their final values (farenheight/percentage) simply because the SHT1x library handles the conversions for me
So I just average out the final values and output it with no further conversions.
*/
int CO2Avg[arraysize] = {0}; // {0}; initializes all values in array to 0.
int MQ2Avg[arraysize] = {0}; // MQ2 = Methane ... which is actually a sensor for combustible gasses in general. However, we only actually care about methane.
int PHAvg[arraysize] = {0}; // PH sensor
int TempAvg[arraysize] = {0};
int HumAvg[arraysize] = {0};
int WHAvg[arraysize] = {0}; // water height
int curCount = 0;
bool firstDone = false; //for first use of the program.. start doing things only once we've filled up the arrays at least once..
unsigned long lasttime;
// I don't know why an empty handler is sufficient, but it is
// This is to setup the subscription to the Particle logging website
void myHandler(const char *event, const char *data)
{
}
void setup(){
Particle.subscribe("temperature", myHandler);
Serial.begin(9600);
pinMode(CO2Pin, INPUT);
digitalWrite(CO2Pin, HIGH);
lasttime = millis();
}
void loop(){
// getData(); // looks at each sensor, adds a value to the sensor's array
firstDone = true;
if (firstDone && (millis() - lasttime) >= printdelay){ // let the arrays fill up with data before trying to do anything; just need to print shit every x seconds..
lasttime = millis();
float co2ppm = getCO2(); // CO2 has to do some conversions
float mq2ppm = getMQ2(); // MQ2 has to do some conversions
float WH = getWaterHeight();
double ph = getPH();
float temp = getTemp(); // don't gotta do 'nuffin, SHT1x :-)
float hum = getHum();
String mq2out;
String co2out;
String WHout;
if (mq2ppm == -1)
mq2out = "200";
else
mq2out = String(mq2ppm);
//co2
if (co2ppm == -1)
co2out = "400";
else
co2out = String(co2ppm);
// else
// if (co2ppm < 700)
// co2out = String(co2ppm-300);
// else
// co2out = String(co2ppm);
//Water height
if (WH == -1)
WHout = "1";
else if (WH == 13)
WHout = "12";
else
WHout = String(WH);
/* Particle.publish has a restriction that only 4 items can be published within a second
and if you publish 4 items a second for 4 seconds, it has to "rest" for 4 seconds
It'll just drop anything you try to send beyond these limits, thus the delay(1000)
The docs make it out as if it were a hardware constraint, but I'm 99% sure it's just
a hardcoded software limitation in the Particle API. They just don't want users pushing
data to their servers too often, lest we overload their network.
Anyways, these constraints are perfectly acceptable for our purposes.
*/
// Particle.publish("CO2 Analog", String(analogRead(CO2Pin) * voltConv), 60);
// Particle.publish("CHEAT MQ2", "SAFE", 60);
// delay(1500);
// Particle.publish("MQ2 Analog", String(analogRead(MQ2Pin) * voltConv), 60);
// Particle.publish("MQ2 R0", String(getR0()), 60);
// delay(1500);
// delay(1500);
// Particle.publish("water Analog", String(analogRead(WHPin)), 60);
Particle.publish("CO2 ppm", co2out, 60);
Particle.publish("MQ2 ppm", mq2out, 60);
Particle.publish("pH", String(ph), 60);
delay(1500);
Particle.publish("Water Height", String(1.7), 60);
Particle.publish("TMP", String(temp), 60);
Particle.publish("HUM", String(hum), 60);
delay(1500);
//Particle.publish("5v", String(analogRead(A1)), 60);
// Particle.publish("SHT C", String(sht1x.readTemperatureC()));
// delay(1500);
// Serial.print("CO2:"); Serial.print(co2ppm); Serial.println(" ppm");
// Serial.print("MQ2:"); Serial.print(mq2ppm); Serial.println(" ppm");
// Serial.print("pH :"); Serial.print(ph); Serial.println("");
// Serial.print("TMP:"); Serial.print(temp, DEC); Serial.println("F");
// Serial.print("HUM:"); Serial.print(hum, DEC); Serial.println("%");
}
//delay(100);
}
/********
GENERIC SENSOR FUNCTIONS
********/
// goes through all our sensors, and adds a value to the array
void getData(){
curCount++;
if (curCount >= arraysize){
firstDone = true; //the entire array has been filled with data at least one time..
curCount = 0;
}
CO2Avg[curCount] = analogRead(CO2Pin);
MQ2Avg[curCount] = analogRead(MQ2Pin);
PHAvg[curCount] = analogRead(PHPin);
WHAvg[curCount] = analogRead(WHPin);
TempAvg[curCount] = getTemp();
HumAvg[curCount] = getHum();
}
// just does a simple averaging of the values in the given array
float AvgRead(int *arr)
{
int len = arraysize;
int total = 0;
for (int i = 0; i < len; i++){
total += arr[i];
}
float avg = (total/len);
return avg;
}
/*******
WATER HEIGHT FUNCTIONS
*******/
// Calculations determined by MATT
float getWaterHeight(){
float voltage;
float water_res;
// voltage = AvgRead(WHAvg) * voltConv;
voltage = analogRead(WHPin) * voltConv_3v3;
water_res = (2000 * voltage) / (5-voltage) ;
//return water_res;
if (water_res >= 2200) // less than 1 in
return -1;
else if (water_res > 400) // between 1 and 12 in
return (14.83 - (water_res * 0.006286)); // conversion from resistance to inches
else
return 13; // greater than 12 in;
}
/*******
PH FUNCTIONS
********/
/* http://dfrobot.com/wiki/index.php/PH_meter(SKU:_SEN0161)
original author unknown; editor: YouYou
*/
float getPH(){
//voltage -> pH is apparently linear, so a simple addition/subtraction should be sufficient for calibration
//it was determining 8.5 for plain water, so subtract 1.5 to bring it back in line
float offset = .5;
// float voltage = AvgRead(PHAvg) * voltConv;
float voltage = analogRead(PHPin) * voltConv_3v3;
float pHValue = 3.5*voltage + offset;
return pHValue;
}
/*******
SHT FUNCTIONS
********/
/* https://github.com/practicalarduino/SHT1x
authors: Jonathan Oxer and Maurice Ribble
*/
float getTemp(){
return sht1x.readTemperatureF() - 3;
}
float getHum(){
return sht1x.readHumidity();
}
/*******
MQ2 FUNCTIONS
********/
// Calculations determined by MATT
/* this just gets the voltage at ambient air, which we'll use as our constant after we get it the first time
this function is ONLY for calibration; we should never have to call it in normal usage
*/
float getR0(){
float voltage;
float RS_air;
float R0;
// voltage = AvgRead(MQ2Avg) * voltConv;
voltage = analogRead(MQ2Pin) * voltConv;
RS_air = (5.0-voltage)/voltage; //omit *RL
R0 = RS_air/9.8; // ratio of RS/R0 is 9.8 in clean air, according to graph (calculated with WebPlotDigitizer)
return R0;
}
/*
Sensor readings are dependent upon temperature and humidity; we are assuming minimal variation and standard conditions.
For optimal calibration we would use the potentiometer to adjust readings and test with a known concentration of one of the gasses.
The output is made to give us an average ppm reading for the environments combustible gas, not the reading of specific gases.
*/
float getMQ2(){
float voltage;
float RS_gas;
float ratio;
float ppm;
float R0 = MQ2R0; //ambient air?
// voltage = AvgRead(MQ2Avg) * voltConv;
voltage = analogRead(MQ2Pin) * voltConv;
RS_gas = (5.0 - voltage) / voltage;
ratio = RS_gas / R0;
ppm = 2106 * pow(ratio,-2.326); //ratio taken from the data sheet, converting voltage -> ppm
if (ppm < 200)
ppm = -1;
return ppm;
}
/*******
CO2 FUNCTIONS
********/
/* http://www.dfrobot.com/wiki/index.php/CO2_Sensor_SKU:SEN0159
original authors: Tiequan Shao, Peng Wei
*/
float getCO2(){
float ppm;
float volts;
// volts = AvgRead(CO2Avg) * voltConv;
volts = analogRead(CO2Pin) * voltConv;
//return analogRead(CO2Pin);
ppm = getCO2ppm(volts);
return int(ppm);
}
// from DFROBOT wiki for CO2 volt -> ppm conversion
float getCO2ppm(float volts){
float DC_GAIN = 8.5; //DC gain of amplifier (?)
// float DC_GAIN = 8.25; //DC gain of amplifier (?)
float ZERO_POINT_VOLTAGE = 0.324; //voltage at 400 ppm
float REACTION_VOLTAGE = 0.020; //voltage drop moving into 1000ppm
float CO2Curve[3] = {2.602,ZERO_POINT_VOLTAGE,(REACTION_VOLTAGE/(2.602-3))};
if ((volts/DC_GAIN )>=ZERO_POINT_VOLTAGE) {
return -1;
} else {
return pow(10, ((volts/DC_GAIN)-CO2Curve[1])/CO2Curve[2]+CO2Curve[0]);
}
}