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.

html.cpp 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. /*
  2. * html.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. #if defined(ARDUINO_ARCH_ESP8266)
  15. #include <ESP8266WiFi.h>
  16. #include <ESP8266WebServer.h>
  17. #include <ESP8266mDNS.h>
  18. #define ESP_PLATFORM_NAME "ESP8266"
  19. #elif defined(ARDUINO_ARCH_ESP32)
  20. #include <WiFi.h>
  21. #include <WebServer.h>
  22. #include <ESPmDNS.h>
  23. #define ESP_PLATFORM_NAME "ESP32"
  24. #elif defined(ARDUINO_ARCH_AVR)
  25. #include <UnoWiFiDevEdSerial1.h>
  26. #include <WiFiLink.h>
  27. #define ESP_PLATFORM_NAME "Uno WiFi"
  28. #endif
  29. #include "config.h"
  30. #include "DebugLog.h"
  31. #include "sensors.h"
  32. #include "servers.h"
  33. #include "memory.h"
  34. #include "relais.h"
  35. #include "moisture.h"
  36. #include "html.h"
  37. #if defined(ARDUINO_ARCH_AVR)
  38. #define ARDUINO_SEND_PARTIAL_PAGE() do { \
  39. size_t len = message.length(), off = 0; \
  40. while (off < len) { \
  41. if ((len - off) >= 50) { \
  42. client.write(message.c_str() + off, 50); \
  43. off += 50; \
  44. } else { \
  45. client.write(message.c_str() + off, len - off); \
  46. off = len; \
  47. } \
  48. } \
  49. message = ""; \
  50. } while (false);
  51. #else
  52. #define ARDUINO_SEND_PARTIAL_PAGE() while (false) { }
  53. #endif
  54. #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
  55. void handlePage(int mode, int id) {
  56. #else
  57. void handlePage(WiFiClient &client, int mode, int id) {
  58. #endif
  59. String message;
  60. message += F("<!DOCTYPE html>");
  61. message += F("<html><head>");
  62. message += F("<meta charset='utf-8'/>");
  63. message += F("<meta name='viewport' content='width=device-width, initial-scale=1'/>");
  64. message += F("<title>" ESP_PLATFORM_NAME " Environment Sensor</title>");
  65. message += F("<style>");
  66. message += F(".log {\n");
  67. message += F( "max-height: 300px;\n");
  68. message += F( "padding: 0 1.0em;\n");
  69. message += F( "max-width: 1200px;\n");
  70. message += F( "margin: auto;\n");
  71. message += F( "margin-top: 1.5em;\n");
  72. message += F( "border: 1px dashed black;\n");
  73. message += F( "font-family: monospace;\n");
  74. message += F( "overflow-y: scroll;\n");
  75. message += F( "word-break: break-all;\n");
  76. message += F("}\n");
  77. message += F("#logbuf {\n");
  78. message += F( "white-space: break-spaces;\n");
  79. message += F("}\n");
  80. message += F("@media (prefers-color-scheme: dark) {");
  81. message += F( "body {");
  82. message += F( "background-color: black;");
  83. message += F( "color: white;");
  84. message += F( "}");
  85. message += F( ".log {\n");
  86. message += F( "border-color: white;");
  87. message += F( "}");
  88. message += F("}");
  89. message += F("</style>");
  90. message += F("</head><body>");
  91. message += F("<h1>" ESP_PLATFORM_NAME " Environment Sensor</h1>");
  92. message += F("\n<p>\n");
  93. message += F("Version: ");
  94. message += ESP_ENV_VERSION;
  95. message += F("\n<br>\n");
  96. message += F("Build Date: ");
  97. message += __DATE__;
  98. message += F("\n<br>\n");
  99. message += F("Build Time: ");
  100. message += __TIME__;
  101. message += F("\n<br>\n");
  102. message += F("Location: ");
  103. message += SENSOR_LOCATION;
  104. message += F("\n<br>\n");
  105. message += F("ID: ");
  106. message += SENSOR_ID;
  107. #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
  108. message += F("\n<br>\n");
  109. message += F("MAC: ");
  110. message += WiFi.macAddress();
  111. #endif
  112. message += F("\n</p>\n");
  113. ARDUINO_SEND_PARTIAL_PAGE();
  114. #if defined(ARDUINO_ARCH_ESP8266)
  115. message += F("<p>");
  116. message += F("Reset reason: ");
  117. message += ESP.getResetReason();
  118. message += F("<br>");
  119. message += F("Free heap: ");
  120. message += String(ESP.getFreeHeap());
  121. message += F(" (");
  122. message += String(ESP.getHeapFragmentation());
  123. message += F("% fragmentation)");
  124. message += F("<br>");
  125. message += F("Free sketch space: ");
  126. message += String(ESP.getFreeSketchSpace());
  127. message += F("<br>");
  128. message += F("Flash chip real size: ");
  129. message += String(ESP.getFlashChipRealSize());
  130. if (ESP.getFlashChipSize() != ESP.getFlashChipRealSize()) {
  131. message += F("<br>");
  132. message += F("WARNING: sdk chip size (");
  133. message += (ESP.getFlashChipSize());
  134. message += F(") does not match!");
  135. }
  136. message += F("</p>");
  137. #elif defined(ARDUINO_ARCH_ESP32)
  138. message += F("<p>");
  139. message += F("Free heap: ");
  140. message += String(ESP.getFreeHeap() / 1024.0);
  141. message += F("k<br>");
  142. message += F("Free sketch space: ");
  143. message += String(ESP.getFreeSketchSpace() / 1024.0);
  144. message += F("k<br>");
  145. message += F("Flash chip size: ");
  146. message += String(ESP.getFlashChipSize() / 1024.0);
  147. message += F("k</p><hr>");
  148. #endif
  149. #ifdef ENABLE_BME280
  150. message += F("\n<p>\n");
  151. if (found_bme1) {
  152. message += F("BME280 Low:");
  153. message += F("\n<br>\n");
  154. message += F("Temperature: ");
  155. message += String(bme1_temp());
  156. message += F("\n<br>\n");
  157. message += F("Humidity: ");
  158. message += String(bme1_humid());
  159. message += F("\n<br>\n");
  160. message += F("Pressure: ");
  161. message += String(bme1_pressure());
  162. message += F("\n<br>\n");
  163. message += F("Offset: ");
  164. message += String(config.bme1_temp_off);
  165. message += F("\n<br>\n");
  166. message += F("<form method=\"GET\" action=\"/calibrate\">");
  167. message += F("<input type=\"text\" name=\"bme1\" placeholder=\"Real Temp.\">");
  168. message += F("<input type=\"submit\" value=\"Calibrate\">");
  169. message += F("</form>");
  170. } else {
  171. message += F("BME280 (low) not connected!");
  172. }
  173. message += F("\n</p><hr>\n");
  174. message += F("\n<p>\n");
  175. if (found_bme2) {
  176. message += F("BME280 High:");
  177. message += F("\n<br>\n");
  178. message += F("Temperature: ");
  179. message += String(bme2_temp());
  180. message += F("\n<br>\n");
  181. message += F("Humidity: ");
  182. message += String(bme2_humid());
  183. message += F("\n<br>\n");
  184. message += F("Pressure: ");
  185. message += String(bme2_pressure());
  186. message += F("\n<br>\n");
  187. message += F("Offset: ");
  188. message += String(config.bme2_temp_off);
  189. message += F("\n<br>\n");
  190. message += F("<form method=\"GET\" action=\"/calibrate\">");
  191. message += F("<input type=\"text\" name=\"bme2\" placeholder=\"Real Temp.\">");
  192. message += F("<input type=\"submit\" value=\"Calibrate\">");
  193. message += F("</form>");
  194. } else {
  195. message += F("BME280 (high) not connected!");
  196. }
  197. message += F("\n</p><hr>\n");
  198. #endif // ENABLE_BME280
  199. ARDUINO_SEND_PARTIAL_PAGE();
  200. message += F("\n<p>\n");
  201. if (found_sht) {
  202. message += F("SHT21:");
  203. message += F("\n<br>\n");
  204. message += F("Temperature: ");
  205. message += String(sht_temp());
  206. message += F("\n<br>\n");
  207. message += F("Humidity: ");
  208. message += String(sht_humid());
  209. message += F("\n<br>\n");
  210. message += F("Offset: ");
  211. message += String(config.sht_temp_off);
  212. message += F("\n<br>\n");
  213. message += F("<form method=\"GET\" action=\"/calibrate\">");
  214. message += F("<input type=\"text\" name=\"sht\" placeholder=\"Real Temp.\">");
  215. message += F("<input type=\"submit\" value=\"Calibrate\">");
  216. message += F("</form>");
  217. } else {
  218. message += F("SHT21 not connected!");
  219. }
  220. message += F("\n</p><hr>\n");
  221. #ifdef ENABLE_CCS811
  222. message += F("\n<p>\n");
  223. if (found_ccs1) {
  224. message += F("CCS811 Low:");
  225. message += F("\n<br>\n");
  226. message += F("eCO2: ");
  227. message += String(ccs1_eco2());
  228. message += F("ppm");
  229. message += F("\n<br>\n");
  230. message += F("TVOC: ");
  231. message += String(ccs1_tvoc());
  232. message += F("ppb");
  233. if (!ccs1_data_valid) {
  234. message += F("\n<br>\n");
  235. message += F("Data invalid (");
  236. message += String(ccs1_error_code);
  237. message += F(")!");
  238. }
  239. } else {
  240. message += F("CCS811 (Low) not connected!");
  241. }
  242. message += F("\n</p><hr>\n");
  243. message += F("\n<p>\n");
  244. if (found_ccs2) {
  245. message += F("CCS811 High:");
  246. message += F("\n<br>\n");
  247. message += F("eCO2: ");
  248. message += String(ccs2_eco2());
  249. message += F("ppm");
  250. message += F("\n<br>\n");
  251. message += F("TVOC: ");
  252. message += String(ccs2_tvoc());
  253. message += F("ppb");
  254. if (!ccs2_data_valid) {
  255. message += F("\n<br>\n");
  256. message += F("Data invalid (");
  257. message += String(ccs2_error_code);
  258. message += F(")!");
  259. }
  260. } else {
  261. message += F("CCS811 (High) not connected!");
  262. }
  263. message += F("\n</p><hr>\n");
  264. #endif // ENABLE_CCS811
  265. ARDUINO_SEND_PARTIAL_PAGE();
  266. #ifdef FEATURE_MOISTURE
  267. for (int i = 0; i < moisture_count(); i++) {
  268. int moisture = moisture_read(i);
  269. if (moisture < moisture_max()) {
  270. message += F("\n<p>\n");
  271. message += F("Sensor ");
  272. message += String(i + 1);
  273. message += F(":\n<br>\n");
  274. message += F("Moisture: ");
  275. message += String(moisture);
  276. message += F(" / ");
  277. message += String(moisture_max());
  278. message += F("\n</p>\n");
  279. }
  280. }
  281. if (moisture_count() <= 0) {
  282. message += F("\n<p>\n");
  283. message += F("No moisture sensors configured!");
  284. message += F("\n</p>\n");
  285. }
  286. ARDUINO_SEND_PARTIAL_PAGE();
  287. #endif // FEATURE_MOISTURE
  288. #ifdef FEATURE_RELAIS
  289. message += F("\n<p>\n");
  290. for (int i = 0; i < relais_count(); i++) {
  291. 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"));
  292. 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"));
  293. }
  294. message += String(F("<a href=\"/on?id=")) + String(relais_count()) + String(F("\">All Relais On</a><br>\n"));
  295. message += String(F("<a href=\"/off?id=")) + String(relais_count()) + String(F("\">All Relais Off</a><br>\n"));
  296. message += F("</p>\n");
  297. if ((mode >= 0) && (mode <= 1)) {
  298. message += F("<p>");
  299. message += F("Turned Relais ");
  300. message += (id < relais_count()) ? String(id) : String(F("1-4"));
  301. message += (mode ? String(F(" On")) : String(F(" Off")));
  302. message += F("</p>\n");
  303. }
  304. message += F("\n<p>\n");
  305. for (int i = 0; i < relais_count(); i++) {
  306. 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"));
  307. }
  308. message += F("</p>\n");
  309. ARDUINO_SEND_PARTIAL_PAGE();
  310. #endif // FEATURE_RELAIS
  311. if (mode == 42) {
  312. message += F("<p>New calibration value saved!</p>\n");
  313. }
  314. #if ! defined(ARDUINO_ARCH_AVR)
  315. message += F("<p>");
  316. message += F("Try <a href=\"/update\">/update</a> for OTA firmware updates!");
  317. message += F("</p><p>");
  318. message += F("Try <a href=\"/reset\">/reset</a> to reset ESP!");
  319. message += F("</p>");
  320. #endif
  321. message += F("<p>");
  322. #ifdef ENABLE_INFLUXDB_LOGGING
  323. message += F("InfluxDB: ");
  324. message += INFLUXDB_DATABASE;
  325. message += F(" @ ");
  326. message += INFLUXDB_HOST;
  327. message += F(":");
  328. message += String(INFLUXDB_PORT);
  329. #else
  330. message += F("InfluxDB logging not enabled!");
  331. #endif
  332. message += F("</p>");
  333. message += F("<p>Uptime: ");
  334. message += String(millis() / 1000);
  335. message += F(" sec.</p>");
  336. #ifdef ENABLE_DEBUGLOG
  337. message += F("<hr><p>Debug Log:</p>");
  338. message += F("<div class='log'><pre id='logbuf'>");
  339. message += debug.getBuffer();
  340. message += F("</pre></div>");
  341. #endif // ENABLE_DEBUGLOG
  342. message += F("</body>");
  343. #ifdef ENABLE_WEBSOCKETS
  344. message += F("<script type='text/javascript'>\n");
  345. message += F("var socket = new WebSocket('ws://' + window.location.hostname + ':81');\n");
  346. message += F("socket.onmessage = function(e) {");
  347. message += F( "var log = document.getElementById('logbuf');");
  348. message += F( "var div = document.getElementsByClassName('log')[0];");
  349. message += F( "log.innerHTML += e.data.substring(4);");
  350. message += F( "if (log.innerHTML.length > (1024 * 1024)) {");
  351. message += F( "log.innerHTML = log.innerHTML.substring(1024 * 1024);");
  352. message += F( "}");
  353. message += F( "div.scrollTop = div.scrollHeight;");
  354. message += F("};\n");
  355. message += F("var hist = document.getElementsByClassName('log')[0];\n");
  356. message += F("hist.scrollTop = hist.scrollHeight;\n");
  357. message += F("</script>\n");
  358. #endif // ENABLE_WEBSOCKETS
  359. message += F("</html>");
  360. #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
  361. server.send(200, "text/html", message);
  362. #else
  363. ARDUINO_SEND_PARTIAL_PAGE();
  364. #endif
  365. }
  366. #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
  367. void handleReset() {
  368. String message;
  369. message += F("<!DOCTYPE html>");
  370. message += F("<html><head>");
  371. message += F("<meta charset='utf-8'/>");
  372. message += F("<meta name='viewport' content='width=device-width, initial-scale=1'/>");
  373. message += F("<meta http-equiv='refresh' content='10; URL=/'/>");
  374. message += F("<title>" ESP_PLATFORM_NAME " Environment Sensor</title>");
  375. message += F("<style>");
  376. message += F("@media (prefers-color-scheme: dark) {");
  377. message += F( "body {");
  378. message += F( "background-color: black;");
  379. message += F( "color: white;");
  380. message += F( "}");
  381. message += F("}");
  382. message += F("</style>");
  383. message += F("</head><body>");
  384. message += F("<p>Resetting in 2s...</p>");
  385. message += F("<p>Auto redirect in 10s. Please retry manually on error.</p>");
  386. message += F("<p>Go <a href=\"/\">back</a> to start.</p>");
  387. message += F("</body></html>");
  388. server.send(200, "text/html", message);
  389. delay(2000);
  390. ESP.restart();
  391. }
  392. #endif