Skip to content
Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ All notable changes to this project will be documented in this file.
- Do not free BT memory when in use (#24480)
- Berry avoid `tasmota.wifi()` returning bad values when wifi is turned off (#24505)
- Don't send extraneous `0\r\n\r\n` with non-chunked HTTP/1.0 (#24518)
- File upload improvements: "/ufsu" api mode, no interrupts disanling, cleaner confirmation page

### Removed
- Berry `tasmota.urlbecload()` superseded by Extension Manager (#24493)
Expand Down
11 changes: 11 additions & 0 deletions tasmota/include/tasmota.h
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,17 @@ enum EmulationOptions {EMUL_NONE, EMUL_WEMO, EMUL_HUE, EMUL_MAX};

enum TopicOptions { CMND, STAT, TELE, nu1, RESULT_OR_CMND, RESULT_OR_STAT, RESULT_OR_TELE };

// Upload type used by HandleUploadLoop() to route incoming data.
// Value 0 is invalid/unset. Each upload endpoint must set the appropriate
// type before HandleUploadLoop() processes the first data block.
// UPL_TASMOTA - OTA firmware update (/u2)
// UPL_SETTINGS - Settings backup restore (/u2)
// UPL_EFM8BB1 - Sonoff RF bridge EFM8BB1 firmware
// UPL_TASMOTACLIENT - Tasmota client (Arduino) hex file
// UPL_EFR32 - Zigbee EZSP (EFR32) firmware
// UPL_SHD - Shelly dimmer firmware
// UPL_CCL - CC2530 Zigbee firmware via CCLoader
// UPL_UFSFILE - Filesystem file upload (/ufsu)
enum UploadTypes { UPL_TASMOTA = 1, UPL_SETTINGS, UPL_EFM8BB1, UPL_TASMOTACLIENT, UPL_EFR32, UPL_SHD, UPL_CCL, UPL_UFSFILE };

enum ExecuteCommandPowerOptions { POWER_OFF, POWER_ON, POWER_TOGGLE, POWER_BLINK, POWER_BLINK_STOP, POWER_OFF_FORCE,
Expand Down
17 changes: 13 additions & 4 deletions tasmota/tasmota_xdrv_driver/xdrv_01_9_webserver.ino
Original file line number Diff line number Diff line change
Expand Up @@ -3502,7 +3502,9 @@ void HandleUploadLoop(void) {
if (Web.upload_error) {
if (!upload_error_signalled) {
if (UPL_TASMOTA == Web.upload_file_type) { Update.end(); }
UploadServices(1);
if (UPL_UFSFILE != Web.upload_file_type) {
UploadServices(1);
}

// AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPLOAD "Upload error %d"), Web.upload_error);

Expand All @@ -3522,7 +3524,10 @@ void HandleUploadLoop(void) {
WebGetArg("fsz", tmp, sizeof(tmp)); // filesize
upload_size = (!strlen(tmp)) ? 0 : atoi(tmp);

UploadServices(0);
// Filesystem uploads don't need to disable interrupts/services
if (UPL_UFSFILE != Web.upload_file_type) {
UploadServices(0);
}

if (0 == upload.filename.c_str()[0]) {
Web.upload_error = 1; // No file selected
Expand Down Expand Up @@ -3667,7 +3672,9 @@ void HandleUploadLoop(void) {

// ***** Step3: Finish upload file
else if (UPLOAD_FILE_END == upload.status) {
UploadServices(1);
if (UPL_UFSFILE != Web.upload_file_type) {
UploadServices(1);
}
if (UPL_SETTINGS == Web.upload_file_type) {
if (!SettingsConfigRestore()) {
Web.upload_error = 8; // File invalid
Expand Down Expand Up @@ -3733,7 +3740,9 @@ void HandleUploadLoop(void) {

// ***** Step4: Abort upload file
else {
UploadServices(1);
if (UPL_UFSFILE != Web.upload_file_type) {
UploadServices(1);
}
Web.upload_error = 7; // Upload aborted
if (UPL_TASMOTA == Web.upload_file_type) { Update.end(); }
}
Expand Down
23 changes: 17 additions & 6 deletions tasmota/tasmota_xdrv_driver/xdrv_50_filesystem.ino
Original file line number Diff line number Diff line change
Expand Up @@ -1353,6 +1353,21 @@ const char HTTP_EDITOR_FORM_END[] PROGMEM =

#endif // #ifdef GUI_EDIT_FILE

// Wrapper around HandleUploadLoop() for /ufsu file uploads.
// HandleUploadLoop() is shared between OTA firmware updates (/u2) and filesystem
// uploads (/ufsu), and uses Web.upload_file_type to distinguish them.
// When uploading via the web UI, the browser first does a GET which calls
// UfsDirectory() and sets upload_file_type = UPL_UFSFILE. But direct POST
// requests (e.g. curl -F "file=@..." /ufsu) skip the GET, leaving
// upload_file_type unset and causing HandleUploadLoop() to treat the file
// as a firmware image, which fails.
// This wrapper ensures upload_file_type is always set before entering the
// shared upload handler.
void HandleUploadUFSLoop(void) {
Web.upload_file_type = UPL_UFSFILE;
HandleUploadLoop();
}

void HandleUploadUFSDone(void) {
if (!HttpCheckPriviledgedAccess()) { return; }

Expand Down Expand Up @@ -1382,7 +1397,7 @@ void HandleUploadUFSDone(void) {
}
WSContentSend_P(PSTR("</div><br>"));

XdrvCall(FUNC_WEB_ADD_MANAGEMENT_BUTTON);
WSContentSend_PD(UFS_WEB_DIR, "/", PSTR(D_MANAGE_FILE_SYSTEM));

WSContentStop();
}
Expand Down Expand Up @@ -1974,13 +1989,9 @@ bool Xdrv50(uint32_t function) {
}
break;
case FUNC_WEB_ADD_HANDLER:
// Webserver->on(F("/ufsd"), UfsDirectory);
// Webserver->on(F("/ufsu"), HTTP_GET, UfsDirectory);
// Webserver->on(F("/ufsu"), HTTP_POST,[](){Webserver->sendHeader(F("Location"),F("/ufsu"));Webserver->send(303);}, HandleUploadLoop);
Webserver->on("/ufsd", UfsDirectory);
Webserver->on("/ufsu", HTTP_GET, UfsDirectory);
//Webserver->on("/ufsu", HTTP_POST,[](){Webserver->sendHeader(F("Location"),F("/ufsu"));Webserver->send(303);}, HandleUploadLoop);
Webserver->on("/ufsu", HTTP_POST, HandleUploadUFSDone, HandleUploadLoop);
Webserver->on("/ufsu", HTTP_POST, HandleUploadUFSDone, HandleUploadUFSLoop);
#ifdef GUI_EDIT_FILE
Webserver->on("/ufse", HTTP_GET, UfsEditor);
Webserver->on("/ufse", HTTP_POST, UfsEditorUpload);
Expand Down