1 // Licence: WTFPLv2 <http://www.wtfpl.net/txt/copying/>
2 // Copyright 2015-2016: Julien Moutinho <julm+air@autogeree.net>
5 #include "SeeedGrayOLED.h"
6 #include "AirQuality.h"
14 #define SERIAL_INPUT_SIZE 25 // "utc=YYYY-MM-DD-HH-mm-ss-d"
15 void loop_serial_read () {
16 char input[SERIAL_INPUT_SIZE + 1];
17 while (Serial.available()) {
18 byte input_size = Serial.readBytesUntil('\n', input, SERIAL_INPUT_SIZE);
19 input[input_size] = 0;
23 r = strchr((data = r), '=');
24 if (!r) continue; *r++ = 0;
25 if (!strcmp(data, "utc")) {
27 // USAGE: TZ=UTC date +"utc=%Y:%m:%d:%H:%M:%S:%u" >/dev/ttyUSB0
28 r = strchr((data = r), ':');
29 if (!r) continue; *r++ = 0;
30 uint16_t year = atoi(data);
32 r = strchr((data = r), ':');
33 if (!r) continue; *r++ = 0;
34 uint8_t month = atoi(data);
36 r = strchr((data = r), ':');
37 if (!r) continue; *r++ = 0;
38 uint8_t dayOfMonth = atoi(data);
39 clock.fillByYMD(year, month, dayOfMonth);
41 r = strchr((data = r), ':');
42 if (!r) continue; *r++ = 0;
43 uint8_t hour = atoi(data);
45 r = strchr((data = r), ':');
46 if (!r) continue; *r++ = 0;
47 uint8_t minute = atoi(data);
49 r = strchr((data = r), ':');
50 if (!r) continue; *r++ = 0;
51 uint8_t second = atoi(data);
52 clock.fillByHMS(hour, minute, second);
55 uint8_t dayOfWeek = atoi(data);
56 clock.fillDayOfWeek(dayOfWeek);
66 SeeedGrayOled.clearDisplay();
67 SeeedGrayOled.setNormalDisplay(); // Set display to normal mode (i.e non-inverse mode)
68 SeeedGrayOled.setVerticalMode();
69 //SeeedGrayOled.setPageMode(); // Set addressing mode to Page Mode
70 SeeedGrayOled.setTextXY(0,0); // Set the cursor to Xth Page, Yth Column
71 SeeedGrayOled.putString("Init..."); // Print the String
76 void setup_buzzer () {
77 pinMode(BUZZER, OUTPUT);
78 digitalWrite(BUZZER, LOW);
88 Serial.write(";time=");
89 Serial.print(clock.year+2000, DEC);
93 Serial.print(clock.month, DEC);
95 if (clock.dayOfMonth < 10)
97 Serial.print(clock.dayOfMonth, DEC);
101 Serial.print(clock.hour, DEC);
103 if (clock.minute < 10)
105 Serial.print(clock.minute, DEC);
107 if (clock.second < 10)
109 Serial.print(clock.second, DEC);
113 SeeedGrayOled.setTextXY(0,0);
114 switch (clock.dayOfWeek) {
116 SeeedGrayOled.putString("lun");
119 SeeedGrayOled.putString("mar");
122 SeeedGrayOled.putString("mer");
125 SeeedGrayOled.putString("jeu");
128 SeeedGrayOled.putString("ven");
131 SeeedGrayOled.putString("sam");
134 SeeedGrayOled.putString("dim");
137 SeeedGrayOled.putString(" ");
138 if (clock.dayOfMonth < 10)
139 SeeedGrayOled.putString("0");
140 SeeedGrayOled.putNumber(clock.dayOfMonth);
141 SeeedGrayOled.putString(" ");
142 switch (clock.month) {
144 SeeedGrayOled.putString("jan.");
147 SeeedGrayOled.putString("fév.");
150 SeeedGrayOled.putString("mars");
153 SeeedGrayOled.putString("avr.");
156 SeeedGrayOled.putString("mai ");
159 SeeedGrayOled.putString("juin");
162 SeeedGrayOled.putString("jui.");
166 SeeedGrayOled.setTextXY(1,0);
168 SeeedGrayOled.putString("0");
169 SeeedGrayOled.putNumber(clock.hour);
170 SeeedGrayOled.putString(":");
171 if (clock.minute < 10)
172 SeeedGrayOled.putString("0");
173 SeeedGrayOled.putNumber(clock.minute);
174 SeeedGrayOled.putString(" UTC");
176 SeeedGrayOled.putString(":");
177 if (clock.second < 10)
178 SeeedGrayOled.putString("0");
179 SeeedGrayOled.putNumber(clock.second);
185 //#define DHTTYPE DHT11 // DHT 11
186 #define DHTTYPE DHT22 // DHT 22 (AM2302)
187 DHT dht(DHTPIN, DHTTYPE);
192 // Reading temperature or humidity takes about 250 milliseconds!
193 // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
194 float t = dht.readTemperature();
195 Serial.write(";temp=");
197 SeeedGrayOled.setTextXY(2,0);
198 SeeedGrayOled.putString("T: ERROR ");
202 SeeedGrayOled.setTextXY(2,0);
203 SeeedGrayOled.putString("T: ");
204 SeeedGrayOled.setTextXY(2,3);
205 SeeedGrayOled.putFloat(t);
206 SeeedGrayOled.putString("*C");
210 float h = dht.readHumidity();
211 Serial.write(";humi=");
213 SeeedGrayOled.setTextXY(3,0);
214 SeeedGrayOled.putString("H: ERROR ");
218 SeeedGrayOled.setTextXY(3,0);
219 SeeedGrayOled.putString("H: ");
220 SeeedGrayOled.setTextXY(3,3);
221 SeeedGrayOled.putFloat(h);
222 SeeedGrayOled.putString("%");
228 uint8_t air_pin = A0;
229 int air_quality = -1;
234 air_quality=air.slope();
235 Serial.write(";air=");
236 if (air_quality >= 0) {
237 Serial.print(air.first_vol,DEC);
238 if (air_quality <= 1)
239 // Air quality is bad.
240 // Let's revert display to make some light!
241 SeeedGrayOled.setInverseDisplay();
243 SeeedGrayOled.setNormalDisplay();
245 SeeedGrayOled.setTextXY(4,0);
246 SeeedGrayOled.putString("Air: ");
247 SeeedGrayOled.setTextXY(4,5);
248 SeeedGrayOled.putNumber(air.first_vol);
250 SeeedGrayOled.setTextXY(5,3);
252 SeeedGrayOled.putString("0/4 (x_x)");
253 else if (air_quality==1)
254 SeeedGrayOled.putString("1/4 (>_<)");
255 else if (air_quality==2)
256 SeeedGrayOled.putString("2/4 (=_=)");
257 else if (air_quality==3)
258 SeeedGrayOled.putString("3/4 (*_*)");
260 SeeedGrayOled.putString("4/4 (^_^)");
263 digitalWrite(BUZZER, HIGH);
265 digitalWrite(BUZZER, LOW);
268 ISR(TIMER2_OVF_vect) {
269 if(air.counter==122) {
270 // NOTE: set 2 seconds as a detected duty
271 air.last_vol = air.first_vol;
272 air.first_vol = analogRead(air_pin);
284 unsigned long dust_duration;
285 unsigned long dust_last_time;
286 unsigned long dust_delay = 30000;
287 unsigned long dust_lowpulseoccupancy = 0;
288 float dust_concentration = 0;
289 float dust_ratio = 0;
291 pinMode(dust_pin,INPUT);
292 dust_last_time = now;
295 dust_duration = pulseIn(dust_pin, LOW);
296 dust_lowpulseoccupancy = dust_lowpulseoccupancy + dust_duration;
297 Serial.write(";dust=");
298 if ((now - dust_last_time) >= dust_delay) {
299 dust_last_time = now;
300 dust_ratio = dust_lowpulseoccupancy / (dust_delay * 10.0); // Integer percentage 0=>100
301 dust_concentration = 1.1*pow(dust_ratio,3)
302 - 3.8*pow(dust_ratio,2)
304 + 0.62; // Using spec sheet curve
306 Serial.print(dust_lowpulseoccupancy);
308 Serial.print(dust_ratio);
310 Serial.print(dust_concentration);
311 SeeedGrayOled.setTextXY(6,0);
312 SeeedGrayOled.putString("Dust: ");
313 SeeedGrayOled.setTextXY(6,7);
314 SeeedGrayOled.putNumber(dust_concentration);
315 dust_lowpulseoccupancy = 0;
319 /* Fire (MQ9: CO CH4 LPG) */
320 unsigned long mq9_last_time;
321 unsigned long mq9_delay = 1000;
323 uint8_t mq9_pin = A2;
328 Serial.write(";fire=");
329 if ((now - mq9_last_time) >= mq9_delay) {
331 int mq9_read = analogRead(mq9_pin);
332 float mq9_volt = (float)mq9_read / 1024 * 5.0;
333 float mq9_RS = (5.0 - mq9_volt) / mq9_volt; // omit *RL
334 /* Replace the name "R0" with the value of R0 in the demo of First Test */
335 //float mq9_ratio = mq9_RS / mq9_R0; // mq9_ratio = RS/R0
336 float mq9_R0_ = mq9_RS / 9.9; // The ratio of RS/R0 is 9.9 in LPG gas from Graph (Found using WebPlotDigitizer)
338 Serial.print(mq9_R0_);
339 SeeedGrayOled.setTextXY(7,0);
340 SeeedGrayOled.putString("Feu: ");
341 SeeedGrayOled.setTextXY(7,5);
342 //SeeedGrayOled.putFloat(mq9_ratio);
343 //Serial.print(mq9_ratio);
344 SeeedGrayOled.putFloat(mq9_R0_);
353 // ; // wait for serial port to connect. Needed for native USB port only
355 Wire.begin(); // Initialize I2C
362 Serial.println("loop;up;time;temp;humi;air;dust;fire");
364 unsigned long counter;
366 counter = counter + 1;
370 Serial.write("loop="); Serial.print(counter);
371 Serial.write(";up="); Serial.print(now);