diff --git a/data-src/index.js b/data-src/index.js index 2055e5e..06a09ec 100644 --- a/data-src/index.js +++ b/data-src/index.js @@ -4834,7 +4834,8 @@ class Firmware { updateFirmware() { let div = this.createFileUploader('/updateFirmware'); let inst = div.querySelector('div[id=divInstText]'); - let html = '
Select a binary file [SomfyController.ino.esp32.bin] containing the device firmware then press the Upload File button.
'; + let chip = document.getElementById('divContainer').getAttribute('data-chipmodel') || ''; + let html = `
Select a binary file [SomfyController.ino.esp32${chip}.bin] containing the device firmware then press the Upload File button.
`; if (this.isMobile()) { html += `
WARNING
`; html += '
This browser does not support automatic backups. It is highly recommended that you back up your configuration using the backup button before proceeding.
'; @@ -4849,7 +4850,8 @@ class Firmware { let div = this.createFileUploader('/updateApplication'); general.reloadApp = true; let inst = div.querySelector('div[id=divInstText]'); - inst.innerHTML = '
Select a binary file [SomfyController.littlefs.<chip>.bin, e.g. SomfyController.littlefs.esp32.bin] containing the littlefs data for the application then press the Upload File button.
'; + let chip = document.getElementById('divContainer').getAttribute('data-chipmodel') || ''; + inst.innerHTML = `
Select a binary file [SomfyController.littlefs.esp32${chip}.bin] containing the littlefs data for the application then press the Upload File button.
`; if (this.isMobile()) { inst.innerHTML += `
WARNING
`; inst.innerHTML += '
This browser does not support automatic backups. It is highly recommended that you back up your configuration using the backup button before proceeding.
'; diff --git a/docs/KNOWN_ISSUES.md b/docs/KNOWN_ISSUES.md index 402fe61..ed15935 100644 --- a/docs/KNOWN_ISSUES.md +++ b/docs/KNOWN_ISSUES.md @@ -267,3 +267,10 @@ On 2026-10-19 the log shows `web GET /controller from 192.168.1.197 total took 2 - **Fixed: a command for an unknown shade left no trace.** `handleShadeCommand`, `handleTiltCommand` and `handleGroupCommand` in [src/entryPoints/Web.cpp](../src/entryPoints/Web.cpp) now log a `not found` warning. On 2026-10-18 Home Assistant sent 10 commands to a device that had no shades yet, and the log showed only the response times. - **Fixed: `last ping 0ms ago` meant the client never pinged.** The disconnect line in [src/outputs/SocketEmitter.cpp](../src/outputs/SocketEmitter.cpp) now says `never pinged`. Browsers don't ping, so they always showed it. - **Open: `.gz does not exist` errors are noise.** `serveStatic` tries `.gz` first. For files stored without one (`appversion`, `icon.png`), LittleFS logs an `E`-level `does not exist, no permits for creation` line on every request. The fix would be for `minify.py` to gzip the plain files too. `setTryGzipFirst(false)` doesn't help: the error comes from `exists()` probing the missing variant, so it would only move the noise to the gzip-only files. + +## Installing "Main" from the update dialog always fails + +**Status:** open. Found 2026-10-20 while reviewing PR #72. +**Location:** `GitUpdater::beginUpdate` in [src/GitOTA.cpp](../src/GitOTA.cpp). + +The update dialog offers a "Main" entry next to the releases. For it, the updater downloads from `https://raw.githubusercontent.com/cjkas/ESPSomfy-RTS/master/`, but the repository holds no `.bin` files, so the firmware download 404s. Nothing is written and the device keeps running, so it does no harm, but the option can't work. Either drop the entry or point it at a build that publishes per-chip images. diff --git a/src/GitOTA.cpp b/src/GitOTA.cpp index 9391624..2c09b9f 100644 --- a/src/GitOTA.cpp +++ b/src/GitOTA.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include "esp_log.h" #include "ConfigSettings.h" #include "GitOTA.h" @@ -43,7 +42,9 @@ void GitRelease::setReleaseProperty(const char *key, const char *val) { void GitRelease::setAssetProperty(const char *key, const char *val) { if(strcmp(key, "name") == 0) { //Serial.println(val); - if(isFsAsset(val)) this->hasFS = true; + char fsFile[64]; + releaseAssetName(fsFile, sizeof(fsFile), "littlefs", settings.chipModel); + if(strcmp(val, fsFile) == 0) this->hasFS = true; else if(strstr(val, "ino.esp32.bin")) { if(strlen(this->hwVersions)) strcat(this->hwVersions, ","); strcat(this->hwVersions, "32"); @@ -353,19 +354,6 @@ void GitUpdater::emitDownloadProgress(uint8_t num, size_t total, size_t loaded, sockEmit.loop(); webServer.loop(); } -// The chip part of this board's release asset names. -static const char *chipName() { - esp_chip_info_t ci; - esp_chip_info(&ci); - switch(ci.model) { - case esp_chip_model_t::CHIP_ESP32S3: return "esp32s3"; - case esp_chip_model_t::CHIP_ESP32S2: return "esp32s2"; - case esp_chip_model_t::CHIP_ESP32C3: return "esp32c3"; - case esp_chip_model_t::CHIP_ESP32C6: return "esp32c6"; - default: return "esp32"; - } -} - bool GitUpdater::beginUpdate(const char *version) { ESP_LOGI(TAG, "Begin update called..."); if(strcmp(version, "Main") == 0) strcpy(this->baseUrl, "https://raw.githubusercontent.com/cjkas/ESPSomfy-RTS/master/"); @@ -373,14 +361,14 @@ bool GitUpdater::beginUpdate(const char *version) { strcpy(this->targetRelease, version); this->emitUpdateCheck(); - releaseAssetName(this->currentFile, sizeof(this->currentFile), "ino", chipName()); + releaseAssetName(this->currentFile, sizeof(this->currentFile), "ino", settings.chipModel); this->partition = U_FLASH; this->lockFS = this->cancelled = false; this->error = 0; this->error = this->downloadFile(); if(this->error == 0 && !this->cancelled) { somfy.commit(); - releaseAssetName(this->currentFile, sizeof(this->currentFile), "littlefs", chipName()); + releaseAssetName(this->currentFile, sizeof(this->currentFile), "littlefs", settings.chipModel); this->partition = U_SPIFFS; this->lockFS = true; this->error = this->downloadFile(); @@ -400,7 +388,7 @@ bool GitUpdater::beginUpdate(const char *version) { } bool GitUpdater::recoverFilesystem() { sprintf(this->baseUrl, "https://github.com/cjkas/ESPSomfy-RTS/releases/download/%s/", settings.fwVersion.name); - releaseAssetName(this->currentFile, sizeof(this->currentFile), "littlefs", chipName()); + releaseAssetName(this->currentFile, sizeof(this->currentFile), "littlefs", settings.chipModel); this->status = GIT_UPDATING; this->partition = U_SPIFFS; this->lockFS = true; diff --git a/src/Utils.cpp b/src/Utils.cpp index 2651f2a..0fc4a0a 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -150,13 +150,8 @@ bool worthRoaming(bool connected, int currentRssi, int apRssi, int minGain) { bool otaProven(bool networkUp, unsigned long uptimeMs, unsigned long minUptimeMs) { return networkUp && uptimeMs >= minUptimeMs; } -bool releaseAssetName(char *buf, size_t size, const char *kind, const char *chip) { - int n = snprintf(buf, size, "SomfyController.%s.%s.bin", kind, chip); - return n >= 0 && (size_t)n < size; -} -bool isFsAsset(const char *name) { - size_t len = strlen(name); - return strstr(name, ".littlefs.") && len >= 4 && strcmp(name + len - 4, ".bin") == 0; +void releaseAssetName(char *buf, size_t size, const char *kind, const char *chipModel) { + snprintf(buf, size, "SomfyController.%s.esp32%s.bin", kind, chipModel); } const char *wifiAuthModeName(uint8_t authMode) { switch(authMode) { diff --git a/src/Utils.h b/src/Utils.h index 723d9d5..7dfbb31 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -86,12 +86,10 @@ heap_emit_t heapEmitTarget(uint8_t num, uint32_t sinceLastMs, uint32_t intervalM // update has proven itself: it has run for minUptimeMs and the network is // up. Until then a reset rolls back to the previous firmware. bool otaProven(bool networkUp, unsigned long uptimeMs, unsigned long minUptimeMs); -// A release asset's name: "SomfyController...bin", kind "ino" for -// the firmware or "littlefs" for the web UI image, chip e.g. "esp32s3". False -// when it doesn't fit in size. -bool releaseAssetName(char *buf, size_t size, const char *kind, const char *chip); -// Whether a release asset is a LittleFS image, for any chip. -bool isFsAsset(const char *name); +// A release asset's name: "SomfyController..esp32.bin", kind +// "ino" for the firmware or "littlefs" for the web UI image, chipModel as in +// ConfigSettings ("" for the ESP32, "s3", "c3", "c6"). +void releaseAssetName(char *buf, size_t size, const char *kind, const char *chipModel); // How well loop() keeps up: the passes it made per second and its longest // pass, over the window since the last memStatus broadcast. Only the loop // task calls record(), rate(), maxUs() and publish(). publish() closes the diff --git a/test/test_utils/test_utils.cpp b/test/test_utils/test_utils.cpp index 2e5db6e..e549f73 100644 --- a/test/test_utils/test_utils.cpp +++ b/test/test_utils/test_utils.cpp @@ -273,31 +273,23 @@ static void test_otaProven_not_without_network() { } /********************************************************************* - * releaseAssetName / isFsAsset + * releaseAssetName ********************************************************************/ static void test_releaseAssetName_matches_the_release_workflow() { - // .github/workflows/build.yaml fwname and fsname. + // .github/workflows/build.yaml fwname and fsname, from ConfigSettings::chipModel. char buf[64]; - TEST_ASSERT_TRUE(releaseAssetName(buf, sizeof(buf), "ino", "esp32")); + releaseAssetName(buf, sizeof(buf), "ino", ""); TEST_ASSERT_EQUAL_STRING("SomfyController.ino.esp32.bin", buf); - TEST_ASSERT_TRUE(releaseAssetName(buf, sizeof(buf), "littlefs", "esp32s3")); + releaseAssetName(buf, sizeof(buf), "littlefs", "s3"); TEST_ASSERT_EQUAL_STRING("SomfyController.littlefs.esp32s3.bin", buf); + releaseAssetName(buf, sizeof(buf), "littlefs", "c6"); + TEST_ASSERT_EQUAL_STRING("SomfyController.littlefs.esp32c6.bin", buf); } -static void test_releaseAssetName_too_small_buffer() { - char buf[16]; - TEST_ASSERT_FALSE(releaseAssetName(buf, sizeof(buf), "littlefs", "esp32c6")); - TEST_ASSERT_EQUAL(sizeof(buf) - 1, strlen(buf)); -} -static void test_isFsAsset_per_chip_images() { - TEST_ASSERT_TRUE(isFsAsset("SomfyController.littlefs.esp32.bin")); - TEST_ASSERT_TRUE(isFsAsset("SomfyController.littlefs.esp32c6.bin")); - TEST_ASSERT_TRUE(isFsAsset("SomfyController.littlefs.bin")); -} -static void test_isFsAsset_not_the_other_assets() { - TEST_ASSERT_FALSE(isFsAsset("SomfyController.ino.esp32.bin")); - TEST_ASSERT_FALSE(isFsAsset("SomfyController.onboard.esp32.bin.zip")); - TEST_ASSERT_FALSE(isFsAsset("SomfyController.littlefs.bin.sha256")); - TEST_ASSERT_FALSE(isFsAsset("")); +static void test_releaseAssetName_keeps_c3() { + // C3 is out of the IDF 5.5 builds for now (ADR 0003) but is coming back. + char buf[64]; + releaseAssetName(buf, sizeof(buf), "ino", "c3"); + TEST_ASSERT_EQUAL_STRING("SomfyController.ino.esp32c3.bin", buf); } /********************************************************************* @@ -431,9 +423,7 @@ int main(int argc, char **argv) { RUN_TEST(test_otaProven_not_before_the_minimum_uptime); RUN_TEST(test_otaProven_not_without_network); RUN_TEST(test_releaseAssetName_matches_the_release_workflow); - RUN_TEST(test_releaseAssetName_too_small_buffer); - RUN_TEST(test_isFsAsset_per_chip_images); - RUN_TEST(test_isFsAsset_not_the_other_assets); + RUN_TEST(test_releaseAssetName_keeps_c3); RUN_TEST(test_wifiAuthModeName_matches_the_idf_enum); RUN_TEST(test_wifiAuthModeName_unknown_past_the_shared_values); RUN_TEST(test_heapEmitTarget_one_client_always_gets_it);