Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add optional SPIFFS/LITTLEFS partition support #47

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Brought spiffs into the scope of this library
  • Loading branch information
tobozo committed Feb 13, 2021
commit a6cd6aa2134f321b90e905a544bb9d5ad00680aa
5 changes: 3 additions & 2 deletions fota/firmware.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
"version": 2,
"host": "192.168.0.100",
"port": 80,
"bin": "/fota/esp32-fota-http-2.bin"
}
"bin": "/fota/esp32-fota-http-2.ino.bin",
"spiffs": "/fota/esp32-fota-http-2.spiffs.bin"
}
152 changes: 113 additions & 39 deletions src/esp32fota.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,45 +33,81 @@ static void splitHeader(String src, String &header, String &headerValue)
return;
}





// OTA Logic


void esp32FOTA::execOTA()
{
bool hasSPIFFS = (String(_spiffs) != "");
// flash spiffs first without restarting
if( hasSPIFFS )
{
execOTA( U_SPIFFS );
}
// flash the app
execOTA( U_FLASH );
ESP.restart();
}


WiFiClient client;
void esp32FOTA::execOTA( int partition )
{

String binFilePath = "";
int contentLength = 0;
bool isValidContentType = false;
bool gotHTTPStatus = false;

switch( partition )
{
case U_SPIFFS: // spiffs partition
if( String(_spiffs) == "" ) {
Serial.println("No spiffs binary was speficied, job finished");
return;
}
binFilePath = String(_spiffs);
break;
case U_FLASH: // app partition (default)
default:
partition = U_FLASH;
binFilePath = String(_bin);
break;
}

Serial.println("Connecting to: " + String(_host));
// Connect to Webserver
if (client.connect(_host.c_str(), _port))
if (clientForOta.connect(_host.c_str(), _port))
{
// Connection Succeed.
// Fetching the bin
Serial.println("Fetching Bin: " + String(_bin));
Serial.println("Fetching Bin: " + binFilePath);

// Get the contents of the bin file
client.print(String("GET ") + _bin + " HTTP/1.1\r\n" +
clientForOta.print(String("GET ") + binFilePath + " HTTP/1.1\r\n" +
"Host: " + _host + "\r\n" +
"Cache-Control: no-cache\r\n" +
"Connection: close\r\n\r\n");

unsigned long timeout = millis();
while (client.available() == 0)
while (clientForOta.available() == 0)
{
if (millis() - timeout > 5000)
{
Serial.println("Client Timeout !");
client.stop();
clientForOta.stop();
return;
}
}

while (client.available())
while (clientForOta.available())
{
String header, headerValue;
// read line till /n
String line = client.readStringUntil('\n');
String line = clientForOta.readStringUntil('\n');
// remove space, to check if the line is end of headers
line.trim();

Expand All @@ -88,7 +124,7 @@ void esp32FOTA::execOTA()
if (line.indexOf("200") < 0)
{
Serial.println("Got a non 200 status code from server. Exiting OTA Update.");
client.stop();
clientForOta.stop();
break;
}
gotHTTPStatus = true;
Expand Down Expand Up @@ -132,22 +168,24 @@ void esp32FOTA::execOTA()
// 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);
bool canBegin = Update.begin(contentLength, partition);

// 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);
size_t written = Update.writeStream(clientForOta);

if (written == contentLength)
{
Expand Down Expand Up @@ -184,13 +222,13 @@ void esp32FOTA::execOTA()
// Understand the partitions and
// space availability
Serial.println("Not enough space to begin OTA");
client.flush();
clientForOta.flush();
}
}
else
{
Serial.println("There was no content in the response");
client.flush();
clientForOta.flush();
}
}

Expand Down Expand Up @@ -241,17 +279,20 @@ bool esp32FOTA::execHTTPcheck()
return false;
}

const char *pltype = JSONDocument["type"];
const char *pltype = JSONDocument["type"];
int plversion = JSONDocument["version"];
const char *plhost = JSONDocument["host"];
const char *plhost = JSONDocument["host"];
_port = JSONDocument["port"];
const char *plbin = JSONDocument["bin"];
const char *plbin = JSONDocument["bin"];
const char *plspiffs = JSONDocument["spiffs"];

String jshost(plhost);
String jsbin(plbin);
String jsspiffs(plspiffs);

_host = jshost;
_bin = jsbin;
_host = jshost;
_bin = jsbin;
_spiffs = jsspiffs;

String fwtype(pltype);

Expand Down Expand Up @@ -288,11 +329,12 @@ String esp32FOTA::getDeviceID()
}

// Force a firmware update regartless on current version
void esp32FOTA::forceUpdate(String firmwareHost, int firmwarePort, String firmwarePath)
void esp32FOTA::forceUpdate(String firmwareHost, int firmwarePort, String firmwarePath, String spiffsPath)
{
_host = firmwareHost;
_bin = firmwarePath;
_port = firmwarePort;
_host = firmwareHost;
_bin = firmwarePath;
_spiffs = spiffsPath;
_port = firmwarePort;
execOTA();
}

Expand All @@ -303,7 +345,7 @@ void esp32FOTA::forceUpdate(String firmwareHost, int firmwarePort, String firmwa
/*
This structure describes the characteristics of a firmware, namely:
the host where it is located
the path of the actual bin file
the path of the actual bin file
the port where it can be retrieved
the type of target device
the version of the firmware
Expand All @@ -314,12 +356,13 @@ typedef struct
int port;
String host;
String bin;
String spiffs;
String type;
} OTADescription;

/*
The constructor sets only the firmware type and its versions, as these two
parameters are hardcoded in the device. The other parameters have to be set
The constructor sets only the firmware type and its versions, as these two
parameters are hardcoded in the device. The other parameters have to be set
separately.
*/
secureEsp32FOTA::secureEsp32FOTA(String firwmareType, int firwmareVersion)
Expand All @@ -346,13 +389,12 @@ bool secureEsp32FOTA::prepareConnection(String destinationServer)
/*
This function performs a GET request to fetch a resource over HTTPS.
It makes use of the attributes of the class, that have to be already set.
In particular, it makes use of the certificate, the descriptionOfFirmwareURL,
In particular, it makes use of the certificate, the descriptionOfFirmwareURL,
the host.
*/
String secureEsp32FOTA::secureGetContent()
{
String destinationURL = _descriptionOfFirmwareURL;
char *certificate = _certificate;

bool canConnectToServer = prepareConnection(_host);
if (canConnectToServer)
Expand Down Expand Up @@ -388,13 +430,12 @@ String secureEsp32FOTA::secureGetContent()
/*
This function checks whether it is necessary to perform an OTA update.
It fetches the description of a firmware from the host, reading descriptionOfFirmwareURL.
In case the version of the fetched firmware is greater than the current version, and
the content has the right format, it returns true, and it modifies the attributes
In case the version of the fetched firmware is greater than the current version, and
the content has the right format, it returns true, and it modifies the attributes
of secureEsp32FOTA accordingly.
*/
bool secureEsp32FOTA::execHTTPSCheck()
{
char *certificate = _certificate;

String destinationUrl = _descriptionOfFirmwareURL;
OTADescription obj;
Expand All @@ -418,16 +459,18 @@ bool secureEsp32FOTA::execHTTPSCheck()

description->type = JSONDocument["type"].as<String>();

description->host = JSONDocument["host"].as<String>();
description->host = JSONDocument["host"].as<String>();
description->version = JSONDocument["version"].as<int>();
description->bin = JSONDocument["bin"].as<String>();
description->bin = JSONDocument["bin"].as<String>();
description->spiffs = JSONDocument["spiffs"].as<String>();

clientForOta.stop();

if (description->version > _firwmareVersion && description->type == _firwmareType)
{
locationOfFirmware = description->host;
_bin = description->bin;
_bin = description->bin;
_spiffs = description->spiffs;
return true;
}

Expand All @@ -452,21 +495,52 @@ This function launches an OTA, using the attributes of the class that describe i
server, url and certificate.
*/


void secureEsp32FOTA::executeOTA()
{
char *certificate = _certificate;
bool hasSPIFFS = (String(_spiffs) != "");
// flash spiffs first without restarting
if( hasSPIFFS )
{
executeOTA( U_SPIFFS );
}
// flash the app
executeOTA( U_FLASH );
ESP.restart();
}


void secureEsp32FOTA::executeOTA( int partition )
{
String binFilePath = "";

switch( partition )
{
case U_SPIFFS: // spiffs partition
if( String(_spiffs) == "" ) {
Serial.println("No spiffs binary was speficied, job finished");
return;
}
binFilePath = String(_spiffs);
break;
case U_FLASH: // app partition (default)
default:
partition = U_FLASH;
binFilePath = String(_bin);
break;
}

Serial.println("location of fw " + String(locationOfFirmware) + _bin + " HTTP/1.0");
Serial.println("location of fw " + String(locationOfFirmware) + binFilePath + " HTTP/1.0");

bool canCorrectlyConnectToServer = prepareConnection(locationOfFirmware);
int contentLength;
bool isValid;
int contentLength = 0; // fix for warning: 'contentLength' may be used uninitialized in this function
bool isValid = false; // fix for warning: 'isValid' may be used uninitialized in this function
bool gotHTTPStatus = false;
if (canCorrectlyConnectToServer)
{
//Serial.println("ok");

clientForOta.println("GET https://" + String(locationOfFirmware) + _bin + " HTTP/1.0");
clientForOta.println("GET https://" + String(locationOfFirmware) + binFilePath + " HTTP/1.0");
clientForOta.println("Host: " + String(locationOfFirmware) + "");
clientForOta.println("Connection: close");
clientForOta.println();
Expand Down Expand Up @@ -519,7 +593,7 @@ void secureEsp32FOTA::executeOTA()
if (contentLength && isValid)
{
//Serial.println("beginn");
bool canBegin = Update.begin(contentLength);
bool canBegin = Update.begin(contentLength, partition);
if (canBegin)
{
//Serial.println("Begin OTA. This may take 2 - 5 mins to complete. Things might be quite for a while.. Patience!");
Expand Down
7 changes: 6 additions & 1 deletion src/esp32fota.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,21 @@ class esp32FOTA
{
public:
esp32FOTA(String firwmareType, int firwmareVersion);
void forceUpdate(String firwmareHost, int firwmarePort, String firwmarePath);
void forceUpdate(String firwmareHost, int firwmarePort, String firwmarePath, String spiffsPath="" );
void execOTA();
void execOTA( int partition );
bool execHTTPcheck();
bool useDeviceID;
String checkURL;
WiFiClient clientForOta;

private:
String getDeviceID();
String _firwmareType;
int _firwmareVersion;
String _host;
String _bin;
String _spiffs;
int _port;
};

Expand All @@ -36,6 +39,7 @@ class secureEsp32FOTA
secureEsp32FOTA(String firwmareType, int firwmareVersion);
bool execHTTPSCheck();
void executeOTA();
void executeOTA( int partition );
String _descriptionOfFirmwareURL;
char *_certificate;
unsigned int _securePort = 443;
Expand All @@ -50,6 +54,7 @@ class secureEsp32FOTA
int _firwmareVersion;
String locationOfFirmware;
String _bin;
String _spiffs;
int _port;
};

Expand Down