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