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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  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("Location: ");
  97. message += SENSOR_LOCATION;
  98. message += F("\n<br>\n");
  99. message += F("ID: ");
  100. message += SENSOR_ID;
  101. #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
  102. message += F("\n<br>\n");
  103. message += F("MAC: ");
  104. message += WiFi.macAddress();
  105. #endif
  106. message += F("\n</p>\n");
  107. ARDUINO_SEND_PARTIAL_PAGE();
  108. #if defined(ARDUINO_ARCH_ESP8266)
  109. message += F("<p>");
  110. message += F("Reset reason: ");
  111. message += ESP.getResetReason();
  112. message += F("<br>");
  113. message += F("Free heap: ");
  114. message += String(ESP.getFreeHeap());
  115. message += F(" (");
  116. message += String(ESP.getHeapFragmentation());
  117. message += F("% fragmentation)");
  118. message += F("<br>");
  119. message += F("Free sketch space: ");
  120. message += String(ESP.getFreeSketchSpace());
  121. message += F("<br>");
  122. message += F("Flash chip real size: ");
  123. message += String(ESP.getFlashChipRealSize());
  124. if (ESP.getFlashChipSize() != ESP.getFlashChipRealSize()) {
  125. message += F("<br>");
  126. message += F("WARNING: sdk chip size (");
  127. message += (ESP.getFlashChipSize());
  128. message += F(") does not match!");
  129. }
  130. message += F("</p>");
  131. #elif defined(ARDUINO_ARCH_ESP32)
  132. message += F("<p>");
  133. message += F("Free heap: ");
  134. message += String(ESP.getFreeHeap() / 1024.0);
  135. message += F("k<br>");
  136. message += F("Free sketch space: ");
  137. message += String(ESP.getFreeSketchSpace() / 1024.0);
  138. message += F("k<br>");
  139. message += F("Flash chip size: ");
  140. message += String(ESP.getFlashChipSize() / 1024.0);
  141. message += F("k</p><hr>");
  142. #endif
  143. #ifdef ENABLE_BME280
  144. message += F("\n<p>\n");
  145. if (found_bme1) {
  146. message += F("BME280 Low:");
  147. message += F("\n<br>\n");
  148. message += F("Temperature: ");
  149. message += String(bme1_temp());
  150. message += F("\n<br>\n");
  151. message += F("Humidity: ");
  152. message += String(bme1_humid());
  153. message += F("\n<br>\n");
  154. message += F("Pressure: ");
  155. message += String(bme1_pressure());
  156. message += F("\n<br>\n");
  157. message += F("Offset: ");
  158. message += String(config.bme1_temp_off);
  159. message += F("\n<br>\n");
  160. message += F("<form method=\"GET\" action=\"/calibrate\">");
  161. message += F("<input type=\"text\" name=\"bme1\" placeholder=\"Real Temp.\">");
  162. message += F("<input type=\"submit\" value=\"Calibrate\">");
  163. message += F("</form>");
  164. } else {
  165. message += F("BME280 (low) not connected!");
  166. }
  167. message += F("\n</p><hr>\n");
  168. message += F("\n<p>\n");
  169. if (found_bme2) {
  170. message += F("BME280 High:");
  171. message += F("\n<br>\n");
  172. message += F("Temperature: ");
  173. message += String(bme2_temp());
  174. message += F("\n<br>\n");
  175. message += F("Humidity: ");
  176. message += String(bme2_humid());
  177. message += F("\n<br>\n");
  178. message += F("Pressure: ");
  179. message += String(bme2_pressure());
  180. message += F("\n<br>\n");
  181. message += F("Offset: ");
  182. message += String(config.bme2_temp_off);
  183. message += F("\n<br>\n");
  184. message += F("<form method=\"GET\" action=\"/calibrate\">");
  185. message += F("<input type=\"text\" name=\"bme2\" placeholder=\"Real Temp.\">");
  186. message += F("<input type=\"submit\" value=\"Calibrate\">");
  187. message += F("</form>");
  188. } else {
  189. message += F("BME280 (high) not connected!");
  190. }
  191. message += F("\n</p><hr>\n");
  192. #endif // ENABLE_BME280
  193. ARDUINO_SEND_PARTIAL_PAGE();
  194. message += F("\n<p>\n");
  195. if (found_sht) {
  196. message += F("SHT21:");
  197. message += F("\n<br>\n");
  198. message += F("Temperature: ");
  199. message += String(sht_temp());
  200. message += F("\n<br>\n");
  201. message += F("Humidity: ");
  202. message += String(sht_humid());
  203. message += F("\n<br>\n");
  204. message += F("Offset: ");
  205. message += String(config.sht_temp_off);
  206. message += F("\n<br>\n");
  207. message += F("<form method=\"GET\" action=\"/calibrate\">");
  208. message += F("<input type=\"text\" name=\"sht\" placeholder=\"Real Temp.\">");
  209. message += F("<input type=\"submit\" value=\"Calibrate\">");
  210. message += F("</form>");
  211. } else {
  212. message += F("SHT21 not connected!");
  213. }
  214. message += F("\n</p><hr>\n");
  215. #ifdef ENABLE_CCS811
  216. message += F("\n<p>\n");
  217. if (found_ccs1) {
  218. message += F("CCS811 Low:");
  219. message += F("\n<br>\n");
  220. message += F("eCO2: ");
  221. message += String(ccs1_eco2());
  222. message += F("ppm");
  223. message += F("\n<br>\n");
  224. message += F("TVOC: ");
  225. message += String(ccs1_tvoc());
  226. message += F("ppb");
  227. if (!ccs1_data_valid) {
  228. message += F("\n<br>\n");
  229. message += F("Data invalid (");
  230. message += String(ccs1_error_code);
  231. message += F(")!");
  232. }
  233. } else {
  234. message += F("CCS811 (Low) not connected!");
  235. }
  236. message += F("\n</p><hr>\n");
  237. message += F("\n<p>\n");
  238. if (found_ccs2) {
  239. message += F("CCS811 High:");
  240. message += F("\n<br>\n");
  241. message += F("eCO2: ");
  242. message += String(ccs2_eco2());
  243. message += F("ppm");
  244. message += F("\n<br>\n");
  245. message += F("TVOC: ");
  246. message += String(ccs2_tvoc());
  247. message += F("ppb");
  248. if (!ccs2_data_valid) {
  249. message += F("\n<br>\n");
  250. message += F("Data invalid (");
  251. message += String(ccs2_error_code);
  252. message += F(")!");
  253. }
  254. } else {
  255. message += F("CCS811 (High) not connected!");
  256. }
  257. message += F("\n</p><hr>\n");
  258. #endif // ENABLE_CCS811
  259. ARDUINO_SEND_PARTIAL_PAGE();
  260. #ifdef FEATURE_MOISTURE
  261. for (int i = 0; i < moisture_count(); i++) {
  262. int moisture = moisture_read(i);
  263. if (moisture < moisture_max()) {
  264. message += F("\n<p>\n");
  265. message += F("Sensor ");
  266. message += String(i + 1);
  267. message += F(":\n<br>\n");
  268. message += F("Moisture: ");
  269. message += String(moisture);
  270. message += F(" / ");
  271. message += String(moisture_max());
  272. message += F("\n</p>\n");
  273. }
  274. }
  275. if (moisture_count() <= 0) {
  276. message += F("\n<p>\n");
  277. message += F("No moisture sensors configured!");
  278. message += F("\n</p>\n");
  279. }
  280. ARDUINO_SEND_PARTIAL_PAGE();
  281. #endif // FEATURE_MOISTURE
  282. #ifdef FEATURE_RELAIS
  283. message += F("\n<p>\n");
  284. for (int i = 0; i < relais_count(); i++) {
  285. 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"));
  286. 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"));
  287. }
  288. message += String(F("<a href=\"/on?id=")) + String(relais_count()) + String(F("\">All Relais On</a><br>\n"));
  289. message += String(F("<a href=\"/off?id=")) + String(relais_count()) + String(F("\">All Relais Off</a><br>\n"));
  290. message += F("</p>\n");
  291. if ((mode >= 0) && (mode <= 1)) {
  292. message += F("<p>");
  293. message += F("Turned Relais ");
  294. message += (id < relais_count()) ? String(id) : String(F("1-4"));
  295. message += (mode ? String(F(" On")) : String(F(" Off")));
  296. message += F("</p>\n");
  297. }
  298. message += F("\n<p>\n");
  299. for (int i = 0; i < relais_count(); i++) {
  300. 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"));
  301. }
  302. message += F("</p>\n");
  303. ARDUINO_SEND_PARTIAL_PAGE();
  304. #endif // FEATURE_RELAIS
  305. if (mode == 42) {
  306. message += F("<p>New calibration value saved!</p>\n");
  307. }
  308. #if ! defined(ARDUINO_ARCH_AVR)
  309. message += F("<p>");
  310. message += F("Try <a href=\"/update\">/update</a> for OTA firmware updates!");
  311. message += F("</p><p>");
  312. message += F("Try <a href=\"/reset\">/reset</a> to reset ESP!");
  313. message += F("</p>");
  314. #endif
  315. message += F("<p>");
  316. #ifdef ENABLE_INFLUXDB_LOGGING
  317. message += F("InfluxDB: ");
  318. message += INFLUXDB_DATABASE;
  319. message += F(" @ ");
  320. message += INFLUXDB_HOST;
  321. message += F(":");
  322. message += String(INFLUXDB_PORT);
  323. #else
  324. message += F("InfluxDB logging not enabled!");
  325. #endif
  326. message += F("</p>");
  327. message += F("<p>Uptime: ");
  328. message += String(millis() / 1000);
  329. message += F(" sec.</p>");
  330. #ifdef ENABLE_DEBUGLOG
  331. message += F("<hr><p>Debug Log:</p>");
  332. message += F("<div class='log'><pre id='logbuf'>");
  333. message += debug.getBuffer();
  334. message += F("</pre></div>");
  335. #endif // ENABLE_DEBUGLOG
  336. message += F("</body>");
  337. #ifdef ENABLE_WEBSOCKETS
  338. message += F("<script type='text/javascript'>\n");
  339. message += F("var socket = new WebSocket('ws://' + window.location.hostname + ':81');\n");
  340. message += F("socket.onmessage = function(e) {");
  341. message += F( "var log = document.getElementById('logbuf');");
  342. message += F( "var div = document.getElementsByClassName('log')[0];");
  343. message += F( "log.innerHTML += e.data.substring(4);");
  344. message += F( "if (log.innerHTML.length > (1024 * 1024)) {");
  345. message += F( "log.innerHTML = log.innerHTML.substring(1024 * 1024);");
  346. message += F( "}");
  347. message += F( "div.scrollTop = div.scrollHeight;");
  348. message += F("};\n");
  349. message += F("var hist = document.getElementsByClassName('log')[0];\n");
  350. message += F("hist.scrollTop = hist.scrollHeight;\n");
  351. message += F("</script>\n");
  352. #endif // ENABLE_WEBSOCKETS
  353. message += F("</html>");
  354. #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
  355. server.send(200, "text/html", message);
  356. #else
  357. ARDUINO_SEND_PARTIAL_PAGE();
  358. #endif
  359. }
  360. #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
  361. void handleReset() {
  362. String message;
  363. message += F("<!DOCTYPE html>");
  364. message += F("<html><head>");
  365. message += F("<meta charset='utf-8'/>");
  366. message += F("<meta name='viewport' content='width=device-width, initial-scale=1'/>");
  367. message += F("<meta http-equiv='refresh' content='10; URL=/'/>");
  368. message += F("<title>" ESP_PLATFORM_NAME " Environment Sensor</title>");
  369. message += F("<style>");
  370. message += F("@media (prefers-color-scheme: dark) {");
  371. message += F( "body {");
  372. message += F( "background-color: black;");
  373. message += F( "color: white;");
  374. message += F( "}");
  375. message += F("}");
  376. message += F("</style>");
  377. message += F("</head><body>");
  378. message += F("<p>Resetting in 2s...</p>");
  379. message += F("<p>Auto redirect in 10s. Please retry manually on error.</p>");
  380. message += F("<p>Go <a href=\"/\">back</a> to start.</p>");
  381. message += F("</body></html>");
  382. server.send(200, "text/html", message);
  383. delay(2000);
  384. ESP.restart();
  385. }
  386. #endif