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