Merge branch 'wled:main' into main

This commit is contained in:
Aogu181
2025-12-04 08:44:39 +08:00
committed by GitHub
8 changed files with 60 additions and 163 deletions

View File

@@ -1,10 +1,6 @@
name: Usermod CI
on:
push:
paths:
- usermods/**
- .github/workflows/usermods.yml
pull_request:
paths:
- usermods/**
@@ -12,6 +8,8 @@ on:
jobs:
get_usermod_envs:
# Only run for pull requests from forks (not from branches within wled/WLED)
if: github.event.pull_request.head.repo.full_name != github.repository
name: Gather Usermods
runs-on: ubuntu-latest
steps:
@@ -31,6 +29,8 @@ jobs:
build:
# Only run for pull requests from forks (not from branches within wled/WLED)
if: github.event.pull_request.head.repo.full_name != github.repository
name: Build Enviornments
runs-on: ubuntu-latest
needs: get_usermod_envs

View File

@@ -26,9 +26,28 @@ Github will pick up the changes so your PR stays up-to-date.
> It has many subtle and unexpected consequences on our github reposistory.
> For example, we regularly lost review comments when the PR author force-pushes code changes. So, pretty please, do not force-push.
> [!TIP]
> use [cherry-picking](https://docs.github.com/en/desktop/managing-commits/cherry-picking-a-commit-in-github-desktop) to copy commits from one branch to another.
You can find a collection of very useful tips and tricks here: https://github.com/wled-dev/WLED/wiki/How-to-properly-submit-a-PR
### Source Code from an AI agent or bot
> [!IMPORTANT]
> Its OK if you took help from an AI for writing your source code.
>
> However, we expect a few things from you as the person making a contribution to WLED:
* Make sure you really understand the code suggested by the AI, and don't just accept it because it "seems to work".
* Don't let the AI change existing code without double-checking by you as the contributor. Often, the result will not be complete. For example, previous source code comments may be lost.
* Remember that AI are still "Often-Wrong" ;-)
* If you don't feel very confident using English, you can use AI for translating code comments and descriptions into English. AI bots are very good at understanding language. However, always check if the results is correct. The translation might still have wrong technical terms, or errors in some details.
#### best practice with AI:
* As the person who contributes source code to WLED, make sure you understand exactly what the AI generated code does
* best practice: add a comment like ``'// below section of my code was generated by an AI``, when larger parts of your source code were not written by you personally.
* always review translations and code comments for correctness
* always review AI generated source code
* If the AI has rewritten existing code, check that the change is necessary and that nothing has been lost or broken. Also check that previous code comments are still intact.
### Code style

View File

@@ -1,122 +0,0 @@
/*-------------------------------------------------------------------------
NeoPixel library helper functions for Esp8266.
FIXED VERSION FROM https://github.com/Makuna/NeoPixelBus/pull/894
This library will overlay/shadow the base version from NeoPixelBus
Written by Michael C. Miller.
Thanks to g3gg0.de for porting the initial DMA support which lead to this.
Thanks to github/cnlohr for the original work on DMA support, which opend
all our minds to a better way (located at https://github.com/cnlohr/esp8266ws2812i2s).
I invest time and resources providing this open source code,
please support me by donating (see https://github.com/Makuna/NeoPixelBus)
-------------------------------------------------------------------------
This file is part of the Makuna/NeoPixelBus library.
NeoPixelBus is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
NeoPixelBus is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with NeoPixel. If not, see
<http://www.gnu.org/licenses/>.
-------------------------------------------------------------------------*/
#pragma once
#ifdef ARDUINO_ARCH_ESP8266
#include "internal/methods/NeoEsp8266DmaMethod.h"
template<typename T_PATTERN> class NeoEsp8266Dma3StepEncodeFixed : public T_PATTERN
{
public:
const static size_t DmaBitsPerPixelBit = 3; // 3 step cadence, matches encoding
static size_t SpacingPixelSize(size_t sizePixel)
{
return sizePixel;
}
static void FillBuffers(uint8_t* i2sBuffer,
const uint8_t* data,
size_t sizeData,
[[maybe_unused]] size_t sizePixel)
{
const uint8_t SrcBitMask = 0x80;
const size_t BitsInSample = sizeof(uint32_t) * 8;
uint32_t* pDma = reinterpret_cast<uint32_t*>(i2sBuffer);
uint32_t dmaValue = 0;
uint8_t destBitsLeft = BitsInSample;
const uint8_t* pSrc = data;
const uint8_t* pEnd = pSrc + sizeData;
while (pSrc < pEnd)
{
uint8_t value = *(pSrc++);
for (uint8_t bitSrc = 0; bitSrc < 8; bitSrc++)
{
const uint16_t Bit = ((value & SrcBitMask) ? T_PATTERN::OneBit3Step : T_PATTERN::ZeroBit3Step);
if (destBitsLeft > 3)
{
destBitsLeft -= 3;
dmaValue |= Bit << destBitsLeft;
#if defined(NEO_DEBUG_DUMP_I2S_BUFFER)
NeoUtil::PrintBin<uint32_t>(dmaValue);
Serial.print(" < ");
Serial.println(destBitsLeft);
#endif
}
else if (destBitsLeft <= 3)
{
uint8_t bitSplit = (3 - destBitsLeft);
dmaValue |= Bit >> bitSplit;
#if defined(NEO_DEBUG_DUMP_I2S_BUFFER)
NeoUtil::PrintBin<uint32_t>(dmaValue);
Serial.print(" > ");
Serial.println(bitSplit);
#endif
// next dma value, store and reset
*(pDma++) = dmaValue;
dmaValue = 0;
destBitsLeft = BitsInSample - bitSplit;
if (bitSplit)
{
dmaValue |= Bit << destBitsLeft;
}
#if defined(NEO_DEBUG_DUMP_I2S_BUFFER)
NeoUtil::PrintBin<uint32_t>(dmaValue);
Serial.print(" v ");
Serial.println(bitSplit);
#endif
}
// Next
value <<= 1;
}
}
// store the remaining bits
if (destBitsLeft != BitsInSample) *pDma++ = dmaValue;
}
};
// Abuse explict specialization to overlay the methods
template<> class NeoEsp8266Dma3StepEncode<NeoEsp8266DmaNormalPattern> : public NeoEsp8266Dma3StepEncodeFixed<NeoEsp8266DmaNormalPattern> {};
template<> class NeoEsp8266Dma3StepEncode<NeoEsp8266DmaInvertedPattern> : public NeoEsp8266Dma3StepEncodeFixed<NeoEsp8266DmaInvertedPattern> {};
#endif

View File

@@ -1,12 +0,0 @@
{
"name": "NeoESP8266DMAFix",
"build": { "libArchive": false },
"platforms": ["espressif8266"],
"dependencies": [
{
"owner": "makuna",
"name": "NeoPixelBus",
"version": "2.8.3"
}
]
}

View File

@@ -160,7 +160,7 @@ lib_compat_mode = strict
lib_deps =
fastled/FastLED @ 3.6.0
IRremoteESP8266 @ 2.8.2
makuna/NeoPixelBus @ 2.8.3
https://github.com/Makuna/NeoPixelBus.git#a0919d1c10696614625978dd6fb750a1317a14ce
https://github.com/Aircoookie/ESPAsyncWebServer.git#v2.4.2
marvinroger/AsyncMqttClient @ 0.9.0
# for I2C interface
@@ -220,7 +220,6 @@ lib_deps =
ESPAsyncUDP
ESP8266PWM
${env.lib_deps}
NeoESP8266DMAFix
;; compatibilty flags - same as 0.14.0 which seems to work better on some 8266 boards. Not using PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48
build_flags_compat =

View File

@@ -1335,7 +1335,7 @@ class AudioReactive : public Usermod {
disableSoundProcessing = true;
} else {
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_DEBUG)
if ((disableSoundProcessing == true) && (audioSyncEnabled == 0) && audioSource->isInitialized()) { // we just switched to "enabled"
if ((disableSoundProcessing == true) && (audioSyncEnabled == 0) && audioSource && audioSource->isInitialized()) { // we just switched to "enabled"
DEBUG_PRINTLN(F("[AR userLoop] realtime mode ended - audio processing resumed."));
DEBUG_PRINTF_P(PSTR(" RealtimeMode = %d; RealtimeOverride = %d\n"), int(realtimeMode), int(realtimeOverride));
}
@@ -1347,7 +1347,7 @@ class AudioReactive : public Usermod {
if (audioSyncEnabled & 0x02) disableSoundProcessing = true; // make sure everything is disabled IF in audio Receive mode
if (audioSyncEnabled & 0x01) disableSoundProcessing = false; // keep running audio IF we're in audio Transmit mode
#ifdef ARDUINO_ARCH_ESP32
if (!audioSource->isInitialized()) disableSoundProcessing = true; // no audio source
if (!audioSource || !audioSource->isInitialized()) disableSoundProcessing = true; // no audio source
// Only run the sampling code IF we're not in Receive mode or realtime mode

View File

@@ -4,9 +4,6 @@
//#define NPB_CONF_4STEP_CADENCE
#include "NeoPixelBus.h"
#ifdef ARDUINO_ARCH_ESP8266
#include <NeoEsp8266DmaMethodFix.h>
#endif
//Hardware SPI Pins
#define P_8266_HS_MOSI 13

View File

@@ -268,10 +268,10 @@
}
// enable/disable LED fields
updateTypeDropdowns(); // restrict bus types in dropdowns to max allowed digital/analog buses
let dC = 0; // count of digital buses (for parallel I2S)
let LTs = d.Sf.querySelectorAll("#mLC select[name^=LT]");
LTs.forEach((s,i)=>{
if (i < LTs.length-1) s.disabled = true; // prevent changing type (as we can't update options)
// is the field a LED type?
var n = s.name.substring(2,3); // bus number (0-Z)
var t = parseInt(s.value);
@@ -448,17 +448,8 @@
{
var o = gEBCN("iST");
var i = o.length;
let disable = (sel,opt) => { sel.querySelectorAll(opt).forEach((o)=>{o.disabled=true;}); }
var f = gId("mLC");
let digitalB = 0, analogB = 0, twopinB = 0, virtB = 0;
f.querySelectorAll("select[name^=LT]").forEach((s)=>{
let t = s.value;
if (isDig(t) && !isD2P(t)) digitalB++;
if (isD2P(t)) twopinB++;
if (isPWM(t)) analogB += numPins(t); // each GPIO is assigned to a channel
if (isVir(t)) virtB++;
});
if ((n==1 && i>=36) || (n==-1 && i==0)) return; // used to be i>=maxB+maxV when virtual buses were limited (now :"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")
var s = chrID(i);
@@ -468,7 +459,7 @@
var cn = `<div class="iST">
<hr class="sml">
${i+1}:
<select name="LT${s}" onchange="UI(true)"></select><br>
<select name="LT${s}" onchange="updateTypeDropdowns();UI(true)"></select><br>
<div id="abl${s}">
mA/LED: <select name="LAsel${s}" onchange="enLA(this,'${s}');UI();">
<option value="55" selected>55mA (typ. 5V WS281x)</option>
@@ -523,18 +514,15 @@ mA/LED: <select name="LAsel${s}" onchange="enLA(this,'${s}');UI();">
}
});
enLA(d.Sf["LAsel"+s],s); // update LED mA
// disable inappropriate LED types
// temporarily set to virtual (network) type to avoid "same type" exception during dropdown update
let sel = d.getElementsByName("LT"+s)[0];
// 32 & S2 supports mono I2S as well as parallel so we need to take that into account; S3 only supports parallel
let maxDB = maxD - (is32() || isS2() || isS3() ? (!d.Sf["PR"].checked)*8 - (!isS3()) : 0); // adjust max digital buses if parallel I2S is not used
if (digitalB >= maxDB) disable(sel,'option[data-type="D"]'); // NOTE: see isDig()
if (twopinB >= 2) disable(sel,'option[data-type="2P"]'); // NOTE: see isD2P() (we will only allow 2 2pin buses)
disable(sel,`option[data-type^="${'A'.repeat(maxA-analogB+1)}"]`); // NOTE: see isPWM()
sel.value = sel.querySelector('option[data-type="N"]').value;
updateTypeDropdowns(); // update valid bus options including this new one
sel.selectedIndex = sel.querySelector('option:not(:disabled)').index;
updateTypeDropdowns(); // update again for the newly selected type
}
if (n==-1) {
o[--i].remove();--i;
o[i].querySelector("[name^=LT]").disabled = false;
}
gId("+").style.display = (i<35) ? "inline":"none"; // was maxB+maxV-1 when virtual buses were limited (now :"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")
@@ -829,6 +817,34 @@ Swap: <select id="xw${s}" name="XW${s}">
}
return opt;
}
// dynamically enforce bus type availability based on current usage
function updateTypeDropdowns() {
let LTs = d.Sf.querySelectorAll("#mLC select[name^=LT]");
let digitalB = 0, analogB = 0, twopinB = 0, virtB = 0;
// count currently used buses
LTs.forEach(sel => {
let t = parseInt(sel.value);
if (isDig(t) && !isD2P(t)) digitalB++;
if (isPWM(t)) analogB += numPins(t);
if (isD2P(t)) twopinB++;
if (isVir(t)) virtB++;
});
// enable/disable type options according to limits in dropdowns
LTs.forEach(sel => {
const curType = parseInt(sel.value);
const disable = (q) => sel.querySelectorAll(q).forEach(o => o.disabled = true);
const enable = (q) => sel.querySelectorAll(q).forEach(o => o.disabled = false);
enable('option'); // reset all first
// max digital buses: ESP32 & S2 support mono I2S as well as parallel so we need to take that into account; S3 only supports parallel
// supported outputs using parallel I2S/mono I2S: S2: 12/5, S3: 12/4, ESP32: 16/9
let maxDB = maxD - ((is32() || isS2() || isS3()) ? (!d.Sf["PR"].checked) * 8 - (!isS3()) : 0); // adjust max digital buses if parallel I2S is not used
// disallow adding more of a type that has reached its limit but allow changing the current type
if (digitalB >= maxDB && !(isDig(curType) && !isD2P(curType))) disable('option[data-type="D"]');
if (twopinB >= 2 && !isD2P(curType)) disable('option[data-type="2P"]');
// Disable PWM types that need more pins than available (accounting for current type's pins if PWM)
disable(`option[data-type^="${'A'.repeat(maxA - analogB + (isPWM(curType)?numPins(curType):0) + 1)}"]`);
});
}
</script>
<style>@import url("style.css");</style>
</head>