Browse Source

support CCS811, serial relais.

Thomas Buck 1 year ago
parent
commit
1684220574
8 changed files with 785 additions and 192 deletions
  1. 1
    1
      README.md
  2. 37
    18
      include/config.h
  3. 1
    2
      include/moisture.h
  4. 4
    4
      include/relais.h
  5. 63
    4
      platformio.ini
  6. 521
    99
      src/main.cpp
  7. 26
    27
      src/moisture.cpp
  8. 132
    37
      src/relais.cpp

+ 1
- 1
README.md View File

2
 
2
 
3
 Small firmware supporting different environmental sensors, as well as different microcontroller platforms.
3
 Small firmware supporting different environmental sensors, as well as different microcontroller platforms.
4
 
4
 
5
-Supports SHT21, BME280, analog moisture sensors.
5
+Supports SHT21, BME280, CCS811, analog moisture sensors, serial or gpio relais.
6
 
6
 
7
 Runs on ESP32, ESP8266, Arduino Uno Wifi Developer Edition.
7
 Runs on ESP32, ESP8266, Arduino Uno Wifi Developer Edition.

+ 37
- 18
include/config.h View File

15
 #define __ESP_ENV_CONFIG__
15
 #define __ESP_ENV_CONFIG__
16
 
16
 
17
 // Sketch version
17
 // Sketch version
18
-const char* esp_env_version = "0.4.0";
18
+#define ESP_ENV_VERSION "0.5.0"
19
 
19
 
20
 // location of sensor, used in DB and hostname
20
 // location of sensor, used in DB and hostname
21
-//const char* sensor_location = "livingroom";
22
-//const char* sensor_location = "bedroom";
23
-//const char* sensor_location = "bathroom";
24
-//const char* sensor_location = "kitchen";
25
-//const char* sensor_location = "hallway";
26
-//const char* sensor_location = "tent";
27
-//const char* sensor_location = "storage";
28
-//const char* sensor_location = "greenhouse";
29
-const char* sensor_location = "testing";
30
-
31
-#define SENSOR_HOSTNAME_PREFIX "ESP-"
21
+//#define SENSOR_LOCATION_LIVINGROOM
22
+//#define SENSOR_LOCATION_BEDROOM
23
+//#define SENSOR_LOCATION_BATHROOM
24
+//#define SENSOR_LOCATION_GREENHOUSE
25
+#define SENSOR_LOCATION_TESTING
32
 
26
 
33
 // WiFi AP settings
27
 // WiFi AP settings
34
-const char* ssid = "WIFI_SSID_HERE";
35
-const char* password = "WIFI_PASSWORD_HERE";
28
+#define WIFI_SSID "WIFI_SSID_HERE"
29
+#define WIFI_PASS "WIFI_PASSWORD_HERE"
30
+
31
+// MQTT settings
32
+#define MQTT_HOST "MQTT_IP_HERE"
33
+#define MQTT_PORT 1883
34
+#define MQTT_USER "USERNAME" // undef to disable auth
35
+#define MQTT_PASS "PASSWORD" // undef to disable auth
36
 
36
 
37
 // InfluxDB settings
37
 // InfluxDB settings
38
 #define INFLUXDB_HOST "INFLUX_IP_HERE"
38
 #define INFLUXDB_HOST "INFLUX_IP_HERE"
39
 #define INFLUXDB_PORT 8086
39
 #define INFLUXDB_PORT 8086
40
 #define INFLUXDB_DATABASE "roomsensorsdiy"
40
 #define INFLUXDB_DATABASE "roomsensorsdiy"
41
 
41
 
42
-// feature selection
43
-#define ENABLE_INFLUXDB_LOGGING
44
-
45
 // all given in milliseconds
42
 // all given in milliseconds
46
 #define SERVER_HANDLE_INTERVAL 10
43
 #define SERVER_HANDLE_INTERVAL 10
47
 #define DB_WRITE_INTERVAL (30 * 1000)
44
 #define DB_WRITE_INTERVAL (30 * 1000)
49
 #define LED_INIT_BLINK_INTERVAL 500
46
 #define LED_INIT_BLINK_INTERVAL 500
50
 #define LED_CONNECT_BLINK_INTERVAL 250
47
 #define LED_CONNECT_BLINK_INTERVAL 250
51
 #define LED_ERROR_BLINK_INTERVAL 100
48
 #define LED_ERROR_BLINK_INTERVAL 100
49
+#define MQTT_RECONNECT_INTERVAL (5 * 1000)
52
 
50
 
53
-#endif // __ESP_ENV_CONFIG__
51
+#if defined(SENSOR_LOCATION_LIVINGROOM)
52
+#define SENSOR_LOCATION "livingroom"
53
+#elif defined(SENSOR_LOCATION_BEDROOM)
54
+#define SENSOR_LOCATION "bedroom"
55
+#elif defined(SENSOR_LOCATION_BATHROOM)
56
+#define SENSOR_LOCATION "bathroom"
57
+#elif defined(SENSOR_LOCATION_GREENHOUSE)
58
+#define SENSOR_LOCATION "greenhouse"
59
+#elif defined(SENSOR_LOCATION_TESTING)
60
+#define SENSOR_LOCATION "testing"
61
+#else
62
+#define SENSOR_LOCATION "unknown"
63
+#endif
54
 
64
 
65
+#if defined(RELAIS_SERIAL) || defined(RELAIS_GPIO)
66
+#define FEATURE_RELAIS
67
+#endif
68
+
69
+#if defined(MOISTURE_ADC_ESP32) || defined(MOISTURE_ADC_ARDUINO)
70
+#define FEATURE_MOISTURE
71
+#endif
72
+
73
+#endif // __ESP_ENV_CONFIG__

+ 1
- 2
include/moisture.h View File

14
 #ifndef __ESP_ADC_MOISTURE_SENSOR__
14
 #ifndef __ESP_ADC_MOISTURE_SENSOR__
15
 #define __ESP_ADC_MOISTURE_SENSOR__
15
 #define __ESP_ADC_MOISTURE_SENSOR__
16
 
16
 
17
+void moisture_init(void);
17
 int moisture_count(void);
18
 int moisture_count(void);
18
 int moisture_read(int sensor);
19
 int moisture_read(int sensor);
19
 int moisture_max(void);
20
 int moisture_max(void);
20
-void moisture_init(void);
21
 
21
 
22
 #endif // __ESP_ADC_MOISTURE_SENSOR__
22
 #endif // __ESP_ADC_MOISTURE_SENSOR__
23
-

+ 4
- 4
include/relais.h View File

14
 #ifndef __ESP_RELAIS_ACTOR__
14
 #ifndef __ESP_RELAIS_ACTOR__
15
 #define __ESP_RELAIS_ACTOR__
15
 #define __ESP_RELAIS_ACTOR__
16
 
16
 
17
-int relais_count(void);
18
-int relais_enable(int relais, unsigned long time);
19
 void relais_init(void);
17
 void relais_init(void);
20
-void relais_run(void);
18
+int relais_count(void);
19
+void relais_set(int relais, int state);
20
+int relais_get(int relais);
21
+String relais_name(int relais);
21
 
22
 
22
 #endif // __ESP_RELAIS_ACTOR__
23
 #endif // __ESP_RELAIS_ACTOR__
23
-

+ 63
- 4
platformio.ini View File

8
 ; Please visit documentation for the other options and examples
8
 ; Please visit documentation for the other options and examples
9
 ; https://docs.platformio.org/page/projectconf.html
9
 ; https://docs.platformio.org/page/projectconf.html
10
 
10
 
11
-[env:esp01_1m]
11
+[env:esp8266env]
12
 platform = espressif8266
12
 platform = espressif8266
13
 board = esp01_1m
13
 board = esp01_1m
14
 framework = arduino
14
 framework = arduino
15
+build_flags =
16
+  -DSENSOR_HOSTNAME_PREFIX=\"env-\"
17
+  -DENABLE_CCS811
18
+  -DENABLE_INFLUXDB_LOGGING
19
+  -DENABLE_MQTT
15
 lib_deps =
20
 lib_deps =
16
     Wire
21
     Wire
17
     ESP8266 Influxdb
22
     ESP8266 Influxdb
18
     Adafruit Unified Sensor
23
     Adafruit Unified Sensor
19
     Adafruit BME280 Library
24
     Adafruit BME280 Library
25
+    https://github.com/adafruit/Adafruit_CCS811
26
+    https://github.com/knolleary/pubsubclient.git#2d228f2f862a95846c65a8518c79f48dfc8f188c
20
 
27
 
21
-[env:esp32dev]
22
-platform = espressif32
28
+[env:esp8266relais]
29
+platform = espressif8266
30
+board = esp01_1m
31
+framework = arduino
32
+build_flags =
33
+  -DSENSOR_HOSTNAME_PREFIX=\"relais-\"
34
+  -DRELAIS_SERIAL
35
+  -DENABLE_INFLUXDB_LOGGING
36
+  -DENABLE_MQTT
37
+lib_deps =
38
+    Wire
39
+    ESP8266 Influxdb
40
+    Adafruit Unified Sensor
41
+    Adafruit BME280 Library
42
+    https://github.com/knolleary/pubsubclient.git#2d228f2f862a95846c65a8518c79f48dfc8f188c
43
+
44
+[env:esp32env]
45
+platform = platformio/espressif32@3.5.0
46
+board = esp32dev
47
+framework = arduino
48
+upload_protocol = esptool
49
+upload_port = /dev/ttyUSB1
50
+monitor_port = /dev/ttyUSB1
51
+monitor_speed = 115200
52
+build_flags =
53
+  -DSENSOR_HOSTNAME_PREFIX=\"env-\"
54
+  -DENABLE_CCS811
55
+  -DENABLE_INFLUXDB_LOGGING
56
+  -DENABLE_MQTT
57
+lib_deps =
58
+    Wire
59
+    Adafruit Unified Sensor
60
+    Adafruit BME280 Library
61
+    https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino.git#66ed5d031caab6953cc79b407a4b49d33b1126dc
62
+    https://github.com/adafruit/Adafruit_CCS811
63
+    https://github.com/knolleary/pubsubclient.git#2d228f2f862a95846c65a8518c79f48dfc8f188c
64
+
65
+[env:esp32moisture]
66
+platform = platformio/espressif32@3.5.0
23
 board = esp32dev
67
 board = esp32dev
24
 framework = arduino
68
 framework = arduino
25
 upload_protocol = esptool
69
 upload_protocol = esptool
70
+upload_port = /dev/ttyUSB1
71
+monitor_port = /dev/ttyUSB1
72
+monitor_speed = 115200
73
+build_flags =
74
+  -DSENSOR_HOSTNAME_PREFIX=\"env-\"
75
+  -DMOISTURE_ADC_ESP32
76
+  -DENABLE_CCS811
77
+  -DENABLE_INFLUXDB_LOGGING
78
+  -DENABLE_MQTT
26
 lib_deps =
79
 lib_deps =
27
     Wire
80
     Wire
28
     Adafruit Unified Sensor
81
     Adafruit Unified Sensor
29
     Adafruit BME280 Library
82
     Adafruit BME280 Library
30
     https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino.git#66ed5d031caab6953cc79b407a4b49d33b1126dc
83
     https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino.git#66ed5d031caab6953cc79b407a4b49d33b1126dc
84
+    https://github.com/adafruit/Adafruit_CCS811
85
+    https://github.com/knolleary/pubsubclient.git#2d228f2f862a95846c65a8518c79f48dfc8f188c
31
 
86
 
32
-[env:arduinowifideved]
87
+[env:arduinomoisture]
33
 platform = atmelavr
88
 platform = atmelavr
34
 board = uno
89
 board = uno
35
 framework = arduino
90
 framework = arduino
36
 upload_port = /dev/ttyACM0
91
 upload_port = /dev/ttyACM0
37
 monitor_port = /dev/ttyACM0
92
 monitor_port = /dev/ttyACM0
38
 monitor_speed = 115200
93
 monitor_speed = 115200
94
+build_flags =
95
+  -DSENSOR_HOSTNAME_PREFIX=\"env-\"
96
+  -DMOISTURE_ADC_ARDUINO
97
+  -DENABLE_INFLUXDB_LOGGING
39
 lib_deps =
98
 lib_deps =
40
     Wire
99
     Wire
41
     Adafruit Unified Sensor
100
     Adafruit Unified Sensor

+ 521
- 99
src/main.cpp View File

15
 #include <Adafruit_BME280.h>
15
 #include <Adafruit_BME280.h>
16
 #include <SHT2x.h>
16
 #include <SHT2x.h>
17
 
17
 
18
+#ifdef ENABLE_CCS811
19
+#include <Adafruit_CCS811.h>
20
+#endif // ENABLE_CCS811
21
+
18
 #if defined(ARDUINO_ARCH_ESP8266)
22
 #if defined(ARDUINO_ARCH_ESP8266)
19
 
23
 
20
 #include <ESP8266WiFi.h>
24
 #include <ESP8266WiFi.h>
35
 
39
 
36
 #include "config.h"
40
 #include "config.h"
37
 #include "moisture.h"
41
 #include "moisture.h"
42
+#include "relais.h"
38
 
43
 
39
 #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
44
 #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
40
 
45
 
46
 UPDATE_WEB_SERVER server(80);
51
 UPDATE_WEB_SERVER server(80);
47
 SimpleUpdater updater;
52
 SimpleUpdater updater;
48
 
53
 
54
+#ifdef ENABLE_MQTT
55
+#include <PubSubClient.h>
56
+WiFiClient mqttClient;
57
+PubSubClient mqtt(mqttClient);
58
+unsigned long last_mqtt_reconnect_time = 0;
59
+#endif // ENABLE_MQTT
60
+
49
 #elif defined(ARDUINO_ARCH_AVR)
61
 #elif defined(ARDUINO_ARCH_AVR)
50
 
62
 
51
 #define ESP_PLATFORM_NAME "Uno WiFi"
63
 #define ESP_PLATFORM_NAME "Uno WiFi"
69
 #define SHT_I2C_ADDRESS HTDU21D_ADDRESS
81
 #define SHT_I2C_ADDRESS HTDU21D_ADDRESS
70
 #define BME_I2C_ADDRESS_1 0x76
82
 #define BME_I2C_ADDRESS_1 0x76
71
 #define BME_I2C_ADDRESS_2 0x77
83
 #define BME_I2C_ADDRESS_2 0x77
84
+#define CCS811_ADDRESS_1 0x5A
85
+#define CCS811_ADDRESS_2 0x5B
72
 
86
 
73
 #if defined(ARDUINO_ARCH_ESP8266)
87
 #if defined(ARDUINO_ARCH_ESP8266)
74
 
88
 
92
 
106
 
93
 #endif
107
 #endif
94
 
108
 
95
-//#define ENABLE_RELAIS_TEST
96
-
97
 Adafruit_BME280 bme1, bme2;
109
 Adafruit_BME280 bme1, bme2;
98
 
110
 
99
 bool found_bme1 = false;
111
 bool found_bme1 = false;
100
 bool found_bme2 = false;
112
 bool found_bme2 = false;
101
 bool found_sht = false;
113
 bool found_sht = false;
102
 
114
 
115
+#ifdef ENABLE_CCS811
116
+Adafruit_CCS811 ccs1, ccs2;
117
+bool found_ccs1 = false;
118
+bool found_ccs2 = false;
119
+bool ccs1_data_valid = false;
120
+bool ccs2_data_valid = false;
121
+int ccs1_error_code = 0;
122
+int ccs2_error_code = 0;
123
+#endif // ENABLE_CCS811
124
+
103
 unsigned long last_server_handle_time = 0;
125
 unsigned long last_server_handle_time = 0;
104
 unsigned long last_db_write_time = 0;
126
 unsigned long last_db_write_time = 0;
105
 unsigned long last_led_blink_time = 0;
127
 unsigned long last_led_blink_time = 0;
106
 
128
 
107
-#ifdef ENABLE_RELAIS_TEST
108
-
109
-#include "relais.h"
110
-
111
-static void relaisTest() {
112
-    for (int i = 0; i < 10; i++) {
113
-        relais_enable(i, 400 + (i * 1000));
114
-        delay(100);
115
-    }
116
-}
117
-
118
-void handleRelaisTest() {
119
-    String message = F("<html><head>");
120
-    message += F("<title>" ESP_PLATFORM_NAME " Environment Sensor</title>");
121
-    message += F("</head><body>");
122
-    message += F("<p>Relais Test started!</p>");
123
-    message += F("<p><a href=\"/\">Return to Home</a></p>");
124
-    message += F("</body></html>");
125
-    
126
-    server.send(200, "text/html", message);
127
-    
128
-    relaisTest();
129
-}
130
-
131
-#endif // ENABLE_RELAIS_TEST
129
+void writeDatabase();
132
 
130
 
133
 static float bme1_temp(void) {
131
 static float bme1_temp(void) {
134
     while (1) {
132
     while (1) {
258
     return 0.0;
256
     return 0.0;
259
 }
257
 }
260
 
258
 
259
+#ifdef ENABLE_CCS811
260
+
261
+static float ccs1_eco2(void) {
262
+    return ccs1.geteCO2();
263
+}
264
+
265
+static float ccs1_tvoc(void) {
266
+    return ccs1.getTVOC();
267
+}
268
+
269
+static float ccs2_eco2(void) {
270
+    return ccs2.geteCO2();
271
+}
272
+
273
+static float ccs2_tvoc(void) {
274
+    return ccs2.getTVOC();
275
+}
276
+
277
+#endif // ENABLE_CCS811
278
+
279
+#if defined(ARDUINO_ARCH_AVR)
280
+#define ARDUINO_SEND_PARTIAL_PAGE() do { \
281
+        size_t len = message.length(), off = 0; \
282
+        while (off < len) { \
283
+            if ((len - off) >= 50) { \
284
+                client.write(message.c_str() + off, 50); \
285
+                off += 50; \
286
+            } else { \
287
+                client.write(message.c_str() + off, len - off); \
288
+                off = len; \
289
+            } \
290
+        } \
291
+        message = ""; \
292
+    } while (false);
293
+#else
294
+#define ARDUINO_SEND_PARTIAL_PAGE() while (false) { }
295
+#endif
296
+
261
 #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
297
 #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
262
-void handleRoot() {
298
+void handlePage(int mode = -1, int id = 0) {
263
 #else
299
 #else
264
-void handleRoot(WiFiClient &client) {
300
+void handlePage(WiFiClient &client, int mode = -1, int id = 0) {
265
 #endif
301
 #endif
266
     String message;
302
     String message;
267
 
303
 
271
     message += F("<h1>" ESP_PLATFORM_NAME " Environment Sensor</h1>");
307
     message += F("<h1>" ESP_PLATFORM_NAME " Environment Sensor</h1>");
272
     message += F("\n<p>\n");
308
     message += F("\n<p>\n");
273
     message += F("Version: ");
309
     message += F("Version: ");
274
-    message += esp_env_version;
310
+    message += ESP_ENV_VERSION;
275
     message += F("\n<br>\n");
311
     message += F("\n<br>\n");
276
     message += F("Location: ");
312
     message += F("Location: ");
277
-    message += sensor_location;
313
+    message += SENSOR_LOCATION;
278
 
314
 
279
 #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
315
 #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
280
     message += F("\n<br>\n");
316
     message += F("\n<br>\n");
284
 
320
 
285
     message += F("\n</p>\n");
321
     message += F("\n</p>\n");
286
 
322
 
287
-#if defined(ARDUINO_ARCH_AVR)
288
-    do {
289
-        size_t len = message.length(), off = 0;
290
-        while (off < len) {
291
-            if ((len - off) >= 50) {
292
-                client.write(message.c_str() + off, 50);
293
-                off += 50;
294
-            } else {
295
-                client.write(message.c_str() + off, len - off);
296
-                off = len;
297
-            }
298
-        }
299
-        message = "";
300
-    } while (false);
301
-#endif
323
+    ARDUINO_SEND_PARTIAL_PAGE();
302
 
324
 
303
 #if defined(ARDUINO_ARCH_ESP8266)
325
 #if defined(ARDUINO_ARCH_ESP8266)
304
     
326
     
376
     }
398
     }
377
     message += F("\n</p>\n");
399
     message += F("\n</p>\n");
378
 
400
 
401
+    ARDUINO_SEND_PARTIAL_PAGE();
402
+
379
     message += F("\n<p>\n");
403
     message += F("\n<p>\n");
380
     if (found_sht) {
404
     if (found_sht) {
381
         message += F("SHT21:");
405
         message += F("SHT21:");
390
     }
414
     }
391
     message += F("\n</p>\n");
415
     message += F("\n</p>\n");
392
 
416
 
393
-#if defined(ARDUINO_ARCH_AVR)
394
-    do {
395
-        size_t len = message.length(), off = 0;
396
-        while (off < len) {
397
-            if ((len - off) >= 50) {
398
-                client.write(message.c_str() + off, 50);
399
-                off += 50;
400
-            } else {
401
-                client.write(message.c_str() + off, len - off);
402
-                off = len;
403
-            }
417
+#ifdef ENABLE_CCS811
418
+
419
+    message += F("\n<p>\n");
420
+    if (found_ccs1) {
421
+        message += F("CCS811 Low:");
422
+        message += F("\n<br>\n");
423
+        message += F("eCO2: ");
424
+        message += String(ccs1_eco2());
425
+        message += F("ppm");
426
+        message += F("\n<br>\n");
427
+        message += F("TVOC: ");
428
+        message += String(ccs1_tvoc());
429
+        message += F("ppb");
430
+
431
+        if (!ccs1_data_valid) {
432
+            message += F("\n<br>\n");
433
+            message += F("Data invalid (");
434
+            message += String(ccs1_error_code);
435
+            message += F(")!");
404
         }
436
         }
405
-        message = "";
406
-    } while (false);
407
-#endif
437
+    } else {
438
+        message += F("CCS811 (Low) not connected!");
439
+    }
440
+    message += F("\n</p>\n");
441
+
442
+    message += F("\n<p>\n");
443
+    if (found_ccs2) {
444
+        message += F("CCS811 High:");
445
+        message += F("\n<br>\n");
446
+        message += F("eCO2: ");
447
+        message += String(ccs2_eco2());
448
+        message += F("ppm");
449
+        message += F("\n<br>\n");
450
+        message += F("TVOC: ");
451
+        message += String(ccs2_tvoc());
452
+        message += F("ppb");
453
+
454
+        if (!ccs2_data_valid) {
455
+            message += F("\n<br>\n");
456
+            message += F("Data invalid (");
457
+            message += String(ccs2_error_code);
458
+            message += F(")!");
459
+        }
460
+    } else {
461
+        message += F("CCS811 (High) not connected!");
462
+    }
463
+    message += F("\n</p>\n");
408
 
464
 
465
+#endif // ENABLE_CCS811
466
+
467
+    ARDUINO_SEND_PARTIAL_PAGE();
468
+
469
+#ifdef FEATURE_MOISTURE
409
     for (int i = 0; i < moisture_count(); i++) {
470
     for (int i = 0; i < moisture_count(); i++) {
410
         int moisture = moisture_read(i);
471
         int moisture = moisture_read(i);
411
         if (moisture < moisture_max()) {
472
         if (moisture < moisture_max()) {
427
         message += F("\n</p>\n");
488
         message += F("\n</p>\n");
428
     }
489
     }
429
 
490
 
491
+    ARDUINO_SEND_PARTIAL_PAGE();
492
+#endif // FEATURE_MOISTURE
493
+
494
+#ifdef FEATURE_RELAIS
495
+    message += F("\n<p>\n");
496
+    for (int i = 0; i < relais_count(); i++) {
497
+        message += String(F("<a href=\"/on?id=")) + String(i) + String(F("\">Relais ")) + String(i) + String(F(" On (")) + relais_name(i) + String(F(")</a><br>\n"));
498
+        message += String(F("<a href=\"/off?id=")) + String(i) + String(F("\">Relais ")) + String(i) + String(F(" Off (")) + relais_name(i) + String(F(")</a><br>\n"));
499
+    }
500
+    message += String(F("<a href=\"/on?id=")) + String(relais_count()) + String(F("\">All Relais On</a><br>\n"));
501
+    message += String(F("<a href=\"/off?id=")) + String(relais_count()) + String(F("\">All Relais Off</a><br>\n"));
502
+    message += F("</p>\n");
503
+
504
+    if (mode >= 0) {
505
+        message += F("<p>");
506
+        message += F("Turned Relais ");
507
+        message += (id < relais_count()) ? String(id) : String(F("1-4"));
508
+        message += (mode ? String(F(" On")) : String(F(" Off")));
509
+        message += F("</p>\n");
510
+    }
511
+
512
+    message += F("\n<p>\n");
513
+    for (int i = 0; i < relais_count(); i++) {
514
+        message += String(F("Relais ")) + String(i) + String(F(" (")) + relais_name(i) + String(F(") = ")) + (relais_get(i) ? String(F("On")) : String(F("Off"))) + String(F("<br>\n"));
515
+    }
516
+    message += F("</p>\n");
517
+
518
+    ARDUINO_SEND_PARTIAL_PAGE();
519
+#endif // FEATURE_RELAIS
520
+
430
 #if ! defined(ARDUINO_ARCH_AVR)
521
 #if ! defined(ARDUINO_ARCH_AVR)
431
     message += F("<p>");
522
     message += F("<p>");
432
     message += F("Try <a href=\"/update\">/update</a> for OTA firmware updates!");
523
     message += F("Try <a href=\"/update\">/update</a> for OTA firmware updates!");
445
     message += F("InfluxDB logging not enabled!");
536
     message += F("InfluxDB logging not enabled!");
446
 #endif
537
 #endif
447
     message += F("</p>");
538
     message += F("</p>");
448
-    
449
-#ifdef ENABLE_RELAIS_TEST
450
-    message += F("<p><a href=\"/relaistest\">Relais Test</a></p>");
451
-#endif // ENABLE_RELAIS_TEST
452
 
539
 
453
     message += F("</body></html>");
540
     message += F("</body></html>");
454
 
541
 
455
 #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
542
 #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
456
     server.send(200, "text/html", message);
543
     server.send(200, "text/html", message);
457
 #else
544
 #else
458
-    do {
459
-        size_t len = message.length(), off = 0;
460
-        while (off < len) {
461
-            if ((len - off) >= 50) {
462
-                client.write(message.c_str() + off, 50);
463
-                off += 50;
464
-            } else {
465
-                client.write(message.c_str() + off, len - off);
466
-                off = len;
467
-            }
545
+    ARDUINO_SEND_PARTIAL_PAGE();
546
+#endif
547
+}
548
+
549
+#ifdef FEATURE_RELAIS
550
+
551
+#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
552
+void handleOn() {
553
+#else
554
+void handleOn(WiFiClient &client) {
555
+#endif
556
+    String id_string = server.arg("id");
557
+    int id = id_string.toInt();
558
+
559
+    if ((id >= 0) && (id < relais_count())) {
560
+        relais_set(id, 1);
561
+    } else {
562
+        for (int i = 0; i < relais_count(); i++) {
563
+            relais_set(i, 1);
468
         }
564
         }
469
-    } while (false);
565
+    }
566
+
567
+#ifdef ENABLE_INFLUXDB_LOGGING
568
+    writeDatabase();
569
+#endif // ENABLE_INFLUXDB_LOGGING
570
+
571
+#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
572
+    handlePage(1, id);
573
+#else
574
+    handlePage(client, 1, id);
470
 #endif
575
 #endif
471
 }
576
 }
472
 
577
 
578
+#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
579
+void handleOff() {
580
+#else
581
+void handleOff(WiFiClient &client) {
582
+#endif
583
+    String id_string = server.arg("id");
584
+    int id = id_string.toInt();
585
+
586
+    if ((id >= 0) && (id < relais_count())) {
587
+        relais_set(id, 0);
588
+    } else {
589
+        for (int i = 0; i < relais_count(); i++) {
590
+            relais_set(i, 0);
591
+        }
592
+    }
593
+
594
+#ifdef ENABLE_INFLUXDB_LOGGING
595
+    writeDatabase();
596
+#endif // ENABLE_INFLUXDB_LOGGING
597
+
598
+#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
599
+    handlePage(0, id);
600
+#else
601
+    handlePage(client, 0, id);
602
+#endif
603
+}
604
+
605
+#endif // FEATURE_RELAIS
606
+
607
+#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
608
+void handleRoot() {
609
+    handlePage();
610
+#else
611
+void handleRoot(WiFiClient &client) {
612
+    handlePage(client);
613
+#endif
614
+}
615
+
616
+#ifdef ENABLE_MQTT
617
+void writeMQTT() {
618
+    if (!mqtt.connected()) {
619
+        return;
620
+    }
621
+
622
+    if (found_bme1) {
623
+        mqtt.publish(SENSOR_LOCATION "/temperature", String(bme1_temp()).c_str());
624
+        mqtt.publish(SENSOR_LOCATION "/humidity", String(bme1_humid()).c_str());
625
+        mqtt.publish(SENSOR_LOCATION "/pressure", String(bme1_pressure()).c_str());
626
+    } else if (found_bme2) {
627
+        mqtt.publish(SENSOR_LOCATION "/temperature", String(bme2_temp()).c_str());
628
+        mqtt.publish(SENSOR_LOCATION "/humidity", String(bme2_humid()).c_str());
629
+        mqtt.publish(SENSOR_LOCATION "/pressure", String(bme2_pressure()).c_str());
630
+    } else if (found_sht) {
631
+        mqtt.publish(SENSOR_LOCATION "/temperature", String(sht_temp()).c_str());
632
+        mqtt.publish(SENSOR_LOCATION "/humidity", String(sht_humid()).c_str());
633
+    }
634
+
635
+#ifdef ENABLE_CCS811
636
+    if (found_ccs1) {
637
+        mqtt.publish(SENSOR_LOCATION "/eco2", String(ccs1_eco2()).c_str());
638
+        mqtt.publish(SENSOR_LOCATION "/tvoc", String(ccs1_tvoc()).c_str());
639
+    } else if (found_ccs2) {
640
+        mqtt.publish(SENSOR_LOCATION "/eco2", String(ccs2_eco2()).c_str());
641
+        mqtt.publish(SENSOR_LOCATION "/tvoc", String(ccs2_tvoc()).c_str());
642
+    }
643
+#endif // ENABLE_CCS811
644
+}
645
+
646
+void mqttCallback(char* topic, byte* payload, unsigned int length) {
647
+#ifdef FEATURE_RELAIS
648
+    int state = 0;
649
+    int id = -1;
650
+
651
+    String ts(topic), ps((char *)payload);
652
+
653
+    String our_topic(SENSOR_LOCATION);
654
+    our_topic += "/";
655
+
656
+    if (!ts.startsWith(our_topic)) {
657
+        Serial.print(F("Unknown MQTT room "));
658
+        Serial.println(ts);
659
+        return;
660
+    }
661
+
662
+    String ids = ts.substring(our_topic.length());
663
+    for (int i = 0; i < relais_count(); i++) {
664
+        if (ids == relais_name(i)) {
665
+            id = i;
666
+            break;
667
+        }
668
+    }
669
+
670
+    if (id < 0) {
671
+        Serial.print(F("Unknown MQTT topic "));
672
+        Serial.println(ts);
673
+        return;
674
+    }
675
+
676
+    if (ps.indexOf("on") != -1) {
677
+        state = 1;
678
+    } else if (ps.indexOf("off") != -1) {
679
+        state = 0;
680
+    } else {
681
+        return;
682
+    }
683
+
684
+    if ((id >= 0) && (id < relais_count())) {
685
+        relais_set(id, state);
686
+
687
+#ifdef ENABLE_INFLUXDB_LOGGING
688
+        writeDatabase();
689
+#endif // ENABLE_INFLUXDB_LOGGING
690
+    }
691
+#endif // FEATURE_RELAIS
692
+}
693
+
694
+void mqttReconnect() {
695
+    // Create a random client ID
696
+    String clientId = F("ESP-" SENSOR_LOCATION "-");
697
+    clientId += String(random(0xffff), HEX);
698
+
699
+    // Attempt to connect
700
+#if defined(MQTT_USER) && defined(MQTT_PASS)
701
+    if (mqtt.connect(clientId.c_str(), MQTT_USER, MQTT_PASS)) {
702
+#else
703
+    if (mqtt.connect(clientId.c_str())) {
704
+#endif
705
+        // Once connected, publish an announcement...
706
+        mqtt.publish(SENSOR_LOCATION, "sensor online");
707
+
708
+        // ... and resubscribe
709
+#ifdef FEATURE_RELAIS
710
+        mqtt.subscribe(SENSOR_LOCATION);
711
+        for (int i = 0; i < relais_count(); i++) {
712
+            String topic(SENSOR_LOCATION);
713
+            topic += String("/") + relais_name(i);
714
+            mqtt.subscribe(topic.c_str());
715
+        }
716
+#endif // FEATURE_RELAIS
717
+    }
718
+}
719
+#endif // ENABLE_MQTT
720
+
473
 void setup() {
721
 void setup() {
474
     pinMode(BUILTIN_LED_PIN, OUTPUT);
722
     pinMode(BUILTIN_LED_PIN, OUTPUT);
475
     
723
     
476
-#ifdef ENABLE_RELAIS_TEST
477
-    relais_init();
478
-#endif // ENABLE_RELAIS_TEST
724
+    Serial.begin(115200);
479
 
725
 
480
     // Blink LED for init
726
     // Blink LED for init
481
     for (int i = 0; i < 2; i++) {
727
     for (int i = 0; i < 2; i++) {
484
         digitalWrite(BUILTIN_LED_PIN, HIGH); // LED off
730
         digitalWrite(BUILTIN_LED_PIN, HIGH); // LED off
485
         delay(LED_INIT_BLINK_INTERVAL);
731
         delay(LED_INIT_BLINK_INTERVAL);
486
     }
732
     }
733
+
734
+    Serial.print(F("Relais"));
735
+    relais_init();
487
     
736
     
737
+    Serial.print(F("Moisture"));
488
     moisture_init();
738
     moisture_init();
489
 
739
 
490
     // Init I2C and try to connect to sensors
740
     // Init I2C and try to connect to sensors
491
 #if defined(ARDUINO_ARCH_ESP8266)
741
 #if defined(ARDUINO_ARCH_ESP8266)
492
 
742
 
743
+    Serial.print(F("Wire2"));
493
     Wire2.begin(I2C_SDA_PIN, I2C_SCL_PIN);
744
     Wire2.begin(I2C_SDA_PIN, I2C_SCL_PIN);
745
+
746
+    Serial.print(F("BME"));
494
     found_bme1 = (!bme1.begin(BME_I2C_ADDRESS_1, &Wire2)) ? false : true;
747
     found_bme1 = (!bme1.begin(BME_I2C_ADDRESS_1, &Wire2)) ? false : true;
495
     found_bme2 = (!bme2.begin(BME_I2C_ADDRESS_2, &Wire2)) ? false : true;
748
     found_bme2 = (!bme2.begin(BME_I2C_ADDRESS_2, &Wire2)) ? false : true;
496
 
749
 
750
+#ifdef ENABLE_CCS811
751
+    Serial.print(F("CCS"));
752
+    found_ccs1 = ccs1.begin(CCS811_ADDRESS_1, &Wire2);
753
+    found_ccs2 = ccs2.begin(CCS811_ADDRESS_2, &Wire2);
754
+#endif // ENABLE_CCS811
755
+
497
 #elif defined(ARDUINO_ARCH_ESP32)
756
 #elif defined(ARDUINO_ARCH_ESP32)
498
 
757
 
758
+    Serial.print(F("Wire"));
499
     Wire.begin();
759
     Wire.begin();
760
+
761
+    Serial.print(F("BME"));
500
     found_bme1 = (!bme1.begin(BME_I2C_ADDRESS_1, &Wire)) ? false : true;
762
     found_bme1 = (!bme1.begin(BME_I2C_ADDRESS_1, &Wire)) ? false : true;
501
     found_bme2 = (!bme2.begin(BME_I2C_ADDRESS_2, &Wire)) ? false : true;
763
     found_bme2 = (!bme2.begin(BME_I2C_ADDRESS_2, &Wire)) ? false : true;
502
 
764
 
765
+#ifdef ENABLE_CCS811
766
+    Serial.print(F("CCS"));
767
+    found_ccs1 = ccs1.begin(CCS811_ADDRESS_1, &Wire);
768
+    found_ccs2 = ccs2.begin(CCS811_ADDRESS_2, &Wire);
769
+#endif // ENABLE_CCS811
770
+
503
 #elif defined(ARDUINO_ARCH_AVR)
771
 #elif defined(ARDUINO_ARCH_AVR)
504
 
772
 
773
+    Serial.print(F("BME"));
505
     found_bme1 = (!bme1.begin(BME_I2C_ADDRESS_1, &Wire)) ? false : true;
774
     found_bme1 = (!bme1.begin(BME_I2C_ADDRESS_1, &Wire)) ? false : true;
506
     found_bme2 = (!bme2.begin(BME_I2C_ADDRESS_2, &Wire)) ? false : true;
775
     found_bme2 = (!bme2.begin(BME_I2C_ADDRESS_2, &Wire)) ? false : true;
507
 
776
 
777
+#ifdef ENABLE_CCS811
778
+    Serial.print(F("CCS"));
779
+    found_ccs1 = ccs1.begin(CCS811_ADDRESS_1, &Wire);
780
+    found_ccs2 = ccs2.begin(CCS811_ADDRESS_2, &Wire);
781
+#endif // ENABLE_CCS811
782
+
508
 #endif
783
 #endif
509
 
784
 
785
+    Serial.print(F("SHT"));
510
     found_sht = sht.GetAlive();
786
     found_sht = sht.GetAlive();
511
 
787
 
512
     // Build hostname string
788
     // Build hostname string
513
     String hostname = SENSOR_HOSTNAME_PREFIX;
789
     String hostname = SENSOR_HOSTNAME_PREFIX;
514
-    hostname += sensor_location;
790
+    hostname += SENSOR_LOCATION;
515
 
791
 
516
 #if defined(ARDUINO_ARCH_ESP8266)
792
 #if defined(ARDUINO_ARCH_ESP8266)
517
 
793
 
518
     // Connect to WiFi AP
794
     // Connect to WiFi AP
795
+    Serial.print(F("Connecting WiFi"));
519
     WiFi.hostname(hostname);
796
     WiFi.hostname(hostname);
520
     WiFi.mode(WIFI_STA);
797
     WiFi.mode(WIFI_STA);
521
-    WiFi.begin(ssid, password);
798
+    WiFi.begin(WIFI_SSID, WIFI_PASS);
522
     while (WiFi.status() != WL_CONNECTED) {
799
     while (WiFi.status() != WL_CONNECTED) {
523
         delay(LED_CONNECT_BLINK_INTERVAL);
800
         delay(LED_CONNECT_BLINK_INTERVAL);
524
         digitalWrite(BUILTIN_LED_PIN, !digitalRead(BUILTIN_LED_PIN));
801
         digitalWrite(BUILTIN_LED_PIN, !digitalRead(BUILTIN_LED_PIN));
802
+        Serial.print(F("."));
525
     }
803
     }
804
+    Serial.println(F("\nWiFi connected!"));
526
     
805
     
527
 #elif defined(ARDUINO_ARCH_ESP32)
806
 #elif defined(ARDUINO_ARCH_ESP32)
528
 
807
 
541
     }, WiFiEvent_t::SYSTEM_EVENT_STA_DISCONNECTED);
820
     }, WiFiEvent_t::SYSTEM_EVENT_STA_DISCONNECTED);
542
 
821
 
543
     // Connect to WiFi AP
822
     // Connect to WiFi AP
823
+    Serial.print(F("Connecting WiFi"));
544
     WiFi.mode(WIFI_STA);
824
     WiFi.mode(WIFI_STA);
545
-    WiFi.begin(ssid, password);
825
+    WiFi.begin(WIFI_SSID, WIFI_PASS);
546
     while (WiFi.status() != WL_CONNECTED) {
826
     while (WiFi.status() != WL_CONNECTED) {
547
         delay(LED_CONNECT_BLINK_INTERVAL);
827
         delay(LED_CONNECT_BLINK_INTERVAL);
548
         digitalWrite(BUILTIN_LED_PIN, !digitalRead(BUILTIN_LED_PIN));
828
         digitalWrite(BUILTIN_LED_PIN, !digitalRead(BUILTIN_LED_PIN));
829
+        Serial.print(F("."));
549
     }
830
     }
831
+    Serial.println(F("\nWiFi connected!"));
550
     
832
     
551
     // Set hostname workaround
833
     // Set hostname workaround
552
     WiFi.setHostname(hostname.c_str());
834
     WiFi.setHostname(hostname.c_str());
553
 
835
 
554
 #elif defined(ARDUINO_ARCH_AVR)
836
 #elif defined(ARDUINO_ARCH_AVR)
555
 
837
 
556
-    Serial.begin(115200);
557
     Serial1.begin(115200);
838
     Serial1.begin(115200);
558
 
839
 
559
     WiFi.init(&Serial1);
840
     WiFi.init(&Serial1);
560
 
841
 
561
     Serial.print(F("Connecting WiFi"));
842
     Serial.print(F("Connecting WiFi"));
562
-    WiFi.begin(ssid, password);
843
+    WiFi.begin(WIFI_SSID, WIFI_PASS);
563
     while (WiFi.status() != WL_CONNECTED) {
844
     while (WiFi.status() != WL_CONNECTED) {
564
         delay(LED_CONNECT_BLINK_INTERVAL);
845
         delay(LED_CONNECT_BLINK_INTERVAL);
565
         digitalWrite(BUILTIN_LED_PIN, !digitalRead(BUILTIN_LED_PIN));
846
         digitalWrite(BUILTIN_LED_PIN, !digitalRead(BUILTIN_LED_PIN));
569
 
850
 
570
 #endif
851
 #endif
571
 
852
 
853
+    Serial.println(F("Seeding"));
854
+    randomSeed(micros());
855
+
856
+#ifdef ENABLE_MQTT
857
+    Serial.println(F("MQTT"));
858
+    mqtt.setServer(MQTT_HOST, MQTT_PORT);
859
+    mqtt.setCallback(mqttCallback);
860
+#endif // ENABLE_MQTT
861
+
572
 #ifdef ENABLE_INFLUXDB_LOGGING
862
 #ifdef ENABLE_INFLUXDB_LOGGING
573
-    // Setup InfluxDB Client
863
+    Serial.println(F("Influx"));
574
     influx.setDb(INFLUXDB_DATABASE);
864
     influx.setDb(INFLUXDB_DATABASE);
575
 #endif // ENABLE_INFLUXDB_LOGGING
865
 #endif // ENABLE_INFLUXDB_LOGGING
576
 
866
 
577
 #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
867
 #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
578
     // Setup HTTP Server
868
     // Setup HTTP Server
869
+    Serial.println(F("HTTP"));
579
     MDNS.begin(hostname.c_str());
870
     MDNS.begin(hostname.c_str());
580
     updater.setup(&server);
871
     updater.setup(&server);
581
     server.on("/", handleRoot);
872
     server.on("/", handleRoot);
582
 
873
 
583
-#ifdef ENABLE_RELAIS_TEST
584
-    server.on("/relaistest", handleRelaisTest);
585
-#endif
874
+#ifdef FEATURE_RELAIS
875
+    server.on("/on", handleOn);
876
+    server.on("/off", handleOff);
877
+#endif // FEATURE_RELAIS
586
 
878
 
587
     MDNS.addService("http", "tcp", 80);
879
     MDNS.addService("http", "tcp", 80);
588
 #endif
880
 #endif
614
                     client.println(F("Content-Type: text/html"));
906
                     client.println(F("Content-Type: text/html"));
615
                     client.println(F("Connection: close"));
907
                     client.println(F("Connection: close"));
616
                     client.println();
908
                     client.println();
909
+
910
+                    // TODO parse path and handle different pages
617
                     handleRoot(client);
911
                     handleRoot(client);
912
+
618
                     break;
913
                     break;
619
                 }
914
                 }
620
 
915
 
680
         InfluxData measurement("environment");
975
         InfluxData measurement("environment");
681
 #endif
976
 #endif
682
 
977
 
683
-        measurement.addTag("location", sensor_location);
978
+        measurement.addTag("location", SENSOR_LOCATION);
684
         measurement.addTag("placement", "1");
979
         measurement.addTag("placement", "1");
685
         measurement.addTag("sensor", "bme280");
980
         measurement.addTag("sensor", "bme280");
686
 
981
 
705
         InfluxData measurement("environment");
1000
         InfluxData measurement("environment");
706
 #endif
1001
 #endif
707
 
1002
 
708
-        measurement.addTag("location", sensor_location);
1003
+        measurement.addTag("location", SENSOR_LOCATION);
709
         measurement.addTag("placement", "2");
1004
         measurement.addTag("placement", "2");
710
         measurement.addTag("sensor", "bme280");
1005
         measurement.addTag("sensor", "bme280");
711
 
1006
 
730
         InfluxData measurement("environment");
1025
         InfluxData measurement("environment");
731
 #endif
1026
 #endif
732
 
1027
 
733
-        measurement.addTag("location", sensor_location);
1028
+        measurement.addTag("location", SENSOR_LOCATION);
734
         measurement.addTag("sensor", "sht21");
1029
         measurement.addTag("sensor", "sht21");
735
 
1030
 
736
 #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
1031
 #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
744
         writeMeasurement(measurement);
1039
         writeMeasurement(measurement);
745
         Serial.println(F("Done!"));
1040
         Serial.println(F("Done!"));
746
     }
1041
     }
747
-    
1042
+
1043
+#ifdef ENABLE_CCS811
1044
+
1045
+    if (found_ccs1) {
1046
+#if defined(ARDUINO_ARCH_AVR)
1047
+        measurement.clear();
1048
+        measurement.setName("environment");
1049
+#else
1050
+        InfluxData measurement("environment");
1051
+#endif
1052
+
1053
+        measurement.addTag("location", SENSOR_LOCATION);
1054
+        measurement.addTag("placement", "1");
1055
+        measurement.addTag("sensor", "ccs811");
1056
+
1057
+        String err(ccs1_error_code);
1058
+        measurement.addTag("error", err);
1059
+
1060
+#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
1061
+        measurement.addTag("device", WiFi.macAddress());
1062
+#endif
1063
+
1064
+        measurement.addValue("eco2", ccs1_eco2());
1065
+        measurement.addValue("tvoc", ccs1_tvoc());
1066
+
1067
+        Serial.println(F("Writing ccs1"));
1068
+        writeMeasurement(measurement);
1069
+        Serial.println(F("Done!"));
1070
+    }
1071
+
1072
+    if (found_ccs2) {
1073
+#if defined(ARDUINO_ARCH_AVR)
1074
+        measurement.clear();
1075
+        measurement.setName("environment");
1076
+#else
1077
+        InfluxData measurement("environment");
1078
+#endif
1079
+
1080
+        measurement.addTag("location", SENSOR_LOCATION);
1081
+        measurement.addTag("placement", "2");
1082
+        measurement.addTag("sensor", "ccs811");
1083
+
1084
+        String err(ccs2_error_code);
1085
+        measurement.addTag("error", err);
1086
+
1087
+#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
1088
+        measurement.addTag("device", WiFi.macAddress());
1089
+#endif
1090
+
1091
+        measurement.addValue("eco2", ccs2_eco2());
1092
+        measurement.addValue("tvoc", ccs2_tvoc());
1093
+
1094
+        Serial.println(F("Writing ccs2"));
1095
+        writeMeasurement(measurement);
1096
+        Serial.println(F("Done!"));
1097
+    }
1098
+
1099
+#endif // ENABLE_CCS811
1100
+
1101
+#ifdef FEATURE_MOISTURE
748
     for (int i = 0; i < moisture_count(); i++) {
1102
     for (int i = 0; i < moisture_count(); i++) {
749
         int moisture = moisture_read(i);
1103
         int moisture = moisture_read(i);
750
         if (moisture < moisture_max()) {
1104
         if (moisture < moisture_max()) {
755
             InfluxData measurement("moisture");
1109
             InfluxData measurement("moisture");
756
 #endif
1110
 #endif
757
 
1111
 
758
-            measurement.addTag("location", sensor_location);
1112
+            measurement.addTag("location", SENSOR_LOCATION);
759
             String sensor(i + 1, DEC);
1113
             String sensor(i + 1, DEC);
760
             measurement.addTag("sensor", sensor);
1114
             measurement.addTag("sensor", sensor);
761
 
1115
 
772
             Serial.println(F("Done!"));
1126
             Serial.println(F("Done!"));
773
         }
1127
         }
774
     }
1128
     }
1129
+#endif // FEATURE_MOISTURE
1130
+
1131
+#ifdef FEATURE_RELAIS
1132
+    for (int i = 0; i < relais_count(); i++) {
1133
+        InfluxData measurement("relais");
1134
+        measurement.addTag("location", SENSOR_LOCATION);
1135
+        measurement.addTag("id", String(i));
1136
+        measurement.addTag("name", relais_name(i));
1137
+
1138
+#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
1139
+        measurement.addTag("device", WiFi.macAddress());
1140
+#endif
1141
+
1142
+        measurement.addValue("state", relais_get(i));
1143
+        writeMeasurement(measurement);
1144
+    }
1145
+#endif // FEATURE_RELAIS
775
 
1146
 
776
     Serial.println(F("All Done!"));
1147
     Serial.println(F("All Done!"));
777
 }
1148
 }
778
 #endif // ENABLE_INFLUXDB_LOGGING
1149
 #endif // ENABLE_INFLUXDB_LOGGING
779
 
1150
 
1151
+#ifdef ENABLE_CCS811
1152
+void ccs_update() {
1153
+    if (found_ccs1) {
1154
+        if (ccs1.available()) {
1155
+            ccs1_error_code = ccs1.readData();
1156
+            ccs1_data_valid = (ccs1_error_code == 0);
1157
+
1158
+            if (found_bme1) {
1159
+                ccs1.setEnvironmentalData(bme1_humid(), bme1_temp());
1160
+            } else if (found_bme2) {
1161
+                ccs1.setEnvironmentalData(bme2_humid(), bme2_temp());
1162
+            } else if (found_sht) {
1163
+                ccs1.setEnvironmentalData(sht_humid(), sht_temp());
1164
+            }
1165
+        }
1166
+    }
1167
+
1168
+    if (found_ccs2) {
1169
+        if (ccs2.available()) {
1170
+            ccs2_error_code = ccs2.readData();
1171
+            ccs2_data_valid = (ccs2_error_code == 0);
1172
+
1173
+            if (found_bme1) {
1174
+                ccs2.setEnvironmentalData(bme1_humid(), bme1_temp());
1175
+            } else if (found_bme2) {
1176
+                ccs2.setEnvironmentalData(bme2_humid(), bme2_temp());
1177
+            } else if (found_sht) {
1178
+                ccs2.setEnvironmentalData(sht_humid(), sht_temp());
1179
+            }
1180
+        }
1181
+    }
1182
+}
1183
+#endif // ENABLE_CCS811
1184
+
780
 void loop() {
1185
 void loop() {
781
     unsigned long time = millis();
1186
     unsigned long time = millis();
782
     
1187
     
783
-#ifdef ENABLE_RELAIS_TEST
784
-    relais_run();
785
-#endif // ENABLE_RELAIS_TEST
1188
+#ifdef ENABLE_CCS811
1189
+    if (found_ccs1 || found_ccs2) {
1190
+        ccs_update();
1191
+    }
1192
+#endif // ENABLE_CCS811
786
 
1193
 
787
     if ((time - last_server_handle_time) >= SERVER_HANDLE_INTERVAL) {
1194
     if ((time - last_server_handle_time) >= SERVER_HANDLE_INTERVAL) {
788
         last_server_handle_time = time;
1195
         last_server_handle_time = time;
789
         handleServers();
1196
         handleServers();
790
     }
1197
     }
791
 
1198
 
792
-#ifdef ENABLE_INFLUXDB_LOGGING
793
     if ((time - last_db_write_time) >= DB_WRITE_INTERVAL) {
1199
     if ((time - last_db_write_time) >= DB_WRITE_INTERVAL) {
794
         last_db_write_time = time;
1200
         last_db_write_time = time;
1201
+
1202
+#ifdef ENABLE_INFLUXDB_LOGGING
795
         writeDatabase();
1203
         writeDatabase();
1204
+#endif // ENABLE_INFLUXDB_LOGGING
1205
+
1206
+#ifdef ENABLE_MQTT
1207
+        writeMQTT();
1208
+#endif // ENABLE_MQTT
796
     }
1209
     }
797
     
1210
     
1211
+#ifdef ENABLE_INFLUXDB_LOGGING
798
 #ifdef INFLUX_MAX_ERRORS_RESET
1212
 #ifdef INFLUX_MAX_ERRORS_RESET
799
     if (error_count >= INFLUX_MAX_ERRORS_RESET) {
1213
     if (error_count >= INFLUX_MAX_ERRORS_RESET) {
800
 #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
1214
 #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
804
 #endif // INFLUX_MAX_ERRORS_RESET
1218
 #endif // INFLUX_MAX_ERRORS_RESET
805
 #endif // ENABLE_INFLUXDB_LOGGING
1219
 #endif // ENABLE_INFLUXDB_LOGGING
806
 
1220
 
1221
+#ifdef ENABLE_MQTT
1222
+    if (!mqtt.connected() && ((millis() - last_mqtt_reconnect_time) >= MQTT_RECONNECT_INTERVAL)) {
1223
+        last_mqtt_reconnect_time = millis();
1224
+        mqttReconnect();
1225
+    }
1226
+
1227
+    mqtt.loop();
1228
+#endif // ENABLE_MQTT
1229
+
807
     // blink heartbeat LED
1230
     // blink heartbeat LED
808
     if ((time - last_led_blink_time) >= LED_BLINK_INTERVAL) {
1231
     if ((time - last_led_blink_time) >= LED_BLINK_INTERVAL) {
809
         last_led_blink_time = time;
1232
         last_led_blink_time = time;
811
     }
1234
     }
812
     
1235
     
813
 #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
1236
 #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
814
-    // reset ESP every 6h to be safe
815
-    if (time >= (6 * 60 * 60 * 1000)) {
1237
+    // reset ESP every 3d to be safe
1238
+    if (time >= (3UL * 24UL * 60UL * 60UL * 1000UL)) {
816
         ESP.restart();
1239
         ESP.restart();
817
     }
1240
     }
818
 #endif
1241
 #endif
819
 }
1242
 }
820
-

+ 26
- 27
src/moisture.cpp View File

14
 #include <Arduino.h>
14
 #include <Arduino.h>
15
 #include "moisture.h"
15
 #include "moisture.h"
16
 
16
 
17
-#if defined(ARDUINO_ARCH_ESP8266)
18
-
19
-int moisture_count(void) {
20
-    return 0;
21
-}
22
-
23
-int moisture_read(int sensor) {
24
-    return 0;
25
-}
26
-
27
-int moisture_max(void) {
28
-    return 0;
29
-}
30
-
31
-void moisture_init(void) { }
32
-
33
-#elif defined(ARDUINO_ARCH_ESP32)
17
+#if defined(MOISTURE_ADC_ESP32)
34
 
18
 
35
 #include <driver/adc.h>
19
 #include <driver/adc.h>
36
 
20
 
56
     return sample_sum / ADC_OVERSAMPLE;
40
     return sample_sum / ADC_OVERSAMPLE;
57
 }
41
 }
58
 
42
 
43
+void moisture_init(void) {
44
+    adc1_config_width(ADC_BITS);
45
+    for (int i = 0; i < SENSOR_COUNT; i++) {
46
+        adc1_config_channel_atten(sensor_pin[i], ADC_ATTENUATION);
47
+    }
48
+}
49
+
59
 int moisture_count(void) {
50
 int moisture_count(void) {
60
     return SENSOR_COUNT;
51
     return SENSOR_COUNT;
61
 }
52
 }
72
     return (1 << ADC_BITWIDTH) - 1;
63
     return (1 << ADC_BITWIDTH) - 1;
73
 }
64
 }
74
 
65
 
75
-void moisture_init(void) {
76
-    adc1_config_width(ADC_BITS);
77
-    for (int i = 0; i < SENSOR_COUNT; i++) {
78
-        adc1_config_channel_atten(sensor_pin[i], ADC_ATTENUATION);
79
-    }
80
-}
81
-
82
-#elif defined(ARDUINO_ARCH_AVR)
66
+#elif defined(MOISTURE_ADC_ARDUINO)
83
 
67
 
84
 // Hardware I2C pins A4 and A5 not usable on Arduino Uno Wifi Dev. Ed.
68
 // Hardware I2C pins A4 and A5 not usable on Arduino Uno Wifi Dev. Ed.
85
 #define SENSOR_COUNT 6
69
 #define SENSOR_COUNT 6
87
 
71
 
88
 #define OVERSAMPLE_COUNT 3
72
 #define OVERSAMPLE_COUNT 3
89
 
73
 
74
+void moisture_init(void) {
75
+
76
+}
77
+
90
 int moisture_count(void) {
78
 int moisture_count(void) {
91
     return SENSOR_COUNT;
79
     return SENSOR_COUNT;
92
 }
80
 }
105
     return 4095;
93
     return 4095;
106
 }
94
 }
107
 
95
 
108
-void moisture_init(void) {
96
+#else
97
+
98
+void moisture_init(void) { }
109
 
99
 
100
+int moisture_count(void) {
101
+    return 0;
110
 }
102
 }
111
 
103
 
112
-#endif
104
+int moisture_read(int sensor) {
105
+    return 0;
106
+}
113
 
107
 
108
+int moisture_max(void) {
109
+    return 0;
110
+}
111
+
112
+#endif

+ 132
- 37
src/relais.cpp View File

13
 
13
 
14
 #include <Arduino.h>
14
 #include <Arduino.h>
15
 #include "relais.h"
15
 #include "relais.h"
16
+#include "config.h"
16
 
17
 
17
-#if defined(ARDUINO_ARCH_ESP8266)
18
+#if defined(RELAIS_SERIAL)
19
+
20
+#define SERIAL_RELAIS_COUNT 4
21
+
22
+/*
23
+Turn OFF the first relay  : A0 01 00 A1
24
+Turn ON the first relay   : A0 01 01 A2
25
+Turn OFF the second relay : A0 02 00 A2
26
+Turn ON the second relay  : A0 02 01 A3
27
+Turn OFF the third relay  : A0 03 00 A3
28
+Turn ON the third relay   : A0 03 01 A4
29
+Turn OFF the fourth relay : A0 04 00 A4
30
+Turn ON the fourth relay  : A0 04 01 A5
31
+*/
32
+
33
+static int states[SERIAL_RELAIS_COUNT];
34
+
35
+static String names[SERIAL_RELAIS_COUNT] = {
36
+#if defined(SENSOR_LOCATION_BATHROOM)
37
+    String("light_small"),
38
+    String("light_big"),
39
+    String("relais_2"),
40
+    String("fan")
41
+#else
42
+    String("relais_0"),
43
+    String("relais_1"),
44
+    String("relais_2"),
45
+    String("relais_3")
46
+#endif
47
+};
48
+
49
+static int initial_values[SERIAL_RELAIS_COUNT] = {
50
+#if defined(SENSOR_LOCATION_BATHROOM)
51
+    1, 0, 0, 1
52
+#else
53
+    0, 0, 0, 0
54
+#endif
55
+};
56
+
57
+void relais_init(void) {
58
+    Serial.begin(115200);
59
+
60
+    for (int i = 0; i < SERIAL_RELAIS_COUNT; i++) {
61
+        relais_set(i, initial_values[i]);
62
+    }
63
+}
18
 
64
 
19
 int relais_count(void) {
65
 int relais_count(void) {
20
-    return 0;
66
+    return SERIAL_RELAIS_COUNT;
21
 }
67
 }
22
 
68
 
23
-int relais_enable(int relais, unsigned long time) {
24
-    return 0;
69
+void relais_set(int relais, int state) {
70
+    if ((relais < 0) || (relais >= SERIAL_RELAIS_COUNT)) {
71
+        return;
72
+    }
73
+
74
+    states[relais] = state;
75
+
76
+    int cmd[4];
77
+    cmd[0] = 0xA0; // command
78
+
79
+    cmd[1] = relais + 1; // relais id, 1-4
80
+    cmd[2] = state ? 1 : 0; // relais state
81
+
82
+    cmd[3] = 0; // checksum
83
+    for (int i = 0; i < 3; i++) {
84
+        cmd[3] += cmd[i];
85
+    }
86
+
87
+    for (int i = 0; i < 4; i++) {
88
+        Serial.write(cmd[i]);
89
+    }
90
+
91
+    delay(100);
25
 }
92
 }
26
 
93
 
27
-void relais_init(void) { }
28
-void relais_run(void) { }
94
+int relais_get(int relais) {
95
+    if ((relais < 0) || (relais >= SERIAL_RELAIS_COUNT)) {
96
+        return 0;
97
+    }
29
 
98
 
30
-#elif defined(ARDUINO_ARCH_ESP32)
99
+    return states[relais];
100
+}
31
 
101
 
32
-#define RELAIS_COUNT 10
102
+String relais_name(int relais) {
103
+    if ((relais < 0) || (relais >= SERIAL_RELAIS_COUNT)) {
104
+        return String(F("Unknown"));
105
+    }
33
 
106
 
34
-struct relais_state {
35
-    unsigned long turn_off;
36
-};
107
+    return names[relais];
108
+}
109
+
110
+#elif defined(RELAIS_GPIO)
111
+
112
+#define GPIO_RELAIS_COUNT 10
37
 
113
 
38
-static struct relais_state state[RELAIS_COUNT];
39
-static int gpios[RELAIS_COUNT] = {
114
+static int gpios[GPIO_RELAIS_COUNT] = {
40
     0, 15, 2, 4,
115
     0, 15, 2, 4,
41
     16, 17, 5, 18,
116
     16, 17, 5, 18,
42
     19, 23
117
     19, 23
43
 };
118
 };
44
 
119
 
45
-static void relais_set(int relais, int state) {
46
-    digitalWrite(gpios[relais], state ? LOW : HIGH);
120
+static int states[GPIO_RELAIS_COUNT];
121
+
122
+static String names[GPIO_RELAIS_COUNT] = {
123
+    String(F("relais_0")),
124
+    String(F("relais_1")),
125
+    String(F("relais_2")),
126
+    String(F("relais_3")),
127
+    String(F("relais_4")),
128
+    String(F("relais_5")),
129
+    String(F("relais_6")),
130
+    String(F("relais_7")),
131
+    String(F("relais_8")),
132
+    String(F("relais_9"))
133
+};
134
+
135
+void relais_init(void) {
136
+    for (int i = 0; i < GPIO_RELAIS_COUNT; i++) {
137
+        pinMode(gpios[i], OUTPUT);
138
+        relais_set(i, 0);
139
+    }
47
 }
140
 }
48
 
141
 
49
 int relais_count(void) {
142
 int relais_count(void) {
50
-    return RELAIS_COUNT;
143
+    return GPIO_RELAIS_COUNT;
51
 }
144
 }
52
 
145
 
53
-int relais_enable(int relais, unsigned long time) {
54
-    if ((relais < 0) || (relais >= RELAIS_COUNT)) {
55
-        return -1;
146
+void relais_set(int relais, int state) {
147
+    if ((relais < 0) || (relais >= GPIO_RELAIS_COUNT)) {
148
+        return;
56
     }
149
     }
57
-    
58
-    relais_set(relais, 1);
59
-    state[relais].turn_off = millis() + time;
60
-    return 0;
150
+
151
+    states[relais] = state;
152
+    digitalWrite(gpios[relais], state ? LOW : HIGH);
61
 }
153
 }
62
 
154
 
63
-void relais_init(void) {
64
-    for (int i = 0; i < RELAIS_COUNT; i++) {
65
-        pinMode(gpios[i], OUTPUT);
66
-        relais_set(i, 0);
67
-        
68
-        state[i].turn_off = 0;
155
+int relais_get(int relais) {
156
+    if ((relais < 0) || (relais >= GPIO_RELAIS_COUNT)) {
157
+        return 0;
69
     }
158
     }
159
+
160
+    return states[relais];
70
 }
161
 }
71
 
162
 
72
-void relais_run(void) {
73
-    for (int i = 0; i < RELAIS_COUNT; i++) {
74
-        if (state[i].turn_off > 0) {
75
-            if (millis() >= state[i].turn_off) {
76
-                relais_set(i, 0);
77
-            }
78
-        }
163
+String relais_name(int relais) {
164
+    if ((relais < 0) || (relais >= GPIO_RELAIS_COUNT)) {
165
+        return String(F("Unknown"));
79
     }
166
     }
167
+
168
+    return names[relais];
80
 }
169
 }
81
 
170
 
82
-#endif
171
+#else
83
 
172
 
173
+void relais_init(void) { }
174
+int relais_count(void) { return 0; }
175
+void relais_set(int relais, int state) { }
176
+int relais_get(int relais) { return 0; }
177
+
178
+#endif

Loading…
Cancel
Save