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);
65 //SeeedGrayOled.init(SH1107G);
66 SeeedGrayOled.init(SSD1327);
67 SeeedGrayOled.clearDisplay();
68 SeeedGrayOled.setNormalDisplay(); // Set display to normal mode (i.e non-inverse mode)
69 SeeedGrayOled.setVerticalMode();
70 //SeeedGrayOled.setPageMode(); // Set addressing mode to Page Mode
71 SeeedGrayOled.setTextXY(0,0); // Set the cursor to Xth Page, Yth Column
72 SeeedGrayOled.putString("Init..."); // Print the String
77 void setup_buzzer () {
78 pinMode(BUZZER, OUTPUT);
79 digitalWrite(BUZZER, LOW);
89 Serial.write(";time=");
90 Serial.print(clock.year+2000, DEC);
94 Serial.print(clock.month, DEC);
96 if (clock.dayOfMonth < 10)
98 Serial.print(clock.dayOfMonth, DEC);
102 Serial.print(clock.hour, DEC);
104 if (clock.minute < 10)
106 Serial.print(clock.minute, DEC);
108 if (clock.second < 10)
110 Serial.print(clock.second, DEC);
114 SeeedGrayOled.setTextXY(0,0);
115 switch (clock.dayOfWeek) {
117 SeeedGrayOled.putString("lun");
120 SeeedGrayOled.putString("mar");
123 SeeedGrayOled.putString("mer");
126 SeeedGrayOled.putString("jeu");
129 SeeedGrayOled.putString("ven");
132 SeeedGrayOled.putString("sam");
135 SeeedGrayOled.putString("dim");
138 SeeedGrayOled.putString(" ");
139 if (clock.dayOfMonth < 10)
140 SeeedGrayOled.putString("0");
141 SeeedGrayOled.putNumber(clock.dayOfMonth);
142 SeeedGrayOled.putString(" ");
143 switch (clock.month) {
145 SeeedGrayOled.putString("jan.");
148 SeeedGrayOled.putString("fév.");
151 SeeedGrayOled.putString("mars");
154 SeeedGrayOled.putString("avr.");
157 SeeedGrayOled.putString("mai ");
160 SeeedGrayOled.putString("juin");
163 SeeedGrayOled.putString("jui.");
167 SeeedGrayOled.setTextXY(1,0);
169 SeeedGrayOled.putString("0");
170 SeeedGrayOled.putNumber(clock.hour);
171 SeeedGrayOled.putString(":");
172 if (clock.minute < 10)
173 SeeedGrayOled.putString("0");
174 SeeedGrayOled.putNumber(clock.minute);
175 SeeedGrayOled.putString(" UTC");
177 SeeedGrayOled.putString(":");
178 if (clock.second < 10)
179 SeeedGrayOled.putString("0");
180 SeeedGrayOled.putNumber(clock.second);
186 //#define DHTTYPE DHT11 // DHT 11
187 #define DHTTYPE DHT22 // DHT 22 (AM2302)
188 DHT dht(DHTPIN, DHTTYPE);
193 // Reading temperature or humidity takes about 250 milliseconds!
194 // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
195 float t = dht.readTemperature();
196 Serial.write(";temp=");
198 SeeedGrayOled.setTextXY(2,0);
199 SeeedGrayOled.putString("T: ERROR ");
203 SeeedGrayOled.setTextXY(2,0);
204 SeeedGrayOled.putString("T: ");
205 SeeedGrayOled.setTextXY(2,3);
206 SeeedGrayOled.putNumber(t);
207 SeeedGrayOled.putString("*C");
211 float h = dht.readHumidity();
212 Serial.write(";humi=");
214 SeeedGrayOled.setTextXY(3,0);
215 SeeedGrayOled.putString("H: ERROR ");
219 SeeedGrayOled.setTextXY(3,0);
220 SeeedGrayOled.putString("H: ");
221 SeeedGrayOled.setTextXY(3,3);
222 SeeedGrayOled.putNumber(h);
223 SeeedGrayOled.putString("%");
229 uint8_t air_pin = A0;
230 int air_quality = -1;
235 air_quality=air.slope();
236 Serial.write(";air=");
237 if (air_quality >= 0) {
238 Serial.print(air.first_vol,DEC);
239 if (air_quality <= 1)
240 // Air quality is bad.
241 // Let's revert display to make some light!
242 SeeedGrayOled.setInverseDisplay();
244 SeeedGrayOled.setNormalDisplay();
246 SeeedGrayOled.setTextXY(4,0);
247 SeeedGrayOled.putString("Air: ");
248 SeeedGrayOled.setTextXY(4,5);
249 SeeedGrayOled.putNumber(air.first_vol);
251 SeeedGrayOled.setTextXY(5,3);
253 SeeedGrayOled.putString("0/4 (x_x)");
254 else if (air_quality==1)
255 SeeedGrayOled.putString("1/4 (>_<)");
256 else if (air_quality==2)
257 SeeedGrayOled.putString("2/4 (=_=)");
258 else if (air_quality==3)
259 SeeedGrayOled.putString("3/4 (*_*)");
261 SeeedGrayOled.putString("4/4 (^_^)");
264 digitalWrite(BUZZER, HIGH);
266 digitalWrite(BUZZER, LOW);
269 ISR(TIMER2_OVF_vect) {
270 if(air.counter==122) {
271 // NOTE: set 2 seconds as a detected duty
272 air.last_vol = air.first_vol;
273 air.first_vol = analogRead(air_pin);
285 unsigned long dust_duration;
286 unsigned long dust_last_time;
287 unsigned long dust_delay = 30000;
288 unsigned long dust_lowpulseoccupancy = 0;
289 float dust_concentration = 0;
290 float dust_ratio = 0;
292 pinMode(dust_pin,INPUT);
293 dust_last_time = now;
296 dust_duration = pulseIn(dust_pin, LOW);
297 dust_lowpulseoccupancy = dust_lowpulseoccupancy + dust_duration;
298 Serial.write(";dust=");
299 if ((now - dust_last_time) >= dust_delay) {
300 dust_last_time = now;
301 dust_ratio = dust_lowpulseoccupancy / (dust_delay * 10.0); // Integer percentage 0=>100
302 dust_concentration = 1.1*pow(dust_ratio,3)
303 - 3.8*pow(dust_ratio,2)
305 + 0.62; // Using spec sheet curve
307 Serial.print(dust_lowpulseoccupancy);
309 Serial.print(dust_ratio);
311 Serial.print(dust_concentration);
312 SeeedGrayOled.setTextXY(6,0);
313 SeeedGrayOled.putString("Dust: ");
314 SeeedGrayOled.setTextXY(6,7);
315 SeeedGrayOled.putNumber(dust_concentration);
316 dust_lowpulseoccupancy = 0;
320 /* Fire (MQ9: CO CH4 LPG) */
321 unsigned long mq9_last_time;
322 unsigned long mq9_delay = 1000;
324 uint8_t mq9_pin = A2;
329 Serial.write(";fire=");
330 if ((now - mq9_last_time) >= mq9_delay) {
332 int mq9_read = analogRead(mq9_pin);
333 float mq9_volt = (float)mq9_read / 1024 * 5.0;
334 float mq9_RS = (5.0 - mq9_volt) / mq9_volt; // omit *RL
335 /* Replace the name "R0" with the value of R0 in the demo of First Test */
336 //float mq9_ratio = mq9_RS / mq9_R0; // mq9_ratio = RS/R0
337 float mq9_R0_ = mq9_RS / 9.9; // The ratio of RS/R0 is 9.9 in LPG gas from Graph (Found using WebPlotDigitizer)
339 Serial.print(mq9_R0_);
340 SeeedGrayOled.setTextXY(7,0);
341 SeeedGrayOled.putString("Feu: ");
342 SeeedGrayOled.setTextXY(7,5);
343 //SeeedGrayOled.putNumber(mq9_ratio);
344 //Serial.print(mq9_ratio);
345 SeeedGrayOled.putNumber(mq9_R0_);
354 // ; // wait for serial port to connect. Needed for native USB port only
356 Wire.begin(); // Initialize I2C
363 Serial.println("loop;up;time;temp;humi;air;dust;fire");
365 unsigned long counter;
367 counter = counter + 1;
371 Serial.write("loop="); Serial.print(counter);
372 Serial.write(";up="); Serial.print(now);