]> Git — Sourcephile - julm/air-duino.git/blob - send.ino
add comment
[julm/air-duino.git] / send.ino
1 // Licence: WTFPLv2 <http://www.wtfpl.net/txt/copying/>
2 // Copyright 2015-2016: Julien Moutinho <julm+air@autogeree.net>
3
4 #include <Wire.h>
5 #include "SeeedGrayOLED.h"
6 #include "AirQuality.h"
7 #include "Arduino.h"
8 #include "DHT.h"
9 #include "DS1307.h"
10
11 unsigned long now;
12
13 /* Serial input */
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;
20 char *r = input;
21 char *data;
22
23 r = strchr((data = r), '=');
24 if (!r) continue; *r++ = 0;
25 if (!strcmp(data, "utc")) {
26 DS1307 clock;
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);
31
32 r = strchr((data = r), ':');
33 if (!r) continue; *r++ = 0;
34 uint8_t month = atoi(data);
35
36 r = strchr((data = r), ':');
37 if (!r) continue; *r++ = 0;
38 uint8_t dayOfMonth = atoi(data);
39 clock.fillByYMD(year, month, dayOfMonth);
40
41 r = strchr((data = r), ':');
42 if (!r) continue; *r++ = 0;
43 uint8_t hour = atoi(data);
44
45 r = strchr((data = r), ':');
46 if (!r) continue; *r++ = 0;
47 uint8_t minute = atoi(data);
48
49 r = strchr((data = r), ':');
50 if (!r) continue; *r++ = 0;
51 uint8_t second = atoi(data);
52 clock.fillByHMS(hour, minute, second);
53
54 data = r;
55 uint8_t dayOfWeek = atoi(data);
56 clock.fillDayOfWeek(dayOfWeek);
57
58 clock.setTime();
59 }
60 }
61 }
62
63 /* Oled */
64 void setup_oled () {
65 SeeedGrayOled.init();
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
72 }
73
74 /* Buzzer */
75 #define BUZZER 10
76 void setup_buzzer () {
77 pinMode(BUZZER, OUTPUT);
78 digitalWrite(BUZZER, LOW);
79 }
80
81 /* RTC */
82 DS1307 clock;
83 void setup_rtc () {
84 clock.begin();
85 }
86 void loop_rtc () {
87 clock.getTime();
88 Serial.write(";time=");
89 Serial.print(clock.year+2000, DEC);
90 Serial.print("-");
91 if (clock.month < 10)
92 Serial.print("0");
93 Serial.print(clock.month, DEC);
94 Serial.print("-");
95 if (clock.dayOfMonth < 10)
96 Serial.print("0");
97 Serial.print(clock.dayOfMonth, DEC);
98 Serial.print("T");
99 if (clock.hour < 10)
100 Serial.print("0");
101 Serial.print(clock.hour, DEC);
102 Serial.print(":");
103 if (clock.minute < 10)
104 Serial.print("0");
105 Serial.print(clock.minute, DEC);
106 Serial.print(":");
107 if (clock.second < 10)
108 Serial.print("0");
109 Serial.print(clock.second, DEC);
110 Serial.print("Z");
111
112 /* Oled */
113 SeeedGrayOled.setTextXY(0,0);
114 switch (clock.dayOfWeek) {
115 case MON:
116 SeeedGrayOled.putString("lun");
117 break;
118 case TUE:
119 SeeedGrayOled.putString("mar");
120 break;
121 case WED:
122 SeeedGrayOled.putString("mer");
123 break;
124 case THU:
125 SeeedGrayOled.putString("jeu");
126 break;
127 case FRI:
128 SeeedGrayOled.putString("ven");
129 break;
130 case SAT:
131 SeeedGrayOled.putString("sam");
132 break;
133 case SUN:
134 SeeedGrayOled.putString("dim");
135 break;
136 }
137 SeeedGrayOled.putString(" ");
138 if (clock.dayOfMonth < 10)
139 SeeedGrayOled.putString("0");
140 SeeedGrayOled.putNumber(clock.dayOfMonth);
141 SeeedGrayOled.putString(" ");
142 switch (clock.month) {
143 case 1:
144 SeeedGrayOled.putString("jan.");
145 break;
146 case 2:
147 SeeedGrayOled.putString("fév.");
148 break;
149 case 3:
150 SeeedGrayOled.putString("mars");
151 break;
152 case 4:
153 SeeedGrayOled.putString("avr.");
154 break;
155 case 5:
156 SeeedGrayOled.putString("mai ");
157 break;
158 case 6:
159 SeeedGrayOled.putString("juin");
160 break;
161 case 7:
162 SeeedGrayOled.putString("jui.");
163 break;
164 }
165
166 SeeedGrayOled.setTextXY(1,0);
167 if (clock.hour < 10)
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");
175 /*
176 SeeedGrayOled.putString(":");
177 if (clock.second < 10)
178 SeeedGrayOled.putString("0");
179 SeeedGrayOled.putNumber(clock.second);
180 */
181 }
182
183 /* DHT */
184 #define DHTPIN 2
185 //#define DHTTYPE DHT11 // DHT 11
186 #define DHTTYPE DHT22 // DHT 22 (AM2302)
187 DHT dht(DHTPIN, DHTTYPE);
188 void setup_dht () {
189 dht.begin();
190 }
191 void loop_dht () {
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=");
196 if (isnan(t)) {
197 SeeedGrayOled.setTextXY(2,0);
198 SeeedGrayOled.putString("T: ERROR ");
199 }
200 else {
201 Serial.print(t);
202 SeeedGrayOled.setTextXY(2,0);
203 SeeedGrayOled.putString("T: ");
204 SeeedGrayOled.setTextXY(2,3);
205 SeeedGrayOled.putFloat(t);
206 SeeedGrayOled.putString("*C");
207
208 }
209
210 float h = dht.readHumidity();
211 Serial.write(";humi=");
212 if (isnan(h)) {
213 SeeedGrayOled.setTextXY(3,0);
214 SeeedGrayOled.putString("H: ERROR ");
215 }
216 else {
217 Serial.print(h);
218 SeeedGrayOled.setTextXY(3,0);
219 SeeedGrayOled.putString("H: ");
220 SeeedGrayOled.setTextXY(3,3);
221 SeeedGrayOled.putFloat(h);
222 SeeedGrayOled.putString("%");
223 }
224 }
225
226 /* Air */
227 AirQuality air;
228 uint8_t air_pin = A0;
229 int air_quality = -1;
230 void setup_air () {
231 air.init(14);
232 }
233 void loop_air () {
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();
242 else
243 SeeedGrayOled.setNormalDisplay();
244
245 SeeedGrayOled.setTextXY(4,0);
246 SeeedGrayOled.putString("Air: ");
247 SeeedGrayOled.setTextXY(4,5);
248 SeeedGrayOled.putNumber(air.first_vol);
249
250 SeeedGrayOled.setTextXY(5,3);
251 if (air_quality==0)
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 (*_*)");
259 else
260 SeeedGrayOled.putString("4/4 (^_^)");
261
262 if (air_quality<1)
263 digitalWrite(BUZZER, HIGH);
264 else
265 digitalWrite(BUZZER, LOW);
266 }
267 }
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);
273 air.counter = 0;
274 air.timer_index = 1;
275 //PORTB=PORTB^0x20;
276 }
277 else {
278 air.counter++;
279 }
280 }
281
282 /* Dust */
283 int dust_pin = 4;
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;
290 void setup_dust () {
291 pinMode(dust_pin,INPUT);
292 dust_last_time = now;
293 }
294 void loop_dust () {
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)
303 + 520*dust_ratio
304 + 0.62; // Using spec sheet curve
305 /*
306 Serial.print(dust_lowpulseoccupancy);
307 Serial.write(';');
308 Serial.print(dust_ratio);
309 */
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;
316 }
317 }
318
319 /* Fire (MQ9: CO CH4 LPG) */
320 unsigned long mq9_last_time;
321 unsigned long mq9_delay = 1000;
322 float mq9_R0 = 0.40;
323 uint8_t mq9_pin = A2;
324 void setup_fire () {
325 mq9_last_time = now;
326 }
327 void loop_fire () {
328 Serial.write(";fire=");
329 if ((now - mq9_last_time) >= mq9_delay) {
330 mq9_last_time = now;
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)
337
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_);
345 }
346 }
347
348 /* Entry points */
349 void setup() {
350 now = millis();
351 Serial.begin(9600);
352 //while (!Serial) {
353 // ; // wait for serial port to connect. Needed for native USB port only
354 // }
355 Wire.begin(); // Initialize I2C
356 setup_oled();
357 setup_rtc();
358 setup_dht();
359 setup_air();
360 setup_dust();
361 setup_fire();
362 Serial.println("loop;up;time;temp;humi;air;dust;fire");
363 }
364 unsigned long counter;
365 void loop() {
366 counter = counter + 1;
367 now = millis();
368
369 loop_serial_read();
370 Serial.write("loop="); Serial.print(counter);
371 Serial.write(";up="); Serial.print(now);
372 loop_rtc();
373 loop_dht();
374 loop_air();
375 loop_dust();
376 loop_fire();
377 Serial.println();
378 }