From 8965358bd3acf77db2921caabcd6bea3f180110c Mon Sep 17 00:00:00 2001 From: Arvind Ravulavaru Date: Wed, 14 Jun 2017 13:42:39 +0530 Subject: [PATCH] added OTA Update S3 example with a sample bin (#445) * added OTA Update S3 example with a sample bin * Update as per comments --- .../AWS_S3_OTA_Update/AWS_S3_OTA_Update.ino | 276 ++++++++++++++++++ .../AWS_S3_OTA_Update/StartCounter.ino.bin | Bin 0 -> 357280 bytes 2 files changed, 276 insertions(+) create mode 100644 libraries/Update/examples/AWS_S3_OTA_Update/AWS_S3_OTA_Update.ino create mode 100644 libraries/Update/examples/AWS_S3_OTA_Update/StartCounter.ino.bin diff --git a/libraries/Update/examples/AWS_S3_OTA_Update/AWS_S3_OTA_Update.ino b/libraries/Update/examples/AWS_S3_OTA_Update/AWS_S3_OTA_Update.ino new file mode 100644 index 00000000..432f2eeb --- /dev/null +++ b/libraries/Update/examples/AWS_S3_OTA_Update/AWS_S3_OTA_Update.ino @@ -0,0 +1,276 @@ +/** + AWS S3 OTA Update + Date: 14th June 2017 + Author: Arvind Ravulavaru + Purpose: Perform an OTA update from a bin located in Amazon S3 (HTTP Only) + + Upload: + Step 1 : Download the sample bin file from the examples folder + Step 2 : Upload it to your Amazon S3 account, in a bucket of your choice + Step 3 : Once uploaded, inside S3, select the bin file >> More (button on top of the file list) >> Make Public + Step 4 : You S3 URL => http://bucket-name.s3.ap-south-1.amazonaws.com/sketch-name.ino.bin + Step 5 : Build the above URL and fire it either in your browser or curl it `curl -I -v http://bucket-name.ap-south-1.amazonaws.com/sketch-name.ino.bin` to validate the same + Step 6: Plug in your SSID, Password, S3 Host and Bin file below + + Build & upload + Step 1 : Menu > Sketch > Export Compiled Library. The bin file will be saved in the sketch folder (Menu > Sketch > Show Sketch folder) + Step 2 : Upload bin to S3 and continue the above process + + // Check the bottom of this sketch for sample serial monitor log, during and after successful OTA Update +*/ + +#include +#include + +WiFiClient client; + +// Variables to validate +// response from S3 +int contentLength = 0; +bool isValidContentType = false; + +// Your SSID and PSWD that the chip needs +// to connect to +char* SSID = "YOUR-SSID"; +char* PSWD = "YOUR-SSID-PSWD"; + +// S3 Bucket Config +String host = "bucket-name.s3.ap-south-1.amazonaws.com"; // Host => bucket-name.s3.region.amazonaws.com +int port = 80; // Non https. For HTTPS 443. As of today, HTTPS doesn't work. +String bin = "/sketch-name.ino.bin"; // bin file name with a slash in front. + +// Utility to extract header value from headers +String getHeaderValue(String header, String headerName) { + return header.substring(strlen(headerName.c_str())); +} + +// OTA Logic +void execOTA() { + Serial.println("Connecting to: " + String(host)); + // Connect to S3 + if (client.connect(host.c_str(), port)) { + // Connection Succeed. + // Fecthing the bin + Serial.println("Fetching Bin: " + String(bin)); + + // Get the contents of the bin file + client.print(String("GET ") + bin + " HTTP/1.1\r\n" + + "Host: " + host + "\r\n" + + "Cache-Control: no-cache\r\n" + + "Connection: close\r\n\r\n"); + + // Check what is being sent + // Serial.print(String("GET ") + bin + " HTTP/1.1\r\n" + + // "Host: " + host + "\r\n" + + // "Cache-Control: no-cache\r\n" + + // "Connection: close\r\n\r\n"); + + delay(100); + // Once the response is available, + // check stuff + + /* + Response Structure + HTTP/1.1 200 OK + x-amz-id-2: NVKxnU1aIQMmpGKhSwpCBh8y2JPbak18QLIfE+OiUDOos+7UftZKjtCFqrwsGOZRN5Zee0jpTd0= + x-amz-request-id: 2D56B47560B764EC + Date: Wed, 14 Jun 2017 03:33:59 GMT + Last-Modified: Fri, 02 Jun 2017 14:50:11 GMT + ETag: "d2afebbaaebc38cd669ce36727152af9" + Accept-Ranges: bytes + Content-Type: application/octet-stream + Content-Length: 357280 + Server: AmazonS3 + + {{BIN FILE CONTENTS}} + + */ + while (client.available()) { + // read line till /n + String line = client.readStringUntil('\n'); + // remove space, to check if the line is end of headers + line.trim(); + + // if the the line is empty, + // this is end of headers + // break the while and feed the + // remaining `client` to the + // Update.writeStream(); + if (!line.length()) { + //headers ended + break; // and get the OTA started + } + + // Check if the HTTP Response is 200 + // else break and Exit Update + if (line.startsWith("HTTP/1.1")) { + if (line.indexOf("200") < 0) { + Serial.println("Got a non 200 status code from server. Exiting OTA Update."); + break; + } + } + + // extract headers here + // Start with content length + if (line.startsWith("Content-Length: ")) { + contentLength = atoi((getHeaderValue(line, "Content-Length: ")).c_str()); + Serial.println("Got " + String(contentLength) + " bytes from server"); + } + + // Next, the content type + if (line.startsWith("Content-Type: ")) { + String contentType = getHeaderValue(line, "Content-Type: "); + Serial.println("Got " + contentType + " payload."); + if (contentType == "application/octet-stream") { + isValidContentType = true; + } + } + } + } else { + // Connect to S3 failed + // May be try? + // Probably a choppy network? + Serial.println("Connection to " + String(host) + " failed. Please check your setup"); + // retry?? + // execOTA(); + } + + // Check what is the contentLength and if content type is `application/octet-stream` + Serial.println("contentLength : " + String(contentLength) + ", isValidContentType : " + String(isValidContentType)); + + // check contentLength and content type + if (contentLength && isValidContentType) { + // Check if there is enough to OTA Update + bool canBegin = Update.begin(contentLength); + + // If yes, begin + if (canBegin) { + Serial.println("Begin OTA. This may take 2 - 5 mins to complete. Things might be quite for a while.. Patience!"); + // No activity would appear on the Serial monitor + // So be patient. This may take 2 - 5mins to complete + size_t written = Update.writeStream(client); + + if (written == contentLength) { + Serial.println("Written : " + String(written) + " successfully"); + } else { + Serial.println("Written only : " + String(written) + "/" + String(contentLength) + ". Retry?" ); + // retry?? + // execOTA(); + } + + if (Update.end()) { + Serial.println("OTA done!"); + if (Update.isFinished()) { + Serial.println("Update successfully completed. Rebooting."); + ESP.restart(); + } else { + Serial.println("Update not finished? Something went wrong!"); + } + } else { + Serial.println("Error Occurred. Error #: " + String(Update.getError())); + } + } else { + // not enough space to begin OTA + // Understand the partitions and + // space availability + Serial.println("Not enough space to begin OTA"); + client.flush(); + } + } else { + Serial.println("There was no content in the response"); + client.flush(); + } +} + +void setup() { + //Begin Serial + Serial.begin(115200); + delay(10); + + Serial.println("Connecting to " + String(SSID)); + + // Connect to provided SSID and PSWD + WiFi.begin(SSID, PSWD); + + // Wait for connection to establish + while (WiFi.status() != WL_CONNECTED) { + Serial.print("."); // Keep the serial monitor lit! + delay(500); + } + + // Connection Succeed + Serial.println(""); + Serial.println("Connected to " + String(SSID)); + + // Execute OTA Update + execOTA(); +} + +void loop() { + // chill +} + +/* + * Serial Monitor log for this sketch + * + * If the OTA succeeded, it would load the preference sketch, with a small modification. i.e. + * Print `OTA Update succeeded!! This is an example sketch : Preferences > StartCounter` + * And then keeps on restarting every 10 seconds, updating the preferences + * + * + rst:0x10 (RTCWDT_RTC_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) + configsip: 0, SPIWP:0x00 + clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 + mode:DIO, clock div:1 + load:0x3fff0008,len:8 + load:0x3fff0010,len:160 + load:0x40078000,len:10632 + load:0x40080000,len:252 + entry 0x40080034 + Connecting to SSID + ...... + Connected to SSID + Connecting to: bucket-name.s3.ap-south-1.amazonaws.com + Fetching Bin: /StartCounter.ino.bin + Got application/octet-stream payload. + Got 357280 bytes from server + contentLength : 357280, isValidContentType : 1 + Begin OTA. This may take 2 - 5 mins to complete. Things might be quite for a while.. Patience! + Written : 357280 successfully + OTA done! + Update successfully completed. Rebooting. + ets Jun 8 2016 00:22:57 + + rst:0x10 (RTCWDT_RTC_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) + configsip: 0, SPIWP:0x00 + clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 + mode:DIO, clock div:1 + load:0x3fff0008,len:8 + load:0x3fff0010,len:160 + load:0x40078000,len:10632 + load:0x40080000,len:252 + entry 0x40080034 + + OTA Update succeeded!! This is an example sketch : Preferences > StartCounter + Current counter value: 1 + Restarting in 10 seconds... + E (102534) wifi: esp_wifi_stop 802 wifi is not init + ets Jun 8 2016 00:22:57 + + rst:0x10 (RTCWDT_RTC_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) + configsip: 0, SPIWP:0x00 + clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 + mode:DIO, clock div:1 + load:0x3fff0008,len:8 + load:0x3fff0010,len:160 + load:0x40078000,len:10632 + load:0x40080000,len:252 + entry 0x40080034 + + OTA Update succeeded!! This is an example sketch : Preferences > StartCounter + Current counter value: 2 + Restarting in 10 seconds... + + .... + * + */ diff --git a/libraries/Update/examples/AWS_S3_OTA_Update/StartCounter.ino.bin b/libraries/Update/examples/AWS_S3_OTA_Update/StartCounter.ino.bin new file mode 100644 index 0000000000000000000000000000000000000000..14732a0adb109d05668916b9b06643358bdf9ca3 GIT binary patch literal 357280 zcmaFK!K7ay#Nohz1-$r=MQ~JTGz3ONU^E0qLtr!nMnhmU1V%$(Gz3ONU^E0qLtr!n zMnhmU1V%$(Gz3ONU^E0qLtr!nMnhmU1V%$(Gz3ONU^E0qLtr!nMnhmU1V%$(Gz3ON zU^E0qLtr!nMnhmU1V%$(Gz3ONU^E0qLtr!nMnhmU1V%$(Gz3ONU^E0qLtr!nMnhmU z1V%$(Gz3ONU^E0qLtr!nMnhmU1V%$(Gz3ONU^E0qLtr!nMnhmU1V%$(Gz3ONU^E0q zLtr!nMnhmU1V%$(Gz3ONU^E0qLtr!nMnhmU1V%$(Gz3ONU^E0qLtr!nMnhmU1V%$( zGz3ONU^E0qLtr!nMnhmU1V%$(Gz3ONU^E0qLtr!nMnhmU1V%$(Gz3ONU^E0qLtr!n zMnhmU1V%$(Gz3ONU^E0qLtr!nMnhmU1V%$(Gz3ONU^E0qLtr!nMnhmU1V%$(Gz3ON zU^E0qLtr!nMnhmU1V%$(Gz3ONU^E0qLtr!nMnhmU1V%$(Gz3ONU^E0qLtr!nMnhmU z1V%$(Gz3ONU^E0qLtr!nMnhmU1V%$(Gz3ONU^E0qLtr!nMnhmU1V%$(Gz3ONU^E0q zLtr!nMnhmU1V%$(Gz3ONU^E0qLtr!nMnhmU1V%$(Gz3ONU^E0qLtr!nMnhmU1V%$( zGz3ONU^E0qLtr!nMnhmU1V%$(Gz3ONU^E0qLtr!nMnhmU1V%$(Gz3ONU^E0qLtr!n zMnhmU1V%$(Gz3ONU^E0qLtr!nMnhmU1V%$(Gz3ONU^E0qLtr!nMnhmU1V%$(Gz3ON zU^E0qLtr!nMnhmU1V%$(Gz3ONU^E0qLtt0~0R{(qjzk8AG8tZnoszr``y_cCM5TBg z++}zjTxED2K1lOAh{*6dERf}O@RZ_p=#u4im?{h5gTz1>B#sM%)FR8(L(M@J*OP*n zjjRrx4YS8qiq`?89>j-XkXn!!h(^XByFlU~8YT{7gT!HCAU2;guS2R7ufr@UUI!;> zUWYPiUWaYcybiadcpV&Nc^%%!Kxi>pUI!2ciA|H|bvWP%!OM}@Ah8%E{u+5+haCzK zb(g)!O1uu!m3bXNd>BU86QBf93ljfeh+u>Gr_3Py z`{ocDBo>I|2M`|{2H6D?2id;}&Hhj&UI&oaBB;GpP?|}P*WtGzufs!AUWX}AF_8UI z^1KeOknBHV4RH%d+yD(IpaE6}1_nt628LQ_Zr#&)WBR5`b8L*4uehrG&C}9$`4^YJ z{7a4IPVYI-u`62DIe$%x2HOcPhK2{`m4_Xj#q(IVZrw52?dwnbm(2bazDBYJKRwEu zqHOjT*WdLQErl5S!5%`ZI6&w~2<^}hp*s#k=&T=Lx}inS5v1;dP%@Zqxjr3Cr=C3v zq7~v7FgYt%koER8P)V^l(IK$k@u;4~( zxJj8a!wJ9i+=Hu~8EhveJc)Sd?9j8dLUz5VOTha_*PcjuyG*+3%Xa=lgUdIshsT+8 zx4LYZd$ZEH;+4y!bY6$6DZCE1Qg|H;W(s>>BWbitqrt&&0 z%iwj`m;vE~#6TD%jthg-BFoK&nu9Fvl?pK%SsgkXW=~`)uLDRuh!4XcwIDGNjf_Ed zfy6;HOdQ4riNnM|Y^^k2hsIQ1hi$364smI`4wKS&9WJHuI($pzb%@R2b>PT=&_)@& z4j>E?>&oVJSlbH0vys>!u>d6gf^1%g%{dTtt8;iA4no-sdAts6L|~A4gm6tBuR}sU z#12AgLGnw=P}N#iL->X@5E`V$3&{^4K0XYxKNZb>%RF8OkXUIR#LP%2eXxkvVPzSw zLu?hV156HNzf?A_gBgiLRZDL^HAOP4oIM|suIM_Kj*w{JPSveROVF0R; zg@XkIKs;s+4i*j&W&sf(5eN??&&*pfD1D+Fd%}2k&&5^k)4^9k&%gsiJ6&&g_W6wnT0il zfq{XEgFu=4iaQ