diff --git a/DECISIONS.md b/DECISIONS.md index 15accaf2d7..0be2f24122 100644 --- a/DECISIONS.md +++ b/DECISIONS.md @@ -311,3 +311,33 @@ its unique suffix (apollo-led-matrix-xxxxxx); only the hotspot name changed. FIRMWARE change: b8 app no longer byte-identical to b7, virgin boot + battery re-run before the walkthrough; the SSID fix reaches existing units via OTA, unlike the FS card. + +### D27. b9 (2026-10-25): a no-WiFi owner's launch preset wins over the setup signpost +BUG in b8 (reported by Justin): with no WiFi configured, beginStrip() applied +preset 9 (dog, then setup card) instead of ANY launch preset, so an AP-only +owner's launch preset was saved and shown in the UI but never ran at boot. +That contradicts D20 (full control with no network). No earlier decision or +QA row covered it; the D13 gate never set a launch preset on an AP-only unit. +FIX: the signpost plays only while WiFi is unconfigured AND the launch +preset is still the factory one (cfg.json def.ps 4) AND the owner has not +chosen one AND presets.json has a named preset 9. "Chosen" is a new +persisted flag (cfg def.psc). It is set when Config > LED & Hardware is +saved while no WiFi is configured (the "Apply preset N at boot" field under +Power up), or when "Apply at boot" is ticked on a DIFFERENT preset in the +preset editor (that box is pre-ticked on the current launch preset, so just +re-saving the dog preset does not count). Choosing the dog itself therefore +works through LED & Hardware. Compiled in only by [env:apollo_m1] +(-D FACTORY_SIGNPOST_PRESET=9 -D FACTORY_BOOT_PRESET=4); other envs of the +fork boot like upstream. No apollo/fs change, so it reaches b8 units by OTA: +an owner who already set a launch preset other than 4 gets it at once. +Also fixes a wiped filesystem (factory reset) and a WLED-MM upgrade without +preset 9, which now run their launch preset (0 = plain Apollo blue) instead +of applying a missing preset 9. +TRADEOFF, ACCEPTED (Justin, 2026-10-25; the narrower "only when the launch +preset number changes" was rejected because an owner could then never pick +the dog, already the factory value, from that page): saving LED & Hardware without WiFi for +ANY reason (for example the HUB75 color order from PR #8) counts as choosing +the launch preset shown there, so the boot signpost stops. The card stays +available on demand as preset 5 "Setup". There is no UI way back to the +signpost short of a full install; do not tell owners to use launch preset +9 for it, because 9 keeps showing the hotspot card after WiFi is set up. diff --git a/QA_CHECKLIST.md b/QA_CHECKLIST.md index 7307b6446f..2fc972ad25 100644 --- a/QA_CHECKLIST.md +++ b/QA_CHECKLIST.md @@ -270,9 +270,10 @@ unit. This is the D20 acceptance: AP mode is a first-class destination. STATIC setup card (D24): STEP 1 JOIN APOLLO WIFI HOTSPOT / 21px QR / STEP 2 SCAN OR OPEN BROWSER TO 4.3.2.1, at brightness 220, holding indefinitely. NO cycling, no page turns. -- [ ] Reset or power-cycle: dog then card return (boot preset 9 playlist - self-heals; customer preset list shows 5 "Setup" to recall the card). -- [ ] Phone joins "Apollo M-1-xxxxxx" (open). Accept any "no internet - +- [ ] Reset or power-cycle, no launch preset saved: dog then card return + (boot preset 9 playlist self-heals; customer preset list shows 5 + "Setup" to recall the card). +- [ ] Phone joins "Apollo M-1" (open). Accept any "no internet - stay connected?" prompt. NO captive popup should appear (D22). - [ ] Scan the QR off the panel with the camera app in NORMAL ROOM LIGHT: browser opens http://4.3.2.1 (with mobile data still ON). @@ -305,3 +306,23 @@ PASS ("everything looks great"), with Sound Bars verified as applies-cleanly-idle on this no-mic unit (reactivity row inherited from the 2026-07-15 glass verification on the mic-equipped unit; audio code untouched b7->b8). SHIP-READY RE-ASSERTED for bundle b8. + +## D27. Launch preset without WiFi (b9+; run on a SECOND factory-fresh unit, +## never on the D13 unit: these steps mark the launch preset as chosen, which +## cannot be undone from the UI and would break D13's final provision row) +Phone on the "Apollo M-1" hotspot, 4.3.2.1, no WiFi ever configured. +- [ ] Full install, power-cycle twice without saving any settings: dog then + card both times. +- [ ] Preset editor: open 4 "Apollo Dog" (Apply at boot is pre-ticked), + rename it, save; power-cycle: dog then card STILL return. +- [ ] Config > LED & Hardware > Power up: "Apply preset 3 at boot" > Save; + power-cycle: Sound Bars starts, no dog, no card. /json/cfg shows + def {"ps":3,"psc":true}. +- [ ] Same field = 4 > Save; power-cycle: dog only, no card. +- [ ] Same field = 2 > Save; power-cycle: Apollo Blue preset. +- [ ] Preset editor: tick "Apply at boot" on 1 "Scrolling Text", save; + power-cycle: Scrolling Text plays. +- [ ] Preset 5 "Setup" from the preset list still shows the card on demand. +- [ ] OTA path (third unit, or after a full install of b8): on b8 set the + LED & Hardware launch preset to 3 (dog then card still show: the b8 + bug), OTA M-1_ota.bin b9, power-cycle: Sound Bars, no re-save needed. diff --git a/apollo/README.md b/apollo/README.md index 3bd55106d9..ba0604b0f6 100644 --- a/apollo/README.md +++ b/apollo/README.md @@ -13,8 +13,9 @@ tree itself. Rules for branches, upstream WLED and releases: CLAUDE.md in the re - fs/presets.json - the factory presets: 1 Scrolling Text, 2 Apollo Blue, 3 Sound Bars, 4 Apollo Dog, 5 Setup (the first-boot setup card at brightness 220), and 9 First Boot (a playlist that plays the dog once for 4 s, then holds the Setup - card; applied automatically at boot while WiFi is unconfigured, see - FACTORY_SIGNPOST_PRESET). Historical note: units shipped on WLED-MM carried no + card; applied at boot while WiFi is unconfigured and the owner has not chosen a + launch preset, see FACTORY_SIGNPOST_PRESET in [env:apollo_m1] and DECISIONS D27). + Historical note: units shipped on WLED-MM carried no presets; these first shipped with the 16.0.1 migration. - fs/apollo_dog.gif - the animated first-boot dog (D19). - fs/setup.gif - the static setup card (D24): join instructions, QR code, and the diff --git a/apollo/boot-signpost-test.js b/apollo/boot-signpost-test.js new file mode 100644 index 0000000000..51f8127543 --- /dev/null +++ b/apollo/boot-signpost-test.js @@ -0,0 +1,116 @@ +// AI: below section was generated by an AI +// Host-side check of the Apollo M-1 boot signpost in wled00/wled.cpp beginStrip() (DECISIONS D23/D24/D27). +// Runs with `npm test` (node --test). It reads the signpost condition from the C++ source and the signpost +// presets from [env:apollo_m1], evaluates the condition for each boot case, and asserts: +// - a factory-fresh unit with no WiFi (factory def.ps, no def.psc) still boots the signpost playlist, +// - a no-WiFi owner's launch preset is honoured once chosen (Apollo Dog included) or when it is not the factory one, +// - WiFi-configured units boot their own preset exactly as upstream, +// - the signpost is compiled in only where [env:apollo_m1] enables it, and the values match apollo/fs, +// - every code path that writes bootPreset from the UI also sets bootPresetChosen, and cfg.cpp persists it. +'use strict'; +const test = require('node:test'); +const assert = require('node:assert'); +const fs = require('fs'); +const path = require('path'); + +const root = path.join(__dirname, '..'); +const read = f => fs.readFileSync(path.join(root, f), 'utf8'); +const stripIniComments = s => s.split('\n').map(l => l.replace(/;.*$/, '')).join('\n'); + +// [env:apollo_m1] build flags (section runs to the next [section] or end of file) +const ini = read('platformio.ini'); +const envStart = ini.indexOf('[env:apollo_m1]'); +assert.ok(envStart >= 0, '[env:apollo_m1] not found in platformio.ini'); +const envEnd = ini.indexOf('\n[', envStart + 1); +const envM1 = stripIniComments(ini.slice(envStart, envEnd < 0 ? undefined : envEnd)); +const flag = name => { const m = envM1.match(new RegExp(`-D\\s*${name}=(\\d+)`)); return m ? +m[1] : undefined; }; +const SIGNPOST = flag('FACTORY_SIGNPOST_PRESET'); +const FACTORY_BOOT = flag('FACTORY_BOOT_PRESET'); + +// beginStrip() body and the signpost condition inside its #ifdef +const wledCpp = read('wled00/wled.cpp'); +const bsStart = wledCpp.indexOf('void WLED::beginStrip()'); +const beginStrip = wledCpp.slice(bsStart, wledCpp.indexOf('\nvoid WLED::', bsStart + 1)); +const gated = beginStrip.match(/#ifdef FACTORY_SIGNPOST_PRESET([\s\S]*?)#endif/); +// if () { String x; if (getPresetName(FACTORY_SIGNPOST_PRESET, x)) bootPs = FACTORY_SIGNPOST_PRESET; } +const condMatch = gated && gated[1].match(/if \(([^;{}]*?)\)\s*\{\s*String (\w+);\s*if \(getPresetName\(FACTORY_SIGNPOST_PRESET, \2\)\)\s*bootPs\s*=\s*FACTORY_SIGNPOST_PRESET;\s*\}/); + +// boot decision as compiled for the M-1: returns the preset applied, or 'DEFAULT_COLOR' when none. +// signpostExists models getPresetName(9): false when presets.json has no named preset 9 (e.g. a WLED-MM upgrade). +function bootM1(wifiConfigured, chosen, bootPreset, signpostExists = true) { + const cond = condMatch[1]; + const ids = new Set(cond.match(/[A-Za-z_]\w*/g)); + const allowed = ['WLED_WIFI_CONFIGURED', 'bootPresetChosen', 'bootPreset', 'FACTORY_BOOT_PRESET', 'FACTORY_SIGNPOST_PRESET']; + assert.ok([...ids].every(id => allowed.includes(id)), `unexpected identifier in signpost condition: ${cond}`); + assert.match(cond, /^[\s!&|=()\w]+$/, `signpost condition is not a plain boolean expression: ${cond}`); + const fn = new Function(...allowed, `return (${cond});`); + const ps = (fn(wifiConfigured, chosen, bootPreset, FACTORY_BOOT, SIGNPOST) && signpostExists) ? SIGNPOST : bootPreset; + return ps > 0 ? ps : 'DEFAULT_COLOR'; +} + +test('signpost is compiled in only by [env:apollo_m1]', () => { + assert.strictEqual(SIGNPOST, 9, '-D FACTORY_SIGNPOST_PRESET missing from [env:apollo_m1]'); + assert.strictEqual(FACTORY_BOOT, 4, '-D FACTORY_BOOT_PRESET missing from [env:apollo_m1]'); + const elsewhere = stripIniComments(ini.slice(0, envStart)).match(/FACTORY_SIGNPOST_PRESET/g); + assert.strictEqual(elsewhere, null, 'another env defines FACTORY_SIGNPOST_PRESET'); + for (const f of ['wled00/const.h', 'wled00/wled.h']) { + assert.doesNotMatch(read(f), /#define\s+FACTORY_SIGNPOST_PRESET/, `${f} must not define a default`); + } + assert.ok(condMatch, 'signpost condition not found inside #ifdef FACTORY_SIGNPOST_PRESET in beginStrip()'); + assert.match(beginStrip, /byte bootPs = bootPreset;/); + assert.match(beginStrip, /if \(bootPs > 0\) \{\s*applyPreset\(bootPs, CALL_MODE_INIT\);/); + assert.doesNotMatch(beginStrip.replace(gated[0], ''), /FACTORY_SIGNPOST_PRESET|bootPresetChosen/, 'signpost code outside the #ifdef'); +}); + +test('flag values match the factory filesystem', () => { + const cfg = JSON.parse(read('apollo/fs/cfg.json')); + const presets = JSON.parse(read('apollo/fs/presets.json')); + assert.strictEqual(cfg.def.ps, FACTORY_BOOT, 'FACTORY_BOOT_PRESET must equal apollo/fs/cfg.json def.ps'); + assert.strictEqual(cfg.def.psc, undefined, 'factory cfg.json must not mark the boot preset as chosen'); + assert.strictEqual(presets[FACTORY_BOOT].seg[0].n, 'apollo_dog.gif'); + const pl = presets[SIGNPOST].playlist; + assert.ok(pl, `preset ${SIGNPOST} must be the signpost playlist`); + assert.deepStrictEqual(pl.ps, [FACTORY_BOOT]); + assert.strictEqual(presets[pl.end].seg[0].n, 'setup.gif', 'signpost playlist must end on the Setup card'); +}); + +test('boot behaviour per case', () => { + const D = FACTORY_BOOT; + // [wifiConfigured, bootPresetChosen, bootPreset, expected, case] + const cases = [ + [false, false, D, SIGNPOST, 'factory-fresh, no WiFi: dog then setup card'], + [false, false, 3, 3, 'no WiFi, launch preset 3 (also b8 units updated by OTA, no psc key)'], + [false, true, 3, 3, 'no WiFi, owner chose 3'], + [false, true, D, D, 'no WiFi, owner chose Apollo Dog'], + [false, true, 0, 'DEFAULT_COLOR', 'no WiFi, owner chose none'], + [false, true, SIGNPOST, SIGNPOST, 'no WiFi, owner chose First Boot on purpose'], + [false, false, 0, 'DEFAULT_COLOR', 'wiped filesystem: Apollo blue, no missing-preset error'], + [false, false, 23, 23, 'WLED-MM upgrade, no WiFi, own boot preset'], + [true, false, D, D, 'WiFi configured: factory dog (D24 self-correction)'], + [true, false, 0, 'DEFAULT_COLOR', 'WiFi configured, no boot preset'], + [true, true, 7, 7, 'WiFi configured, owner preset'], + ]; + for (const [wifi, chosen, bp, want, name] of cases) assert.strictEqual(bootM1(wifi, chosen, bp), want, name); + // no named preset 9 in presets.json (WLED-MM upgrade, or the owner deleted it): the owner's preset 4 runs + assert.strictEqual(bootM1(false, false, D, false), D, 'no preset 9: launch preset 4 runs instead of a missing preset'); +}); + +test('every UI write of bootPreset marks it chosen, and cfg.cpp persists the flag', () => { + for (const f of ['wled00/set.cpp', 'wled00/presets.cpp', 'wled00/json.cpp']) { + const lines = read(f).split('\n'); + lines.forEach((l, i) => { + if (!/\bbootPreset\s*=[^=]/.test(l)) return; + const around = lines.slice(Math.max(0, i - 4), i + 4).join('\n'); // the guard may sit just before or just after the write + assert.match(around, /#ifdef FACTORY_SIGNPOST_PRESET\s*\n[^\n]*bootPresetChosen = true;/, `${f}:${i + 1} writes bootPreset without setting bootPresetChosen`); + }); + } + // LED & Hardware save counts only without WiFi; "Apply at boot" counts only when it picks a different preset + // (the box is pre-ticked on the current boot preset, so re-saving the dog preset must not end the signpost) + assert.match(read('wled00/set.cpp'), /if \(!WLED_WIFI_CONFIGURED\) bootPresetChosen = true;/); + assert.match(read('wled00/presets.cpp'), /if \(\(sObj\[FPSTR\(bootPS\)\] \| bootPreset\) != bootPreset\) bootPresetChosen = true;/); + const cfg = read('wled00/cfg.cpp'); + assert.match(cfg, /CJSON\(bootPreset, def\["ps"\]\);\s*#ifdef FACTORY_SIGNPOST_PRESET\s*CJSON\(bootPresetChosen, def\["psc"\]\);/); + assert.match(cfg, /def\["ps"\] = bootPreset;\s*#ifdef FACTORY_SIGNPOST_PRESET\s*def\["psc"\] = bootPresetChosen;/); + assert.match(read('wled00/wled.h'), /#ifdef FACTORY_SIGNPOST_PRESET\s*WLED_GLOBAL bool bootPresetChosen _INIT\(false\);/); +}); +// AI: end diff --git a/apollo/wiki-rewrites/no-wifi-mode.md b/apollo/wiki-rewrites/no-wifi-mode.md index 8ddd1f4cee..634cd6a318 100644 --- a/apollo/wiki-rewrites/no-wifi-mode.md +++ b/apollo/wiki-rewrites/no-wifi-mode.md @@ -21,10 +21,9 @@ panel shows a setup card and keeps showing it until you are set up. The card has both steps and a QR code, so there is nothing to wait for. 1. **STEP 1 - join the M-1's WiFi.** On your phone or computer, open the - WiFi list and join the network called **Apollo M-1-xxxxxx** (the letters - at the end are unique to your unit). There is no password. If your phone - warns "this network has no internet - stay connected?", choose **stay - connected**. You can leave mobile data on. + WiFi list and join the network called **Apollo M-1**. There is no + password. If your phone warns "this network has no internet - stay + connected?", choose **stay connected**. You can leave mobile data on. 2. **STEP 2 - scan the code on the card.** Point your camera app at the QR code at the bottom of the card and tap the link. Your browser opens the M-1's control page. @@ -38,10 +37,23 @@ ever touching a network. ### Good to know -- The setup card only appears while the M-1 has no WiFi configured. Once - you connect it to your home WiFi, it boots straight to the Apollo dog - instead, and you reach it at its normal network address. You can always - bring the card back from the preset list (preset "Setup"). +- The setup card appears at power-on only while the M-1 has no WiFi + configured and you have not chosen what it should start with. Once you + connect it to your home WiFi, it starts on its launch preset instead (the + Apollo dog, unless you changed it), and you reach it at its normal network + address. You can always bring the card back from the preset list (preset + "Setup"). +- **Staying without WiFi? Choose what it starts with (firmware b9 or + later).** Open **Config > LED & Hardware**, scroll to **Power up**, set + **Apply preset ___ at boot** (4 = Apollo dog, 1 = Scrolling Text, + 2 = Apollo Blue) and press **Save**. Or open a different preset, tick + **Apply at boot**, and save it. From then on it starts on that preset, + without the setup card. +- Saving the **LED & Hardware** page while the M-1 has no WiFi, for any + reason (for example changing the color order), also counts as choosing: + it starts on the preset shown in **Apply preset ___ at boot** and the + setup card no longer appears at power-on. The card is still in the preset + list as "Setup". - The hotspot stays available as a fallback: if the M-1 ever cannot reach your WiFi, it opens its hotspot again and 4.3.2.1 works as above. - Uploading GIFs from the **WLED phone app** does not work (a known bug in diff --git a/platformio.ini b/platformio.ini index 5ad2a4ee39..d6d5f64425 100644 --- a/platformio.ini +++ b/platformio.ini @@ -916,6 +916,7 @@ build_flags = ${env:esp32s3dev_16MB_opi_hub75.build_flags} -D WLED_MDNS_PREFIX='"apollo-led-matrix"' ;; factory boot: one 64x64 half-scan panel as a 2D matrix, brightness limiter off -D DEFAULT_COLOR=0x4379AA ;; Apollo blue welcome color (needs the FX.h ifndef guard) + -D FACTORY_SIGNPOST_PRESET=9 -D FACTORY_BOOT_PRESET=4 ;; setup signpost (D24/D27): apollo/fs presets.json 9 and cfg.json def.ps; other envs compile it out -D DATA_PINS=64,64,1,1,1 ;; HUB75 slots = panelW,panelH,chain,rows,cols (not GPIOs) -D MAX_LEDS=16388 ;; 4-panel chain is EXACTLY 16384 and the driver guard is >=; +4 pad mirrors WLED-MM (QA D10 finding) -D MAX_LED_MEMORY=262144 ;; 4-panel chain estimate is 180224B; stock 192K cap leaves 17K margin before the bus is silently replaced by a placeholder = dark panels (QA D10) diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index fe0d5d0792..be836cff28 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -590,6 +590,9 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { JsonObject def = doc["def"]; CJSON(bootPreset, def["ps"]); + #ifdef FACTORY_SIGNPOST_PRESET + CJSON(bootPresetChosen, def["psc"]); // absent in the factory cfg.json and on b8 units: not chosen + #endif CJSON(turnOnAtBoot, def["on"]); // true CJSON(briS, def["bri"]); // 128 @@ -1127,6 +1130,9 @@ void serializeConfig(JsonObject root) { JsonObject def = root.createNestedObject("def"); def["ps"] = bootPreset; + #ifdef FACTORY_SIGNPOST_PRESET + def["psc"] = bootPresetChosen; + #endif def["on"] = turnOnAtBoot; def["bri"] = briS; diff --git a/wled00/const.h b/wled00/const.h index 25a787e4d0..f39e2a20eb 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -457,10 +457,6 @@ static_assert(WLED_MAX_BUSSES <= 32, "WLED_MAX_BUSSES exceeds hard limit"); #define SEG_CAPABILITY_W 0x02 #define SEG_CAPABILITY_CCT 0x04 -#ifndef FACTORY_SIGNPOST_PRESET -#define FACTORY_SIGNPOST_PRESET 9 // preset applied at boot while WiFi is unconfigured (setup signpost); no-op if the preset does not exist -#endif - // WLED Error modes #define ERR_NONE 0 // All good :) #define ERR_DENIED 1 // Permission denied diff --git a/wled00/presets.cpp b/wled00/presets.cpp index 9023baf344..42dcc1e6e9 100644 --- a/wled00/presets.cpp +++ b/wled00/presets.cpp @@ -237,6 +237,9 @@ void savePreset(byte index, const char* pname, JsonObject sObj) const char *bootPS = PSTR("bootps"); if (!sObj[FPSTR(bootPS)].isNull()) { + #ifdef FACTORY_SIGNPOST_PRESET + if ((sObj[FPSTR(bootPS)] | bootPreset) != bootPreset) bootPresetChosen = true; // a newly ticked "Apply at boot" stops the setup signpost; re-saving the pre-ticked boot preset does not + #endif bootPreset = sObj[FPSTR(bootPS)] | bootPreset; sObj.remove(FPSTR(bootPS)); configNeedsWrite = true; diff --git a/wled00/set.cpp b/wled00/set.cpp index fb516ac7d6..a5b7d486ae 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -374,6 +374,9 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) turnOnAtBoot = request->hasArg(F("BO")); t = request->arg(F("BP")).toInt(); if (t <= 250) bootPreset = t; + #ifdef FACTORY_SIGNPOST_PRESET + if (!WLED_WIFI_CONFIGURED) bootPresetChosen = true; // saving LED & Hardware without WiFi confirms "Apply preset N at boot": the setup signpost stops + #endif gammaCorrectBri = request->hasArg(F("GB")); gammaCorrectCol = request->hasArg(F("GC")); gammaCorrectVal = request->arg(F("GV")).toFloat(); diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 499da38e66..ac613118d0 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -626,14 +626,23 @@ void WLED::beginStrip() else briLast = briS; // go to startup brightness (set in UI) when turning on (can be overruled by a preset) colorUpdated(CALL_MODE_INIT); // set bootup brightness immediately, do not send notification (brightness is also set for preset if used, useful for swipe etc.) - if (!WLED_WIFI_CONFIGURED && bootPreset != FACTORY_SIGNPOST_PRESET) { - // WiFi not configured yet: show the setup signpost tour (logo / AP address / QR code) - // instead of the regular boot preset; self-corrects to bootPreset once provisioned. - // (cannot use showWelcomePage: it is computed after beginStrip() in setup()) - applyPreset(FACTORY_SIGNPOST_PRESET, CALL_MODE_INIT); + byte bootPs = bootPreset; + #ifdef FACTORY_SIGNPOST_PRESET + // AI: below section was generated by an AI + // Apollo M-1 setup signpost (DECISIONS D23/D24/D27), enabled by [env:apollo_m1] only. With no WiFi configured and the + // launch preset still the factory one (cfg.json def.ps), boot plays the signpost playlist (dog, then the setup card) + // instead. It stops once WiFi is configured or the owner picks a launch preset (bootPresetChosen), so a no-WiFi + // owner's choice is honoured, Apollo Dog included. A wiped filesystem (bootPreset 0), a WLED-MM upgrade with its own + // boot preset, or a filesystem without preset 9 takes the normal path. The preset-9 lookup is one presets.json read, + // done only on unprovisioned units. (cannot use showWelcomePage: it is computed after beginStrip() in setup()) + if (!WLED_WIFI_CONFIGURED && !bootPresetChosen && bootPreset == FACTORY_BOOT_PRESET) { + String spName; + if (getPresetName(FACTORY_SIGNPOST_PRESET, spName)) bootPs = FACTORY_SIGNPOST_PRESET; } - else if (bootPreset > 0) { - applyPreset(bootPreset, CALL_MODE_INIT); + // AI: end + #endif + if (bootPs > 0) { + applyPreset(bootPs, CALL_MODE_INIT); } else { // set color to warm welcoming orange (aka DEFAULT_COLOR) if no preset loaded (will fade to this color once turned on) diff --git a/wled00/wled.h b/wled00/wled.h index 399b9ffa70..9af709b7ac 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -395,6 +395,9 @@ WLED_GLOBAL uint8_t txPower _INIT(WIFI_POWER_19_5dBm); // LED CONFIG WLED_GLOBAL bool turnOnAtBoot _INIT(true); // turn on LEDs at power-up WLED_GLOBAL byte bootPreset _INIT(0); // save preset to load after power-up +#ifdef FACTORY_SIGNPOST_PRESET +WLED_GLOBAL bool bootPresetChosen _INIT(false); // owner picked the boot preset (LED settings or "Apply at boot"): no setup signpost at boot +#endif //if true, a segment per bus will be created on boot and LED settings save //if false, only one segment spanning the total LEDs is created,