webinterface.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. #include "webinterface.h"
  2. #include <WiFi.h>
  3. #include <WiFiClient.h>
  4. #include <WebServer.h>
  5. #include <WiFiAP.h>
  6. #include <ESPmDNS.h>
  7. #include <Update.h>
  8. #include "parameters.h"
  9. #include "romfs.h"
  10. #include "check_firmware.h"
  11. static WebServer server(80);
  12. /*
  13. serve files from ROMFS
  14. */
  15. class ROMFS_Handler : public RequestHandler
  16. {
  17. bool canHandle(HTTPMethod method, String uri) {
  18. if (uri == "/") {
  19. uri = "/index.html";
  20. }
  21. uri = "web" + uri;
  22. if (ROMFS::exists(uri.c_str())) {
  23. return true;
  24. }
  25. return false;
  26. }
  27. bool handle(WebServer& server, HTTPMethod requestMethod, String requestUri) {
  28. if (requestUri == "/") {
  29. requestUri = "/index.html";
  30. }
  31. String uri = "web" + requestUri;
  32. Serial.printf("handle: '%s'\n", requestUri.c_str());
  33. // work out content type
  34. const char *content_type = "text/html";
  35. const struct {
  36. const char *extension;
  37. const char *content_type;
  38. } extensions[] = {
  39. { ".js", "text/javascript" },
  40. { ".jpg", "image/jpeg" },
  41. { ".css", "text/css" },
  42. };
  43. for (const auto &e : extensions) {
  44. if (uri.endsWith(e.extension)) {
  45. content_type = e.content_type;
  46. break;
  47. }
  48. }
  49. auto *f = ROMFS::find_stream(uri.c_str());
  50. if (f != nullptr) {
  51. server.sendHeader("Content-Encoding", "gzip");
  52. server.streamFile(*f, content_type);
  53. delete f;
  54. return true;
  55. }
  56. return false;
  57. }
  58. } ROMFS_Handler;
  59. #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
  60. typedef struct {
  61. String name;
  62. String value;
  63. } json_table_t;
  64. /*
  65. create a json string from a table
  66. */
  67. static String json_format(const json_table_t *table, uint8_t n)
  68. {
  69. String s = "{";
  70. for (uint8_t i=0; i<n; i++) {
  71. const auto &t = table[i];
  72. s += "\"" + t.name + "\" : ";
  73. s += "\"" + t.value + "\"";
  74. if (i != n-1) {
  75. s += ",";
  76. }
  77. }
  78. s += "}";
  79. return s;
  80. }
  81. /*
  82. serve files from ROMFS
  83. */
  84. class AJAX_Handler : public RequestHandler
  85. {
  86. bool canHandle(HTTPMethod method, String uri) {
  87. Serial.printf("ajax check '%s'", uri);
  88. return uri == "/ajax/status.json";
  89. }
  90. bool handle(WebServer& server, HTTPMethod requestMethod, String requestUri) {
  91. if (requestUri != "/ajax/status.json") {
  92. return false;
  93. }
  94. const uint32_t now_s = millis() / 1000;
  95. const uint32_t sec = now_s % 60;
  96. const uint32_t min = (now_s / 60) % 60;
  97. const uint32_t hr = (now_s / 3600) % 24;
  98. const json_table_t table[] = {
  99. { "STATUS:VERSION", String(FW_VERSION_MAJOR) + "." + String(FW_VERSION_MINOR) },
  100. { "STATUS:UPTIME", String(hr) + ":" + String(min) + ":" + String(sec) },
  101. { "STATUS:FREEMEM", String(ESP.getFreeHeap()) },
  102. };
  103. server.send(200, "application/json", json_format(table, ARRAY_SIZE(table)));
  104. return true;
  105. }
  106. } AJAX_Handler;
  107. /*
  108. init web server
  109. */
  110. void WebInterface::init(void)
  111. {
  112. Serial.printf("WAP start %s %s\n", g.wifi_ssid, g.wifi_password);
  113. WiFi.softAP(g.wifi_ssid, g.wifi_password);
  114. IPAddress myIP = WiFi.softAPIP();
  115. server.addHandler( &ROMFS_Handler );
  116. server.addHandler( &AJAX_Handler );
  117. /*handling uploading firmware file */
  118. server.on("/update", HTTP_POST, []() {
  119. server.sendHeader("Connection", "close");
  120. server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK");
  121. ESP.restart();
  122. }, [this]() {
  123. HTTPUpload& upload = server.upload();
  124. if (upload.status == UPLOAD_FILE_START) {
  125. Serial.printf("Update: %s\n", upload.filename.c_str());
  126. lead_len = 0;
  127. if (!Update.begin(UPDATE_SIZE_UNKNOWN)) { //start with max available size
  128. Update.printError(Serial);
  129. }
  130. } else if (upload.status == UPLOAD_FILE_WRITE) {
  131. /* flashing firmware to ESP*/
  132. if (lead_len < sizeof(lead_bytes)) {
  133. uint32_t n = sizeof(lead_bytes)-lead_len;
  134. if (n > upload.currentSize) {
  135. n = upload.currentSize;
  136. }
  137. memcpy(&lead_bytes[lead_len], upload.buf, n);
  138. lead_len += n;
  139. }
  140. if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
  141. Update.printError(Serial);
  142. }
  143. } else if (upload.status == UPLOAD_FILE_END) {
  144. // write extra bytes to force flush of the buffer before we check signature
  145. uint32_t extra = SPI_FLASH_SEC_SIZE+1;
  146. while (extra--) {
  147. uint8_t ff = 0xff;
  148. Update.write(&ff, 1);
  149. }
  150. if (!CheckFirmware::check_OTA_next(lead_bytes, lead_len)) {
  151. Serial.printf("failed firmware check\n");
  152. } else if (Update.end(true)) {
  153. Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize);
  154. } else {
  155. Update.printError(Serial);
  156. }
  157. }
  158. });
  159. Serial.printf("WAP started\n");
  160. server.begin();
  161. }
  162. void WebInterface::update()
  163. {
  164. if (!initialised) {
  165. init();
  166. initialised = true;
  167. }
  168. server.handleClient();
  169. }