ESP_IOT v2.5
IOT ESP Coding
OTAImageUpdate.cpp
Go to the documentation of this file.
1/**
2* \link OTAImageUpdate \endlink
3*/
4
5//
6// OTAImageUpdate.c
7// M5Stick
8//
9// Created by Scott Moody on 3/8/22.
10//
11//!Code from AWS_S3_OTA_Update, it only uses HTTP (not https)
12//!https://www.tutorialspoint.com/esp32_for_iot/performing_the_over_the_air_update_of_esp32_firmware.htm
13#include "OTAImageUpdate.h"
14#ifdef USE_MQTT_NETWORKING
15
16#include <WiFi.h>
17
18#include <Update.h>
19
20//the WiFi client for connecting to the website to grab the binary image.
21WiFiClient _client;
22
23// Variables to validate
24// response from S3
27
28// S3 Bucket Config
29//!String _hostIP = "konacurrents.com"; // Host => bucket-name.s3.region.amazonaws.com
30//! host IP address (cannot be https)
31String _hostIP = "KnowledgeShark.org";
32//! Non https. For HTTPS 443. As of today, HTTPS doesn't work.
33int _port = 80;
34
35#ifdef ESP_M5
36//!location of bin file
37String _binName = "/OTA/ESP_IOT.ino.m5stick_c_plus.bin"; // bin file name with a slash in front.
38#endif
39#ifdef ESP_32
40#ifdef BOARD
41//!location of bin file
42String _binName = "/OTA/OTA_Board/ESP_IOT.ino.esp32.bin"; // bin file name with a slash in front.
43#else
44//!location of bin file
45String _binName = "/OTA/ESP_IOT.ino.esp32.bin"; // bin file name with a slash in front.
46#endif
47#endif
48//TODO note: this needs an ESP_M5 version and others ...
49
50//! Utility to extract header value from headers
51String getHeaderValue(String header, String headerName) {
52 return header.substring(strlen(headerName.c_str()));
53}
54
55//#define JUST_TESTING
56
57//! OTA Logic
58void execOTA()
59{
60 SerialDebug.println("Connecting to: " + String(_hostIP) + ", bin = " + String(_binName));
61#ifdef TRY_WITHOUT_THIS_MAYBE_OTHER_THREAD_GOOFS
62#ifdef USE_MQTT_NETWORKING
63 //note needs # or won't send. the {device} is tacked on..
64 sendMessageMQTT((char*)"#UPDATING_OTA");
65#endif
66#endif
67
68 //try this.. still talking some time..
70#ifdef USE_DISPLAY_MODULE
72#endif
73
74
75#ifdef JUST_TESTING
76 return;
77#endif
78 //see if delay gets BLE out of it's funk.
79 //https://esp32.com/viewtopic.php?t=10411
80//https://arduino.stackexchange.com/questions/72876/task-watchdog-gets-triggered-during-bluetooth-initialization
81
82 //! Connect to S3
83 if (_client.connect(_hostIP.c_str(), _port)) {
84 // Connection Succeed.
85 // Fecthing the bin
86 SerialDebug.println("Fetching Bin: " + String(_binName));
87
88 //! Get the contents of the bin file
89 _client.print(String("GET ") + _binName + " HTTP/1.1\r\n" +
90 "Host: " + _hostIP + "\r\n" +
91 "Cache-Control: no-cache\r\n" +
92 "Connection: close\r\n\r\n");
93
94 // Check what is being sent
95 // SerialDebug.print(String("GET ") + _binName + " HTTP/1.1\r\n" +
96 // "Host: " + _hostIP + "\r\n" +
97 // "Cache-Control: no-cache\r\n" +
98 // "Connection: close\r\n\r\n");
99
100 unsigned long timeout = millis();
101 while (_client.available() == 0) {
102 //delay(1);
103 if (millis() - timeout > 5000) {
104 SerialDebug.println("Client Timeout !");
105 _client.stop();
106 return;
107 }
108 }
109 // Once the response is available,
110 // check stuff
111
112 /**
113 Response Structure
114 HTTP/1.1 200 OK
115 x-amz-id-2: NVKxnU1aIQMmpGKhSwpCBh8y2JPbak18QLIfE+OiUDOos+7UftZKjtCFqrwsGOZRN5Zee0jpTd0=
116 x-amz-request-id: 2D56B47560B764EC
117 Date: Wed, 14 Jun 2017 03:33:59 GMT
118 Last-Modified: Fri, 02 Jun 2017 14:50:11 GMT
119 ETag: "d2afebbaaebc38cd669ce36727152af9"
120 Accept-Ranges: bytes
121 Content-Type: application/octet-stream
122 Content-Length: 357280
123 Server: AmazonS3
124
125 {{BIN FILE CONTENTS}}
126
127 */
128 while (_client.available()) {
129 // read line till /n
130 String line = _client.readStringUntil('\n');
131 // remove space, to check if the line is end of headers
132 line.trim();
133
134 // if the the line is empty,
135 // this is end of headers
136 // break the while and feed the
137 // remaining `client` to the
138 // Update.writeStream();
139 if (!line.length()) {
140 //headers ended
141 break; // and get the OTA started
142 }
143
144 //! Check if the HTTP Response is 200
145 //! else break and Exit Update
146 if (line.startsWith("HTTP/1.1")) {
147 if (line.indexOf("200") < 0) {
148 SerialDebug.println("Got a non 200 status code from server. Exiting OTA Update.");
149 break;
150 }
151 }
152
153 //! extract headers here
154 //! Start with content length
155 if (line.startsWith("Content-Length: ")) {
156 _contentLength = atol((getHeaderValue(line, "Content-Length: ")).c_str());
157 SerialDebug.println("Content-Length: " + String(_contentLength) + " bytes from server");
158 }
159
160 //! Next, the content type
161 if (line.startsWith("Content-Type: ")) {
162 String contentType = getHeaderValue(line, "Content-Type: ");
163 SerialDebug.println("Got " + contentType + " payload.");
164 if (contentType == "application/octet-stream") {
165 _isValidContentType = true;
166 }
167 }
168 }
169 } else {
170 // Connect to S3 failed
171 // May be try?
172 // Probably a choppy network?
173 SerialDebug.println("Connection to " + String(_hostIP) + " failed. Please check your setup");
174 // retry??
175 // execOTA();
176 }
177
178 // Check what is the contentLength and if content type is `application/octet-stream`
179 SerialDebug.println("contentLength : " + String(_contentLength) + ", _isValidContentType : " + String(_isValidContentType));
180
181 //! check contentLength and content type
183 //! Check if there is enough to OTA Update
184 bool canBegin = Update.begin(_contentLength);
185
186 // If yes, begin
187 if (canBegin) {
188 SerialDebug.println("Begin OTA streaming those bytes from the server..");
189 SerialDebug.println("This may take 2 - 5 mins to complete. Things might be quiet for a while.. Patience!");
190 // No activity would appear on the Serial monitor
191 // So be patient. This may take 2 - 5mins to complete
192 size_t written = Update.writeStream(_client);
193
194 if (written == _contentLength) {
195 SerialDebug.println("Written : " + String(written) + " successfully *****");
196 } else {
197 SerialDebug.println("******* ERROR: Written only : " + String(written) + "/" + String(_contentLength));
198 // retry??
199 // execOTA();
200 }
201
202 if (Update.end()) {
203 SerialInfo.println("OTA done!");
204 if (Update.isFinished()) {
205 SerialDebug.println("Update successfully completed. Rebooting.");
206 blinkMessageCallback((char*)"OTA Done");
207
208 ESP.restart();
209 } else {
210 SerialDebug.println("Update not finished? Something went wrong!");
211 for (int i=0;i<3;i++)
212 {
213 blinkMessageCallback((char*)"OTA error");
214 }
215 }
216 } else {
217 SerialDebug.println("Error Occurred. Error #: " + String(Update.getError()));
218 for (int i=0;i<3;i++)
219 {
220 blinkMessageCallback((char*)"OTA error");
221 }
222 }
223 } else {
224 // not enough space to begin OTA
225 // Understand the partitions and
226 // space availability
227 SerialError.println("**** Not enough space to begin OTA ** REPORT THIS TO DEVELOPERS");
228 _client.flush();
229 }
230 } else {
231 SerialError.println("There was no content in the response");
232 _client.flush();
233 }
234
235 //!restart .. which will ony effect if not rebooting..
237
238}
239
240//!address of bin string
241char _binAddress[100];
242
243//!connects to host and grabs the http file and tries to update the binary (OTA)
244//! kind = esp32, m5
245void performOTAUpdate(char *hostname, char *httpAddress)
246{
247 char *after = rindex(hostname,'/');
248 after++;
249 // hostname = &hostname[i+1];
250 //not using kind
251 _hostIP = after;
252//strip http://
253 sprintf(_binAddress, "/%s", httpAddress);
255
256 execOTA();
257}
258
259
260//!retrieves from constant location
262{
263 SerialDebug.println("OTAImageUpdate.performOTAUpdateSimple");
264 execOTA();
265}
266
267#endif // use MQTT
void showOTAUpdatingMessage()
show an OTA message..
void sendMessageMQTT(char *message)
void stopProcessesForOTAUpdate_mainModule()
stop all loops... while OTA working..
Definition: MainModule.cpp:11
void blinkMessageCallback(char *message)
callback for blinking led
void restartProcessesForOTAUpdate_mainModule()
restart all loops... while OTA working..
Definition: MainModule.cpp:16
void performOTAUpdateSimple()
retrieves from constant location
bool _isValidContentType
WiFiClient _client
long _contentLength
int _port
Non https. For HTTPS 443. As of today, HTTPS doesn't work.
String getHeaderValue(String header, String headerName)
Utility to extract header value from headers.
String _hostIP
char _binAddress[100]
address of bin string
void performOTAUpdate(char *hostname, char *httpAddress)
connects to host and grabs the http file and tries to update the binary (OTA)
String _binName
location of bin file
void execOTA()
OTA Logic.