Skip to content

Commit 2d4adb8

Browse files
committed
Support multiple firmware types in a single manifest
1 parent 8289799 commit 2d4adb8

File tree

2 files changed

+73
-45
lines changed

2 files changed

+73
-45
lines changed

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,25 @@ Version information can be either a single number or a semantic version string.
6060
}
6161
```
6262

63+
A single JSON file can provide information on multiple firmware types by combining them together into an array. When this is loaded, the firmware manifest with a type matching the one passed to the esp32FOTA constructor will be selected:
64+
65+
```json
66+
[
67+
{
68+
"type":"esp32-fota-http",
69+
"version":"0.0.2",
70+
"url":"http://192.168.0.100/fota/esp32-fota-http-2.bin",
71+
"check_signature":true
72+
},
73+
{
74+
"type":"esp32-other-hardware",
75+
"version":"0.0.3",
76+
"url":"http://192.168.0.100/fota/esp32-other-hardware.bin"
77+
}
78+
]
79+
```
80+
81+
6382
#### Firmware types
6483

6584
Types are used to compare with the current loaded firmware, this is used to make sure that when loaded, the device will still do the intended job.

src/esp32fota.cpp

Lines changed: 54 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -318,13 +318,13 @@ void esp32FOTA::execOTA()
318318
}
319319

320320
bool esp32FOTA::checkJSONManifest(JsonVariant JSONDocument) {
321-
log_i("Payload type: %s", JSONDocument["type"].as<const char *>() );
322321

323322
if(strcmp(JSONDocument["type"].as<const char *>(), _firmwareType.c_str()) != 0) {
323+
log_i("Payload type in manifest %s doesn't match current firmware %s", JSONDocument["type"].as<const char *>(), _firmwareType.c_str() );
324324
log_i("Doesn't match type: %s", _firmwareType.c_str() );
325325
return false; // Move to the next entry in the manifest
326326
}
327-
log_i("Matches type: %s", _firmwareType.c_str() );
327+
log_i("Payload type in manifest %s matches current firmware %s", JSONDocument["type"].as<const char *>(), _firmwareType.c_str() );
328328

329329
semver_free(&_payloadVersion);
330330
if(JSONDocument["version"].is<uint16_t>()) {
@@ -393,62 +393,71 @@ bool esp32FOTA::execHTTPcheck()
393393
return false; // WiFi not connected
394394
}
395395

396-
HTTPClient http;
397-
WiFiClientSecure client;
398-
399-
if( useURL.substring( 0, 5 ) == "https" ) {
400-
if (!_allow_insecure_https) {
401-
// If the checkURL is https load the root-CA and connect with that
402-
log_i( "Loading root_ca.pem" );
403-
File root_ca_file = SPIFFS.open( "/root_ca.pem" );
404-
if( !root_ca_file ) {
405-
log_e( "Could not open root_ca.pem" );
406-
return false;
407-
}
408-
{
409-
std::string root_ca = "";
410-
while( root_ca_file.available() ){
411-
root_ca.push_back( root_ca_file.read() );
412-
}
413-
root_ca_file.close();
414-
http.begin( useURL, root_ca.c_str() );
396+
HTTPClient http;
397+
WiFiClientSecure client;
398+
399+
if( useURL.substring( 0, 5 ) == "https" ) {
400+
if (!_allow_insecure_https) {
401+
// If the checkURL is https load the root-CA and connect with that
402+
log_i( "Loading root_ca.pem" );
403+
File root_ca_file = SPIFFS.open( "/root_ca.pem" );
404+
if( !root_ca_file ) {
405+
log_e( "Could not open root_ca.pem" );
406+
return false;
407+
}
408+
{
409+
std::string root_ca = "";
410+
while( root_ca_file.available() ){
411+
root_ca.push_back( root_ca_file.read() );
415412
}
416-
} else {
417-
// We're downloading from a secure port, but we don't want to validate the root cert.
418-
client.setInsecure();
419-
http.begin(client, useURL);
413+
root_ca_file.close();
414+
http.begin( useURL, root_ca.c_str() );
420415
}
421416
} else {
422-
http.begin(useURL); //Specify the URL
417+
// We're downloading from a secure port, but we don't want to validate the root cert.
418+
client.setInsecure();
419+
http.begin(client, useURL);
423420
}
424-
int httpCode = http.GET(); //Make the request
421+
} else {
422+
http.begin(useURL); //Specify the URL
423+
}
424+
int httpCode = http.GET(); //Make the request
425425

426-
if( httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY ) { //Check is a file was returned
426+
if( httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY ) { //Check is a file was returned
427427

428-
String payload = http.getString();
428+
String payload = http.getString();
429429

430-
int str_len = payload.length() + 1;
431-
char JSONMessage[str_len];
432-
payload.toCharArray(JSONMessage, str_len);
430+
int str_len = payload.length() + 1;
431+
char JSONMessage[str_len];
432+
payload.toCharArray(JSONMessage, str_len);
433433

434-
StaticJsonDocument<300> JSONDocument; //Memory pool
435-
DeserializationError err = deserializeJson(JSONDocument, JSONMessage);
434+
DynamicJsonDocument JSONResult(2048);
435+
DeserializationError err = deserializeJson(JSONResult, JSONMessage);
436436

437-
http.end(); // We're done with HTTP - free the resources
437+
http.end(); // We're done with HTTP - free the resources
438438

439-
if (err) { //Check for errors in parsing
440-
log_e("Parsing failed");
441-
return false;
442-
}
439+
if (err) { //Check for errors in parsing
440+
log_e("Parsing failed");
441+
return false;
442+
}
443443

444-
if(checkJSONManifest(JSONDocument.as<JsonVariant>())) {
445-
return true;
444+
if (JSONResult.is<JsonArray>()) {
445+
// We already received an array of multiple firmware types
446+
JsonArray arr = JSONResult.as<JsonArray>();
447+
for (JsonVariant JSONDocument : arr) {
448+
if(checkJSONManifest(JSONDocument)) {
449+
return true;
450+
}
446451
}
447-
448-
return false; // We didn't get a hit against the above, return false
449-
} else {
450-
log_e("Error on HTTP request");
452+
} else if (JSONResult.is<JsonObject>()) {
453+
if(checkJSONManifest(JSONResult.as<JsonVariant>()))
454+
return true;
451455
}
456+
457+
return false; // We didn't get a hit against the above, return false
458+
} else {
459+
log_e("Error on HTTP request");
460+
http.end();
452461
return false;
453462
}
454463
}

0 commit comments

Comments
 (0)