Compare commits

..

13 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
db71cf3289 Remove unnecessary must-revalidate and _codeql gitignore entry
Co-authored-by: DedeHai <6280424+DedeHai@users.noreply.github.com>
2025-11-28 06:12:11 +00:00
copilot-swe-agent[bot]
714a7f816c Change WEB_BUILD_TIME to UNIX timestamp integer for flash savings
Co-authored-by: DedeHai <6280424+DedeHai@users.noreply.github.com>
2025-11-27 13:52:25 +00:00
copilot-swe-agent[bot]
0adfc17617 Change WEB_BUILD_TIME format to YYMMDD_hhmmss (UTC)
Co-authored-by: Aircoookie <21045690+Aircoookie@users.noreply.github.com>
2025-11-27 13:13:42 +00:00
copilot-swe-agent[bot]
54f650a0e9 Add WEB_BUILD_TIME to html_ui.h and use it for ETag generation
Co-authored-by: DedeHai <6280424+DedeHai@users.noreply.github.com>
2025-11-27 13:00:02 +00:00
copilot-swe-agent[bot]
441bd62ad6 Remove CodeQL artifact and add to gitignore
Co-authored-by: DedeHai <6280424+DedeHai@users.noreply.github.com>
2025-11-27 11:56:17 +00:00
copilot-swe-agent[bot]
2dfe09e1b5 Add must-revalidate to Cache-Control header for better cache invalidation
Co-authored-by: DedeHai <6280424+DedeHai@users.noreply.github.com>
2025-11-27 11:55:55 +00:00
copilot-swe-agent[bot]
c9ac77a2b7 Add must-revalidate to Cache-Control header for better cache invalidation
Co-authored-by: DedeHai <6280424+DedeHai@users.noreply.github.com>
2025-11-27 11:54:48 +00:00
copilot-swe-agent[bot]
9fcdfd976a Initial plan 2025-11-27 11:48:16 +00:00
Damian Schneider
6b607fb545 refined PS replacement ifdefs (#5103)
* refined PS replacement ifdefs

* bugfixes, added glitter and sparkle as they a lightweight (1k of flash)
2025-11-26 22:25:10 +01:00
Damian Schneider
e761418531 adding legacy support for "edit?list=/" command, fix indentation (#5092) 2025-11-26 22:23:37 +01:00
Damian Schneider
fca921ee82 Adding "Complete" mode to Dissolve FX: always fades completely (#5016)
This allows for much slower speed setting to not turn into "twinkle" effect
2025-11-26 22:22:13 +01:00
Damian Schneider
fc7993f4a7 update default AP channel to 6, possible fix for "AP does not show" (#5115) 2025-11-26 21:22:22 +01:00
Damian Schneider
f12e3e03ac set default AP channel to 7 to help with bad antennas
Channel 1 can have very bad performance on some designs, its better to use a center channel.
2025-11-26 07:33:47 +01:00
5 changed files with 79 additions and 85 deletions

View File

@@ -38,6 +38,11 @@ const wledBanner = `
\t\t\x1b[36m build script for web UI
\x1b[0m`;
// Generate build timestamp as UNIX timestamp (seconds since epoch)
function generateBuildTime() {
return Math.floor(Date.now() / 1000);
}
const singleHeader = `/*
* Binary array for the Web UI.
* gzip is used for smaller size and improved speeds.
@@ -45,6 +50,9 @@ const singleHeader = `/*
* Please see https://kno.wled.ge/advanced/custom-features/#changing-web-ui
* to find out how to easily modify the web UI source!
*/
// Automatically generated build time for cache busting (UNIX timestamp)
#define WEB_BUILD_TIME ${generateBuildTime()}
`;

View File

@@ -25,51 +25,11 @@ class StairwayWipeUsermod : public Usermod {
public:
void setup() {
}
/**
* @brief Drives the stairway wipe state machine and reacts to user variables.
*
* @details
* Reads userVar0 (U0) and userVar1 (U1) to control a directional stairway color wipe:
* - U0 = 0: off.
* - U0 = 1: start/keep wipe from local side.
* - U0 = 2: start/keep wipe from opposite side.
* - U0 = 3: toggle mode for direction 1 (becomes 1 when off, 0 when on).
* - U0 = 4: toggle mode for direction 2 (becomes 2 when off, 0 when on).
*
* Manages a small state machine:
* - State 0: idle, will start a wipe.
* - State 1: wiping; transitions to static when wipe completes.
* - State 2: static/hold; transitions to off after U1 seconds if U1 > 0.
* - State 3: prepare to wipe off (or immediately off if off-wipe is disabled).
* - State 4: wiping off; turns fully off when wipe-off completes.
*
* The wipe duration and wipe-off timing are derived from the current effectSpeed. A change
* in trigger side (previousUserVar0 differing from userVar0) forces the usermod to begin
* turning off. When turning on/off the code invokes startWipe() or turnOff() and issues
* color/state update notifications as appropriate.
*
* @note Defining STAIRCASE_WIPE_OFF enables a reverse color-wipe transition when turning off;
* without it the lights fade off immediately.
*/
void loop() {
void loop() {
//userVar0 (U0 in HTTP API):
//has to be set to 1 if movement is detected on the PIR that is the same side of the staircase as the ESP8266
//has to be set to 2 if movement is detected on the PIR that is the opposite side
//can be set to 0 if no movement is detected. Otherwise LEDs will turn off after a configurable timeout (userVar1 seconds)
//U0 = 3: Toggle mode for direction 1 (if off, turn on with U0=1; if on, turn off with U0=0)
//U0 = 4: Toggle mode for direction 2 (if off, turn on with U0=2; if on, turn off with U0=0)
// Handle toggle modes U0=3 and U0=4
if (userVar0 == 3 || userVar0 == 4) {
if (wipeState == 0 || wipeState == 3 || wipeState == 4) {
// Lights are off or turning off, so turn them on
wipeState = 0; // Reset state so the state machine starts fresh
userVar0 = (userVar0 == 3) ? 1 : 2;
} else {
// Lights are on or turning on, so turn them off
userVar0 = 0;
}
}
if (userVar0 > 0)
{

View File

@@ -15,14 +15,25 @@
#include "fcn_declare.h"
#if !(defined(WLED_DISABLE_PARTICLESYSTEM2D) && defined(WLED_DISABLE_PARTICLESYSTEM1D))
#include "FXparticleSystem.h"
#include "FXparticleSystem.h" // include particle system code only if at least one system is enabled
#ifdef WLED_DISABLE_PARTICLESYSTEM2D
#define WLED_PS_DONT_REPLACE_2D_FX
#endif
#ifdef WLED_DISABLE_PARTICLESYSTEM1D
#define WLED_PS_DONT_REPLACE_1D_FX
#endif
#ifdef ESP8266
#if !defined(WLED_DISABLE_PARTICLESYSTEM2D) && !defined(WLED_DISABLE_PARTICLESYSTEM1D)
#error ESP8266 does not support 1D and 2D particle systems simultaneously. Please disable one of them.
#error ESP8266 does not support 1D and 2D particle systems simultaneously. Please disable one of them.
#endif
#endif
#else
#define WLED_PS_DONT_REPLACE_FX
#define WLED_PS_DONT_REPLACE_1D_FX
#define WLED_PS_DONT_REPLACE_2D_FX
#endif
#ifdef WLED_PS_DONT_REPLACE_FX
#define WLED_PS_DONT_REPLACE_1D_FX
#define WLED_PS_DONT_REPLACE_2D_FX
#endif
//////////////
@@ -713,7 +724,7 @@ uint16_t dissolve(uint32_t color) {
if (SEGENV.aux0) { //dissolve to primary/palette
if (pixels[i] == SEGCOLOR(1)) {
pixels[i] = color == SEGCOLOR(0) ? SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0) : color;
break; //only spawn 1 new pixel per frame per 50 LEDs
break; //only spawn 1 new pixel per frame
}
} else { //dissolve to secondary
if (pixels[i] != SEGCOLOR(1)) {
@@ -724,14 +735,27 @@ uint16_t dissolve(uint32_t color) {
}
}
}
// fix for #4401
for (unsigned i = 0; i < SEGLEN; i++) SEGMENT.setPixelColor(i, pixels[i]);
unsigned incompletePixels = 0;
for (unsigned i = 0; i < SEGLEN; i++) {
SEGMENT.setPixelColor(i, pixels[i]); // fix for #4401
if (SEGMENT.check2) {
if (SEGENV.aux0) {
if (pixels[i] == SEGCOLOR(1)) incompletePixels++;
} else {
if (pixels[i] != SEGCOLOR(1)) incompletePixels++;
}
}
}
if (SEGENV.step > (255 - SEGMENT.speed) + 15U) {
SEGENV.aux0 = !SEGENV.aux0;
SEGENV.step = 0;
} else {
SEGENV.step++;
if (SEGMENT.check2) {
if (incompletePixels == 0)
SEGENV.step++; // only advance step once all pixels have changed
} else
SEGENV.step++;
}
return FRAMETIME;
@@ -744,7 +768,7 @@ uint16_t dissolve(uint32_t color) {
uint16_t mode_dissolve(void) {
return dissolve(SEGMENT.check1 ? SEGMENT.color_wheel(hw_random8()) : SEGCOLOR(0));
}
static const char _data_FX_MODE_DISSOLVE[] PROGMEM = "Dissolve@Repeat speed,Dissolve speed,,,,Random;!,!;!";
static const char _data_FX_MODE_DISSOLVE[] PROGMEM = "Dissolve@Repeat speed,Dissolve speed,,,,Random,Complete;!,!;!";
/*
@@ -755,7 +779,6 @@ uint16_t mode_dissolve_random(void) {
}
static const char _data_FX_MODE_DISSOLVE_RANDOM[] PROGMEM = "Dissolve Rnd@Repeat speed,Dissolve speed;,!;!";
/*
* Blinks one LED at a time.
* Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
@@ -777,7 +800,6 @@ uint16_t mode_sparkle(void) {
}
static const char _data_FX_MODE_SPARKLE[] PROGMEM = "Sparkle@!,,,,,,Overlay;!,!;!;;m12=0";
/*
* Lights all LEDs in the color. Flashes single col 1 pixels randomly. (List name: Sparkle Dark)
* Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
@@ -1752,7 +1774,6 @@ uint16_t mode_tricolor_fade(void) {
}
static const char _data_FX_MODE_TRICOLOR_FADE[] PROGMEM = "Tri Fade@!;1,2,3;!";
#ifdef WLED_PS_DONT_REPLACE_FX
/*
* Creates random comets
* Custom mode by Keith Lord: https://github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/MultiComet.h
@@ -1791,7 +1812,6 @@ uint16_t mode_multi_comet(void) {
}
static const char _data_FX_MODE_MULTI_COMET[] PROGMEM = "Multi Comet@!,Fade;!,!;!;1";
#undef MAX_COMETS
#endif // WLED_PS_DONT_REPLACE_FX
/*
* Running random pixels ("Stream 2")
@@ -2118,7 +2138,7 @@ uint16_t mode_palette() {
}
static const char _data_FX_MODE_PALETTE[] PROGMEM = "Palette@Shift,Size,Rotation,,,Animate Shift,Animate Rotation,Anamorphic;;!;12;ix=112,c1=0,o1=1,o2=0,o3=1";
#ifdef WLED_PS_DONT_REPLACE_FX
#if defined(WLED_PS_DONT_REPLACE_1D_FX) || defined(WLED_PS_DONT_REPLACE_2D_FX)
// WLED limitation: Analog Clock overlay will NOT work when Fire2012 is active
// Fire2012 by Mark Kriegsman, July 2012
// as part of "Five Elements" shown here: http://youtu.be/knWiGsmgycY
@@ -2205,7 +2225,7 @@ uint16_t mode_fire_2012() {
return FRAMETIME;
}
static const char _data_FX_MODE_FIRE_2012[] PROGMEM = "Fire 2012@Cooling,Spark rate,,2D Blur,Boost;;!;1;pal=35,sx=64,ix=160,m12=1,c2=128"; // bars
#endif // WLED_PS_DONT_REPLACE_FX
#endif // WLED_PS_DONT_REPLACE_x_FX
// colored stripes pulsing at a defined Beats-Per-Minute (BPM)
uint16_t mode_bpm() {
@@ -3056,7 +3076,7 @@ uint16_t mode_bouncing_balls(void) {
}
static const char _data_FX_MODE_BOUNCINGBALLS[] PROGMEM = "Bouncing Balls@Gravity,# of balls,,,,,Overlay;!,!,!;!;1;m12=1"; //bar
#ifdef WLED_PS_DONT_REPLACE_FX
#ifdef WLED_PS_DONT_REPLACE_1D_FX
/*
* bouncing balls on a track track Effect modified from Aircoookie's bouncing balls
* Courtesy of pjhatch (https://github.com/pjhatch)
@@ -3156,7 +3176,7 @@ static uint16_t rolling_balls(void) {
return FRAMETIME;
}
static const char _data_FX_MODE_ROLLINGBALLS[] PROGMEM = "Rolling Balls@!,# of balls,,,,Collide,Overlay,Trails;!,!,!;!;1;m12=1"; //bar
#endif // WLED_PS_DONT_REPLACE_FX
#endif // WLED_PS_DONT_REPLACE_1D_FX
/*
* Sinelon stolen from FASTLED examples
@@ -3213,7 +3233,6 @@ uint16_t mode_sinelon_rainbow(void) {
}
static const char _data_FX_MODE_SINELON_RAINBOW[] PROGMEM = "Sinelon Rainbow@!,Trail;,,!;!";
// utility function that will add random glitter to SEGMENT
void glitter_base(uint8_t intensity, uint32_t col = ULTRAWHITE) {
if (intensity > hw_random8()) SEGMENT.setPixelColor(hw_random16(SEGLEN), col);
@@ -3418,7 +3437,7 @@ uint16_t mode_candle_multi()
}
static const char _data_FX_MODE_CANDLE_MULTI[] PROGMEM = "Candle Multi@!,!;!,!;!;;sx=96,ix=224,pal=0";
#ifdef WLED_PS_DONT_REPLACE_FX
#ifdef WLED_PS_DONT_REPLACE_1D_FX
/*
/ Fireworks in starburst effect
/ based on the video: https://www.reddit.com/r/arduino/comments/c3sd46/i_made_this_fireworks_effect_for_my_led_strips/
@@ -3550,9 +3569,9 @@ uint16_t mode_starburst(void) {
}
#undef STARBURST_MAX_FRAG
static const char _data_FX_MODE_STARBURST[] PROGMEM = "Fireworks Starburst@Chance,Fragments,,,,,Overlay;,!;!;;pal=11,m12=0";
#endif // WLED_PS_DONT_REPLACE_FX
#endif // WLED_PS_DONT_REPLACE_1DFX
#ifdef WLED_PS_DONT_REPLACE_FX
#if defined(WLED_PS_DONT_REPLACE_1D_FX) || defined(WLED_PS_DONT_REPLACE_2D_FX)
/*
* Exploding fireworks effect
* adapted from: http://www.anirama.com/1000leds/1d-fireworks/
@@ -3690,7 +3709,7 @@ uint16_t mode_exploding_fireworks(void)
}
#undef MAX_SPARKS
static const char _data_FX_MODE_EXPLODING_FIREWORKS[] PROGMEM = "Fireworks 1D@Gravity,Firing side;!,!;!;12;pal=11,ix=128";
#endif // WLED_PS_DONT_REPLACE_FX
#endif // WLED_PS_DONT_REPLACE_x_FX
/*
* Drip Effect
@@ -4338,7 +4357,7 @@ static const char _data_FX_MODE_CHUNCHUN[] PROGMEM = "Chunchun@!,Gap size;!,!;!"
#define SPOT_MAX_COUNT 49 //Number of simultaneous waves
#endif
#ifdef WLED_PS_DONT_REPLACE_FX
#ifdef WLED_PS_DONT_REPLACE_1D_FX
//13 bytes
typedef struct Spotlight {
float speed;
@@ -4472,7 +4491,7 @@ uint16_t mode_dancing_shadows(void)
return FRAMETIME;
}
static const char _data_FX_MODE_DANCING_SHADOWS[] PROGMEM = "Dancing Shadows@!,# of shadows;!;!";
#endif // WLED_PS_DONT_REPLACE_FX
#endif // WLED_PS_DONT_REPLACE_1D_FX
/*
Imitates a washing machine, rotating same waves forward, then pause, then backward.
@@ -6033,7 +6052,7 @@ uint16_t mode_2Dcrazybees(void) {
static const char _data_FX_MODE_2DCRAZYBEES[] PROGMEM = "Crazy Bees@!,Blur,,,,Smear;;!;2;pal=11,ix=0";
#undef MAX_BEES
#ifdef WLED_PS_DONT_REPLACE_FX
#ifdef WLED_PS_DONT_REPLACE_2D_FX
/////////////////////////
// 2D Ghost Rider //
/////////////////////////
@@ -6221,7 +6240,7 @@ uint16_t mode_2Dfloatingblobs(void) {
}
static const char _data_FX_MODE_2DBLOBS[] PROGMEM = "Blobs@!,# blobs,Blur,Trail;!;!;2;c1=8";
#undef MAX_BLOBS
#endif // WLED_PS_DONT_REPLACE_FX
#endif // WLED_PS_DONT_REPLACE_2D_FX
////////////////////////////
// 2D Scrolling text //
@@ -10873,16 +10892,18 @@ void WS2812FX::setupEffectData() {
addEffect(FX_MODE_SPOTS, &mode_spots, _data_FX_MODE_SPOTS);
addEffect(FX_MODE_SPOTS_FADE, &mode_spots_fade, _data_FX_MODE_SPOTS_FADE);
addEffect(FX_MODE_COMET, &mode_comet, _data_FX_MODE_COMET);
#ifdef WLED_PS_DONT_REPLACE_FX
addEffect(FX_MODE_MULTI_COMET, &mode_multi_comet, _data_FX_MODE_MULTI_COMET);
addEffect(FX_MODE_ROLLINGBALLS, &rolling_balls, _data_FX_MODE_ROLLINGBALLS);
#if defined(WLED_PS_DONT_REPLACE_1D_FX) || defined(WLED_PS_DONT_REPLACE_2D_FX)
addEffect(FX_MODE_FIRE_2012, &mode_fire_2012, _data_FX_MODE_FIRE_2012);
addEffect(FX_MODE_EXPLODING_FIREWORKS, &mode_exploding_fireworks, _data_FX_MODE_EXPLODING_FIREWORKS);
#endif
addEffect(FX_MODE_SPARKLE, &mode_sparkle, _data_FX_MODE_SPARKLE);
addEffect(FX_MODE_GLITTER, &mode_glitter, _data_FX_MODE_GLITTER);
addEffect(FX_MODE_SOLID_GLITTER, &mode_solid_glitter, _data_FX_MODE_SOLID_GLITTER);
addEffect(FX_MODE_MULTI_COMET, &mode_multi_comet, _data_FX_MODE_MULTI_COMET);
#ifdef WLED_PS_DONT_REPLACE_1D_FX
addEffect(FX_MODE_ROLLINGBALLS, &rolling_balls, _data_FX_MODE_ROLLINGBALLS);
addEffect(FX_MODE_STARBURST, &mode_starburst, _data_FX_MODE_STARBURST);
addEffect(FX_MODE_DANCING_SHADOWS, &mode_dancing_shadows, _data_FX_MODE_DANCING_SHADOWS);
addEffect(FX_MODE_FIRE_2012, &mode_fire_2012, _data_FX_MODE_FIRE_2012);
addEffect(FX_MODE_EXPLODING_FIREWORKS, &mode_exploding_fireworks, _data_FX_MODE_EXPLODING_FIREWORKS);
#endif
addEffect(FX_MODE_CANDLE, &mode_candle, _data_FX_MODE_CANDLE);
addEffect(FX_MODE_BOUNCINGBALLS, &mode_bouncing_balls, _data_FX_MODE_BOUNCINGBALLS);
@@ -10946,7 +10967,7 @@ void WS2812FX::setupEffectData() {
addEffect(FX_MODE_2DSPACESHIPS, &mode_2Dspaceships, _data_FX_MODE_2DSPACESHIPS);
addEffect(FX_MODE_2DCRAZYBEES, &mode_2Dcrazybees, _data_FX_MODE_2DCRAZYBEES);
#ifdef WLED_PS_DONT_REPLACE_FX
#ifdef WLED_PS_DONT_REPLACE_2D_FX
addEffect(FX_MODE_2DGHOSTRIDER, &mode_2Dghostrider, _data_FX_MODE_2DGHOSTRIDER);
addEffect(FX_MODE_2DBLOBS, &mode_2Dfloatingblobs, _data_FX_MODE_2DBLOBS);
#endif

View File

@@ -365,7 +365,7 @@ WLED_GLOBAL wifi_options_t wifiOpt _INIT_N(({0, 1, false, AP_BEHAVIOR_BOOT_NO_CO
#define force802_3g wifiOpt.force802_3g
#else
WLED_GLOBAL int8_t selectedWiFi _INIT(0);
WLED_GLOBAL byte apChannel _INIT(1); // 2.4GHz WiFi AP channel (1-13)
WLED_GLOBAL byte apChannel _INIT(6); // 2.4GHz WiFi AP channel (1-13)
WLED_GLOBAL byte apHide _INIT(0); // hidden AP SSID
WLED_GLOBAL byte apBehavior _INIT(AP_BEHAVIOR_BOOT_NO_CONN); // access point opens when no connection after boot by default
#ifdef ARDUINO_ARCH_ESP32

View File

@@ -27,6 +27,7 @@ static const char s_accessdenied[] PROGMEM = "Access Denied";
static const char s_not_found[] PROGMEM = "Not found";
static const char s_wsec[] PROGMEM = "wsec.json";
static const char s_func[] PROGMEM = "func";
static const char s_list[] PROGMEM = "list";
static const char s_path[] PROGMEM = "path";
static const char s_cache_control[] PROGMEM = "Cache-Control";
static const char s_no_store[] PROGMEM = "no-store";
@@ -66,7 +67,7 @@ static bool inLocalSubnet(const IPAddress &client) {
*/
static void generateEtag(char *etag, uint16_t eTagSuffix) {
sprintf_P(etag, PSTR("%7d-%02x-%04x"), VERSION, cacheInvalidate, eTagSuffix);
sprintf_P(etag, PSTR("%u-%02x-%04x"), WEB_BUILD_TIME, cacheInvalidate, eTagSuffix);
}
static void setStaticContentCacheHeaders(AsyncWebServerResponse *response, int code, uint16_t eTagSuffix = 0) {
@@ -226,14 +227,18 @@ void createEditHandler() {
return;
}
const String& func = request->arg(FPSTR(s_func));
bool legacyList = false;
if (request->hasArg(FPSTR(s_list))) {
legacyList = true; // support for '?list=/'
}
if(func.length() == 0) {
if(func.length() == 0 && !legacyList) {
// default: serve the editor page
handleStaticContent(request, FPSTR(_edit_htm), 200, FPSTR(CONTENT_TYPE_HTML), PAGE_edit, PAGE_edit_length);
return;
}
if (func == "list") {
if (func == FPSTR(s_list) || legacyList) {
bool first = true;
AsyncResponseStream* response = request->beginResponseStream(FPSTR(CONTENT_TYPE_JSON));
response->addHeader(FPSTR(s_cache_control), FPSTR(s_no_store));
@@ -243,15 +248,15 @@ void createEditHandler() {
File rootdir = WLED_FS.open("/", "r");
File rootfile = rootdir.openNextFile();
while (rootfile) {
String name = rootfile.name();
if (name.indexOf(FPSTR(s_wsec)) >= 0) {
rootfile = rootdir.openNextFile(); // skip wsec.json
continue;
}
if (!first) response->write(',');
first = false;
response->printf_P(PSTR("{\"name\":\"%s\",\"type\":\"file\",\"size\":%u}"), name.c_str(), rootfile.size());
rootfile = rootdir.openNextFile();
String name = rootfile.name();
if (name.indexOf(FPSTR(s_wsec)) >= 0) {
rootfile = rootdir.openNextFile(); // skip wsec.json
continue;
}
if (!first) response->write(',');
first = false;
response->printf_P(PSTR("{\"name\":\"%s\",\"type\":\"file\",\"size\":%u}"), name.c_str(), rootfile.size());
rootfile = rootdir.openNextFile();
}
rootfile.close();
rootdir.close();