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