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.

my_OTA.h 9.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. /**
  2. Bibliothèque pour avoir une mise à jour Over The Air d'un code source.
  3. Utilisation :
  4. Dans le setup, rajouter OTA_setup();
  5. Dans la loop, rajouter OTA_doUpdate();
  6. Fonctionnement :
  7. Toutes les OTA_TimerInSecond secondes, le programme va vérifier qu'il y a une mise à jour sur le serveur.
  8. Si une mise à jour existe, elle est téléchargée et installé et l'ESP reboot.
  9. S'il n'y a pas de mise à jour, le serveur le dit et on ne fait rien.
  10. Avant toutes upload de ce script dans un Arduino, il faut executer un script Python de récupération de certificats qui
  11. se trouve sur le repot https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WiFi/examples/BearSSL_CertStore/certs-from-mozilla.py
  12. */
  13. #include <ESP8266WiFi.h>
  14. #include <ESP8266WiFiMulti.h>
  15. #include <ESP8266HTTPClient.h>
  16. #include <ESP8266httpUpdate.h>
  17. char outputBuffer[100]; // Pour les messages à afficher
  18. char macAdresse[12];
  19. // Fait un serveur de mise à jour local dans l'ESP
  20. #include <ESP8266HTTPUpdateServer.h>
  21. #include <ESP8266WebServer.h>
  22. ESP8266WebServer OTA_HttpServer(80);
  23. ESP8266HTTPUpdateServer OTA_httpUpdater;
  24. const char* OTA_update_username = "ESPadmin";
  25. const char* OTA_update_password = "admin";
  26. const char* OTA_update_path = "/firmware";
  27. boolean g_BOO_UpdateFirmware = true;
  28. const String firmwareUrlMiseAJour = "https://update.alex-design.fr/MQTT-leds-color/update.php";
  29. const String fileSystemUrlMiseAJour = "https://update.alex-design.fr/MQTT-leds-color/updateFS.php";
  30. //const String firmwareUrlMiseAJour = "http://192.168.0.32:9090/MQTT-leds-color/update.php"; <- Ne peut pas fonctionner car il est en http, et on veut du https
  31. // Define global variable to know if upate is available
  32. long OTA_UpdateTimer;
  33. const int OTA_TimerInSecond = 60 * 10; // every 10 minute
  34. // Utilisation d'un certificat ------------------------------------------
  35. // Pour mettre à jour l'heure (obligatoire avec un certificat https)
  36. #include <time.h>
  37. // A single, global CertStore which can be used by all
  38. // connections. Needs to stay live the entire time any of
  39. // the WiFiClientBearSSLs are present.
  40. #include <CertStoreBearSSL.h>
  41. BearSSL::CertStore certStore;
  42. #include <FS.h>
  43. #include <LittleFS.h>
  44. char versionLitteFS[10] = "0.0.0";
  45. // Define a wifi client
  46. ESP8266WiFiMulti WiFiMulti;
  47. /**
  48. ----------------------------------------------------------------------------------------------------------------
  49. Callback lorsque la maj OTA démarre
  50. */
  51. void _update_started() {
  52. DEBUG("CALLBACK: HTTPS update process started");
  53. }
  54. /**
  55. ----------------------------------------------------------------------------------------------------------------
  56. Callback lorsque la maj OTA est terminée
  57. */
  58. void _update_finished() {
  59. DEBUG("CALLBACK: HTTPS update process finished. Reboot");
  60. }
  61. /**
  62. ----------------------------------------------------------------------------------------------------------------
  63. Callback lorsque la maj OTA est en cours
  64. */
  65. void _update_progress(int cur, int total) {
  66. sprintf(outputBuffer, "CALLBACK: HTTPS update process at %d of %d bytes...", cur, total);
  67. DEBUG( outputBuffer );
  68. }
  69. /**
  70. ----------------------------------------------------------------------------------------------------------------
  71. Callback lorsque la maj OTA a plantée
  72. */
  73. void _update_error(int err) {
  74. sprintf(outputBuffer, "CALLBACK: HTTPS update fatal error code %d\n", err);
  75. DEBUG( outputBuffer );
  76. if (err == -103) {
  77. DEBUG(" Please allow me, I am ");
  78. DEBUG(WiFi.macAddress());
  79. DEBUG(WiFi.localIP());
  80. }
  81. if ( err == 0 ) {
  82. DEBUG("La mise à jour du firmware via OTA n'a pas marché, on stop !!!!!!!!!!!!");
  83. g_BOO_UpdateFirmware = false;
  84. }
  85. }
  86. /**
  87. ----------------------------------------------------------------------------------------------------------------
  88. Set time via NTP, as required for x.509 validation
  89. ----------------------------------------------------------------------------------------------------------------
  90. */
  91. void OTA_setClock() {
  92. configTime(0, 0, "pool.ntp.org", "time.nist.gov"); // UTC
  93. DEBUG("OTA Waiting for NTP time sync: ");
  94. time_t now = time(nullptr);
  95. while (now < 8 * 3600 * 2) {
  96. yield();
  97. delay(500);
  98. Serial.print(F("."));
  99. now = time(nullptr);
  100. }
  101. struct tm timeinfo;
  102. gmtime_r(&now, &timeinfo);
  103. DEBUG("Current time: ");
  104. DEBUG(asctime(&timeinfo));
  105. }
  106. /**
  107. ----------------------------------------------------------------------------------------------------------------
  108. Initialisation d'une connexion wifi à l'aide des settings de wifimanager en eeprom.
  109. ----------------------------------------------------------------------------------------------------------------
  110. */
  111. void OTA_setup() {
  112. /* Mise en place d'un serveur pour uploader directement un binaire */
  113. OTA_httpUpdater.setup(&OTA_HttpServer, OTA_update_path, OTA_update_username, OTA_update_password);
  114. OTA_HttpServer.begin();
  115. sprintf(outputBuffer, "OTA HTTPUpdateServer ready! Open http://%d.%d.%d.%d%s in your browser and login with username '%s' and password '%s'\n",
  116. WiFi.localIP()[0], WiFi.localIP()[1], WiFi.localIP()[2], WiFi.localIP()[3], OTA_update_path, OTA_update_username, OTA_update_password);
  117. DEBUG(outputBuffer);
  118. MQTT_publishDebug(String(outputBuffer));
  119. // Test la version du file system littleFS en place
  120. if ( !LittleFS.begin()) {
  121. DEBUG("Il n'y a pas de file system little FS installé, lecture impossible !");
  122. } else {
  123. // Get version of the certificat in LittleFS (frome file version.txt
  124. File file = LittleFS.open("/version.txt", "r");
  125. if ( file ) {
  126. while (file.available()) {
  127. strcpy(versionLitteFS, file.readString().c_str() );
  128. }
  129. file.close();
  130. }
  131. // Récupération des CA stockés dans LittleFS pour les certificats SSL
  132. int numCerts = certStore.initCertStore(LittleFS, PSTR("/certs.idx"), PSTR("/certs.ar"));
  133. DEBUG("Number of CA certs read: ");
  134. DEBUG(numCerts);
  135. if (numCerts == 0) {
  136. DEBUG(F("No certs found. Did you run certs-from-mozill.py and upload the LittleFS directory before running?"));
  137. }
  138. }
  139. DEBUG("Numéro de version de littleFS : " + String(versionLitteFS) );
  140. // Création de la connection Wifi à partir du SSID et PWD sauvé par wifimanager
  141. /*
  142. WiFi.mode(WIFI_STA);
  143. WiFiMulti.addAP(wifiManager.getWiFiSSID(true).c_str(), wifiManager.getWiFiPass(true).c_str());
  144. */
  145. // We will request a firmware update in OTA_TimerInSecond secondes
  146. OTA_UpdateTimer = (OTA_TimerInSecond * 1000);
  147. }
  148. /**
  149. ----------------------------------------------------------------------------------------------------------------
  150. Va voir sur l'URL si une mise à jour du firmware est disponible. Si c'est le cas,
  151. la télécharge et met à jour le firmeware.
  152. ----------------------------------------------------------------------------------------------------------------
  153. */
  154. boolean OTA_doUpdate() {
  155. // Si on a pas besoin de faire de mise à jour (ou ça c'est planté la dernière fois)
  156. if ( !g_BOO_UpdateFirmware ) {
  157. return false;
  158. }
  159. // Fait tourner le serveur http sur l'ESP
  160. // Lorsqu'on se connect à ce serveur, il est possible d'uploader un firmware ou un filesystem
  161. OTA_HttpServer.handleClient();
  162. // Check is this is the time to check a new update
  163. delay( 1 ); // Wait 1 milliseconde
  164. if (OTA_UpdateTimer > 0 ) {
  165. OTA_UpdateTimer--;
  166. return false;
  167. }
  168. if (WiFiMulti.run() == WL_CONNECTED) {
  169. // WiFiClient client; // Client simple (incompatioble en https )
  170. // Mise à jour de l'heure via un serveur NTP
  171. OTA_setClock();
  172. // Récupération du certificat SSL pour la connexion https
  173. BearSSL::WiFiClientSecure client; // Client securise
  174. bool mfln = client.probeMaxFragmentLength(fileSystemUrlMiseAJour, 443, 1024); // server must be the same as in ESPhttpUpdate.update()
  175. if (mfln) {
  176. client.setBufferSizes(1024, 1024);
  177. }
  178. client.setCertStore(&certStore);
  179. // Add optional callback notifiers
  180. ESPhttpUpdate.onStart(_update_started);
  181. ESPhttpUpdate.onEnd(_update_finished);
  182. ESPhttpUpdate.onProgress(_update_progress);
  183. ESPhttpUpdate.onError(_update_error);
  184. ESPhttpUpdate.setLedPin(LED_BUILTIN, LOW);
  185. // Get the mac adresse in a char
  186. snprintf(macAdresse, 12, "%06X", (uint32_t)ESP.getChipId() );
  187. // Try to update the filesystem
  188. DEBUG(fileSystemUrlMiseAJour + "?chipID=" + String(macAdresse) );
  189. t_httpUpdate_return ret = ESPhttpUpdate.updateFS(client, fileSystemUrlMiseAJour + "?chipID=" + String(macAdresse), versionLitteFS);
  190. if (ret == HTTP_UPDATE_OK) {
  191. DEBUG("Update FileSystem Successfully");
  192. }
  193. // Try to update the firmware
  194. DEBUG(firmwareUrlMiseAJour + "?chipID=" + String(macAdresse) );
  195. DEBUG("Version firmware :" + firmwareActualVersion );
  196. ret = ESPhttpUpdate.update(client, firmwareUrlMiseAJour + "?chipID=" + String(macAdresse), firmwareActualVersion);
  197. switch (ret) {
  198. case HTTP_UPDATE_FAILED:
  199. sprintf(outputBuffer, "HTTP_UPDATE_FAILED Error (%d): %s\n", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
  200. DEBUG( outputBuffer );
  201. OTA_UpdateTimer = (OTA_TimerInSecond * 1000);
  202. break;
  203. case HTTP_UPDATE_NO_UPDATES:
  204. DEBUG("No new update available");
  205. OTA_UpdateTimer = (OTA_TimerInSecond * 1000);
  206. break;
  207. default:
  208. break;
  209. }
  210. return true;
  211. }
  212. return false;
  213. }