ESP32 / ESP8266 & BME280 / SHT2x sensor with InfluxDB support
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

main.cpp 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. /*
  2. * main.cpp
  3. *
  4. * ESP8266 / ESP32 Environmental Sensor
  5. *
  6. * ----------------------------------------------------------------------------
  7. * "THE BEER-WARE LICENSE" (Revision 42):
  8. * <xythobuz@xythobuz.de> wrote this file. As long as you retain this notice
  9. * you can do whatever you want with this stuff. If we meet some day, and you
  10. * think this stuff is worth it, you can buy me a beer in return. Thomas Buck
  11. * ----------------------------------------------------------------------------
  12. */
  13. #include <Arduino.h>
  14. #include <Wire.h>
  15. #include <Adafruit_BME280.h>
  16. #include <SHT2x.h>
  17. #if defined(ARDUINO_ARCH_ESP8266)
  18. #include <ESP8266WiFi.h>
  19. #include <ESP8266WebServer.h>
  20. #include <ESP8266mDNS.h>
  21. #define ESP_PLATFORM_NAME "ESP8266"
  22. #elif defined(ARDUINO_ARCH_ESP32)
  23. #include <WiFi.h>
  24. #include <WebServer.h>
  25. #include <ESPmDNS.h>
  26. #define ESP_PLATFORM_NAME "ESP32"
  27. #endif
  28. #include "config.h"
  29. #include "moisture.h"
  30. #include "relais.h"
  31. #include "SimpleUpdater.h"
  32. #define BUILTIN_LED_PIN 1
  33. UPDATE_WEB_SERVER server(80);
  34. SimpleUpdater updater;
  35. #ifdef ENABLE_INFLUXDB_LOGGING
  36. #include <InfluxDb.h>
  37. Influxdb influx(INFLUXDB_HOST, INFLUXDB_PORT);
  38. #define INFLUX_MAX_ERRORS_RESET 10
  39. int error_count = 0;
  40. #endif // ENABLE_INFLUXDB_LOGGING
  41. #define SHT_I2C_ADDRESS HTDU21D_ADDRESS
  42. #define BME_I2C_ADDRESS_1 0x76
  43. #define BME_I2C_ADDRESS_2 0x77
  44. #if defined(ARDUINO_ARCH_ESP8266)
  45. #define I2C_SDA_PIN 2
  46. #define I2C_SCL_PIN 0
  47. TwoWire Wire2;
  48. SHT2x sht(SHT_I2C_ADDRESS, &Wire2);
  49. #elif defined(ARDUINO_ARCH_ESP32)
  50. SHT2x sht(SHT_I2C_ADDRESS, &Wire);
  51. #endif
  52. Adafruit_BME280 bme1, bme2;
  53. bool found_bme1 = false;
  54. bool found_bme2 = false;
  55. bool found_sht = false;
  56. unsigned long last_server_handle_time = 0;
  57. unsigned long last_db_write_time = 0;
  58. unsigned long last_led_blink_time = 0;
  59. static void relaisTest() {
  60. for (int i = 0; i < 10; i++) {
  61. relais_enable(i, 400 + (i * 1000));
  62. delay(100);
  63. }
  64. }
  65. void handleRelaisTest() {
  66. String message = F("<html><head>\n");
  67. message += F("<title>" ESP_PLATFORM_NAME " Environment Sensor</title>\n");
  68. message += F("</head><body>\n");
  69. message += F("<p>Relais Test started!</p>\n");
  70. message += F("<p><a href=\"/\">Return to Home</a></p>\n");
  71. message += F("</body></html>\n");
  72. server.send(200, "text/html", message);
  73. relaisTest();
  74. }
  75. void handleRoot() {
  76. String message = F("<html><head>\n");
  77. message += F("<title>" ESP_PLATFORM_NAME " Environment Sensor</title>\n");
  78. message += F("</head><body>\n");
  79. message += F("<h1>" ESP_PLATFORM_NAME " Environment Sensor</h1>\n");
  80. message += F("\n<p>\n");
  81. message += F("Version: ");
  82. message += esp_env_version;
  83. message += F("\n<br>\n");
  84. message += F("Location: ");
  85. message += sensor_location;
  86. message += F("\n<br>\n");
  87. message += F("MAC: ");
  88. message += WiFi.macAddress();
  89. message += F("\n</p>\n");
  90. #if defined(ARDUINO_ARCH_ESP8266)
  91. message += F("\n<p>\n");
  92. message += F("Reset reason: ");
  93. message += ESP.getResetReason();
  94. message += F("\n<br>\n");
  95. message += F("Free heap: ");
  96. message += String(ESP.getFreeHeap());
  97. message += F(" (");
  98. message += String(ESP.getHeapFragmentation());
  99. message += F("% fragmentation)");
  100. message += F("\n<br>\n");
  101. message += F("Free sketch space: ");
  102. message += String(ESP.getFreeSketchSpace());
  103. message += F("\n<br>\n");
  104. message += F("Flash chip real size: ");
  105. message += String(ESP.getFlashChipRealSize());
  106. if (ESP.getFlashChipSize() != ESP.getFlashChipRealSize()) {
  107. message += F("\n<br>\n");
  108. message += F("WARNING: sdk chip size (");
  109. message += (ESP.getFlashChipSize());
  110. message += F(") does not match!");
  111. }
  112. message += F("\n</p>\n");
  113. #elif defined(ARDUINO_ARCH_ESP32)
  114. message += F("\n<p>\n");
  115. message += F("Free heap: ");
  116. message += String(ESP.getFreeHeap() / 1024.0);
  117. message += F("k\n<br>\n");
  118. message += F("Free sketch space: ");
  119. message += String(ESP.getFreeSketchSpace() / 1024.0);
  120. message += F("k\n<br>\n");
  121. message += F("Flash chip size: ");
  122. message += String(ESP.getFlashChipSize() / 1024.0);
  123. message += F("k\n</p>\n");
  124. #endif
  125. message += F("\n<p>\n");
  126. if (found_bme1) {
  127. message += F("BME280 Low:");
  128. message += F("\n<br>\n");
  129. message += F("Temperature: ");
  130. message += String(bme1.readTemperature());
  131. message += F("\n<br>\n");
  132. message += F("Humidity: ");
  133. message += String(bme1.readHumidity());
  134. message += F("\n<br>\n");
  135. message += F("Pressure: ");
  136. message += String(bme1.readPressure());
  137. } else {
  138. message += F("BME280 (low) not connected!");
  139. }
  140. message += F("\n</p>\n");
  141. message += F("\n<p>\n");
  142. if (found_bme2) {
  143. message += F("BME280 High:");
  144. message += F("\n<br>\n");
  145. message += F("Temperature: ");
  146. message += String(bme2.readTemperature());
  147. message += F("\n<br>\n");
  148. message += F("Humidity: ");
  149. message += String(bme2.readHumidity());
  150. message += F("\n<br>\n");
  151. message += F("Pressure: ");
  152. message += String(bme2.readPressure());
  153. } else {
  154. message += F("BME280 (high) not connected!");
  155. }
  156. message += F("\n</p>\n");
  157. message += F("\n<p>\n");
  158. if (found_sht) {
  159. message += F("SHT21:");
  160. message += F("\n<br>\n");
  161. message += F("Temperature: ");
  162. message += String(sht.GetTemperature());
  163. message += F("\n<br>\n");
  164. message += F("Humidity: ");
  165. message += String(sht.GetHumidity());
  166. } else {
  167. message += F("SHT21 not connected!");
  168. }
  169. message += F("\n</p>\n");
  170. for (int i = 0; i < moisture_count(); i++) {
  171. int moisture = moisture_read(i);
  172. if (moisture < moisture_max()) {
  173. message += F("\n<p>\n");
  174. message += F("Sensor ");
  175. message += String(i + 1);
  176. message += F(":\n<br>\n");
  177. message += F("Moisture: ");
  178. message += String(moisture);
  179. message += F(" / ");
  180. message += String(moisture_max());
  181. message += F("\n</p>\n");
  182. }
  183. }
  184. if (moisture_count() <= 0) {
  185. message += F("\n<p>\n");
  186. message += F("No moisture sensors configured!");
  187. message += F("\n</p>\n");
  188. }
  189. message += F("<p>\n");
  190. message += F("Try <a href=\"/update\">/update</a> for OTA firmware updates!\n");
  191. message += F("</p>\n");
  192. message += F("<p>\n");
  193. #ifdef ENABLE_INFLUXDB_LOGGING
  194. message += F("InfluxDB: ");
  195. message += INFLUXDB_DATABASE;
  196. message += F(" @ ");
  197. message += INFLUXDB_HOST;
  198. message += F(":");
  199. message += String(INFLUXDB_PORT);
  200. message += F("\n");
  201. #else
  202. message += F("InfluxDB logging not enabled!\n");
  203. #endif
  204. message += F("</p>\n");
  205. message += F("<p><a href=\"/relaistest\">Relais Test</a></p>\n");
  206. message += F("</body></html>\n");
  207. server.send(200, "text/html", message);
  208. }
  209. void setup() {
  210. pinMode(BUILTIN_LED_PIN, OUTPUT);
  211. relais_init();
  212. // Blink LED for init
  213. for (int i = 0; i < 2; i++) {
  214. digitalWrite(BUILTIN_LED_PIN, LOW); // LED on
  215. delay(LED_INIT_BLINK_INTERVAL);
  216. digitalWrite(BUILTIN_LED_PIN, HIGH); // LED off
  217. delay(LED_INIT_BLINK_INTERVAL);
  218. }
  219. moisture_init();
  220. // Init I2C and try to connect to sensors
  221. #if defined(ARDUINO_ARCH_ESP8266)
  222. Wire2.begin(I2C_SDA_PIN, I2C_SCL_PIN);
  223. found_bme1 = (!bme1.begin(BME_I2C_ADDRESS_1, &Wire2)) ? false : true;
  224. found_bme2 = (!bme2.begin(BME_I2C_ADDRESS_2, &Wire2)) ? false : true;
  225. #elif defined(ARDUINO_ARCH_ESP32)
  226. Wire.begin();
  227. found_bme1 = (!bme1.begin(BME_I2C_ADDRESS_1, &Wire)) ? false : true;
  228. found_bme2 = (!bme2.begin(BME_I2C_ADDRESS_2, &Wire)) ? false : true;
  229. #endif
  230. found_sht = sht.GetAlive();
  231. // Build hostname string
  232. String hostname = SENSOR_HOSTNAME_PREFIX;
  233. hostname += sensor_location;
  234. #if defined(ARDUINO_ARCH_ESP8266)
  235. // Connect to WiFi AP
  236. WiFi.hostname(hostname);
  237. WiFi.mode(WIFI_STA);
  238. WiFi.begin(ssid, password);
  239. while (WiFi.status() != WL_CONNECTED) {
  240. delay(LED_CONNECT_BLINK_INTERVAL);
  241. digitalWrite(BUILTIN_LED_PIN, !digitalRead(BUILTIN_LED_PIN));
  242. }
  243. #elif defined(ARDUINO_ARCH_ESP32)
  244. // Set hostname workaround
  245. WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE);
  246. WiFi.setHostname(hostname.c_str());
  247. // Workaround for WiFi connecting only every 2nd reset
  248. // https://github.com/espressif/arduino-esp32/issues/2501#issuecomment-513602522
  249. WiFi.onEvent([](WiFiEvent_t event, WiFiEventInfo_t info) {
  250. if (info.disconnected.reason == 202) {
  251. esp_sleep_enable_timer_wakeup(10);
  252. esp_deep_sleep_start();
  253. delay(100);
  254. }
  255. }, WiFiEvent_t::SYSTEM_EVENT_STA_DISCONNECTED);
  256. // Connect to WiFi AP
  257. WiFi.mode(WIFI_STA);
  258. WiFi.begin(ssid, password);
  259. while (WiFi.status() != WL_CONNECTED) {
  260. delay(LED_CONNECT_BLINK_INTERVAL);
  261. digitalWrite(BUILTIN_LED_PIN, !digitalRead(BUILTIN_LED_PIN));
  262. }
  263. // Set hostname workaround
  264. WiFi.setHostname(hostname.c_str());
  265. #endif
  266. #ifdef ENABLE_INFLUXDB_LOGGING
  267. // Setup InfluxDB Client
  268. influx.setDb(INFLUXDB_DATABASE);
  269. #endif // ENABLE_INFLUXDB_LOGGING
  270. // Setup HTTP Server
  271. MDNS.begin(hostname.c_str());
  272. updater.setup(&server);
  273. server.on("/", handleRoot);
  274. server.on("/relaistest", handleRelaisTest);
  275. server.begin();
  276. MDNS.addService("http", "tcp", 80);
  277. }
  278. void handleServers() {
  279. server.handleClient();
  280. #if defined(ARDUINO_ARCH_ESP8266)
  281. MDNS.update();
  282. #endif
  283. }
  284. static boolean writeMeasurement(InfluxData &measurement) {
  285. boolean success = influx.write(measurement);
  286. if (!success) {
  287. error_count++;
  288. for (int i = 0; i < 10; i++) {
  289. digitalWrite(BUILTIN_LED_PIN, LOW); // LED on
  290. delay(LED_ERROR_BLINK_INTERVAL);
  291. digitalWrite(BUILTIN_LED_PIN, HIGH); // LED off
  292. delay(LED_ERROR_BLINK_INTERVAL);
  293. }
  294. }
  295. return success;
  296. }
  297. #ifdef ENABLE_INFLUXDB_LOGGING
  298. void writeDatabase() {
  299. if (found_bme1) {
  300. InfluxData measurement("environment");
  301. measurement.addTag("location", sensor_location);
  302. measurement.addTag("placement", "1");
  303. measurement.addTag("device", WiFi.macAddress());
  304. measurement.addTag("sensor", "bme280");
  305. measurement.addValue("temperature", bme1.readTemperature());
  306. measurement.addValue("pressure", bme1.readPressure());
  307. measurement.addValue("humidity", bme1.readHumidity());
  308. writeMeasurement(measurement);
  309. }
  310. if (found_bme2) {
  311. InfluxData measurement("environment");
  312. measurement.addTag("location", sensor_location);
  313. measurement.addTag("placement", "2");
  314. measurement.addTag("device", WiFi.macAddress());
  315. measurement.addTag("sensor", "bme280");
  316. measurement.addValue("temperature", bme2.readTemperature());
  317. measurement.addValue("pressure", bme2.readPressure());
  318. measurement.addValue("humidity", bme2.readHumidity());
  319. writeMeasurement(measurement);
  320. }
  321. if (found_sht) {
  322. InfluxData measurement("environment");
  323. measurement.addTag("location", sensor_location);
  324. measurement.addTag("device", WiFi.macAddress());
  325. measurement.addTag("sensor", "sht21");
  326. measurement.addValue("temperature", sht.GetTemperature());
  327. measurement.addValue("humidity", sht.GetHumidity());
  328. writeMeasurement(measurement);
  329. }
  330. for (int i = 0; i < moisture_count(); i++) {
  331. int moisture = moisture_read(i);
  332. if (moisture < moisture_max()) {
  333. InfluxData measurement("moisture");
  334. measurement.addTag("location", sensor_location);
  335. measurement.addTag("device", WiFi.macAddress());
  336. measurement.addTag("sensor", String(i + 1));
  337. measurement.addValue("value", moisture);
  338. measurement.addValue("maximum", moisture_max());
  339. writeMeasurement(measurement);
  340. }
  341. }
  342. }
  343. #endif // ENABLE_INFLUXDB_LOGGING
  344. void loop() {
  345. unsigned long time = millis();
  346. relais_run();
  347. if ((time - last_server_handle_time) >= SERVER_HANDLE_INTERVAL) {
  348. last_server_handle_time = time;
  349. handleServers();
  350. }
  351. #ifdef ENABLE_INFLUXDB_LOGGING
  352. if ((time - last_db_write_time) >= DB_WRITE_INTERVAL) {
  353. last_db_write_time = time;
  354. writeDatabase();
  355. }
  356. #ifdef INFLUX_MAX_ERRORS_RESET
  357. if (error_count >= INFLUX_MAX_ERRORS_RESET) {
  358. ESP.restart();
  359. }
  360. #endif // INFLUX_MAX_ERRORS_RESET
  361. #endif // ENABLE_INFLUXDB_LOGGING
  362. if ((time - last_led_blink_time) >= LED_BLINK_INTERVAL) {
  363. last_led_blink_time = time;
  364. digitalWrite(BUILTIN_LED_PIN, !digitalRead(BUILTIN_LED_PIN));
  365. }
  366. }