Compare commits
12 Commits
copilot/fi
...
copilot/fi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f706c6cbed | ||
|
|
18dfc7081c | ||
|
|
5c0c84eb6b | ||
|
|
691c058ae8 | ||
|
|
7d550baf94 | ||
|
|
42ff73ffe7 | ||
|
|
2d8edfcb24 | ||
|
|
fb077ecadc | ||
|
|
caf3d900fd | ||
|
|
e920d2e101 | ||
|
|
54746c9730 | ||
|
|
8225a2a07c |
3
.github/FUNDING.yml
vendored
3
.github/FUNDING.yml
vendored
@@ -1,3 +1,2 @@
|
||||
github: [Aircoookie,blazoncek,DedeHai,lost-hope,willmmiles]
|
||||
github: [Aircoookie,blazoncek]
|
||||
custom: ['https://paypal.me/Aircoookie','https://paypal.me/blazoncek']
|
||||
thanks_dev: u/gh/netmindz
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
Import("env")
|
||||
import shutil
|
||||
import os
|
||||
|
||||
node_ex = shutil.which("node")
|
||||
# Check if Node.js is installed and present in PATH if it failed, abort the build
|
||||
@@ -12,6 +13,21 @@ else:
|
||||
print('\x1b[6;33;42m' + 'Installing node packages' + '\x1b[0m')
|
||||
env.Execute("npm ci")
|
||||
|
||||
# Extract the release name from build flags
|
||||
release_name = "Custom"
|
||||
build_flags = env.get("BUILD_FLAGS", [])
|
||||
for flag in build_flags:
|
||||
if 'WLED_RELEASE_NAME=' in flag:
|
||||
# Extract the release name, remove quotes and handle different formats
|
||||
parts = flag.split('WLED_RELEASE_NAME=')
|
||||
if len(parts) > 1:
|
||||
release_name = parts[1].split()[0].strip('\"\\')
|
||||
break
|
||||
|
||||
# Set environment variable for cdata.js to use
|
||||
os.environ['WLED_RELEASE_NAME'] = release_name
|
||||
print(f'Building web UI with release name: {release_name}')
|
||||
|
||||
# Call the bundling script
|
||||
exitCode = env.Execute("npm run build")
|
||||
|
||||
|
||||
@@ -10,12 +10,10 @@
|
||||
|
||||
</p>
|
||||
|
||||
# Welcome to WLED! ✨
|
||||
# Welcome to my project WLED! ✨
|
||||
|
||||
A fast and feature-rich implementation of an ESP32 and ESP8266 webserver to control NeoPixel (WS2812B, WS2811, SK6812) LEDs or also SPI based chipsets like the WS2801 and APA102!
|
||||
|
||||
Originally created by [Aircoookie](https://github.com/Aircoookie)
|
||||
|
||||
## ⚙️ Features
|
||||
- WS2812FX library with more than 100 special effects
|
||||
- FastLED noise effects and 50 palettes
|
||||
@@ -34,7 +32,7 @@ Originally created by [Aircoookie](https://github.com/Aircoookie)
|
||||
- Filesystem-based config for easier backup of presets and settings
|
||||
|
||||
## 💡 Supported light control interfaces
|
||||
- WLED app for [Android](https://play.google.com/store/apps/details?id=ca.cgagnier.wlednativeandroid) and [iOS](https://apps.apple.com/gb/app/wled-native/id6446207239)
|
||||
- WLED app for [Android](https://play.google.com/store/apps/details?id=com.aircoookie.WLED) and [iOS](https://apps.apple.com/us/app/wled/id1475695033)
|
||||
- JSON and HTTP request APIs
|
||||
- MQTT
|
||||
- E1.31, Art-Net, DDP and TPM2.net
|
||||
|
||||
@@ -95,6 +95,11 @@ function adoptVersionAndRepo(html) {
|
||||
if (version) {
|
||||
html = html.replaceAll("##VERSION##", version);
|
||||
}
|
||||
|
||||
// Replace ##RELEASE## with the actual release name from build environment
|
||||
const releaseName = process.env.WLED_RELEASE_NAME || 'Custom';
|
||||
html = html.replaceAll("##RELEASE##", releaseName);
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,10 +13,6 @@
|
||||
#include "FXparticleSystem.h" // TODO: better define the required function (mem service) in FX.h?
|
||||
#include "palettes.h"
|
||||
|
||||
#ifndef DEFAULT_LED_COLOR_ORDER
|
||||
#define DEFAULT_LED_COLOR_ORDER COL_ORDER_GRB //default to GRB
|
||||
#endif
|
||||
|
||||
/*
|
||||
Custom per-LED mapping has moved!
|
||||
|
||||
@@ -1177,22 +1173,12 @@ void WS2812FX::finalizeInit() {
|
||||
|
||||
// create buses/outputs
|
||||
unsigned mem = 0;
|
||||
for (auto bus : busConfigs) {
|
||||
// Calculate what this bus would use with its current configuration
|
||||
unsigned busMemUsage = bus.memUsage(Bus::isDigital(bus.type) && !Bus::is2Pin(bus.type) ? digitalCount : 0);
|
||||
|
||||
// If memory exceeds limit, set count to minimum of current count and default length
|
||||
if (mem + busMemUsage > MAX_LED_MEMORY) {
|
||||
bus.count = min(bus.count, DEFAULT_LED_COUNT);
|
||||
DEBUG_PRINTF_P(PSTR("Bus %d memory usage exceeds limit, setting count to %d\n"), (int)bus.type, bus.count);
|
||||
}
|
||||
|
||||
if (BusManager::add(bus) != -1) {
|
||||
mem += bus.memUsage(Bus::isDigital(bus.type) && !Bus::is2Pin(bus.type) ? digitalCount : 0);
|
||||
if (Bus::isDigital(bus.type) && !Bus::is2Pin(bus.type)) digitalCount++;
|
||||
} else break;
|
||||
for (const auto &bus : busConfigs) {
|
||||
mem += bus.memUsage(Bus::isDigital(bus.type) && !Bus::is2Pin(bus.type) ? digitalCount++ : 0); // includes global buffer
|
||||
if (mem <= MAX_LED_MEMORY) {
|
||||
if (BusManager::add(bus) == -1) break;
|
||||
} else DEBUG_PRINTF_P(PSTR("Out of LED memory! Bus %d (%d) #%u not created."), (int)bus.type, (int)bus.count, digitalCount);
|
||||
}
|
||||
|
||||
busConfigs.clear();
|
||||
busConfigs.shrink_to_fit();
|
||||
|
||||
|
||||
@@ -668,20 +668,9 @@ function parseInfo(i) {
|
||||
if (loc) name = "(L) " + name;
|
||||
d.title = name;
|
||||
simplifiedUI = i.simplifiedui;
|
||||
// Add safety checks for LED count data to prevent UI crashes
|
||||
if (i.leds && typeof i.leds.count !== 'undefined') {
|
||||
ledCount = i.leds.count;
|
||||
} else {
|
||||
console.warn('LED count data missing, using fallback value');
|
||||
ledCount = 30; // Fallback value matching firmware default
|
||||
}
|
||||
ledCount = i.leds.count;
|
||||
//syncTglRecv = i.str;
|
||||
if (i.leds && typeof i.leds.maxseg !== 'undefined') {
|
||||
maxSeg = i.leds.maxseg;
|
||||
} else {
|
||||
console.warn('Max segment data missing, using fallback value');
|
||||
maxSeg = 16; // Reasonable fallback for max segments
|
||||
}
|
||||
maxSeg = i.leds.maxseg;
|
||||
pmt = i.fs.pmt;
|
||||
if (pcMode && !i.wifi.ap) gId('edit').classList.remove("hide"); else gId('edit').classList.add("hide");
|
||||
gId('buttonNodes').style.display = lastinfo.ndc > 0 ? null:"none";
|
||||
@@ -923,24 +912,12 @@ function populateSegments(s)
|
||||
gId(`segr${i}`).classList.add("hide");
|
||||
}
|
||||
if (segCount < 2) {
|
||||
// Add safety check for segment elements to prevent UI crashes
|
||||
const segdElement = gId(`segd${lSeg}`);
|
||||
if (segdElement) segdElement.classList.add("hide"); // hide delete if only one segment
|
||||
const seg0briElement = gId("seg0bri");
|
||||
const segp0Element = gId(`segp0`);
|
||||
if (seg0briElement && segp0Element && parseInt(seg0briElement.value)==255) segp0Element.classList.add("hide");
|
||||
gId(`segd${lSeg}`).classList.add("hide"); // hide delete if only one segment
|
||||
if (parseInt(gId("seg0bri").value)==255) gId(`segp0`).classList.add("hide");
|
||||
// hide segment controls if there is only one segment in simplified UI
|
||||
if (simplifiedUI) gId("segcont").classList.add("hide");
|
||||
}
|
||||
// Add safety checks for segment control elements
|
||||
const segSElement = gId(`seg${lSeg}s`);
|
||||
const segEElement = gId(`seg${lSeg}e`);
|
||||
const segrElement = gId(`segr${lSeg}`);
|
||||
if (!isM && !noNewSegs && segSElement && segEElement && segrElement) {
|
||||
const segLen = cfg.comp.seglen ? parseInt(segSElement.value) : 0;
|
||||
const segEnd = parseInt(segEElement.value);
|
||||
if (segLen + segEnd < ledCount) segrElement.classList.remove("hide");
|
||||
}
|
||||
if (!isM && !noNewSegs && (cfg.comp.seglen?parseInt(gId(`seg${lSeg}s`).value):0)+parseInt(gId(`seg${lSeg}e`).value)<ledCount) gId(`segr${lSeg}`).classList.remove("hide");
|
||||
gId('segutil2').style.display = (segCount > 1) ? "block":"none"; // rsbtn parent
|
||||
|
||||
if (Array.isArray(li.maps) && li.maps.length>1) {
|
||||
@@ -2276,9 +2253,7 @@ function rptSeg(s)
|
||||
var rev = gId(`seg${s}rev`).checked;
|
||||
var mi = gId(`seg${s}mi`).checked;
|
||||
var sel = gId(`seg${s}sel`).checked;
|
||||
// Add safety check for segment power element to prevent UI crashes
|
||||
const segPwrElement = gId(`seg${s}pwr`);
|
||||
var pwr = segPwrElement ? segPwrElement.classList.contains('act') : false;
|
||||
var pwr = gId(`seg${s}pwr`).classList.contains('act');
|
||||
var obj = {"seg": {"id": s, "n": name, "start": start, "stop": (cfg.comp.seglen?start:0)+stop, "rev": rev, "mi": mi, "on": pwr, "bri": parseInt(gId(`seg${s}bri`).value), "sel": sel}};
|
||||
if (gId(`seg${s}grp`)) {
|
||||
var grp = parseInt(gId(`seg${s}grp`).value);
|
||||
@@ -2405,13 +2380,7 @@ function setGrp(s, g)
|
||||
|
||||
function setSegPwr(s)
|
||||
{
|
||||
// Add safety check for segment power element to prevent UI crashes
|
||||
const segPwrElement = gId(`seg${s}pwr`);
|
||||
if (!segPwrElement) {
|
||||
console.warn('Segment power element not found, skipping power toggle');
|
||||
return;
|
||||
}
|
||||
var pwr = segPwrElement.classList.contains('act');
|
||||
var pwr = gId(`seg${s}pwr`).classList.contains('act');
|
||||
var obj = {"seg": {"id": s, "on": !pwr}};
|
||||
requestJson(obj);
|
||||
}
|
||||
|
||||
@@ -28,10 +28,13 @@
|
||||
<h2>WLED Software Update</h2>
|
||||
<form method='POST' action='./update' id='upd' enctype='multipart/form-data' onsubmit="toggle('upd')">
|
||||
Installed version: <span class="sip">WLED ##VERSION##</span><br>
|
||||
Release: <span class="sip">##RELEASE##</span><br>
|
||||
Download the latest binary: <a href="https://github.com/wled-dev/WLED/releases" target="_blank"
|
||||
style="vertical-align: text-bottom; display: inline-flex;">
|
||||
<img src="https://img.shields.io/github/release/wled-dev/WLED.svg?style=flat-square"></a><br>
|
||||
<input type='file' name='update' required><br> <!--should have accept='.bin', but it prevents file upload from android app-->
|
||||
<input type='checkbox' name='skipValidation' id='skipValidation'>
|
||||
<label for='skipValidation'>Ignore firmware validation</label><br>
|
||||
<button type="submit">Update!</button><br>
|
||||
<hr class="sml">
|
||||
<button id="rev" type="button" onclick="cR()">Revert update</button><br>
|
||||
|
||||
122
wled00/ota_release_check.cpp
Normal file
122
wled00/ota_release_check.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
#include "ota_release_check.h"
|
||||
#include "wled.h"
|
||||
|
||||
#ifdef ESP32
|
||||
#include <esp_app_format.h>
|
||||
#include <esp_ota_ops.h>
|
||||
#endif
|
||||
|
||||
// Same hash function used at compile time (must match wled_custom_desc.cpp)
|
||||
static uint32_t djb2_hash(const char* str) {
|
||||
uint32_t hash = 5381;
|
||||
while (*str) {
|
||||
hash = ((hash << 5) + hash) + *str++;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
bool extractReleaseFromCustomDesc(const uint8_t* binaryData, size_t dataSize, char* extractedRelease) {
|
||||
if (!binaryData || !extractedRelease || dataSize < 64) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Search in first 8KB only - ESP32 .rodata.wled_desc and ESP8266 .ver_number
|
||||
// sections appear early in binary. 8KB should be sufficient for metadata discovery
|
||||
// while minimizing processing time for large firmware files.
|
||||
const size_t search_limit = min(dataSize, (size_t)8192);
|
||||
|
||||
for (size_t offset = 0; offset <= search_limit - sizeof(wled_custom_desc_t); offset++) {
|
||||
const wled_custom_desc_t* custom_desc = (const wled_custom_desc_t*)(binaryData + offset);
|
||||
|
||||
// Check for magic number
|
||||
if (custom_desc->magic == WLED_CUSTOM_DESC_MAGIC) {
|
||||
// Found potential match, validate version
|
||||
if (custom_desc->version != WLED_CUSTOM_DESC_VERSION) {
|
||||
DEBUG_PRINTF_P(PSTR("Found WLED structure at offset %u but version mismatch: %u\n"),
|
||||
offset, custom_desc->version);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Validate hash using same algorithm as compile-time
|
||||
uint32_t expected_hash = djb2_hash(custom_desc->release_name);
|
||||
if (custom_desc->crc32 != expected_hash) {
|
||||
DEBUG_PRINTF_P(PSTR("Found WLED structure at offset %u but hash mismatch\n"), offset);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Valid structure found
|
||||
strncpy(extractedRelease, custom_desc->release_name, WLED_RELEASE_NAME_MAX_LEN - 1);
|
||||
extractedRelease[WLED_RELEASE_NAME_MAX_LEN - 1] = '\0';
|
||||
|
||||
#ifdef ESP32
|
||||
DEBUG_PRINTF_P(PSTR("Extracted ESP32 release name from .rodata.wled_desc section at offset %u: '%s'\n"),
|
||||
offset, extractedRelease);
|
||||
#else
|
||||
DEBUG_PRINTF_P(PSTR("Extracted ESP8266 release name from .ver_number section at offset %u: '%s'\n"),
|
||||
offset, extractedRelease);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_PRINTLN(F("No WLED custom description found in binary"));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool validateReleaseCompatibility(const char* extractedRelease) {
|
||||
if (!extractedRelease || strlen(extractedRelease) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Simple string comparison - releases must match exactly
|
||||
bool match = strcmp(releaseString, extractedRelease) == 0;
|
||||
|
||||
DEBUG_PRINTF_P(PSTR("Release compatibility check: current='%s', uploaded='%s', match=%s\n"),
|
||||
releaseString, extractedRelease, match ? "YES" : "NO");
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
bool shouldAllowOTA(const uint8_t* binaryData, size_t dataSize, bool skipValidation, char* errorMessage) {
|
||||
// Clear error message
|
||||
if (errorMessage) {
|
||||
errorMessage[0] = '\0';
|
||||
}
|
||||
|
||||
// Ensure our custom description structure is referenced (prevents optimization)
|
||||
const wled_custom_desc_t* local_desc = getWledCustomDesc();
|
||||
(void)local_desc; // Suppress unused variable warning
|
||||
|
||||
// If user chose to ignore release check, allow OTA
|
||||
if (skipValidation) {
|
||||
DEBUG_PRINTLN(F("OTA release check bypassed by user"));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try to extract release name directly from binary data
|
||||
char extractedRelease[WLED_RELEASE_NAME_MAX_LEN];
|
||||
bool hasCustomDesc = extractReleaseFromCustomDesc(binaryData, dataSize, extractedRelease);
|
||||
|
||||
if (!hasCustomDesc) {
|
||||
// No custom description - this could be a legacy binary
|
||||
if (errorMessage) {
|
||||
strcpy(errorMessage, "Binary has no release compatibility metadata. Check 'Ignore validation' to proceed.");
|
||||
}
|
||||
DEBUG_PRINTLN(F("OTA blocked: No custom description found"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate compatibility using extracted release name
|
||||
if (!validateReleaseCompatibility(extractedRelease)) {
|
||||
if (errorMessage) {
|
||||
snprintf(errorMessage, 127, "Release mismatch: current='%s', uploaded='%s'. Check 'Ignore validation' to proceed.",
|
||||
releaseString, extractedRelease);
|
||||
}
|
||||
DEBUG_PRINTF_P(PSTR("OTA blocked: Release mismatch current='%s', uploaded='%s'\n"),
|
||||
releaseString, extractedRelease);
|
||||
return false;
|
||||
}
|
||||
|
||||
DEBUG_PRINTLN(F("OTA allowed: Release names match"));
|
||||
return true;
|
||||
}
|
||||
64
wled00/ota_release_check.h
Normal file
64
wled00/ota_release_check.h
Normal file
@@ -0,0 +1,64 @@
|
||||
#ifndef WLED_OTA_RELEASE_CHECK_H
|
||||
#define WLED_OTA_RELEASE_CHECK_H
|
||||
|
||||
/*
|
||||
* OTA Release Compatibility Checking using ESP-IDF Custom Description Section
|
||||
* Functions to extract and validate release names from uploaded binary files using embedded metadata
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#ifdef ESP32
|
||||
#include <esp_app_format.h>
|
||||
#endif
|
||||
|
||||
#define WLED_CUSTOM_DESC_MAGIC 0x57535453 // "WSTS" (WLED System Tag Structure)
|
||||
#define WLED_CUSTOM_DESC_VERSION 1
|
||||
#define WLED_RELEASE_NAME_MAX_LEN 48
|
||||
|
||||
/**
|
||||
* WLED Custom Description Structure
|
||||
* This structure is embedded in platform-specific sections at a fixed offset
|
||||
* in ESP32/ESP8266 binaries, allowing extraction without modifying the binary format
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t magic; // Magic number to identify WLED custom description
|
||||
uint32_t version; // Structure version for future compatibility
|
||||
char release_name[WLED_RELEASE_NAME_MAX_LEN]; // Release name (null-terminated)
|
||||
uint32_t crc32; // CRC32 of the above fields for integrity check
|
||||
} __attribute__((packed)) wled_custom_desc_t;
|
||||
|
||||
/**
|
||||
* Extract release name from binary using ESP-IDF custom description section
|
||||
* @param binaryData Pointer to binary file data
|
||||
* @param dataSize Size of binary data in bytes
|
||||
* @param extractedRelease Buffer to store extracted release name (should be at least WLED_RELEASE_NAME_MAX_LEN bytes)
|
||||
* @return true if release name was found and extracted, false otherwise
|
||||
*/
|
||||
bool extractReleaseFromCustomDesc(const uint8_t* binaryData, size_t dataSize, char* extractedRelease);
|
||||
|
||||
/**
|
||||
* Validate if extracted release name matches current release
|
||||
* @param extractedRelease Release name from uploaded binary
|
||||
* @return true if releases match (OTA should proceed), false if they don't match
|
||||
*/
|
||||
bool validateReleaseCompatibility(const char* extractedRelease);
|
||||
|
||||
/**
|
||||
* Check if OTA should be allowed based on release compatibility using custom description
|
||||
* @param binaryData Pointer to binary file data (not modified)
|
||||
* @param dataSize Size of binary data in bytes
|
||||
* @param skipValidation If true, skip release validation
|
||||
* @param errorMessage Buffer to store error message if validation fails (should be at least 128 bytes)
|
||||
* @return true if OTA should proceed, false if it should be blocked
|
||||
*/
|
||||
bool shouldAllowOTA(const uint8_t* binaryData, size_t dataSize, bool skipValidation, char* errorMessage);
|
||||
|
||||
/**
|
||||
* Get pointer to the embedded custom description structure
|
||||
* This ensures the structure is referenced and not optimized out
|
||||
* @return pointer to the custom description structure
|
||||
*/
|
||||
const wled_custom_desc_t* getWledCustomDesc();
|
||||
|
||||
#endif // WLED_OTA_RELEASE_CHECK_H
|
||||
31
wled00/wled_custom_desc.cpp
Normal file
31
wled00/wled_custom_desc.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
#include "ota_release_check.h"
|
||||
#include "wled.h"
|
||||
|
||||
// Simple compile-time hash function for release name validation
|
||||
constexpr uint32_t djb2_hash(const char* str) {
|
||||
uint32_t hash = 5381;
|
||||
while (*str) {
|
||||
hash = ((hash << 5) + hash) + *str++;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
// Single structure definition for both platforms
|
||||
#ifdef ESP32
|
||||
const wled_custom_desc_t __attribute__((section(".rodata.wled_desc"))) wled_custom_description = {
|
||||
#elif defined(ESP8266)
|
||||
const wled_custom_desc_t __attribute__((section(".ver_number"))) wled_custom_description = {
|
||||
#endif
|
||||
WLED_CUSTOM_DESC_MAGIC, // magic
|
||||
WLED_CUSTOM_DESC_VERSION, // version
|
||||
WLED_RELEASE_NAME, // release_name
|
||||
djb2_hash(WLED_RELEASE_NAME) // crc32 - computed at compile time
|
||||
};
|
||||
|
||||
// Single reference to ensure it's not optimized away
|
||||
const wled_custom_desc_t* __attribute__((used)) wled_custom_desc_ref = &wled_custom_description;
|
||||
|
||||
// Function to ensure the structure is referenced by code
|
||||
const wled_custom_desc_t* getWledCustomDesc() {
|
||||
return &wled_custom_description;
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
#else
|
||||
#include <Update.h>
|
||||
#endif
|
||||
#include "ota_release_check.h"
|
||||
#endif
|
||||
#include "html_ui.h"
|
||||
#include "html_settings.h"
|
||||
@@ -424,32 +425,81 @@ void initServer()
|
||||
return;
|
||||
}
|
||||
if (!correctPIN || otaLock) return;
|
||||
|
||||
// Static variable to track release check status across chunks
|
||||
static bool releaseCheckPassed = false;
|
||||
|
||||
if(!index){
|
||||
DEBUG_PRINTLN(F("OTA Update Start"));
|
||||
|
||||
// Check if user wants to ignore release check
|
||||
bool skipValidation = request->hasParam("skipValidation", true);
|
||||
|
||||
// Validate OTA release compatibility using the first chunk data directly
|
||||
char errorMessage[128];
|
||||
releaseCheckPassed = shouldAllowOTA(data, len, skipValidation, errorMessage);
|
||||
|
||||
if (!releaseCheckPassed) {
|
||||
DEBUG_PRINTF_P(PSTR("OTA blocked: %s\n"), errorMessage);
|
||||
request->send(400, FPSTR(CONTENT_TYPE_PLAIN), errorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_PRINTLN(F("Release check passed, starting OTA update"));
|
||||
|
||||
#if WLED_WATCHDOG_TIMEOUT > 0
|
||||
WLED::instance().disableWatchdog();
|
||||
#endif
|
||||
UsermodManager::onUpdateBegin(true); // notify usermods that update is about to begin (some may require task de-init)
|
||||
lastEditTime = millis(); // make sure PIN does not lock during update
|
||||
|
||||
// Start the actual OTA update
|
||||
strip.suspend();
|
||||
backupConfig(); // backup current config in case the update ends badly
|
||||
strip.resetSegments(); // free as much memory as you can
|
||||
#ifdef ESP8266
|
||||
Update.runAsync(true);
|
||||
#endif
|
||||
Update.begin((ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000);
|
||||
}
|
||||
if(!Update.hasError()) Update.write(data, len);
|
||||
if(isFinal){
|
||||
if(Update.end(true)){
|
||||
DEBUG_PRINTLN(F("Update Success"));
|
||||
} else {
|
||||
DEBUG_PRINTLN(F("Update Failed"));
|
||||
|
||||
// Begin update with the firmware size from content length
|
||||
size_t updateSize = request->contentLength() > 0 ? request->contentLength() : ((ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000);
|
||||
if (!Update.begin(updateSize)) {
|
||||
DEBUG_PRINTF_P(PSTR("OTA Failed to begin: %s\n"), Update.getErrorString().c_str());
|
||||
strip.resume();
|
||||
UsermodManager::onUpdateBegin(false); // notify usermods that update has failed (some may require task init)
|
||||
UsermodManager::onUpdateBegin(false);
|
||||
#if WLED_WATCHDOG_TIMEOUT > 0
|
||||
WLED::instance().enableWatchdog();
|
||||
#endif
|
||||
#ifdef ESP32
|
||||
request->send(500, FPSTR(CONTENT_TYPE_PLAIN), String("Update.begin failed: ") + Update.errorString());
|
||||
#else
|
||||
request->send(500, FPSTR(CONTENT_TYPE_PLAIN), String("Update.begin failed: ") + Update.getErrorString());
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Write chunk data to OTA update (only if release check passed)
|
||||
if (releaseCheckPassed && !Update.hasError()) {
|
||||
if (Update.write(data, len) != len) {
|
||||
DEBUG_PRINTF_P(PSTR("OTA write failed on chunk %zu: %s\n"), index, Update.getErrorString().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if(isFinal){
|
||||
DEBUG_PRINTLN(F("OTA Update End"));
|
||||
|
||||
if (releaseCheckPassed) {
|
||||
if(Update.end(true)){
|
||||
DEBUG_PRINTLN(F("Update Success"));
|
||||
} else {
|
||||
DEBUG_PRINTLN(F("Update Failed"));
|
||||
strip.resume();
|
||||
UsermodManager::onUpdateBegin(false); // notify usermods that update has failed (some may require task init)
|
||||
#if WLED_WATCHDOG_TIMEOUT > 0
|
||||
WLED::instance().enableWatchdog();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user