-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathairrohr-firmware.ino
721 lines (622 loc) · 26 KB
/
airrohr-firmware.ino
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
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
#include <Arduino.h>
/*****************************************************************
/* *
/* This source code needs to be compiled for the board *
/* NodeMCU 1.0 (ESP-12E Module) *
/* *
/*****************************************************************
/* OK LAB Particulate Matter Sensor *
/* - nodemcu-LoLin board *
/* - Nova SDS0111 *
/* http://inovafitness.com/en/Laser-PM2-5-Sensor-SDS011-35.html *
/* *
/* Wiring Instruction: *
/* - SDS011 Pin 1 (TX) -> Pin D1 / GPIO5 *
/* - SDS011 Pin 2 (RX) -> Pin D2 / GPIO4 *
/* - SDS011 Pin 3 (GND) -> GND *
/* - SDS011 Pin 4 (2.5m) -> unused *
/* - SDS011 Pin 5 (5V) -> VU *
/* - SDS011 Pin 6 (1m) -> unused *
/* *
/*****************************************************************
/* Extension: DHT22 (AM2303) *
/* http://www.aosong.com/en/products/details.asp?id=117 *
/* *
/* DHT22 Wiring Instruction *
/* (left to right, front is perforated side): *
/* - DHT22 Pin 1 (VDD) -> Pin 3V3 (3.3V) *
/* - DHT22 Pin 2 (DATA) -> Pin D7 (GPIO13) *
/* - DHT22 Pin 3 (NULL) -> unused *
/* - DHT22 Pin 4 (GND) -> Pin GND *
/* *
/*****************************************************************/
/*****************************************************************
/* Includes *
/*****************************************************************/
#include <ESP8266WiFi.h>
#include <SoftwareSerial.h>
#include <base64.h>
#include <ArduinoJson.h>
#include <DHT.h>
#include <PubSubClient.h>
#include "constants.h"
long int sample_count = 0;
WiFiClient espClient;
PubSubClient mqttClient(espClient);
/*****************************************************************
/* SDS011 declarations *
/*****************************************************************/
SoftwareSerial serialSDS(SDS_PIN_RX, SDS_PIN_TX, false, 128);
/*****************************************************************
/* DHT declaration *
/*****************************************************************/
DHT dht(DHT_PIN, DHT_TYPE);
bool send_now = false;
unsigned long start_time_ms;
unsigned long start_SDS_time_ms;
unsigned long act_micro;
unsigned long current_time_ms;
unsigned long last_micro = 0;
unsigned long min_micro = 1000000000; // TODO: use official min value from limits.h
unsigned long max_micro = 0;
unsigned long diff_micro = 0;
bool is_SDS_running = true;
unsigned long sending_time = 0;
bool send_failed = false;
int sds_pm10_sum = 0;
int sds_pm25_sum = 0;
int sds_val_count = 0;
int sds_pm10_max = 0;
int sds_pm10_min = 20000; // TODO: use official min value from limits.h
int sds_pm25_max = 0;
int sds_pm25_min = 20000; // TODO: use official min value from limits.h
String last_value_SDS_P1 = "";
String last_value_SDS_P2 = "";
String last_value_DHT_T = "";
String last_value_DHT_H = "";
String esp_chip_id;
String server_name;
String basic_auth_influx = "";
long last_page_load = millis();
bool first_csv_line = true;
String mqtt_topic = "";
String mqtt_data_DHT = "";
String mqtt_data_SDS = "";
String mqtt_data_WIFI = "";
String data_first_part = "{\"sensordatavalues\":[";
/*****************************************************************
/* Debug output *
/*****************************************************************/
void debug_out(const String& text, const int level, const bool linebreak) {
if (level <= DEBUG_LEVEL) {
if (linebreak) {
Serial.println(text);
} else {
Serial.print(text);
}
}
}
/*****************************************************************
/* IPAddress to String *
/*****************************************************************/
String ip_to_string(const IPAddress& ip) {
char str[24];
sprintf(str, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
return String(str);
}
/*****************************************************************
/* convert float to string with a *
/* precision of two decimal places *
/*****************************************************************/
String float_to_string(const float value) {
char temp[15];
String s;
dtostrf(value, 13, 2, temp);
s = String(temp);
s.trim();
return s;
}
/*****************************************************************
/* convert value to json string *
/*****************************************************************/
String value_to_json(const String& type, const String& value) {
String s = F("{\"value_type\":\"{t}\",\"value\":\"{v}\"},");
s.replace("{t}", type); s.replace("{v}", value);
return s;
}
/*****************************************************************
/* Base64 encode user:password *
/*****************************************************************/
void create_basic_auth_strings() {
basic_auth_influx = "";
if (strcmp(USER_INFLUX, "") != 0 || strcmp(PWD_INFLUX, "") != 0) {
basic_auth_influx = base64::encode(String(USER_INFLUX) + ":" + String(PWD_INFLUX));
}
}
/*****************************************************************
/* start SDS011 sensor *
/*****************************************************************/
void start_SDS() {
debug_out(F("Start SDS"), DEBUG_INFO, 1);
const uint8_t start_SDS_cmd[] = {0xAA, 0xB4, 0x06, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x06, 0xAB};
serialSDS.write(start_SDS_cmd, sizeof(start_SDS_cmd));
is_SDS_running = true;
}
/*****************************************************************
/* stop SDS011 sensor *
/*****************************************************************/
void stop_SDS() {
debug_out(F("Stop SDS"), DEBUG_INFO, 1);
const uint8_t stop_SDS_cmd[] = {0xAA, 0xB4, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x05, 0xAB};
serialSDS.write(stop_SDS_cmd, sizeof(stop_SDS_cmd));
is_SDS_running = false;
}
/*****************************************************************
/* WiFi auto connecting script *
/*****************************************************************/
void connect_WIFI() {
int retry_count = 0;
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PWD); // Start WiFI
debug_out(F("Connecting to "), DEBUG_INFO, 0);
debug_out(WIFI_SSID, DEBUG_INFO, 1);
while ((WiFi.status() != WL_CONNECTED) && (retry_count < WIFI_CONNECT_RETRIES)) {
delay(500);
debug_out(".", DEBUG_INFO, 0);
retry_count++;
}
debug_out("", DEBUG_INFO, 1);
if (WiFi.status() != WL_CONNECTED) {
debug_out(F("Could not connect to WIFI"), DEBUG_ERROR, 1);
return;
}
debug_out(F("WiFi connected\nIP address: "), DEBUG_INFO, 0);
debug_out(ip_to_string(WiFi.localIP()), DEBUG_INFO, 1);
}
/*****************************************************************
/* send data to rest api *
/*****************************************************************/
void send_data(const String& data, const int pin, const char* host, const int httpPort, const char* url, const char* basic_auth_string, const String& contentType) {
debug_out(F("Start connecting to "), DEBUG_INFO, 0);
debug_out(host, DEBUG_INFO, 1);
String request_head = F("POST "); request_head += String(url); request_head += F(" HTTP/1.1\r\n");
request_head += F("Host: "); request_head += String(host) + "\r\n";
request_head += F("Content-Type: "); request_head += contentType + "\r\n";
if (basic_auth_string != "") { request_head += F("Authorization: Basic "); request_head += String(basic_auth_string) + "\r\n";}
request_head += F("X-PIN: "); request_head += String(pin) + "\r\n";
request_head += F("X-Sensor: esp8266-"); request_head += esp_chip_id + "\r\n";
request_head += F("Content-Length: "); request_head += String(data.length(), DEC) + "\r\n";
request_head += F("Connection: close\r\n\r\n");
if (httpPort == 443) {
WiFiClientSecure client_s;
client_s.setNoDelay(true);
client_s.setTimeout(20000);
if (!client_s.connect(host, httpPort)) {
debug_out(F("connection failed"), DEBUG_ERROR, 1);
return;
}
debug_out(F("Requesting URL: "), DEBUG_INFO, 0);
debug_out(url, DEBUG_INFO, 1);
client_s.print(request_head);
client_s.println(data);
delay(10);
// Read reply from server and print them
while(client_s.available()) {
char c = client_s.read();
debug_out(String(c), DEBUG_DEBUG, 0);
}
} else {
WiFiClient client;
client.setNoDelay(true);
client.setTimeout(20000);
if (!client.connect(host, httpPort)) {
debug_out(F("connection failed"), DEBUG_ERROR, 1);
return;
}
debug_out(F("Requesting URL: "), DEBUG_INFO, 0);
debug_out(url, DEBUG_INFO, 1);
client.print(request_head);
client.println(data);
delay(10);
// Read reply from server and print them
while(client.available()) {
char c = client.read();
debug_out(String(c), DEBUG_DEBUG, 0);
}
}
debug_out(F("End connecting to "), DEBUG_INFO, 0);
debug_out(host, DEBUG_INFO, 1);
wdt_reset(); // nodemcu is alive
yield();
}
void send_to_mqtt(const String topic, const String data) {
if (!mqttClient.connected()) {
return;
}
mqttClient.publish(topic.c_str(), data.c_str());
debug_out(data, DEBUG_INFO, 1);
}
/*****************************************************************
/* send single sensor data to luftdaten.info api *
/*****************************************************************/
void send_to_luftdaten(const String& data, const int pin, const char* host, const int httpPort, const char* url, const char* replace_str) {
if (!SEND_TO_LUFTDATEN) {
return;
}
String data_4_luftdaten = "";
data_4_luftdaten = data_first_part + data;
data_4_luftdaten.remove(data_4_luftdaten.length() - 1);
data_4_luftdaten.replace(replace_str, "");
data_4_luftdaten += "]}";
if (data != "") {
send_data(data_4_luftdaten, pin, host, httpPort, url, "", FPSTR(TXT_CONTENT_TYPE_JSON));
} else {
debug_out(F("No data sent..."), DEBUG_INFO, 1);
}
}
/*****************************************************************
/* send data to influxdb *
/*****************************************************************/
String create_influxdb_string(const String& data) {
String tmp_str;
String data_4_influxdb;
debug_out(F("Parse JSON for influx DB"), DEBUG_INFO, 1);
debug_out(data, DEBUG_INFO, 1);
StaticJsonBuffer<2000> jsonBuffer;
JsonObject& json2data = jsonBuffer.parseObject(data);
if (json2data.success()) {
data_4_influxdb = "";
data_4_influxdb += F("feinstaub,node=esp8266-");
data_4_influxdb += esp_chip_id + " ";
for (int i = 0; i < json2data["sensordatavalues"].size() - 1; i++) {
tmp_str = jsonBuffer.strdup(json2data["sensordatavalues"][i]["value_type"].as<char*>());
data_4_influxdb += tmp_str + "=";
tmp_str = jsonBuffer.strdup(json2data["sensordatavalues"][i]["value"].as<char*>());
data_4_influxdb += tmp_str;
if (i < (json2data["sensordatavalues"].size() - 2)) { data_4_influxdb += ","; }
}
data_4_influxdb += "\n";
} else {
debug_out(F("Data read failed"), DEBUG_ERROR, 1);
}
return data_4_influxdb;
}
/*****************************************************************
/* send data as csv to serial out *
/*****************************************************************/
void send_csv(const String& data) {
char* s;
String tmp_str;
String headline;
String valueline;
int value_count = 0;
StaticJsonBuffer<1000> jsonBuffer;
JsonObject& json2data = jsonBuffer.parseObject(data);
debug_out(F("CSV Output"), DEBUG_INFO, 1);
debug_out(data, DEBUG_INFO, 1);
if (json2data.success()) {
headline = F("Timestamp_ms;");
valueline = String(current_time_ms) + ";";
for (int i = 0; i < json2data["sensordatavalues"].size(); i++) {
tmp_str = jsonBuffer.strdup(json2data["sensordatavalues"][i]["value_type"].as<char*>());
headline += tmp_str + ";";
tmp_str = jsonBuffer.strdup(json2data["sensordatavalues"][i]["value"].as<char*>());
valueline += tmp_str + ";";
}
if (first_csv_line) {
if (headline.length() > 0) { headline.remove(headline.length() - 1); }
Serial.println(headline);
first_csv_line = false;
}
if (valueline.length() > 0) { valueline.remove(valueline.length() - 1); }
Serial.println(valueline);
} else {
debug_out(F("Data read failed"), DEBUG_ERROR, 1);
}
}
/*****************************************************************
/* read DHT22 sensor values *
/*****************************************************************/
String read_DHT() {
String s = "";
int i = 0;
float h;
float t;
debug_out(F("Start reading DHT11/22"), DEBUG_DEBUG, 1);
// Check if valid number if non NaN (not a number) will be send.
last_value_DHT_T = "";
last_value_DHT_H = "";
while ((i++ < 5) && (s == "")) {
h = dht.readHumidity(); //Read Humidity
t = dht.readTemperature(); //Read Temperature
if (isnan(t) || isnan(h)) {
delay(100);
h = dht.readHumidity(true); //Read Humidity
t = dht.readTemperature(false, true); //Read Temperature
}
if (isnan(t) || isnan(h)) {
debug_out(F("DHT22 couldn't be read"), DEBUG_ERROR, 1);
} else {
debug_out(F("Humidity : "), DEBUG_INFO, 0);
debug_out(String(h) + "%%", DEBUG_INFO, 1);
debug_out(F("Temperature : "), DEBUG_INFO, 0);
debug_out(String(t) + char(223) + "C", DEBUG_INFO, 1);
last_value_DHT_T = float_to_string(t);
last_value_DHT_H = float_to_string(h);
s += value_to_json(F("temperature"), last_value_DHT_T);
s += value_to_json(F("humidity"), last_value_DHT_H);
mqtt_data_DHT = "field1=" + last_value_DHT_T + "&field2=" + last_value_DHT_H;
last_value_DHT_T.remove(last_value_DHT_T.length() - 1);
last_value_DHT_H.remove(last_value_DHT_H.length() - 1);
}
}
debug_out(F("------"), DEBUG_INFO, 1);
debug_out(F("End reading DHT11/22"), DEBUG_DEBUG, 1);
return s;
}
/*****************************************************************
/* read SDS011 sensor values *
/*****************************************************************/
String read_SDS() {
String s = "";
String value_hex;
char buffer;
int value;
int len = 0;
int pm10_serial = 0;
int pm25_serial = 0;
int checksum_is;
int checksum_ok = 0;
int position = 0;
if (long(current_time_ms - start_time_ms) < (long(SEND_INTERVAL_MS) - long(SDS_WARMUP_TIME_MS + SDS_READING_TIME_MS))) {
if (is_SDS_running) {
stop_SDS();
}
} else {
debug_out(F("Start reading SDS"), DEBUG_DEBUG, 1);
if (!is_SDS_running) {
start_SDS();
}
while (serialSDS.available() > 0) {
buffer = serialSDS.read();
debug_out(String(len) + " - " + String(buffer, DEC) + " - " + String(buffer, HEX) + " - " + int(buffer) + " .", DEBUG_DEBUG, 1);
value = int(buffer);
switch (len) {
case (0): if (value != 170) { len = -1; }; break;
case (1): if (value != 192) { len = -1; }; break;
case (2): pm25_serial = value; checksum_is = value; break;
case (3): pm25_serial += (value << 8); checksum_is += value; break;
case (4): pm10_serial = value; checksum_is += value; break;
case (5): pm10_serial += (value << 8); checksum_is += value; break;
case (6): checksum_is += value; break;
case (7): checksum_is += value; break;
case (8):
debug_out(F("Checksum is: "), DEBUG_DEBUG, 0); debug_out(String(checksum_is % 256), DEBUG_DEBUG, 0);
debug_out(F(" - should: "), DEBUG_DEBUG, 0); debug_out(String(value), DEBUG_DEBUG, 1);
if (value == (checksum_is % 256)) { checksum_ok = 1; } else { len = -1; }; break;
case (9): if (value != 171) { len = -1; }; break;
}
len++;
if (len == 10 && checksum_ok == 1 && (long(current_time_ms - start_time_ms) > (long(SEND_INTERVAL_MS) - long(SDS_READING_TIME_MS)))) {
if ((! isnan(pm10_serial)) && (! isnan(pm25_serial))) {
sds_pm10_sum += pm10_serial;
sds_pm25_sum += pm25_serial;
if (sds_pm10_min > pm10_serial) { sds_pm10_min = pm10_serial; }
if (sds_pm10_max < pm10_serial) { sds_pm10_max = pm10_serial; }
if (sds_pm25_min > pm25_serial) { sds_pm25_min = pm25_serial; }
if (sds_pm25_max < pm25_serial) { sds_pm25_max = pm25_serial; }
debug_out(F("PM10 (sec.) : "), DEBUG_DEBUG, 0); debug_out(float_to_string(float(pm10_serial) / 10), DEBUG_DEBUG, 1);
debug_out(F("PM2.5 (sec.): "), DEBUG_DEBUG, 0); debug_out(float_to_string(float(pm25_serial) / 10), DEBUG_DEBUG, 1);
sds_val_count++;
}
len = 0; checksum_ok = 0; pm10_serial = 0.0; pm25_serial = 0.0; checksum_is = 0;
}
yield();
}
}
if (send_now) {
last_value_SDS_P1 = "";
last_value_SDS_P2 = "";
if (sds_val_count > 2) {
sds_pm10_sum = sds_pm10_sum - sds_pm10_min - sds_pm10_max;
sds_pm25_sum = sds_pm25_sum - sds_pm25_min - sds_pm25_max;
sds_val_count = sds_val_count - 2;
}
if (sds_val_count > 0) {
debug_out("PM10: " + float_to_string(float(sds_pm10_sum) / (sds_val_count * 10.0)), DEBUG_INFO, 1);
debug_out("PM2.5: " + float_to_string(float(sds_pm25_sum) / (sds_val_count * 10.0)), DEBUG_INFO, 1);
debug_out("------", DEBUG_INFO, 1);
last_value_SDS_P1 = float_to_string(float(sds_pm10_sum) / (sds_val_count * 10.0));
last_value_SDS_P2 = float_to_string(float(sds_pm25_sum) / (sds_val_count * 10.0));
s += value_to_json("SDS_P1", last_value_SDS_P1);
s += value_to_json("SDS_P2", last_value_SDS_P2);
mqtt_data_SDS = "field3=" + last_value_SDS_P1 + "&field4=" + last_value_SDS_P2;
last_value_SDS_P1.remove(last_value_SDS_P1.length() - 1);
last_value_SDS_P2.remove(last_value_SDS_P2.length() - 1);
}
sds_pm10_sum = 0; sds_pm25_sum = 0; sds_val_count = 0;
sds_pm10_max = 0; sds_pm10_min = 20000; sds_pm25_max = 0; sds_pm25_min = 20000;
if ((SEND_INTERVAL_MS > (SDS_WARMUP_TIME_MS + SDS_READING_TIME_MS))) {
stop_SDS();
}
}
return s;
}
void reconnect_mqtt() {
debug_out(F("Attempting MQTT connection..."), DEBUG_INFO, 0);
// Create a random client ID
String clientId = "ESP8266Client-";
clientId += String(random(0xffff), HEX);
// Attempt to connect
if (mqttClient.connect(clientId.c_str())) {
debug_out("connected", DEBUG_INFO, 1);
} else {
debug_out("failed, rc=", DEBUG_INFO, 0);
debug_out(String(mqttClient.state()), DEBUG_INFO, 1);
}
}
/*****************************************************************
/* The Setup *
/*****************************************************************/
void setup() {
Serial.begin(9600);
randomSeed(micros());
esp_chip_id = String(ESP.getChipId());
WiFi.persistent(false);
connect_WIFI();
serialSDS.begin(9600);
dht.begin(); // Start DHT
delay(10);
debug_out(F("Chip id: "), DEBUG_INFO, 0);
debug_out(esp_chip_id, DEBUG_INFO, 1);
create_basic_auth_strings();
debug_out(F("Configuration:"), DEBUG_INFO, 1);
if (SDS_ENABLED) { debug_out(F(" * Read SDS"), DEBUG_INFO, 1); }
if (DHT_ENABLED) { debug_out(F(" * Read DHT"), DEBUG_INFO, 1); }
if (SEND_TO_LUFTDATEN) { debug_out(F(" * Send to luftdaten.info"), DEBUG_INFO, 1); }
if (SEND_TO_MADAVI) { debug_out(F(" * Send to madavi.de"), DEBUG_INFO, 1); }
if (SEND_TO_OPENSENSEMAP) { debug_out(F(" * Send to opensensemap.org"), DEBUG_INFO, 1); }
if (SEND_TO_CSV) { debug_out(F(" * Send to CSV to serial"), DEBUG_INFO, 1); }
if (SEND_TO_INFLUX) { debug_out(F(" * Send to custom influx DB"), DEBUG_INFO, 1); }
if (SEND_TO_MQTT) {
debug_out(F(" * Send to custom MQTT DB"), DEBUG_INFO, 1);
debug_out(F(" - Broker: "), DEBUG_INFO, 0); debug_out(MQTT_BROKER, DEBUG_INFO, 1);
mqtt_topic = String(MQTT_TOPIC);
debug_out(F(" - Topic: "), DEBUG_INFO, 0); debug_out(mqtt_topic, DEBUG_INFO, 1);
mqttClient.setServer(MQTT_BROKER, MQTT_PORT);
}
// Stop SDS as it is running by default after startup
stop_SDS();
wdt_disable();
wdt_enable(WATHDOG_TIMER_MS);
start_time_ms = millis();
start_SDS_time_ms = millis();
// Initialize LED as an output
pinMode(LED_GPIO, OUTPUT);
// Turn LED off
digitalWrite(LED_GPIO, HIGH);
}
/*****************************************************************
/* And action *
/*****************************************************************/
void loop() {
String data = "";
String data_4_influxdb = "";
String data_sample_times = "";
String result_SDS = "";
String result_DHT = "";
String signal_strength = "";
unsigned long sum_send_time_ms = 0;
unsigned long start_send_time_ms;
send_failed = false;
if (SEND_TO_MQTT) {
if (WiFi.status() == WL_CONNECTED) {
if (!mqttClient.connected()) {
reconnect_mqtt();
}
mqttClient.loop();
}
}
act_micro = micros();
current_time_ms = millis();
send_now = (current_time_ms - start_time_ms) > SEND_INTERVAL_MS;
sample_count++;
wdt_reset(); // nodemcu is alive
if (last_micro != 0) {
diff_micro = act_micro - last_micro;
if (max_micro < diff_micro) { max_micro = diff_micro;}
if (min_micro > diff_micro) { min_micro = diff_micro;}
last_micro = act_micro;
} else {
last_micro = act_micro;
}
if (((current_time_ms - start_SDS_time_ms) > SDS_SAMPLE_TIME_MS) || ((current_time_ms - start_time_ms) > SEND_INTERVAL_MS)) {
if (SDS_ENABLED) {
result_SDS = read_SDS();
start_SDS_time_ms = current_time_ms;
}
}
if (send_now) {
digitalWrite(LED_GPIO, LOW);
if (DHT_ENABLED) {
debug_out(F("Call read_DHT"), DEBUG_DEBUG, 1);
result_DHT = read_DHT();
}
data = data_first_part;
data_sample_times = value_to_json("samples", String(long(sample_count)));
data_sample_times += value_to_json("min_micro", String(long(min_micro)));
data_sample_times += value_to_json("max_micro", String(long(max_micro)));
signal_strength = String(WiFi.RSSI());
if (SDS_ENABLED) {
data += result_SDS;
if (SEND_TO_LUFTDATEN) {
debug_out(F("## Sending to luftdaten.info (SDS): "), DEBUG_INFO, 1);
start_send_time_ms = millis();
send_to_luftdaten(result_SDS, SDS_API_PIN, HOST_LUFTDATEN, PORT_LUFTDATEN, URL_LUFTDATEN, "SDS_");
sum_send_time_ms += millis() - start_send_time_ms;
}
}
if (DHT_ENABLED) {
data += result_DHT;
if (SEND_TO_LUFTDATEN) {
debug_out(F("## Sending to luftdaten.info (DHT): "), DEBUG_INFO, 1);
start_send_time_ms = millis();
send_to_luftdaten(result_DHT, DHT_API_PIN, HOST_LUFTDATEN, PORT_LUFTDATEN, URL_LUFTDATEN, "DHT_");
sum_send_time_ms += millis() - start_send_time_ms;
}
}
data_sample_times += value_to_json("signal", signal_strength);
mqtt_data_WIFI = "field5=" + signal_strength;
if (SEND_TO_MQTT) {
debug_out(F("## Publish data to MQTT broker"), DEBUG_INFO, 1);
String mqtt_data = "";
mqtt_data = mqtt_data_DHT + "&" + mqtt_data_SDS + "&" + mqtt_data_WIFI;
start_send_time_ms = millis();
send_to_mqtt(mqtt_topic, mqtt_data);
sum_send_time_ms += millis() - start_send_time_ms;
}
data += data_sample_times;
if (data.lastIndexOf(',') == (data.length() - 1)) {
data.remove(data.length() - 1);
}
data += "]}";
debug_out(data, DEBUG_INFO, 1);
// sending to api(s)
if (SEND_TO_MADAVI) {
debug_out(F("## Sending to madavi.de: "), DEBUG_INFO, 1);
start_send_time_ms = millis();
send_data(data, 0, HOST_MADAVI, PORT_MADAVI, URL_MADAVI, "", FPSTR(TXT_CONTENT_TYPE_JSON));
sum_send_time_ms += millis() - start_send_time_ms;
}
if (SEND_TO_OPENSENSEMAP) {
debug_out(F("## Sending to opensensemap: "), DEBUG_INFO, 1);
start_send_time_ms = millis();
send_data(data, 0, HOST_OPENSENSEMAP, PORT_OPENSENSEMAP, URL_OPENSENSEMAP, "", FPSTR(TXT_CONTENT_TYPE_JSON));
sum_send_time_ms += millis() - start_send_time_ms;
}
if (SEND_TO_INFLUX) {
debug_out(F("## Sending to custom influx db: "), DEBUG_INFO, 1);
data_4_influxdb = create_influxdb_string(data);
start_send_time_ms = millis();
send_data(data_4_influxdb, 0, HOST_INFLUX, PORT_INFLUX, URL_INFLUX, basic_auth_influx.c_str(), FPSTR(TXT_CONTENT_TYPE_INFLUXDB));
sum_send_time_ms += millis() - start_send_time_ms;
}
if (SEND_TO_CSV) {
debug_out(F("## Sending as csv: "), DEBUG_INFO, 1);
send_csv(data);
}
debug_out(F("Time (ms) for sending data: "), DEBUG_INFO, 0);
debug_out(String(sum_send_time_ms), DEBUG_INFO, 1);
if (WiFi.status() != WL_CONNECTED) { // reconnect if connection lost
connect_WIFI();
}
// Reset variables for next sampling
sample_count = 0;
last_micro = 0;
min_micro = 1000000000;
max_micro = 0;
start_time_ms = millis(); // store the start time
digitalWrite(LED_GPIO, HIGH);
}
yield();
}