AsyncElegantOTA.h 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. #ifndef AsyncElegantOTA_h
  2. #define AsyncElegantOTA_h
  3. #include "Arduino.h"
  4. #include "stdlib_noniso.h"
  5. #if defined(ESP8266)
  6. #include "ESP8266WiFi.h"
  7. #include "ESPAsyncTCP.h"
  8. #elif defined(ESP32)
  9. #include "WiFi.h"
  10. #include "AsyncTCP.h"
  11. #include "Update.h"
  12. #include "esp_int_wdt.h"
  13. #include "esp_task_wdt.h"
  14. #endif
  15. #include "ESPAsyncWebServer.h"
  16. #include "FS.h"
  17. #include "elegantWebpage.h"
  18. class AsyncElegantOtaClass{
  19. public:
  20. void setID(const char* id){
  21. _id = id;
  22. }
  23. void begin(AsyncWebServer *server, const char* username = "", const char* password = ""){
  24. _server = server;
  25. if(strlen(username) > 0){
  26. _authRequired = true;
  27. _username = username;
  28. _password = password;
  29. }else{
  30. _authRequired = false;
  31. _username = "";
  32. _password = "";
  33. }
  34. _server->on("/update/identity", HTTP_GET, [&](AsyncWebServerRequest *request){
  35. if(_authRequired){
  36. if(!request->authenticate(_username.c_str(), _password.c_str()))
  37. return request->requestAuthentication();
  38. }
  39. }
  40. #if defined(ESP8266)
  41. _server->send(200, "application/json", "{\"id\": "+_id+", \"hardware\": \"ESP8266\"}");
  42. #elif defined(ESP32)
  43. _server->send(200, "application/json", "{\"id\": "+_id+", \"hardware\": \"ESP32\"}");
  44. #endif
  45. });
  46. _server->on("/update", HTTP_GET, [&](AsyncWebServerRequest *request){
  47. if(_authRequired){
  48. if(!request->authenticate(_username.c_str(), _password.c_str()))
  49. return request->requestAuthentication();
  50. }
  51. }
  52. AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", ELEGANT_HTML, ELEGANT_HTML_SIZE);
  53. response->addHeader("Content-Encoding", "gzip");
  54. request->send(response);
  55. });
  56. _server->on("/update", HTTP_POST, [&](AsyncWebServerRequest *request) {
  57. if(_authRequired){
  58. if(!request->authenticate(_username.c_str(), _password.c_str()))
  59. return request->requestAuthentication();
  60. }
  61. }
  62. // the request handler is triggered after the upload has finished...
  63. // create the response, add header, and send response
  64. AsyncWebServerResponse *response = request->beginResponse((Update.hasError())?500:200, "text/plain", (Update.hasError())?"FAIL":"OK");
  65. response->addHeader("Connection", "close");
  66. response->addHeader("Access-Control-Allow-Origin", "*");
  67. request->send(response);
  68. restartRequired = true;
  69. }, [](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
  70. //Upload handler chunks in data
  71. if(_authRequired){
  72. if(!request->authenticate(_username.c_str(), _password.c_str()))
  73. return request->requestAuthentication();
  74. }
  75. }
  76. if (!index) {
  77. int cmd = (filename.indexOf("spiffs") > -1) ? U_FS : U_FLASH;
  78. #if defined(ESP8266)
  79. Update.runAsync(true);
  80. size_t fsSize = ((size_t) &_FS_end - (size_t) &_FS_start);
  81. uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
  82. if (!Update.begin((cmd == U_FS)?fsSize:maxSketchSpace, cmd)){ // Start with max available size
  83. #elif defined(ESP32)
  84. if (!Update.begin(UPDATE_SIZE_UNKNOWN, cmd)) { // Start with max available size
  85. #endif
  86. Update.printError(Serial);
  87. return request->send(400, "text/plain", "OTA could not begin");
  88. }
  89. }
  90. // Write chunked data to the free sketch space
  91. if(len){
  92. if (Update.write(data, len) != len) {
  93. Update.printError(Serial);
  94. return request->send(400, "text/plain", "OTA could not begin");
  95. }
  96. }
  97. if (final) { // if the final flag is set then this is the last frame of data
  98. if (!Update.end(true)) { //true to set the size to the current progress
  99. Update.printError(Serial);
  100. return request->send(400, "text/plain", "Could not end OTA");
  101. }
  102. }else{
  103. return;
  104. }
  105. });
  106. }
  107. void loop(){
  108. if(restartRequired){
  109. yield();
  110. delay(1000);
  111. yield();
  112. #if defined(ESP8266)
  113. ESP.restart();
  114. #elif defined(ESP32)
  115. // ESP32 will commit sucide
  116. esp_task_wdt_init(1,true);
  117. esp_task_wdt_add(NULL);
  118. while(true);
  119. #endif
  120. }
  121. }
  122. private:
  123. AsyncWebServer *_server;
  124. String _id = String(ESP.getChipId());
  125. String _username = "";
  126. String _password = "";
  127. bool _authRequired = false;
  128. bool restartRequired = false;
  129. };
  130. AsyncElegantOtaClass AsyncElegantOTA;
  131. #endif