Fork of the espurna firmware for `mhsw` switches
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

230 lines
5.9 KiB

7 years ago
  1. /*
  2. OTA MODULE
  3. Copyright (C) 2016-2018 by Xose Pérez <xose dot perez at gmail dot com>
  4. */
  5. #include "ArduinoOTA.h"
  6. // -----------------------------------------------------------------------------
  7. // Arduino OTA
  8. // -----------------------------------------------------------------------------
  9. void _otaConfigure() {
  10. ArduinoOTA.setPort(OTA_PORT);
  11. ArduinoOTA.setHostname(getSetting("hostname").c_str());
  12. #if USE_PASSWORD
  13. ArduinoOTA.setPassword(getSetting("adminPass", ADMIN_PASS).c_str());
  14. #endif
  15. }
  16. void _otaLoop() {
  17. ArduinoOTA.handle();
  18. }
  19. // -----------------------------------------------------------------------------
  20. // Terminal OTA
  21. // -----------------------------------------------------------------------------
  22. #if TERMINAL_SUPPORT
  23. #include <ESPAsyncTCP.h>
  24. AsyncClient * _ota_client;
  25. char * _ota_host;
  26. char * _ota_url;
  27. unsigned long _ota_size = 0;
  28. const char OTA_REQUEST_TEMPLATE[] PROGMEM =
  29. "GET %s HTTP/1.1\r\n"
  30. "Host: %s\r\n"
  31. "User-Agent: ESPurna\r\n"
  32. "Connection: close\r\n"
  33. "Content-Type: application/x-www-form-urlencoded\r\n"
  34. "Content-Length: 0\r\n\r\n\r\n";
  35. void _otaFrom(const char * host, unsigned int port, const char * url) {
  36. if (_ota_host) free(_ota_host);
  37. if (_ota_url) free(_ota_url);
  38. _ota_host = strdup(host);
  39. _ota_url = strdup(url);
  40. _ota_size = 0;
  41. if (_ota_client == NULL) {
  42. _ota_client = new AsyncClient();
  43. }
  44. _ota_client->onDisconnect([](void *s, AsyncClient *c) {
  45. DEBUG_MSG_P(PSTR("\n"));
  46. if (Update.end(true)){
  47. DEBUG_MSG_P(PSTR("[OTA] Success: %u bytes\n"), _ota_size);
  48. deferredReset(100, CUSTOM_RESET_OTA);
  49. } else {
  50. #ifdef DEBUG_PORT
  51. Update.printError(DEBUG_PORT);
  52. #endif
  53. }
  54. DEBUG_MSG_P(PSTR("[OTA] Disconnected\n"));
  55. _ota_client->free();
  56. delete _ota_client;
  57. _ota_client = NULL;
  58. free(_ota_host);
  59. _ota_host = NULL;
  60. free(_ota_url);
  61. _ota_url = NULL;
  62. }, 0);
  63. _ota_client->onTimeout([](void *s, AsyncClient *c, uint32_t time) {
  64. _ota_client->close(true);
  65. }, 0);
  66. _ota_client->onData([](void * arg, AsyncClient * c, void * data, size_t len) {
  67. char * p = (char *) data;
  68. if (_ota_size == 0) {
  69. Update.runAsync(true);
  70. if (!Update.begin((ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000)) {
  71. #ifdef DEBUG_PORT
  72. Update.printError(DEBUG_PORT);
  73. #endif
  74. }
  75. p = strstr((char *)data, "\r\n\r\n") + 4;
  76. len = len - (p - (char *) data);
  77. }
  78. if (!Update.hasError()) {
  79. if (Update.write((uint8_t *) p, len) != len) {
  80. #ifdef DEBUG_PORT
  81. Update.printError(DEBUG_PORT);
  82. #endif
  83. }
  84. }
  85. _ota_size += len;
  86. DEBUG_MSG_P(PSTR("[OTA] Progress: %u bytes\r"), _ota_size);
  87. }, NULL);
  88. _ota_client->onConnect([](void * arg, AsyncClient * client) {
  89. DEBUG_MSG_P(PSTR("[OTA] Downloading %s\n"), _ota_url);
  90. char buffer[strlen_P(OTA_REQUEST_TEMPLATE) + strlen(_ota_url) + strlen(_ota_host)];
  91. snprintf_P(buffer, sizeof(buffer), OTA_REQUEST_TEMPLATE, _ota_url, _ota_host);
  92. client->write(buffer);
  93. }, NULL);
  94. bool connected = _ota_client->connect(host, port);
  95. if (!connected) {
  96. DEBUG_MSG_P(PSTR("[OTA] Connection failed\n"));
  97. _ota_client->close(true);
  98. }
  99. }
  100. void _otaFrom(String url) {
  101. // Port from protocol
  102. unsigned int port = 80;
  103. if (url.startsWith("https://")) port = 443;
  104. url = url.substring(url.indexOf("/") + 2);
  105. // Get host
  106. String host = url.substring(0, url.indexOf("/"));
  107. // Explicit port
  108. int p = host.indexOf(":");
  109. if (p > 0) {
  110. port = host.substring(p + 1).toInt();
  111. host = host.substring(0, p);
  112. }
  113. // Get URL
  114. String uri = url.substring(url.indexOf("/"));
  115. _otaFrom(host.c_str(), port, uri.c_str());
  116. }
  117. void _otaInitCommands() {
  118. settingsRegisterCommand(F("OTA"), [](Embedis* e) {
  119. if (e->argc < 2) {
  120. DEBUG_MSG_P(PSTR("-ERROR: Wrong arguments\n"));
  121. } else {
  122. DEBUG_MSG_P(PSTR("+OK\n"));
  123. String url = String(e->argv[1]);
  124. _otaFrom(url);
  125. }
  126. });
  127. }
  128. #endif // TERMINAL_SUPPORT
  129. // -----------------------------------------------------------------------------
  130. void otaSetup() {
  131. _otaConfigure();
  132. #if WEB_SUPPORT
  133. wsOnAfterParseRegister(_otaConfigure);
  134. #endif
  135. #if TERMINAL_SUPPORT
  136. _otaInitCommands();
  137. #endif
  138. // Register loop
  139. espurnaRegisterLoop(_otaLoop);
  140. // -------------------------------------------------------------------------
  141. ArduinoOTA.onStart([]() {
  142. DEBUG_MSG_P(PSTR("[OTA] Start\n"));
  143. #if WEB_SUPPORT
  144. wsSend_P(PSTR("{\"message\": 2}"));
  145. #endif
  146. });
  147. ArduinoOTA.onEnd([]() {
  148. DEBUG_MSG_P(PSTR("\n"));
  149. DEBUG_MSG_P(PSTR("[OTA] Done, restarting...\n"));
  150. #if WEB_SUPPORT
  151. wsSend_P(PSTR("{\"action\": \"reload\"}"));
  152. #endif
  153. deferredReset(100, CUSTOM_RESET_OTA);
  154. });
  155. ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
  156. DEBUG_MSG_P(PSTR("[OTA] Progress: %u%%\r"), (progress / (total / 100)));
  157. });
  158. ArduinoOTA.onError([](ota_error_t error) {
  159. #if DEBUG_SUPPORT
  160. DEBUG_MSG_P(PSTR("\n[OTA] Error #%u: "), error);
  161. if (error == OTA_AUTH_ERROR) DEBUG_MSG_P(PSTR("Auth Failed\n"));
  162. else if (error == OTA_BEGIN_ERROR) DEBUG_MSG_P(PSTR("Begin Failed\n"));
  163. else if (error == OTA_CONNECT_ERROR) DEBUG_MSG_P(PSTR("Connect Failed\n"));
  164. else if (error == OTA_RECEIVE_ERROR) DEBUG_MSG_P(PSTR("Receive Failed\n"));
  165. else if (error == OTA_END_ERROR) DEBUG_MSG_P(PSTR("End Failed\n"));
  166. #endif
  167. });
  168. ArduinoOTA.begin();
  169. }