Open sharandac opened 3 years ago
hey thanks for your feedback :-)
just don't use setupFSCallbacks() with OTA Update and it should be fine
Thank you for your answer. I have not yet used setFSCallbacks(). I have only used the following in two different places with
#define DEST_FS_USES_SPIFFS
#include <ESP32-targz.h>
Without any further code.
two different places :thinking: maybe it doesn't like multiple instances ?
What does the targz setup code look like, can you share a snippet with all the statements calling this library ?
Here is the first snippet with the function that use your lib
#define DEST_FS_USES_SPIFFS
#include <ESP32-targz.h>
/*
// some other code
*/
bool http_ota_start_compressed( const char* url, const char* md5, int32_t firmwaresize ) {
bool retval = false;
int32_t size = UPDATE_SIZE_UNKNOWN;
HTTPClient http;
/**
* start get firmware file
*/
http.setUserAgent( "ESP32-UPDATE-" __FIRMWARE__ );
http.begin( url );
int httpCode = http.GET();
if ( httpCode > 0 && httpCode == HTTP_CODE_OK ) {
/**
* send http_ota_start event
*/
http_ota_send_event_cb( HTTP_OTA_START, (void *)NULL );
/**
* start an unpacker instance, reister progress callback and put the stream in
*/
GzUnpacker *GZUnpacker = new GzUnpacker();
GZUnpacker->setGzProgressCallback( http_ota_progress_cb );
GZUnpacker->setPsram( true );
http_ota_send_event_cb( HTTP_OTA_START, (void*)"start flashing ..." );
/**
* if firmware size known set the right value
*/
if ( firmwaresize != 0 )
size = firmwaresize;
/**
* progress the stream
*/
if( !GZUnpacker->gzStreamUpdater( http.getStreamPtr(), size, 0, false ) ) {
log_e("gzStreamUpdater failed with return code #%d\n", GZUnpacker->tarGzGetError() );
http_ota_send_event_cb( HTTP_OTA_ERROR, (void*)"error ... weak wifi?" );
}
else {
http_ota_send_event_cb( HTTP_OTA_FINISH, (void*)"Flashing ... done!" );
retval = true;
}
}
else {
http_ota_send_event_cb( HTTP_OTA_ERROR, (void*)"http error ... weak wifi?" );
}
http.end();
return( retval );
}
At this point it works perfect. But if I add in a second place, it fails. I have reduce it to only
#define DEST_FS_USES_SPIFFS
#include <ESP32-targz.h>
interesting, this makes me realize there's no test suite for using gzStreamUpdater()
with HTTP stream
Can you try to add this:
GZUnpacker->setupFSCallbacks( nullprt, nullptr );
then try to compile, if it still fails comment this out:
// GZUnpacker->setGzProgressCallback( http_ota_progress_cb );
and see if it improves ?
Meanwhile I'll see if I can create an example sketch out of your snippet.
With both changes comes the same compiler error. I am a bit confused, because actually the
#ifndef _TGZ_FSFOOLS_
should prevent this. But I don't see any reason why it does.
idea: separate the gathering of the http stream pointer from the gz logic
Here's a function I use for that, it can even follow redirects:
#include <WiFi.h>
#include <HTTPClient.h>
#include <WiFiClientSecure.h>
HTTPClient http;
WiFiClient *getFirmwareClientPtr( WiFiClientSecure *client, const char* url, const char *cert = NULL )
{
client->setCACert( cert );
const char* UserAgent = "ESP32-HTTP-TarGzUpdater-Client";
http.setReuse(true); // handle 301 redirects gracefully
http.setUserAgent( UserAgent );
http.setConnectTimeout( 10000 ); // 10s timeout = 10000
if( ! http.begin(*client, url ) ) {
log_e("Can't open url %s", url );
return nullptr;
}
const char * headerKeys[] = {"location", "redirect", "Content-Type", "Content-Length", "Content-Disposition" };
const size_t numberOfHeaders = 5;
http.collectHeaders(headerKeys, numberOfHeaders);
int httpCode = http.GET();
// file found at server
if (httpCode == HTTP_CODE_FOUND || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
String newlocation = "";
String headerLocation = http.header("location");
String headerRedirect = http.header("redirect");
if( headerLocation !="" ) {
newlocation = headerLocation;
Serial.printf("302 (location): %s => %s\n", url, headerLocation.c_str());
} else if ( headerRedirect != "" ) {
Serial.printf("301 (redirect): %s => %s\n", url, headerLocation.c_str());
newlocation = headerRedirect;
}
http.end();
if( newlocation != "" ) {
log_w("Found 302/301 location header: %s", newlocation.c_str() );
// delete client;
return getFirmwareClientPtr( client, newlocation.c_str(), cert );
} else {
log_e("Empty redirect !!");
return nullptr;
}
}
if( httpCode != 200 ) return nullptr;
return http.getStreamPtr();
}
So later I can do this:
WiFiClientSecure *client = new WiFiClientSecure;
Stream *streamptr = getFirmwareClientPtr( client, URL, certificate );
Unpacker->gzStreamUpdater( streamptr, UPDATE_SIZE_UNKNOWN, 0, false );
also I don't include <ESP32-targz>
from multiple places, maybe gather all unpacking logic into a single document for simplicity ?
That will probably be the solution, that I will pack the functions into a file. Many thanks for your help!
I've updated the example with a gzStreamUpdater test:
https://github.com/tobozo/ESP32-targz/tree/1.0.5-beta/examples/ESP32/Update_from_gz_stream
I don't see a compilation error but I've only tested with Arduino IDE, does it compile in your platformio environment ?
Hey,
only wanted to mention, that it can be also resolved simply by putting the declarations of targzFreeBytesFn
and targzTotalBytesFn
in the ESP32-targz-lib.h file, and the definitions in the ESP32-targz-lib.cpp file. The FSInfo fsinfo
declaration should also be moved to the ESP32-targz-lib.h header so it can be used by the targzFreeBytesFn
function.
At least this worked for me :-)
@tibotix doing this breaks esp8266 compatibility, but I'm not sure I'll keep on maintaining the esp8266 part of the library so I'll keep your suggestion in mind
@tobozo oh okay I see. That was not intended.
Anyway, for others that might face this issue: if you have to include the ESP32-targz.h
header multiple times, you could define the tarGzFS
and FS_NAME
Macros as well as the targzFreeBytesFn
and targzTotalBytesFn
functions and if needed the FSInfo fsinfo
variable yourself and include the ESP32-targz-lib.h
directly instead of the ESP32-targz.h
header.
Strange thing is thatI have included ESP32-targz.h
only once, but still have this error. I ended up declaring targzFreeBytesFn
and targzTotalBytesFn
locally.
@monte-monte this was solved a year ago, what core and library versions are you using?
@tobozo version=1.1.4, esp8266 with latest core in platformio.
Hey hey. I tried today to use ESP32-targz in several places in the same project. This results in the following error ...
Any Idea?