Compare commits
259 Commits
power-ap
...
tricolor-f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fc35f0aab2 | ||
|
|
68a853455d | ||
|
|
c24f67c479 | ||
|
|
d1763024bf | ||
|
|
b155f80dc7 | ||
|
|
2df536c0a4 | ||
|
|
dba31cb433 | ||
|
|
7a52144e98 | ||
|
|
9c82add757 | ||
|
|
4e1ca9be49 | ||
|
|
a9f52a132b | ||
|
|
0ecae7e831 | ||
|
|
a24d4bc7e9 | ||
|
|
26080b23b1 | ||
|
|
b6d9aad6b4 | ||
|
|
4f3992b4dc | ||
|
|
78252c6885 | ||
|
|
9dc7e81ba7 | ||
|
|
ab2c975c36 | ||
|
|
ec51804f33 | ||
|
|
83ae6d07a7 | ||
|
|
4b42f6bbe2 | ||
|
|
b27541e3e4 | ||
|
|
6fa2f4893d | ||
|
|
39f3c99cc1 | ||
|
|
e428e80d94 | ||
|
|
cfa8b735f4 | ||
|
|
1808fa776b | ||
|
|
232dc044e7 | ||
|
|
a25fc6e098 | ||
|
|
00ab1daadb | ||
|
|
2f31ff047d | ||
|
|
5ec39f7fd3 | ||
|
|
ecfe6e625d | ||
|
|
2e4f3f8729 | ||
|
|
0597102f7f | ||
|
|
6e7fffefec | ||
|
|
a353a64568 | ||
|
|
5cac18f844 | ||
|
|
3830d49bf8 | ||
|
|
22eee967c2 | ||
|
|
8654c2e4da | ||
|
|
9bddfb1158 | ||
|
|
7455ea7dde | ||
|
|
741bdf08ec | ||
|
|
bbc9b9c173 | ||
|
|
a38d6075c7 | ||
|
|
762679177c | ||
|
|
b008a6476b | ||
|
|
47a9e4aa51 | ||
|
|
249c124176 | ||
|
|
e16c4b8681 | ||
|
|
7b521c7c40 | ||
|
|
4c01893bd8 | ||
|
|
ddec6fbb11 | ||
|
|
d9629039a6 | ||
|
|
0a28acf6e7 | ||
|
|
6572efbf9f | ||
|
|
dbe76479a2 | ||
|
|
dc3d463925 | ||
|
|
f593d404cb | ||
|
|
b75a2de485 | ||
|
|
642a9e3652 | ||
|
|
85d3f6f11c | ||
|
|
f490908278 | ||
|
|
1fc3cc83bd | ||
|
|
e96fd8ae58 | ||
|
|
c46e328b59 | ||
|
|
fa2f831044 | ||
|
|
1bf13ea525 | ||
|
|
edc6022441 | ||
|
|
2ac4d03160 | ||
|
|
cc4a4c4ae1 | ||
|
|
4e11ecda4b | ||
|
|
473700e4c0 | ||
|
|
0d5a0fb830 | ||
|
|
012143bd7b | ||
|
|
700a7076fd | ||
|
|
5fc2175dd4 | ||
|
|
c9b95e22d3 | ||
|
|
a265318037 | ||
|
|
866a4c8ab6 | ||
|
|
9dc1022010 | ||
|
|
faadb67eb0 | ||
|
|
a111a2e7a1 | ||
|
|
32864d8986 | ||
|
|
d7bebc2659 | ||
|
|
af410ae2d0 | ||
|
|
1891cc816f | ||
|
|
9a4073e606 | ||
|
|
b78229d1e2 | ||
|
|
71b242874f | ||
|
|
9328e6faca | ||
|
|
bbacc2daae | ||
|
|
3e22f9cabb | ||
|
|
a121f5b61b | ||
|
|
251062170e | ||
|
|
92e59af4d8 | ||
|
|
fa4c23b76e | ||
|
|
a0a46850f5 | ||
|
|
4cd0563a93 | ||
|
|
b83f0f461c | ||
|
|
685ad83d4b | ||
|
|
62ddb18a1a | ||
|
|
3668ede0ff | ||
|
|
6a12378475 | ||
|
|
945584384a | ||
|
|
b1dd27b516 | ||
|
|
dcba1aad10 | ||
|
|
acc8b9cdbc | ||
|
|
d26b3108da | ||
|
|
6cbdd825eb | ||
|
|
cc55f6015d | ||
|
|
c89e4576b4 | ||
|
|
bc79f44a26 | ||
|
|
7ece14ff3f | ||
|
|
95718ab6ec | ||
|
|
feab27295d | ||
|
|
ca176c7549 | ||
|
|
f8a7a0d6e8 | ||
|
|
1a8aaa3b26 | ||
|
|
cd1c13b4b1 | ||
|
|
d87c5035dd | ||
|
|
77967731d5 | ||
|
|
0b54034470 | ||
|
|
0b3643132b | ||
|
|
a5693fbf8d | ||
|
|
5c5b70f52b | ||
|
|
ae97e388a6 | ||
|
|
37cddcaacc | ||
|
|
a1b332fc78 | ||
|
|
86d7c24513 | ||
|
|
b28add3b8b | ||
|
|
5fd3a513a4 | ||
|
|
b98a8a10b0 | ||
|
|
2bee2793ef | ||
|
|
2f6fa66f4d | ||
|
|
8ad2583785 | ||
|
|
dd533a9ab4 | ||
|
|
5b989adebc | ||
|
|
5d38acd787 | ||
|
|
e607fcb5c5 | ||
|
|
8a18555ae4 | ||
|
|
beb709dc8f | ||
|
|
20f8d3c8a9 | ||
|
|
0c77dbb7ea | ||
|
|
2448e2ae3b | ||
|
|
d53d7aa2e2 | ||
|
|
7a58c69a80 | ||
|
|
0be1df7ee8 | ||
|
|
1082c85789 | ||
|
|
568d2edd96 | ||
|
|
6aef0e145c | ||
|
|
32dc54ce72 | ||
|
|
548736f432 | ||
|
|
89d587e7dd | ||
|
|
5c8b2ebf7a | ||
|
|
5ac8ba9bae | ||
|
|
49fb16e2c6 | ||
|
|
545bfa6ef9 | ||
|
|
c596b5a17d | ||
|
|
84dd26c1b7 | ||
|
|
a765903a41 | ||
|
|
25ab381916 | ||
|
|
4d3df5d98f | ||
|
|
6fe2024542 | ||
|
|
4cd4c13b2d | ||
|
|
d2d56ebbd2 | ||
|
|
86be5df475 | ||
|
|
8c5e0cd4e9 | ||
|
|
a9b0b8adc8 | ||
|
|
ba01cb82f7 | ||
|
|
223b97b884 | ||
|
|
5de86d3d91 | ||
|
|
536444f9d1 | ||
|
|
271a07a7d6 | ||
|
|
4634ace74e | ||
|
|
3733715184 | ||
|
|
bf37ac53a3 | ||
|
|
70323b9477 | ||
|
|
7d0951a08a | ||
|
|
d98ca9a202 | ||
|
|
3c2c5bedc5 | ||
|
|
749d34cd30 | ||
|
|
1898be2fe1 | ||
|
|
af34da4160 | ||
|
|
fa053b7e60 | ||
|
|
4588219e31 | ||
|
|
6e89346f00 | ||
|
|
2703c9899a | ||
|
|
d05c358fd2 | ||
|
|
7c6bc5c421 | ||
|
|
798c398f23 | ||
|
|
4cc2cc4ad4 | ||
|
|
dcfdca6351 | ||
|
|
832599b8c5 | ||
|
|
c81ef2669e | ||
|
|
19d837c222 | ||
|
|
4f48ddfaec | ||
|
|
2e01fe0b5b | ||
|
|
7d067d8c30 | ||
|
|
b3b326738c | ||
|
|
2bb2caf2d2 | ||
|
|
2a094883ad | ||
|
|
6d1126b8aa | ||
|
|
26a47537f9 | ||
|
|
01d43c69fb | ||
|
|
7db1989093 | ||
|
|
0a97e28aab | ||
|
|
98a6907976 | ||
|
|
e9d2182390 | ||
|
|
5e29f2c1b7 | ||
|
|
44e28f96e0 | ||
|
|
a0e81da8c5 | ||
|
|
85a7c3c60d | ||
|
|
01e07ca0bc | ||
|
|
1468ee5fde | ||
|
|
49f044ecde | ||
|
|
37f32ab197 | ||
|
|
a60231ba59 | ||
|
|
c8dafede6d | ||
|
|
7deea9eb75 | ||
|
|
5e9a46d54d | ||
|
|
488974dd3e | ||
|
|
5975b9125f | ||
|
|
f301296f1e | ||
|
|
407477dc68 | ||
|
|
1b0ce9a123 | ||
|
|
7b855c851d | ||
|
|
ba636b17a0 | ||
|
|
2a07eb84f6 | ||
|
|
949b9fb10e | ||
|
|
ae1b6af0d4 | ||
|
|
dd27504d30 | ||
|
|
c30a08cfc5 | ||
|
|
a4c49aa35e | ||
|
|
402fba734a | ||
|
|
262af0678f | ||
|
|
3765d558b6 | ||
|
|
4ed8ded502 | ||
|
|
7fa25ca7ae | ||
|
|
d3c401ed4e | ||
|
|
10d8cfde85 | ||
|
|
6f221852a2 | ||
|
|
6dc2c680c5 | ||
|
|
9a4b56db6e | ||
|
|
8180f2c742 | ||
|
|
c600c6da63 | ||
|
|
e789a18553 | ||
|
|
3f3c986932 | ||
|
|
3ccc5babc1 | ||
|
|
45cf90094a | ||
|
|
ae1df20893 | ||
|
|
71148740d4 | ||
|
|
4ef583c844 | ||
|
|
16f61ea96d | ||
|
|
32f9616b6e | ||
|
|
1346eb4f76 | ||
|
|
d4268ba070 |
80
.github/workflows/build.yml
vendored
Normal file
80
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
name: WLED Build
|
||||
|
||||
# Only included into other workflows
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
|
||||
get_default_envs:
|
||||
name: Gather Environments
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
cache: 'pip'
|
||||
- name: Install PlatformIO
|
||||
run: pip install -r requirements.txt
|
||||
- name: Get default environments
|
||||
id: envs
|
||||
run: |
|
||||
echo "environments=$(pio project config --json-output | jq -cr '.[0][1][0][1]')" >> $GITHUB_OUTPUT
|
||||
outputs:
|
||||
environments: ${{ steps.envs.outputs.environments }}
|
||||
|
||||
|
||||
build:
|
||||
name: Build Enviornments
|
||||
runs-on: ubuntu-latest
|
||||
needs: get_default_envs
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
environment: ${{ fromJSON(needs.get_default_envs.outputs.environments) }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
cache: 'npm'
|
||||
- run: npm ci
|
||||
- name: Cache PlatformIO
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.platformio/.cache
|
||||
~/.buildcache
|
||||
build_output
|
||||
key: pio-${{ runner.os }}-${{ matrix.environment }}-${{ hashFiles('platformio.ini', 'pio-scripts/output_bins.py') }}-${{ hashFiles('wled00/**', 'usermods/**') }}
|
||||
restore-keys: pio-${{ runner.os }}-${{ matrix.environment }}-${{ hashFiles('platformio.ini', 'pio-scripts/output_bins.py') }}-
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
cache: 'pip'
|
||||
- name: Install PlatformIO
|
||||
run: pip install -r requirements.txt
|
||||
- name: Build firmware
|
||||
run: pio run -e ${{ matrix.environment }}
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: firmware-${{ matrix.environment }}
|
||||
path: |
|
||||
build_output/release/*.bin
|
||||
build_output/release/*_ESP02*.bin.gz
|
||||
|
||||
|
||||
testCdata:
|
||||
name: Test cdata.js
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Use Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20.x'
|
||||
cache: 'npm'
|
||||
- run: npm ci
|
||||
- run: npm test
|
||||
36
.github/workflows/release.yml
vendored
Normal file
36
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
name: WLED Release CI
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
|
||||
wled_build:
|
||||
uses: ./.github/workflows/build.yml
|
||||
|
||||
release:
|
||||
name: Create Release
|
||||
runs-on: ubuntu-latest
|
||||
needs: wled_build
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
merge-multiple: true
|
||||
- name: "✏️ Generate release changelog"
|
||||
id: changelog
|
||||
uses: janheinrichmerker/action-github-changelog-generator@v2.3
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
sinceTag: v0.15.0
|
||||
releaseBranch: 0_15_x
|
||||
- name: Create draft release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
body: ${{ steps.changelog.outputs.changelog }}
|
||||
draft: True
|
||||
files: |
|
||||
*.bin
|
||||
*.bin.gz
|
||||
|
||||
97
.github/workflows/wled-ci.yml
vendored
97
.github/workflows/wled-ci.yml
vendored
@@ -1,94 +1,11 @@
|
||||
name: WLED CI
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
|
||||
get_default_envs:
|
||||
name: Gather Environments
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
cache: 'pip'
|
||||
- name: Install PlatformIO
|
||||
run: pip install -r requirements.txt
|
||||
- name: Get default environments
|
||||
id: envs
|
||||
run: |
|
||||
echo "environments=$(pio project config --json-output | jq -cr '.[0][1][0][1]')" >> $GITHUB_OUTPUT
|
||||
outputs:
|
||||
environments: ${{ steps.envs.outputs.environments }}
|
||||
|
||||
|
||||
build:
|
||||
name: Build Enviornments
|
||||
runs-on: ubuntu-latest
|
||||
needs: get_default_envs
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
environment: ${{ fromJSON(needs.get_default_envs.outputs.environments) }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
cache: 'npm'
|
||||
- run: npm ci
|
||||
- name: Cache PlatformIO
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.platformio/.cache
|
||||
~/.buildcache
|
||||
build_output
|
||||
key: pio-${{ runner.os }}-${{ matrix.environment }}-${{ hashFiles('platformio.ini', 'pio-scripts/output_bins.py') }}-${{ hashFiles('wled00/**', 'usermods/**') }}
|
||||
restore-keys: pio-${{ runner.os }}-${{ matrix.environment }}-${{ hashFiles('platformio.ini', 'pio-scripts/output_bins.py') }}-
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
cache: 'pip'
|
||||
- name: Install PlatformIO
|
||||
run: pip install -r requirements.txt
|
||||
- name: Build firmware
|
||||
run: pio run -e ${{ matrix.environment }}
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: firmware-${{ matrix.environment }}
|
||||
path: |
|
||||
build_output/release/*.bin
|
||||
build_output/release/*_ESP02*.bin.gz
|
||||
release:
|
||||
name: Create Release
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
merge-multiple: true
|
||||
- name: Create draft release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
draft: True
|
||||
files: |
|
||||
*.bin
|
||||
*.bin.gz
|
||||
|
||||
|
||||
testCdata:
|
||||
name: Test cdata.js
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Use Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20.x'
|
||||
cache: 'npm'
|
||||
- run: npm ci
|
||||
- run: npm test
|
||||
wled_build:
|
||||
uses: ./.github/workflows/build.yml
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -15,6 +15,7 @@ wled-update.sh
|
||||
|
||||
/build_output/
|
||||
/node_modules/
|
||||
/logs/
|
||||
|
||||
/wled00/extLibs
|
||||
/wled00/LittleFS
|
||||
|
||||
44
CHANGELOG.md
44
CHANGELOG.md
@@ -1,9 +1,53 @@
|
||||
## WLED changelog
|
||||
|
||||
#### Build 2412100
|
||||
- WLED 0.15.0 release
|
||||
- Usermod BME280: Fix "Unit of Measurement" for temperature
|
||||
- WiFi reconnect bugfix (@blazoncek)
|
||||
|
||||
#### Build 2411250
|
||||
- WLED 0.15.0-rc1 release
|
||||
- Add support for esp32S3_wroom2 (#4243 by @softhack007)
|
||||
- Fix mixed LED SK6812 and ws2812b booloop (#4301 by @willmmiles)
|
||||
- Improved FPS calculation (by DedeHai)
|
||||
- Fix crashes when using HTTP API within MQTT (#4269 by @willmmiles)
|
||||
- Fix array overflow in exploding_fireworks (#4120 by @willmmiles)
|
||||
- Fix MQTT topic buffer length (#4293 by @WouterGritter)
|
||||
- Fix SparkFunDMX fix for possible array bounds violation in DMX.write (by @softhack007)
|
||||
- Allow TV Simulator on single LED segments (by @softhack007)
|
||||
- Fix WLED_RELEASE_NAME (by @netmindz)
|
||||
|
||||
|
||||
#### Build 2410270
|
||||
- WLED 0.15.0-b7 release
|
||||
- Re-license the WLED project from MIT to EUPL (#4194 by @Aircoookie)
|
||||
- Fix alexa devices invisible/uncontrollable (#4214 by @Svennte)
|
||||
- Add visual expand button on hover (#4172)
|
||||
- Usermod: Audioreactive tuning and performance enhancements (by @softhack007)
|
||||
- `/json/live` (JSON live data/peek) only enabled when WebSockets are disabled
|
||||
- Various bugfixes and optimisations: #4179, #4215, #4219, #4222, #4223, #4224, #4228, #4230
|
||||
|
||||
#### Build 2410140
|
||||
- WLED 0.15.0-b6 release
|
||||
- Added BRT timezone (#4188 by @LuisFadini)
|
||||
- Fixed the positioning of the "Download the latest binary" button (#4184 by @maxi4329)
|
||||
- Add WLED_AUTOSEGMENTS compile flag (#4183 by @PaoloTK)
|
||||
- New 512kB FS parition map for 4MB devices
|
||||
- Internal API change: Static PinManager & UsermodManager
|
||||
- Change in Improv chip ID and version generation
|
||||
- Various optimisations, bugfixes and enhancements (#4005, #4174 & #4175 by @Xevel, #4180, #4168, #4154, #4189 by @dosipod)
|
||||
|
||||
#### Build 2409170
|
||||
- UI: Introduce common.js in settings pages (size optimisation)
|
||||
- Add the ability to toggle the reception of palette synchronizations (#4137 by @felddy)
|
||||
- Usermod/FX: Temperature usermod added Temperature effect (example usermod effect by @blazoncek)
|
||||
- Fix AsyncWebServer version pin
|
||||
|
||||
#### Build 2409140
|
||||
- Configure different kinds of busses at compile (#4107 by @PaoloTK)
|
||||
- BREAKING: removes LEDPIN and DEFAULT_LED_TYPE compile overrides
|
||||
- Fetch LED types from Bus classes (dynamic UI) (#4129 by @netmindz, @blazoncek, @dedehai)
|
||||
- Temperature usermod: update OneWire to 2.3.8 (#4131 by @iammattcoleman)
|
||||
|
||||
#### Build 2409100
|
||||
- WLED 0.15.0-b5 release
|
||||
|
||||
307
LICENSE
307
LICENSE
@@ -1,21 +1,294 @@
|
||||
MIT License
|
||||
Copyright (c) 2016-present Christian Schwinne and individual WLED contributors
|
||||
Licensed under the EUPL v. 1.2 or later
|
||||
|
||||
Copyright (c) 2016 Christian Schwinne
|
||||
EUROPEAN UNION PUBLIC LICENCE v. 1.2
|
||||
EUPL © the European Union 2007, 2016
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
This European Union Public Licence (the ‘EUPL’) applies to the Work (as
|
||||
defined below) which is provided under the terms of this Licence. Any use of
|
||||
the Work, other than as authorised under this Licence is prohibited (to the
|
||||
extent such use is covered by a right of the copyright holder of the Work).
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
The Work is provided under the terms of this Licence when the Licensor (as
|
||||
defined below) has placed the following notice immediately following the
|
||||
copyright notice for the Work:
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
Licensed under the EUPL
|
||||
|
||||
or has expressed by any other means his willingness to license under the EUPL.
|
||||
|
||||
1. Definitions
|
||||
|
||||
In this Licence, the following terms have the following meaning:
|
||||
|
||||
- ‘The Licence’: this Licence.
|
||||
|
||||
- ‘The Original Work’: the work or software distributed or communicated by the
|
||||
Licensor under this Licence, available as Source Code and also as Executable
|
||||
Code as the case may be.
|
||||
|
||||
- ‘Derivative Works’: the works or software that could be created by the
|
||||
Licensee, based upon the Original Work or modifications thereof. This
|
||||
Licence does not define the extent of modification or dependence on the
|
||||
Original Work required in order to classify a work as a Derivative Work;
|
||||
this extent is determined by copyright law applicable in the country
|
||||
mentioned in Article 15.
|
||||
|
||||
- ‘The Work’: the Original Work or its Derivative Works.
|
||||
|
||||
- ‘The Source Code’: the human-readable form of the Work which is the most
|
||||
convenient for people to study and modify.
|
||||
|
||||
- ‘The Executable Code’: any code which has generally been compiled and which
|
||||
is meant to be interpreted by a computer as a program.
|
||||
|
||||
- ‘The Licensor’: the natural or legal person that distributes or communicates
|
||||
the Work under the Licence.
|
||||
|
||||
- ‘Contributor(s)’: any natural or legal person who modifies the Work under
|
||||
the Licence, or otherwise contributes to the creation of a Derivative Work.
|
||||
|
||||
- ‘The Licensee’ or ‘You’: any natural or legal person who makes any usage of
|
||||
the Work under the terms of the Licence.
|
||||
|
||||
- ‘Distribution’ or ‘Communication’: any act of selling, giving, lending,
|
||||
renting, distributing, communicating, transmitting, or otherwise making
|
||||
available, online or offline, copies of the Work or providing access to its
|
||||
essential functionalities at the disposal of any other natural or legal
|
||||
person.
|
||||
|
||||
2. Scope of the rights granted by the Licence
|
||||
|
||||
The Licensor hereby grants You a worldwide, royalty-free, non-exclusive,
|
||||
sublicensable licence to do the following, for the duration of copyright
|
||||
vested in the Original Work:
|
||||
|
||||
- use the Work in any circumstance and for all usage,
|
||||
- reproduce the Work,
|
||||
- modify the Work, and make Derivative Works based upon the Work,
|
||||
- communicate to the public, including the right to make available or display
|
||||
the Work or copies thereof to the public and perform publicly, as the case
|
||||
may be, the Work,
|
||||
- distribute the Work or copies thereof,
|
||||
- lend and rent the Work or copies thereof,
|
||||
- sublicense rights in the Work or copies thereof.
|
||||
|
||||
Those rights can be exercised on any media, supports and formats, whether now
|
||||
known or later invented, as far as the applicable law permits so.
|
||||
|
||||
In the countries where moral rights apply, the Licensor waives his right to
|
||||
exercise his moral right to the extent allowed by law in order to make
|
||||
effective the licence of the economic rights here above listed.
|
||||
|
||||
The Licensor grants to the Licensee royalty-free, non-exclusive usage rights
|
||||
to any patents held by the Licensor, to the extent necessary to make use of
|
||||
the rights granted on the Work under this Licence.
|
||||
|
||||
3. Communication of the Source Code
|
||||
|
||||
The Licensor may provide the Work either in its Source Code form, or as
|
||||
Executable Code. If the Work is provided as Executable Code, the Licensor
|
||||
provides in addition a machine-readable copy of the Source Code of the Work
|
||||
along with each copy of the Work that the Licensor distributes or indicates,
|
||||
in a notice following the copyright notice attached to the Work, a repository
|
||||
where the Source Code is easily and freely accessible for as long as the
|
||||
Licensor continues to distribute or communicate the Work.
|
||||
|
||||
4. Limitations on copyright
|
||||
|
||||
Nothing in this Licence is intended to deprive the Licensee of the benefits
|
||||
from any exception or limitation to the exclusive rights of the rights owners
|
||||
in the Work, of the exhaustion of those rights or of other applicable
|
||||
limitations thereto.
|
||||
|
||||
5. Obligations of the Licensee
|
||||
|
||||
The grant of the rights mentioned above is subject to some restrictions and
|
||||
obligations imposed on the Licensee. Those obligations are the following:
|
||||
|
||||
Attribution right: The Licensee shall keep intact all copyright, patent or
|
||||
trademarks notices and all notices that refer to the Licence and to the
|
||||
disclaimer of warranties. The Licensee must include a copy of such notices and
|
||||
a copy of the Licence with every copy of the Work he/she distributes or
|
||||
communicates. The Licensee must cause any Derivative Work to carry prominent
|
||||
notices stating that the Work has been modified and the date of modification.
|
||||
|
||||
Copyleft clause: If the Licensee distributes or communicates copies of the
|
||||
Original Works or Derivative Works, this Distribution or Communication will be
|
||||
done under the terms of this Licence or of a later version of this Licence
|
||||
unless the Original Work is expressly distributed only under this version of
|
||||
the Licence — for example by communicating ‘EUPL v. 1.2 only’. The Licensee
|
||||
(becoming Licensor) cannot offer or impose any additional terms or conditions
|
||||
on the Work or Derivative Work that alter or restrict the terms of the
|
||||
Licence.
|
||||
|
||||
Compatibility clause: If the Licensee Distributes or Communicates Derivative
|
||||
Works or copies thereof based upon both the Work and another work licensed
|
||||
under a Compatible Licence, this Distribution or Communication can be done
|
||||
under the terms of this Compatible Licence. For the sake of this clause,
|
||||
‘Compatible Licence’ refers to the licences listed in the appendix attached to
|
||||
this Licence. Should the Licensee's obligations under the Compatible Licence
|
||||
conflict with his/her obligations under this Licence, the obligations of the
|
||||
Compatible Licence shall prevail.
|
||||
|
||||
Provision of Source Code: When distributing or communicating copies of the
|
||||
Work, the Licensee will provide a machine-readable copy of the Source Code or
|
||||
indicate a repository where this Source will be easily and freely available
|
||||
for as long as the Licensee continues to distribute or communicate the Work.
|
||||
|
||||
Legal Protection: This Licence does not grant permission to use the trade
|
||||
names, trademarks, service marks, or names of the Licensor, except as required
|
||||
for reasonable and customary use in describing the origin of the Work and
|
||||
reproducing the content of the copyright notice.
|
||||
|
||||
6. Chain of Authorship
|
||||
|
||||
The original Licensor warrants that the copyright in the Original Work granted
|
||||
hereunder is owned by him/her or licensed to him/her and that he/she has the
|
||||
power and authority to grant the Licence.
|
||||
|
||||
Each Contributor warrants that the copyright in the modifications he/she
|
||||
brings to the Work are owned by him/her or licensed to him/her and that he/she
|
||||
has the power and authority to grant the Licence.
|
||||
|
||||
Each time You accept the Licence, the original Licensor and subsequent
|
||||
Contributors grant You a licence to their contributions to the Work, under the
|
||||
terms of this Licence.
|
||||
|
||||
7. Disclaimer of Warranty
|
||||
|
||||
The Work is a work in progress, which is continuously improved by numerous
|
||||
Contributors. It is not a finished work and may therefore contain defects or
|
||||
‘bugs’ inherent to this type of development.
|
||||
|
||||
For the above reason, the Work is provided under the Licence on an ‘as is’
|
||||
basis and without warranties of any kind concerning the Work, including
|
||||
without limitation merchantability, fitness for a particular purpose, absence
|
||||
of defects or errors, accuracy, non-infringement of intellectual property
|
||||
rights other than copyright as stated in Article 6 of this Licence.
|
||||
|
||||
This disclaimer of warranty is an essential part of the Licence and a
|
||||
condition for the grant of any rights to the Work.
|
||||
|
||||
8. Disclaimer of Liability
|
||||
|
||||
Except in the cases of wilful misconduct or damages directly caused to natural
|
||||
persons, the Licensor will in no event be liable for any direct or indirect,
|
||||
material or moral, damages of any kind, arising out of the Licence or of the
|
||||
use of the Work, including without limitation, damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, loss of data or any commercial
|
||||
damage, even if the Licensor has been advised of the possibility of such
|
||||
damage. However, the Licensor will be liable under statutory product liability
|
||||
laws as far such laws apply to the Work.
|
||||
|
||||
9. Additional agreements
|
||||
|
||||
While distributing the Work, You may choose to conclude an additional
|
||||
agreement, defining obligations or services consistent with this Licence.
|
||||
However, if accepting obligations, You may act only on your own behalf and on
|
||||
your sole responsibility, not on behalf of the original Licensor or any other
|
||||
Contributor, and only if You agree to indemnify, defend, and hold each
|
||||
Contributor harmless for any liability incurred by, or claims asserted against
|
||||
such Contributor by the fact You have accepted any warranty or additional
|
||||
liability.
|
||||
|
||||
10. Acceptance of the Licence
|
||||
|
||||
The provisions of this Licence can be accepted by clicking on an icon ‘I
|
||||
agree’ placed under the bottom of a window displaying the text of this Licence
|
||||
or by affirming consent in any other similar way, in accordance with the rules
|
||||
of applicable law. Clicking on that icon indicates your clear and irrevocable
|
||||
acceptance of this Licence and all of its terms and conditions.
|
||||
|
||||
Similarly, you irrevocably accept this Licence and all of its terms and
|
||||
conditions by exercising any rights granted to You by Article 2 of this
|
||||
Licence, such as the use of the Work, the creation by You of a Derivative Work
|
||||
or the Distribution or Communication by You of the Work or copies thereof.
|
||||
|
||||
11. Information to the public
|
||||
|
||||
In case of any Distribution or Communication of the Work by means of
|
||||
electronic communication by You (for example, by offering to download the Work
|
||||
from a remote location) the distribution channel or media (for example, a
|
||||
website) must at least provide to the public the information requested by the
|
||||
applicable law regarding the Licensor, the Licence and the way it may be
|
||||
accessible, concluded, stored and reproduced by the Licensee.
|
||||
|
||||
12. Termination of the Licence
|
||||
|
||||
The Licence and the rights granted hereunder will terminate automatically upon
|
||||
any breach by the Licensee of the terms of the Licence.
|
||||
|
||||
Such a termination will not terminate the licences of any person who has
|
||||
received the Work from the Licensee under the Licence, provided such persons
|
||||
remain in full compliance with the Licence.
|
||||
|
||||
13. Miscellaneous
|
||||
|
||||
Without prejudice of Article 9 above, the Licence represents the complete
|
||||
agreement between the Parties as to the Work.
|
||||
|
||||
If any provision of the Licence is invalid or unenforceable under applicable
|
||||
law, this will not affect the validity or enforceability of the Licence as a
|
||||
whole. Such provision will be construed or reformed so as necessary to make it
|
||||
valid and enforceable.
|
||||
|
||||
The European Commission may publish other linguistic versions or new versions
|
||||
of this Licence or updated versions of the Appendix, so far this is required
|
||||
and reasonable, without reducing the scope of the rights granted by the
|
||||
Licence. New versions of the Licence will be published with a unique version
|
||||
number.
|
||||
|
||||
All linguistic versions of this Licence, approved by the European Commission,
|
||||
have identical value. Parties can take advantage of the linguistic version of
|
||||
their choice.
|
||||
|
||||
14. Jurisdiction
|
||||
|
||||
Without prejudice to specific agreement between parties,
|
||||
|
||||
- any litigation resulting from the interpretation of this License, arising
|
||||
between the European Union institutions, bodies, offices or agencies, as a
|
||||
Licensor, and any Licensee, will be subject to the jurisdiction of the Court
|
||||
of Justice of the European Union, as laid down in article 272 of the Treaty
|
||||
on the Functioning of the European Union,
|
||||
|
||||
- any litigation arising between other parties and resulting from the
|
||||
interpretation of this License, will be subject to the exclusive
|
||||
jurisdiction of the competent court where the Licensor resides or conducts
|
||||
its primary business.
|
||||
|
||||
15. Applicable Law
|
||||
|
||||
Without prejudice to specific agreement between parties,
|
||||
|
||||
- this Licence shall be governed by the law of the European Union Member State
|
||||
where the Licensor has his seat, resides or has his registered office,
|
||||
|
||||
- this licence shall be governed by Belgian law if the Licensor has no seat,
|
||||
residence or registered office inside a European Union Member State.
|
||||
|
||||
Appendix
|
||||
|
||||
‘Compatible Licences’ according to Article 5 EUPL are:
|
||||
|
||||
- GNU General Public License (GPL) v. 2, v. 3
|
||||
- GNU Affero General Public License (AGPL) v. 3
|
||||
- Open Software License (OSL) v. 2.1, v. 3.0
|
||||
- Eclipse Public License (EPL) v. 1.0
|
||||
- CeCILL v. 2.0, v. 2.1
|
||||
- Mozilla Public Licence (MPL) v. 2
|
||||
- GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3
|
||||
- Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) for
|
||||
works other than software
|
||||
- European Union Public Licence (EUPL) v. 1.1, v. 1.2
|
||||
- Québec Free and Open-Source Licence — Reciprocity (LiLiQ-R) or Strong
|
||||
Reciprocity (LiLiQ-R+).
|
||||
|
||||
The European Commission may update this Appendix to later versions of the
|
||||
above licences without producing a new version of the EUPL, as long as they
|
||||
provide the rights granted in Article 2 of this Licence and protect the
|
||||
covered Source Code from exclusive appropriation.
|
||||
|
||||
All other changes or additions to this Appendix require the production of a
|
||||
new EUPL version.
|
||||
128
package-lock.json
generated
128
package-lock.json
generated
@@ -1,18 +1,21 @@
|
||||
{
|
||||
"name": "wled",
|
||||
"version": "0.15.0-b5",
|
||||
"version": "0.15.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "wled",
|
||||
"version": "0.15.0-b5",
|
||||
"version": "0.15.1",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"clean-css": "^5.3.3",
|
||||
"html-minifier-terser": "^7.2.0",
|
||||
"inliner": "^1.13.1",
|
||||
"nodemon": "^3.0.2"
|
||||
"nodemon": "^3.1.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/gen-mapping": {
|
||||
@@ -54,9 +57,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/sourcemap-codec": {
|
||||
"version": "1.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
|
||||
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
|
||||
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="
|
||||
},
|
||||
"node_modules/@jridgewell/trace-mapping": {
|
||||
"version": "0.3.25",
|
||||
@@ -67,15 +70,10 @@
|
||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||
}
|
||||
},
|
||||
"node_modules/abbrev": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
||||
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "8.11.3",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
|
||||
"integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==",
|
||||
"version": "8.12.1",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
|
||||
"integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==",
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
@@ -190,9 +188,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/aws4": {
|
||||
"version": "1.12.0",
|
||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz",
|
||||
"integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg=="
|
||||
"version": "1.13.2",
|
||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz",
|
||||
"integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw=="
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
@@ -233,11 +231,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/braces": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
||||
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
|
||||
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
|
||||
"dependencies": {
|
||||
"fill-range": "^7.0.1"
|
||||
"fill-range": "^7.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
@@ -701,9 +699,9 @@
|
||||
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
|
||||
},
|
||||
"node_modules/fill-range": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
||||
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
||||
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
|
||||
"dependencies": {
|
||||
"to-regex-range": "^5.0.1"
|
||||
},
|
||||
@@ -1281,17 +1279,6 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/mime": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
||||
@@ -1375,9 +1362,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/nodemon": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.0.tgz",
|
||||
"integrity": "sha512-xqlktYlDMCepBJd43ZQhjWwMw2obW/JRvkrLxq5RCNcuDDX1DbcPT+qT1IlIIdf+DhnWs90JpTMe+Y5KxOchvA==",
|
||||
"version": "3.1.7",
|
||||
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.7.tgz",
|
||||
"integrity": "sha512-hLj7fuMow6f0lbB0cD14Lz2xNjwsyruH251Pk4t/yIitCFJbmY1myuLlHm/q06aST4jg6EgAh74PIBBrRqpVAQ==",
|
||||
"dependencies": {
|
||||
"chokidar": "^3.5.2",
|
||||
"debug": "^4",
|
||||
@@ -1402,11 +1389,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/nodemon/node_modules/debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"version": "4.3.7",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
|
||||
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
|
||||
"dependencies": {
|
||||
"ms": "2.1.2"
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
@@ -1418,9 +1405,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/nodemon/node_modules/ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
||||
},
|
||||
"node_modules/nodemon/node_modules/supports-color": {
|
||||
"version": "5.5.0",
|
||||
@@ -1433,20 +1420,6 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/nopt": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
|
||||
"integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==",
|
||||
"dependencies": {
|
||||
"abbrev": "1"
|
||||
},
|
||||
"bin": {
|
||||
"nopt": "bin/nopt.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/normalize-path": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||
@@ -1507,6 +1480,7 @@
|
||||
"version": "0.1.5",
|
||||
"resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
|
||||
"integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
|
||||
"deprecated": "This package is no longer supported.",
|
||||
"dependencies": {
|
||||
"os-homedir": "^1.0.0",
|
||||
"os-tmpdir": "^1.0.0"
|
||||
@@ -1620,6 +1594,7 @@
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
|
||||
"integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==",
|
||||
"deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)",
|
||||
"engines": {
|
||||
"node": ">=0.6.0",
|
||||
"teleport": ">=0.2.0"
|
||||
@@ -1826,12 +1801,9 @@
|
||||
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.6.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
|
||||
"integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"version": "7.6.3",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
|
||||
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
@@ -1993,9 +1965,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/terser": {
|
||||
"version": "5.29.2",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.29.2.tgz",
|
||||
"integrity": "sha512-ZiGkhUBIM+7LwkNjXYJq8svgkd+QK3UUr0wJqY4MieaezBSAIPgbSPZyIx0idM6XWK5CMzSWa8MJIzmRcB8Caw==",
|
||||
"version": "5.34.0",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.34.0.tgz",
|
||||
"integrity": "sha512-y5NUX+U9HhVsK/zihZwoq4r9dICLyV2jXGOriDAVOeKhq3LKVjgJbGO90FisozXLlJfvjHqgckGmJFBb9KYoWQ==",
|
||||
"dependencies": {
|
||||
"@jridgewell/source-map": "^0.3.3",
|
||||
"acorn": "^8.8.2",
|
||||
@@ -2042,12 +2014,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/touch": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
|
||||
"integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==",
|
||||
"dependencies": {
|
||||
"nopt": "~1.0.10"
|
||||
},
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz",
|
||||
"integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==",
|
||||
"bin": {
|
||||
"nodetouch": "bin/nodetouch.js"
|
||||
}
|
||||
@@ -2065,9 +2034,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.6.2",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
|
||||
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz",
|
||||
"integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA=="
|
||||
},
|
||||
"node_modules/tunnel-agent": {
|
||||
"version": "0.6.0",
|
||||
@@ -2229,11 +2198,6 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
},
|
||||
"node_modules/yargs": {
|
||||
"version": "3.10.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wled",
|
||||
"version": "0.15.0-b5",
|
||||
"version": "0.15.2-beta1",
|
||||
"description": "Tools for WLED project",
|
||||
"main": "tools/cdata.js",
|
||||
"directories": {
|
||||
@@ -26,6 +26,9 @@
|
||||
"clean-css": "^5.3.3",
|
||||
"html-minifier-terser": "^7.2.0",
|
||||
"inliner": "^1.13.1",
|
||||
"nodemon": "^3.0.2"
|
||||
"nodemon": "^3.1.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,21 @@
|
||||
Import('env')
|
||||
Import("env")
|
||||
import shutil
|
||||
|
||||
env.Execute("npm run build")
|
||||
node_ex = shutil.which("node")
|
||||
# Check if Node.js is installed and present in PATH if it failed, abort the build
|
||||
if node_ex is None:
|
||||
print('\x1b[0;31;43m' + 'Node.js is not installed or missing from PATH html css js will not be processed check https://kno.wled.ge/advanced/compiling-wled/' + '\x1b[0m')
|
||||
exitCode = env.Execute("null")
|
||||
exit(exitCode)
|
||||
else:
|
||||
# Install the necessary node packages for the pre-build asset bundling script
|
||||
print('\x1b[6;33;42m' + 'Installing node packages' + '\x1b[0m')
|
||||
env.Execute("npm install")
|
||||
|
||||
# Call the bundling script
|
||||
exitCode = env.Execute("npm run build")
|
||||
|
||||
# If it failed, abort the build
|
||||
if (exitCode):
|
||||
print('\x1b[0;31;43m' + 'npm run build fails check https://kno.wled.ge/advanced/compiling-wled/' + '\x1b[0m')
|
||||
exit(exitCode)
|
||||
@@ -19,8 +19,9 @@ def _create_dirs(dirs=["map", "release", "firmware"]):
|
||||
os.makedirs(os.path.join(OUTPUT_DIR, d), exist_ok=True)
|
||||
|
||||
def create_release(source):
|
||||
release_name = _get_cpp_define_value(env, "WLED_RELEASE_NAME")
|
||||
if release_name:
|
||||
release_name_def = _get_cpp_define_value(env, "WLED_RELEASE_NAME")
|
||||
if release_name_def:
|
||||
release_name = release_name_def.replace("\\\"", "")
|
||||
version = _get_cpp_define_value(env, "WLED_VERSION")
|
||||
release_file = os.path.join(OUTPUT_DIR, "release", f"WLED_{version}_{release_name}.bin")
|
||||
release_gz_file = release_file + ".gz"
|
||||
|
||||
137
platformio.ini
137
platformio.ini
@@ -10,7 +10,7 @@
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# CI/release binaries
|
||||
default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, nodemcuv2_160, esp8266_2m_160, esp01_1m_full_160, nodemcuv2_compat, esp8266_2m_compat, esp01_1m_full_compat, esp32dev, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_16MB_opi, esp32s3dev_8MB_opi, esp32s3_4M_qspi, esp32_wrover
|
||||
default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, nodemcuv2_160, esp8266_2m_160, esp01_1m_full_160, nodemcuv2_compat, esp8266_2m_compat, esp01_1m_full_compat, esp32dev, esp32dev_V4, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_16MB_opi, esp32s3dev_8MB_opi, esp32s3_4M_qspi, esp32_wrover
|
||||
|
||||
src_dir = ./wled00
|
||||
data_dir = ./wled00/data
|
||||
@@ -138,9 +138,9 @@ lib_compat_mode = strict
|
||||
lib_deps =
|
||||
fastled/FastLED @ 3.6.0
|
||||
IRremoteESP8266 @ 2.8.2
|
||||
makuna/NeoPixelBus @ 2.8.0
|
||||
makuna/NeoPixelBus @ 2.8.3
|
||||
#https://github.com/makuna/NeoPixelBus.git#CoreShaderBeta
|
||||
https://github.com/Aircoookie/ESPAsyncWebServer.git#v2.2.1
|
||||
https://github.com/Aircoookie/ESPAsyncWebServer.git#v2.4.2
|
||||
# for I2C interface
|
||||
;Wire
|
||||
# ESP-NOW library
|
||||
@@ -176,6 +176,7 @@ lib_deps =
|
||||
extra_scripts = ${scripts_defaults.extra_scripts}
|
||||
|
||||
[esp8266]
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags =
|
||||
-DESP8266
|
||||
-DFP_IN_IROM
|
||||
@@ -197,6 +198,7 @@ build_flags =
|
||||
; decrease code cache size and increase IRAM to fit all pixel functions
|
||||
-D PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48 ;; in case of linker errors like "section `.text1' will not fit in region `iram1_0_seg'"
|
||||
; -D PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48_SECHEAP_SHARED ;; (experimental) adds some extra heap, but may cause slowdown
|
||||
-D NON32XFER_HANDLER ;; ask forgiveness for PROGMEM misuse
|
||||
|
||||
lib_deps =
|
||||
#https://github.com/lorol/LITTLEFS.git
|
||||
@@ -241,10 +243,12 @@ lib_deps_compat =
|
||||
#platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.2.3/platform-espressif32-2.0.2.3.zip
|
||||
platform = espressif32@3.5.0
|
||||
platform_packages = framework-arduinoespressif32 @ https://github.com/Aircoookie/arduino-esp32.git#1.0.6.4
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = -g
|
||||
-DARDUINO_ARCH_ESP32
|
||||
#-DCONFIG_LITTLEFS_FOR_IDF_3_2
|
||||
-D CONFIG_ASYNC_TCP_USE_WDT=0
|
||||
-D CONFIG_ASYNC_TCP_STACK_SIZE=8192
|
||||
#use LITTLEFS library by lorol in ESP32 core 1.x.x instead of built-in in 2.x.x
|
||||
-D LOROL_LITTLEFS
|
||||
; -DARDUINO_USB_CDC_ON_BOOT=0 ;; this flag is mandatory for "classic ESP32" when building with arduino-esp32 >=2.0.3
|
||||
@@ -256,11 +260,13 @@ large_partitions = tools/WLED_ESP32_8MB.csv
|
||||
extreme_partitions = tools/WLED_ESP32_16MB_9MB_FS.csv
|
||||
lib_deps =
|
||||
https://github.com/lorol/LITTLEFS.git
|
||||
https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
|
||||
esp32async/AsyncTCP @ 3.4.7
|
||||
${env.lib_deps}
|
||||
# additional build flags for audioreactive
|
||||
AR_build_flags = -D USERMOD_AUDIOREACTIVE
|
||||
AR_build_flags = -D USERMOD_AUDIOREACTIVE
|
||||
-D sqrt_internal=sqrtf ;; -fsingle-precision-constant ;; forces ArduinoFFT to use float math (2x faster)
|
||||
AR_lib_deps = kosme/arduinoFFT @ 2.0.1
|
||||
board_build.partitions = ${esp32.default_partitions} ;; default partioning for 4MB Flash - can be overridden in build envs
|
||||
|
||||
[esp32_idf_V4]
|
||||
;; experimental build environment for ESP32 using ESP-IDF 4.4.x / arduino-esp32 v2.0.5
|
||||
@@ -270,67 +276,81 @@ AR_lib_deps = kosme/arduinoFFT @ 2.0.1
|
||||
;; You need to completely erase your device (esptool erase_flash) first, then install the "V4" build from VSCode+platformio.
|
||||
platform = espressif32@ ~6.3.2
|
||||
platform_packages = platformio/framework-arduinoespressif32 @ 3.20009.0 ;; select arduino-esp32 v2.0.9 (arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them)
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = -g
|
||||
-Wshadow=compatible-local ;; emit warning in case a local variable "shadows" another local one
|
||||
-DARDUINO_ARCH_ESP32 -DESP32
|
||||
-D CONFIG_ASYNC_TCP_USE_WDT=0
|
||||
-D CONFIG_ASYNC_TCP_STACK_SIZE=8192
|
||||
-DARDUINO_USB_CDC_ON_BOOT=0 ;; this flag is mandatory for "classic ESP32" when building with arduino-esp32 >=2.0.3
|
||||
-D WLED_ENABLE_DMX_INPUT
|
||||
lib_deps =
|
||||
https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
|
||||
esp32async/AsyncTCP @ 3.4.7
|
||||
https://github.com/someweisguy/esp_dmx.git#47db25d
|
||||
${env.lib_deps}
|
||||
board_build.partitions = ${esp32.default_partitions} ;; default partioning for 4MB Flash - can be overridden in build envs
|
||||
|
||||
[esp32s2]
|
||||
;; generic definitions for all ESP32-S2 boards
|
||||
platform = espressif32@ ~6.3.2
|
||||
platform_packages = platformio/framework-arduinoespressif32 @ 3.20009.0 ;; select arduino-esp32 v2.0.9 (arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them)
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = -g
|
||||
-DARDUINO_ARCH_ESP32
|
||||
-DARDUINO_ARCH_ESP32S2
|
||||
-DCONFIG_IDF_TARGET_ESP32S2=1
|
||||
-D CONFIG_ASYNC_TCP_USE_WDT=0
|
||||
-D CONFIG_ASYNC_TCP_STACK_SIZE=8192
|
||||
-DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_USB_DFU_ON_BOOT=0
|
||||
-DCO
|
||||
-DARDUINO_USB_MODE=0 ;; this flag is mandatory for ESP32-S2 !
|
||||
;; please make sure that the following flags are properly set (to 0 or 1) by your board.json, or included in your custom platformio_override.ini entry:
|
||||
;; ARDUINO_USB_CDC_ON_BOOT
|
||||
lib_deps =
|
||||
https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
|
||||
esp32async/AsyncTCP @ 3.4.7
|
||||
${env.lib_deps}
|
||||
board_build.partitions = ${esp32.default_partitions} ;; default partioning for 4MB Flash - can be overridden in build envs
|
||||
|
||||
[esp32c3]
|
||||
;; generic definitions for all ESP32-C3 boards
|
||||
platform = espressif32@ ~6.3.2
|
||||
platform_packages = platformio/framework-arduinoespressif32 @ 3.20009.0 ;; select arduino-esp32 v2.0.9 (arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them)
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = -g
|
||||
-DARDUINO_ARCH_ESP32
|
||||
-DARDUINO_ARCH_ESP32C3
|
||||
-DCONFIG_IDF_TARGET_ESP32C3=1
|
||||
-D CONFIG_ASYNC_TCP_USE_WDT=0
|
||||
-D CONFIG_ASYNC_TCP_STACK_SIZE=8192
|
||||
-DCO
|
||||
-DARDUINO_USB_MODE=1 ;; this flag is mandatory for ESP32-C3
|
||||
;; please make sure that the following flags are properly set (to 0 or 1) by your board.json, or included in your custom platformio_override.ini entry:
|
||||
;; ARDUINO_USB_CDC_ON_BOOT
|
||||
lib_deps =
|
||||
https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
|
||||
esp32async/AsyncTCP @ 3.4.7
|
||||
${env.lib_deps}
|
||||
board_build.partitions = ${esp32.default_partitions} ;; default partioning for 4MB Flash - can be overridden in build envs
|
||||
|
||||
[esp32s3]
|
||||
;; generic definitions for all ESP32-S3 boards
|
||||
platform = espressif32@ ~6.3.2
|
||||
platform_packages = platformio/framework-arduinoespressif32 @ 3.20009.0 ;; select arduino-esp32 v2.0.9 (arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them)
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = -g
|
||||
-DESP32
|
||||
-DARDUINO_ARCH_ESP32
|
||||
-DARDUINO_ARCH_ESP32S3
|
||||
-DCONFIG_IDF_TARGET_ESP32S3=1
|
||||
-D CONFIG_ASYNC_TCP_USE_WDT=0
|
||||
-D CONFIG_ASYNC_TCP_STACK_SIZE=8192
|
||||
-DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_DFU_ON_BOOT=0
|
||||
-DCO
|
||||
;; please make sure that the following flags are properly set (to 0 or 1) by your board.json, or included in your custom platformio_override.ini entry:
|
||||
;; ARDUINO_USB_MODE, ARDUINO_USB_CDC_ON_BOOT
|
||||
lib_deps =
|
||||
https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
|
||||
esp32async/AsyncTCP @ 3.4.7
|
||||
${env.lib_deps}
|
||||
board_build.partitions = ${esp32.large_partitions} ;; default partioning for 8MB flash - can be overridden in build envs
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
@@ -343,7 +363,7 @@ platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=ESP8266 #-DWLED_DISABLE_2D
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP8266\" #-DWLED_DISABLE_2D
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
monitor_filters = esp8266_exception_decoder
|
||||
|
||||
@@ -352,13 +372,13 @@ extends = env:nodemcuv2
|
||||
;; using platform version and build options from WLED 0.14.0
|
||||
platform = ${esp8266.platform_compat}
|
||||
platform_packages = ${esp8266.platform_packages_compat}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=ESP8266_compat #-DWLED_DISABLE_2D
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=\"ESP8266_compat\" #-DWLED_DISABLE_2D
|
||||
;; lib_deps = ${esp8266.lib_deps_compat} ;; experimental - use older NeoPixelBus 2.7.9
|
||||
|
||||
[env:nodemcuv2_160]
|
||||
extends = env:nodemcuv2
|
||||
board_build.f_cpu = 160000000L
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=ESP8266_160 #-DWLED_DISABLE_2D
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP8266_160\" #-DWLED_DISABLE_2D
|
||||
-D USERMOD_AUDIOREACTIVE
|
||||
|
||||
[env:esp8266_2m]
|
||||
@@ -367,7 +387,7 @@ platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_2m512k}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=ESP02
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP02\"
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
|
||||
[env:esp8266_2m_compat]
|
||||
@@ -375,12 +395,12 @@ extends = env:esp8266_2m
|
||||
;; using platform version and build options from WLED 0.14.0
|
||||
platform = ${esp8266.platform_compat}
|
||||
platform_packages = ${esp8266.platform_packages_compat}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=ESP02_compat #-DWLED_DISABLE_2D
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=\"ESP02_compat\" #-DWLED_DISABLE_2D
|
||||
|
||||
[env:esp8266_2m_160]
|
||||
extends = env:esp8266_2m
|
||||
board_build.f_cpu = 160000000L
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=ESP02_160
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP02_160\"
|
||||
-D USERMOD_AUDIOREACTIVE
|
||||
|
||||
[env:esp01_1m_full]
|
||||
@@ -389,7 +409,7 @@ platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_1m128k}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=ESP01 -D WLED_DISABLE_OTA
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP01\" -D WLED_DISABLE_OTA
|
||||
; -D WLED_USE_REAL_MATH ;; may fix wrong sunset/sunrise times, at the cost of 7064 bytes FLASH and 975 bytes RAM
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
|
||||
@@ -398,12 +418,12 @@ extends = env:esp01_1m_full
|
||||
;; using platform version and build options from WLED 0.14.0
|
||||
platform = ${esp8266.platform_compat}
|
||||
platform_packages = ${esp8266.platform_packages_compat}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=ESP01_compat -D WLED_DISABLE_OTA #-DWLED_DISABLE_2D
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=\"ESP01_compat\" -D WLED_DISABLE_OTA #-DWLED_DISABLE_2D
|
||||
|
||||
[env:esp01_1m_full_160]
|
||||
extends = env:esp01_1m_full
|
||||
board_build.f_cpu = 160000000L
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=ESP01_160 -D WLED_DISABLE_OTA
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP01_160\" -D WLED_DISABLE_OTA
|
||||
-D USERMOD_AUDIOREACTIVE
|
||||
; -D WLED_USE_REAL_MATH ;; may fix wrong sunset/sunrise times, at the cost of 7064 bytes FLASH and 975 bytes RAM
|
||||
|
||||
@@ -412,32 +432,63 @@ board = esp32dev
|
||||
platform = ${esp32.platform}
|
||||
platform_packages = ${esp32.platform_packages}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=ESP32 #-D WLED_DISABLE_BROWNOUT_DET
|
||||
build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"ESP32\" #-D WLED_DISABLE_BROWNOUT_DET
|
||||
${esp32.AR_build_flags}
|
||||
lib_deps = ${esp32.lib_deps}
|
||||
${esp32.AR_lib_deps}
|
||||
monitor_filters = esp32_exception_decoder
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
|
||||
[env:esp32dev_V4]
|
||||
board = esp32dev
|
||||
platform = ${esp32_idf_V4.platform}
|
||||
platform_packages = ${esp32_idf_V4.platform_packages}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_V4\" #-D WLED_DISABLE_BROWNOUT_DET
|
||||
${esp32.AR_build_flags}
|
||||
lib_deps = ${esp32_idf_V4.lib_deps}
|
||||
${esp32.AR_lib_deps}
|
||||
monitor_filters = esp32_exception_decoder
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
|
||||
[env:esp32dev_8M]
|
||||
board = esp32dev
|
||||
platform = ${esp32_idf_V4.platform}
|
||||
platform_packages = ${esp32_idf_V4.platform_packages}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=ESP32_8M #-D WLED_DISABLE_BROWNOUT_DET
|
||||
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_8M\" #-D WLED_DISABLE_BROWNOUT_DET
|
||||
${esp32.AR_build_flags}
|
||||
lib_deps = ${esp32_idf_V4.lib_deps}
|
||||
${esp32.AR_lib_deps}
|
||||
monitor_filters = esp32_exception_decoder
|
||||
board_build.partitions = ${esp32.large_partitions}
|
||||
board_upload.flash_size = 8MB
|
||||
board_upload.maximum_size = 8388608
|
||||
; board_build.f_flash = 80000000L
|
||||
; board_build.flash_mode = qio
|
||||
|
||||
[env:esp32dev_16M]
|
||||
board = esp32dev
|
||||
platform = ${esp32_idf_V4.platform}
|
||||
platform_packages = ${esp32_idf_V4.platform_packages}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_16M\" #-D WLED_DISABLE_BROWNOUT_DET
|
||||
${esp32.AR_build_flags}
|
||||
lib_deps = ${esp32_idf_V4.lib_deps}
|
||||
${esp32.AR_lib_deps}
|
||||
monitor_filters = esp32_exception_decoder
|
||||
board_build.partitions = ${esp32.extreme_partitions}
|
||||
board_upload.flash_size = 16MB
|
||||
board_upload.maximum_size = 16777216
|
||||
board_build.f_flash = 80000000L
|
||||
board_build.flash_mode = dio
|
||||
|
||||
;[env:esp32dev_audioreactive]
|
||||
;board = esp32dev
|
||||
;platform = ${esp32.platform}
|
||||
;platform_packages = ${esp32.platform_packages}
|
||||
;build_unflags = ${common.build_unflags}
|
||||
;build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=ESP32_audioreactive #-D WLED_DISABLE_BROWNOUT_DET
|
||||
;build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"ESP32_audioreactive\" #-D WLED_DISABLE_BROWNOUT_DET
|
||||
; ${esp32.AR_build_flags}
|
||||
;lib_deps = ${esp32.lib_deps}
|
||||
; ${esp32.AR_lib_deps}
|
||||
@@ -452,7 +503,7 @@ platform = ${esp32.platform}
|
||||
platform_packages = ${esp32.platform_packages}
|
||||
upload_speed = 921600
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=ESP32_Ethernet -D RLYPIN=-1 -D WLED_USE_ETHERNET -D BTNPIN=-1
|
||||
build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"ESP32_Ethernet\" -D RLYPIN=-1 -D WLED_USE_ETHERNET -D BTNPIN=-1
|
||||
; -D WLED_DISABLE_ESPNOW ;; ESP-NOW requires wifi, may crash with ethernet only
|
||||
${esp32.AR_build_flags}
|
||||
lib_deps = ${esp32.lib_deps}
|
||||
@@ -468,7 +519,7 @@ board_build.f_flash = 80000000L
|
||||
board_build.flash_mode = qio
|
||||
board_build.partitions = ${esp32.extended_partitions}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=ESP32_WROVER
|
||||
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_WROVER\"
|
||||
-DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue ;; Older ESP32 (rev.<3) need a PSRAM fix (increases static RAM used) https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/external-ram.html
|
||||
-D DATA_PINS=25
|
||||
${esp32.AR_build_flags}
|
||||
@@ -482,7 +533,7 @@ platform_packages = ${esp32c3.platform_packages}
|
||||
framework = arduino
|
||||
board = esp32-c3-devkitm-1
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
build_flags = ${common.build_flags} ${esp32c3.build_flags} -D WLED_RELEASE_NAME=ESP32-C3
|
||||
build_flags = ${common.build_flags} ${esp32c3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-C3\"
|
||||
-D WLED_WATCHDOG_TIMEOUT=0
|
||||
-DLOLIN_WIFI_FIX ; seems to work much better with this
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1 ;; for virtual CDC USB
|
||||
@@ -499,7 +550,7 @@ platform = ${esp32s3.platform}
|
||||
platform_packages = ${esp32s3.platform_packages}
|
||||
upload_speed = 921600
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=ESP32-S3_16MB_opi
|
||||
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_16MB_opi\"
|
||||
-D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0
|
||||
;-D ARDUINO_USB_CDC_ON_BOOT=0 ;; -D ARDUINO_USB_MODE=1 ;; for boards with serial-to-USB chip
|
||||
-D ARDUINO_USB_CDC_ON_BOOT=1 -D ARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB")
|
||||
@@ -508,6 +559,8 @@ build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=
|
||||
lib_deps = ${esp32s3.lib_deps}
|
||||
${esp32.AR_lib_deps}
|
||||
board_build.partitions = ${esp32.extreme_partitions}
|
||||
board_upload.flash_size = 16MB
|
||||
board_upload.maximum_size = 16777216
|
||||
board_build.f_flash = 80000000L
|
||||
board_build.flash_mode = qio
|
||||
monitor_filters = esp32_exception_decoder
|
||||
@@ -520,7 +573,7 @@ platform = ${esp32s3.platform}
|
||||
platform_packages = ${esp32s3.platform_packages}
|
||||
upload_speed = 921600
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=ESP32-S3_8MB_opi
|
||||
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_8MB_opi\"
|
||||
-D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0
|
||||
;-D ARDUINO_USB_CDC_ON_BOOT=0 ;; -D ARDUINO_USB_MODE=1 ;; for boards with serial-to-USB chip
|
||||
-D ARDUINO_USB_CDC_ON_BOOT=1 -D ARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB")
|
||||
@@ -533,6 +586,33 @@ board_build.f_flash = 80000000L
|
||||
board_build.flash_mode = qio
|
||||
monitor_filters = esp32_exception_decoder
|
||||
|
||||
[env:esp32S3_wroom2]
|
||||
;; For ESP32-S3 WROOM-2, a.k.a. ESP32-S3 DevKitC-1 v1.1
|
||||
;; with >= 16MB FLASH and >= 8MB PSRAM (memory_type: opi_opi)
|
||||
platform = ${esp32s3.platform}
|
||||
platform_packages = ${esp32s3.platform_packages}
|
||||
board = esp32s3camlcd ;; this is the only standard board with "opi_opi"
|
||||
board_build.arduino.memory_type = opi_opi
|
||||
upload_speed = 921600
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_WROOM-2\"
|
||||
-D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0
|
||||
-D ARDUINO_USB_CDC_ON_BOOT=0 ;; -D ARDUINO_USB_MODE=1 ;; for boards with serial-to-USB chip
|
||||
;; -D ARDUINO_USB_CDC_ON_BOOT=1 -D ARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB")
|
||||
-DBOARD_HAS_PSRAM
|
||||
-D LEDPIN=38 -D DATA_PINS=38 ;; buildin WS2812b LED
|
||||
-D BTNPIN=0 -D RLYPIN=16 -D IRPIN=17 -D AUDIOPIN=-1
|
||||
-D WLED_DEBUG
|
||||
${esp32.AR_build_flags}
|
||||
-D SR_DMTYPE=1 -D I2S_SDPIN=13 -D I2S_CKPIN=14 -D I2S_WSPIN=15 -D MCLK_PIN=4 ;; I2S mic
|
||||
lib_deps = ${esp32s3.lib_deps}
|
||||
${esp32.AR_lib_deps}
|
||||
|
||||
board_build.partitions = ${esp32.extreme_partitions}
|
||||
board_upload.flash_size = 16MB
|
||||
board_upload.maximum_size = 16777216
|
||||
monitor_filters = esp32_exception_decoder
|
||||
|
||||
[env:esp32s3_4M_qspi]
|
||||
;; ESP32-S3, with 4MB FLASH and <= 4MB PSRAM (memory_type: qio_qspi)
|
||||
board = lolin_s3_mini ;; -S3 mini, 4MB flash 2MB PSRAM
|
||||
@@ -540,7 +620,7 @@ platform = ${esp32s3.platform}
|
||||
platform_packages = ${esp32s3.platform_packages}
|
||||
upload_speed = 921600
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=ESP32-S3_4M_qspi
|
||||
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_4M_qspi\"
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1 -DARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB")
|
||||
-DBOARD_HAS_PSRAM
|
||||
-DLOLIN_WIFI_FIX ; seems to work much better with this
|
||||
@@ -561,7 +641,7 @@ board_build.partitions = ${esp32.default_partitions}
|
||||
board_build.flash_mode = qio
|
||||
board_build.f_flash = 80000000L
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32s2.build_flags} -D WLED_RELEASE_NAME=ESP32-S2
|
||||
build_flags = ${common.build_flags} ${esp32s2.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S2\"
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1
|
||||
-DARDUINO_USB_MSC_ON_BOOT=0
|
||||
-DARDUINO_USB_DFU_ON_BOOT=0
|
||||
@@ -569,6 +649,7 @@ build_flags = ${common.build_flags} ${esp32s2.build_flags} -D WLED_RELEASE_NAME=
|
||||
-DLOLIN_WIFI_FIX ; seems to work much better with this
|
||||
-D WLED_WATCHDOG_TIMEOUT=0
|
||||
-D CONFIG_ASYNC_TCP_USE_WDT=0
|
||||
-D CONFIG_ASYNC_TCP_STACK_SIZE=8192
|
||||
-D DATA_PINS=16
|
||||
-D HW_PIN_SCL=35
|
||||
-D HW_PIN_SDA=33
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# Please visit documentation: https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[platformio]
|
||||
default_envs = WLED_tasmota_1M # define as many as you need
|
||||
default_envs = WLED_generic8266_1M, esp32dev_V4_dio80 # put the name(s) of your own build environment here. You can define as many as you need
|
||||
|
||||
#----------
|
||||
# SAMPLE
|
||||
@@ -28,8 +28,8 @@ lib_deps = ${esp8266.lib_deps}
|
||||
; robtillaart/SHT85@~0.3.3
|
||||
; ;gmag11/QuickESPNow @ ~0.7.0 # will also load QuickDebug
|
||||
; https://github.com/blazoncek/QuickESPNow.git#optional-debug ;; exludes debug library
|
||||
; ${esp32.AR_lib_deps} ;; used for USERMOD_AUDIOREACTIVE
|
||||
; bitbank2/PNGdec@^1.0.1 ;; used for POV display uncomment following
|
||||
; ${esp32.AR_lib_deps} ;; needed for USERMOD_AUDIOREACTIVE
|
||||
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags}
|
||||
@@ -37,7 +37,7 @@ build_flags = ${common.build_flags} ${esp8266.build_flags}
|
||||
; *** To use the below defines/overrides, copy and paste each onto it's own line just below build_flags in the section above.
|
||||
;
|
||||
; Set a release name that may be used to distinguish required binary for flashing
|
||||
; -D WLED_RELEASE_NAME=ESP32_MULTI_USREMODS
|
||||
; -D WLED_RELEASE_NAME=\"ESP32_MULTI_USREMODS\"
|
||||
;
|
||||
; disable specific features
|
||||
; -D WLED_DISABLE_OTA
|
||||
@@ -111,7 +111,6 @@ build_flags = ${common.build_flags} ${esp8266.build_flags}
|
||||
;
|
||||
; Use 4 Line Display usermod with SPI display
|
||||
; -D USERMOD_FOUR_LINE_DISPLAY
|
||||
; -D USE_ALT_DISPlAY # mandatory
|
||||
; -DFLD_SPI_DEFAULT
|
||||
; -D FLD_TYPE=SSD1306_SPI64
|
||||
; -D FLD_PIN_CLOCKSPI=14
|
||||
@@ -142,7 +141,8 @@ build_flags = ${common.build_flags} ${esp8266.build_flags}
|
||||
; -D PIR_SENSOR_MAX_SENSORS=2 # max allowable sensors (uses OR logic for triggering)
|
||||
;
|
||||
; Use Audioreactive usermod and configure I2S microphone
|
||||
; -D USERMOD_AUDIOREACTIVE
|
||||
; ${esp32.AR_build_flags} ;; default flags required to properly configure ArduinoFFT
|
||||
; ;; don't forget to add ArduinoFFT to your libs_deps: ${esp32.AR_lib_deps}
|
||||
; -D AUDIOPIN=-1
|
||||
; -D DMTYPE=1 # 0-analog/disabled, 1-I2S generic, 2-ES7243, 3-SPH0645, 4-I2S+mclk, 5-I2S PDM
|
||||
; -D I2S_SDPIN=36
|
||||
@@ -158,17 +158,22 @@ build_flags = ${common.build_flags} ${esp8266.build_flags}
|
||||
; -D USERMOD_POV_DISPLAY
|
||||
; Use built-in or custom LED as a status indicator (assumes LED is connected to GPIO16)
|
||||
; -D STATUSLED=16
|
||||
;
|
||||
;
|
||||
; set the name of the module - make sure there is a quote-backslash-quote before the name and a backslash-quote-quote after the name
|
||||
; -D SERVERNAME="\"WLED\""
|
||||
;
|
||||
;
|
||||
; set the number of LEDs
|
||||
; -D DEFAULT_LED_COUNT=30
|
||||
; -D PIXEL_COUNTS=30
|
||||
; or this for multiple outputs
|
||||
; -D PIXEL_COUNTS=30,30
|
||||
;
|
||||
; set the default LED type
|
||||
; -D DEFAULT_LED_TYPE=22 # see const.h (TYPE_xxxx)
|
||||
; -D LED_TYPES=22 # see const.h (TYPE_xxxx)
|
||||
; or this for multiple outputs
|
||||
; -D LED_TYPES=TYPE_SK6812_RGBW,TYPE_WS2812_RGB
|
||||
;
|
||||
; set default color order of your led strip
|
||||
; -D DEFAULT_LED_COLOR_ORDER=COL_ORDER_GRB
|
||||
;
|
||||
; set milliampere limit when using ESP power pin (or inadequate PSU) to power LEDs
|
||||
; -D ABL_MILLIAMPS_DEFAULT=850
|
||||
@@ -177,9 +182,6 @@ build_flags = ${common.build_flags} ${esp8266.build_flags}
|
||||
; enable IR by setting remote type
|
||||
; -D IRTYPE=0 # 0 Remote disabled | 1 24-key RGB | 2 24-key with CT | 3 40-key blue | 4 40-key RGB | 5 21-key RGB | 6 6-key black | 7 9-key red | 8 JSON remote
|
||||
;
|
||||
; set default color order of your led strip
|
||||
; -D DEFAULT_LED_COLOR_ORDER=COL_ORDER_GRB
|
||||
;
|
||||
; use PSRAM on classic ESP32 rev.1 (rev.3 or above has no issues)
|
||||
; -DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue # needed only for classic ESP32 rev.1
|
||||
;
|
||||
@@ -237,14 +239,13 @@ build_flags = ${common.build_flags} ${esp8266.build_flags} -D DATA_PINS=1 -D WLE
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
|
||||
[env:esp32dev_qio80]
|
||||
extends = env:esp32dev # we want to extend the existing esp32dev environment (and define only updated options)
|
||||
board = esp32dev
|
||||
platform = ${esp32.platform}
|
||||
platform_packages = ${esp32.platform_packages}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32.build_flags} #-D WLED_DISABLE_BROWNOUT_DET
|
||||
${esp32.AR_build_flags} ;; optional - includes USERMOD_AUDIOREACTIVE
|
||||
lib_deps = ${esp32.lib_deps}
|
||||
${esp32.AR_lib_deps} ;; needed for USERMOD_AUDIOREACTIVE
|
||||
monitor_filters = esp32_exception_decoder
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
board_build.f_flash = 80000000L
|
||||
board_build.flash_mode = qio
|
||||
|
||||
@@ -252,26 +253,25 @@ board_build.flash_mode = qio
|
||||
;; experimental ESP32 env using ESP-IDF V4.4.x
|
||||
;; Warning: this build environment is not stable!!
|
||||
;; please erase your device before installing.
|
||||
extends = esp32_idf_V4 # based on newer "esp-idf V4" platform environment
|
||||
board = esp32dev
|
||||
platform = ${esp32_idf_V4.platform}
|
||||
platform_packages = ${esp32_idf_V4.platform_packages}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} #-D WLED_DISABLE_BROWNOUT_DET
|
||||
${esp32.AR_build_flags} ;; includes USERMOD_AUDIOREACTIVE
|
||||
lib_deps = ${esp32_idf_V4.lib_deps}
|
||||
${esp32.AR_lib_deps} ;; needed for USERMOD_AUDIOREACTIVE
|
||||
monitor_filters = esp32_exception_decoder
|
||||
board_build.partitions = ${esp32_idf_V4.default_partitions}
|
||||
board_build.partitions = ${esp32.default_partitions} ;; if you get errors about "out of program space", change this to ${esp32.extended_partitions} or even ${esp32.big_partitions}
|
||||
board_build.f_flash = 80000000L
|
||||
board_build.flash_mode = dio
|
||||
|
||||
[env:esp32s2_saola]
|
||||
extends = esp32s2
|
||||
board = esp32-s2-saola-1
|
||||
platform = ${esp32s2.platform}
|
||||
platform_packages = ${esp32s2.platform_packages}
|
||||
framework = arduino
|
||||
board_build.partitions = tools/WLED_ESP32_4MB_1MB_FS.csv
|
||||
board_build.flash_mode = qio
|
||||
upload_speed = 460800
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32s2.build_flags}
|
||||
;-DLOLIN_WIFI_FIX ;; try this in case Wifi does not work
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1
|
||||
@@ -308,7 +308,7 @@ platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_USE_SHOJO_PCB
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_USE_SHOJO_PCB ;; NB: WLED_USE_SHOJO_PCB is not used anywhere in the source code. Not sure why its needed.
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
|
||||
[env:d1_mini_debug]
|
||||
@@ -359,38 +359,52 @@ upload_speed = 115200
|
||||
lib_deps = ${esp32c3.lib_deps}
|
||||
board_build.partitions = tools/WLED_ESP32_2MB_noOTA.csv
|
||||
board_build.flash_mode = dio
|
||||
board_upload.flash_size = 2MB
|
||||
board_upload.maximum_size = 2097152
|
||||
|
||||
[env:wemos_shield_esp32]
|
||||
extends = esp32 ;; use default esp32 platform
|
||||
board = esp32dev
|
||||
platform = ${esp32.platform}
|
||||
platform_packages = ${esp32.platform_packages}
|
||||
upload_speed = 460800
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32.build_flags}
|
||||
-D WLED_RELEASE_NAME=\"ESP32_wemos_shield\"
|
||||
-D DATA_PINS=16
|
||||
-D RLYPIN=19
|
||||
-D BTNPIN=17
|
||||
-D IRPIN=18
|
||||
-D UWLED_USE_MY_CONFIG
|
||||
-UWLED_USE_MY_CONFIG
|
||||
-D USERMOD_DALLASTEMPERATURE
|
||||
-D USERMOD_FOUR_LINE_DISPLAY
|
||||
-D TEMPERATURE_PIN=23
|
||||
-D USE_ALT_DISPlAY ; new versions of USERMOD_FOUR_LINE_DISPLAY and USERMOD_ROTARY_ENCODER_UI
|
||||
-D USERMOD_AUDIOREACTIVE
|
||||
${esp32.AR_build_flags} ;; includes USERMOD_AUDIOREACTIVE
|
||||
lib_deps = ${esp32.lib_deps}
|
||||
OneWire@~2.3.5
|
||||
olikraus/U8g2 @ ^2.28.8
|
||||
https://github.com/blazoncek/arduinoFFT.git
|
||||
OneWire@~2.3.5 ;; needed for USERMOD_DALLASTEMPERATURE
|
||||
olikraus/U8g2 @ ^2.28.8 ;; needed for USERMOD_FOUR_LINE_DISPLAY
|
||||
${esp32.AR_lib_deps} ;; needed for USERMOD_AUDIOREACTIVE
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
|
||||
[env:m5atom]
|
||||
board = esp32dev
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32.build_flags} -D DATA_PINS=27 -D BTNPIN=39
|
||||
[env:esp32_pico-D4]
|
||||
extends = esp32 ;; use default esp32 platform
|
||||
board = pico32 ;; pico32-D4 is different from the standard esp32dev
|
||||
;; hardware details from https://github.com/srg74/WLED-ESP32-pico
|
||||
build_flags = ${common.build_flags} ${esp32.build_flags}
|
||||
-D WLED_RELEASE_NAME=\"pico32-D4\" -D SERVERNAME='"WLED-pico32"'
|
||||
-D WLED_DISABLE_ADALIGHT ;; no serial-to-USB chip on this board - better to disable serial protocols
|
||||
-D DATA_PINS=2,18 ;; LED pins
|
||||
-D RLYPIN=19 -D BTNPIN=0 -D IRPIN=-1 ;; no default pin for IR
|
||||
${esp32.AR_build_flags} ;; include USERMOD_AUDIOREACTIVE
|
||||
-D UM_AUDIOREACTIVE_ENABLE ;; enable AR by default
|
||||
;; Audioreactive settings for on-board microphone (ICS-43432)
|
||||
-D SR_DMTYPE=1 -D I2S_SDPIN=25 -D I2S_WSPIN=15 -D I2S_CKPIN=14
|
||||
-D SR_SQUELCH=5 -D SR_GAIN=30
|
||||
lib_deps = ${esp32.lib_deps}
|
||||
platform = ${esp32.platform}
|
||||
platform_packages = ${esp32.platform_packages}
|
||||
${esp32.AR_lib_deps} ;; needed for USERMOD_AUDIOREACTIVE
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
board_build.f_flash = 80000000L
|
||||
|
||||
[env:m5atom]
|
||||
extends = env:esp32dev # we want to extend the existing esp32dev environment (and define only updated options)
|
||||
build_flags = ${common.build_flags} ${esp32.build_flags} -D DATA_PINS=27 -D BTNPIN=39
|
||||
|
||||
[env:sp501e]
|
||||
board = esp_wroom_02
|
||||
@@ -413,7 +427,7 @@ platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_2m512k}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D BTNPIN=-1 -D RLYPIN=-1 -D DATA_PINS=4,12,14,13,5
|
||||
-D DEFAULT_LED_TYPE=TYPE_ANALOG_5CH -D WLED_DISABLE_INFRARED -D WLED_MAX_CCT_BLEND=0
|
||||
-D LED_TYPES=TYPE_ANALOG_5CH -D WLED_DISABLE_INFRARED -D WLED_MAX_CCT_BLEND=0
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
|
||||
[env:Athom_15w_RGBCW] ;15w bulb
|
||||
@@ -423,7 +437,7 @@ platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_2m512k}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D BTNPIN=-1 -D RLYPIN=-1 -D DATA_PINS=4,12,14,5,13
|
||||
-D DEFAULT_LED_TYPE=TYPE_ANALOG_5CH -D WLED_DISABLE_INFRARED -D WLED_MAX_CCT_BLEND=0 -D WLED_USE_IC_CCT
|
||||
-D LED_TYPES=TYPE_ANALOG_5CH -D WLED_DISABLE_INFRARED -D WLED_MAX_CCT_BLEND=0 -D WLED_USE_IC_CCT
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
|
||||
[env:Athom_3Pin_Controller] ;small controller with only data
|
||||
@@ -489,9 +503,8 @@ lib_deps = ${esp8266.lib_deps}
|
||||
# EleksTube-IPS
|
||||
# ------------------------------------------------------------------------------
|
||||
[env:elekstube_ips]
|
||||
extends = esp32 ;; use default esp32 platform
|
||||
board = esp32dev
|
||||
platform = ${esp32.platform}
|
||||
platform_packages = ${esp32.platform_packages}
|
||||
upload_speed = 921600
|
||||
build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_DISABLE_BROWNOUT_DET -D WLED_DISABLE_INFRARED
|
||||
-D USERMOD_RTC
|
||||
@@ -499,7 +512,7 @@ build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_DISABLE_BROWNOU
|
||||
-D DATA_PINS=12
|
||||
-D RLYPIN=27
|
||||
-D BTNPIN=34
|
||||
-D DEFAULT_LED_COUNT=6
|
||||
-D PIXEL_COUNTS=6
|
||||
# Display config
|
||||
-D ST7789_DRIVER
|
||||
-D TFT_WIDTH=135
|
||||
@@ -515,5 +528,4 @@ build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_DISABLE_BROWNOU
|
||||
monitor_filters = esp32_exception_decoder
|
||||
lib_deps =
|
||||
${esp32.lib_deps}
|
||||
TFT_eSPI @ ^2.3.70
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
TFT_eSPI @ 2.5.33 ;; this is the last version that compiles with the WLED default framework - newer versions require platform = espressif32 @ ^6.3.2
|
||||
|
||||
@@ -61,7 +61,7 @@ See [here](https://kno.wled.ge/basics/compatible-hardware)!
|
||||
|
||||
## ✌️ Other
|
||||
|
||||
Licensed under the MIT license
|
||||
Licensed under the EUPL v1.2 license
|
||||
Credits [here](https://kno.wled.ge/about/contributors/)!
|
||||
|
||||
Join the Discord server to discuss everything about WLED!
|
||||
@@ -80,5 +80,5 @@ If WLED really brightens up your day, you can [ {
|
||||
for i in {0..10}
|
||||
do
|
||||
echo -n " http://${HOST}/settings.js?p=$i -o ${TGT_PATH}/$i.xml"
|
||||
done
|
||||
}
|
||||
read -a TARGETS <<< $(replicate)
|
||||
|
||||
mkdir -p ${TGT_PATH}
|
||||
curl ${CURL_ARGS} ${TARGETS[@]}
|
||||
@@ -101,6 +101,7 @@ function adoptVersionAndRepo(html) {
|
||||
async function minify(str, type = "plain") {
|
||||
const options = {
|
||||
collapseWhitespace: true,
|
||||
conservativeCollapse: true, // preserve spaces in text
|
||||
collapseBooleanAttributes: true,
|
||||
collapseInlineTagWhitespace: true,
|
||||
minifyCSS: true,
|
||||
|
||||
@@ -102,9 +102,9 @@ private:
|
||||
|
||||
void secondsEffectSineFade(int16_t secondLed, Toki::Time const& time) {
|
||||
uint32_t ms = time.ms % 1000;
|
||||
uint8_t b0 = (cos8(ms * 64 / 1000) - 128) * 2;
|
||||
uint8_t b0 = (cos8_t(ms * 64 / 1000) - 128) * 2;
|
||||
setPixelColor(secondLed, gamma32(scale32(secondColor, b0)));
|
||||
uint8_t b1 = (sin8(ms * 64 / 1000) - 128) * 2;
|
||||
uint8_t b1 = (sin8_t(ms * 64 / 1000) - 128) * 2;
|
||||
setPixelColor(inc(secondLed, 1, secondsSegment), gamma32(scale32(secondColor, b1)));
|
||||
}
|
||||
|
||||
|
||||
@@ -425,10 +425,10 @@ class Animated_Staircase : public Usermod {
|
||||
}
|
||||
|
||||
void appendConfigData() {
|
||||
//oappend(SET_F("dd=addDropdown('staircase','selectfield');"));
|
||||
//oappend(SET_F("addOption(dd,'1st value',0);"));
|
||||
//oappend(SET_F("addOption(dd,'2nd value',1);"));
|
||||
//oappend(SET_F("addInfo('staircase:selectfield',1,'additional info');")); // 0 is field type, 1 is actual field
|
||||
//oappend(F("dd=addDropdown('staircase','selectfield');"));
|
||||
//oappend(F("addOption(dd,'1st value',0);"));
|
||||
//oappend(F("addOption(dd,'2nd value',1);"));
|
||||
//oappend(F("addInfo('staircase:selectfield',1,'additional info');")); // 0 is field type, 1 is actual field
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -444,6 +444,7 @@ public:
|
||||
configComplete &= getJsonValue(top[F("PublishAlways")], PublishAlways, false);
|
||||
configComplete &= getJsonValue(top[F("UseCelsius")], UseCelsius, true);
|
||||
configComplete &= getJsonValue(top[F("HomeAssistantDiscovery")], HomeAssistantDiscovery, false);
|
||||
tempScale = UseCelsius ? "°C" : "°F";
|
||||
|
||||
DEBUG_PRINT(FPSTR(_name));
|
||||
if (!initDone) {
|
||||
|
||||
@@ -767,22 +767,22 @@ void UsermodBME68X::appendConfigData() {
|
||||
// snprintf_P(charbuffer, 127, PSTR("addInfo('%s:%s',1,'*) Set to minus to deactivate (all sensors)');"), UMOD_NAME, _nameTemp); oappend(charbuffer);
|
||||
|
||||
/* Dropdown for Celsius/Fahrenheit*/
|
||||
oappend(SET_F("dd=addDropdown('"));
|
||||
oappend(F("dd=addDropdown('"));
|
||||
oappend(UMOD_NAME);
|
||||
oappend(SET_F("','"));
|
||||
oappend(F("','"));
|
||||
oappend(_nameTempScale);
|
||||
oappend(SET_F("');"));
|
||||
oappend(SET_F("addOption(dd,'Celsius',0);"));
|
||||
oappend(SET_F("addOption(dd,'Fahrenheit',1);"));
|
||||
oappend(F("');"));
|
||||
oappend(F("addOption(dd,'Celsius',0);"));
|
||||
oappend(F("addOption(dd,'Fahrenheit',1);"));
|
||||
|
||||
/* i²C Address*/
|
||||
oappend(SET_F("dd=addDropdown('"));
|
||||
oappend(F("dd=addDropdown('"));
|
||||
oappend(UMOD_NAME);
|
||||
oappend(SET_F("','"));
|
||||
oappend(F("','"));
|
||||
oappend(_nameI2CAdr);
|
||||
oappend(SET_F("');"));
|
||||
oappend(SET_F("addOption(dd,'0x76',0x76);"));
|
||||
oappend(SET_F("addOption(dd,'0x77',0x77);"));
|
||||
oappend(F("');"));
|
||||
oappend(F("addOption(dd,'0x76',0x76);"));
|
||||
oappend(F("addOption(dd,'0x77',0x77);"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -478,29 +478,29 @@ class UsermodBattery : public Usermod
|
||||
void appendConfigData()
|
||||
{
|
||||
// Total: 462 Bytes
|
||||
oappend(SET_F("td=addDropdown('Battery','type');")); // 34 Bytes
|
||||
oappend(SET_F("addOption(td,'Unkown','0');")); // 28 Bytes
|
||||
oappend(SET_F("addOption(td,'LiPo','1');")); // 26 Bytes
|
||||
oappend(SET_F("addOption(td,'LiOn','2');")); // 26 Bytes
|
||||
oappend(SET_F("addInfo('Battery:type',1,'<small style=\"color:orange\">requires reboot</small>');")); // 81 Bytes
|
||||
oappend(SET_F("addInfo('Battery:min-voltage',1,'v');")); // 38 Bytes
|
||||
oappend(SET_F("addInfo('Battery:max-voltage',1,'v');")); // 38 Bytes
|
||||
oappend(SET_F("addInfo('Battery:interval',1,'ms');")); // 36 Bytes
|
||||
oappend(SET_F("addInfo('Battery:HA-discovery',1,'');")); // 38 Bytes
|
||||
oappend(SET_F("addInfo('Battery:auto-off:threshold',1,'%');")); // 45 Bytes
|
||||
oappend(SET_F("addInfo('Battery:indicator:threshold',1,'%');")); // 46 Bytes
|
||||
oappend(SET_F("addInfo('Battery:indicator:duration',1,'s');")); // 45 Bytes
|
||||
oappend(F("td=addDropdown('Battery','type');")); // 34 Bytes
|
||||
oappend(F("addOption(td,'Unkown','0');")); // 28 Bytes
|
||||
oappend(F("addOption(td,'LiPo','1');")); // 26 Bytes
|
||||
oappend(F("addOption(td,'LiOn','2');")); // 26 Bytes
|
||||
oappend(F("addInfo('Battery:type',1,'<small style=\"color:orange\">requires reboot</small>');")); // 81 Bytes
|
||||
oappend(F("addInfo('Battery:min-voltage',1,'v');")); // 38 Bytes
|
||||
oappend(F("addInfo('Battery:max-voltage',1,'v');")); // 38 Bytes
|
||||
oappend(F("addInfo('Battery:interval',1,'ms');")); // 36 Bytes
|
||||
oappend(F("addInfo('Battery:HA-discovery',1,'');")); // 38 Bytes
|
||||
oappend(F("addInfo('Battery:auto-off:threshold',1,'%');")); // 45 Bytes
|
||||
oappend(F("addInfo('Battery:indicator:threshold',1,'%');")); // 46 Bytes
|
||||
oappend(F("addInfo('Battery:indicator:duration',1,'s');")); // 45 Bytes
|
||||
|
||||
// this option list would exeed the oappend() buffer
|
||||
// a list of all presets to select one from
|
||||
// oappend(SET_F("bd=addDropdown('Battery:low-power-indicator', 'preset');"));
|
||||
// the loop generates: oappend(SET_F("addOption(bd, 'preset name', preset id);"));
|
||||
// oappend(F("bd=addDropdown('Battery:low-power-indicator', 'preset');"));
|
||||
// the loop generates: oappend(F("addOption(bd, 'preset name', preset id);"));
|
||||
// for(int8_t i=1; i < 42; i++) {
|
||||
// oappend(SET_F("addOption(bd, 'Preset#"));
|
||||
// oappend(F("addOption(bd, 'Preset#"));
|
||||
// oappendi(i);
|
||||
// oappend(SET_F("',"));
|
||||
// oappend(F("',"));
|
||||
// oappendi(i);
|
||||
// oappend(SET_F(");"));
|
||||
// oappend(F(");"));
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
@@ -287,11 +287,11 @@ class MyExampleUsermod : public Usermod {
|
||||
*/
|
||||
void appendConfigData() override
|
||||
{
|
||||
oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":great")); oappend(SET_F("',1,'<i>(this is a great config value)</i>');"));
|
||||
oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":testString")); oappend(SET_F("',1,'enter any string you want');"));
|
||||
oappend(SET_F("dd=addDropdown('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F("','testInt');"));
|
||||
oappend(SET_F("addOption(dd,'Nothing',0);"));
|
||||
oappend(SET_F("addOption(dd,'Everything',42);"));
|
||||
oappend(F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(F(":great")); oappend(F("',1,'<i>(this is a great config value)</i>');"));
|
||||
oappend(F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(F(":testString")); oappend(F("',1,'enter any string you want');"));
|
||||
oappend(F("dd=addDropdown('")); oappend(String(FPSTR(_name)).c_str()); oappend(F("','testInt');"));
|
||||
oappend(F("addOption(dd,'Nothing',0);"));
|
||||
oappend(F("addOption(dd,'Everything',42);"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -149,11 +149,11 @@ public:
|
||||
void appendConfigData()
|
||||
{
|
||||
// Display 'ms' next to the 'Loop Interval' setting
|
||||
oappend(SET_F("addInfo('Internal Temperature:Loop Interval', 1, 'ms');"));
|
||||
oappend(F("addInfo('Internal Temperature:Loop Interval', 1, 'ms');"));
|
||||
// Display '°C' next to the 'Activation Threshold' setting
|
||||
oappend(SET_F("addInfo('Internal Temperature:Activation Threshold', 1, '°C');"));
|
||||
oappend(F("addInfo('Internal Temperature:Activation Threshold', 1, '°C');"));
|
||||
// Display '0 = Disabled' next to the 'Preset To Activate' setting
|
||||
oappend(SET_F("addInfo('Internal Temperature:Preset To Activate', 1, '0 = unused');"));
|
||||
oappend(F("addInfo('Internal Temperature:Preset To Activate', 1, '0 = unused');"));
|
||||
}
|
||||
|
||||
bool readFromConfig(JsonObject &root)
|
||||
|
||||
@@ -511,8 +511,8 @@ void PIRsensorSwitch::addToConfig(JsonObject &root)
|
||||
|
||||
void PIRsensorSwitch::appendConfigData()
|
||||
{
|
||||
oappend(SET_F("addInfo('PIRsensorSwitch:HA-discovery',1,'HA=Home Assistant');")); // 0 is field type, 1 is actual field
|
||||
oappend(SET_F("addInfo('PIRsensorSwitch:override',1,'Cancel timer on change');")); // 0 is field type, 1 is actual field
|
||||
oappend(F("addInfo('PIRsensorSwitch:HA-discovery',1,'HA=Home Assistant');")); // 0 is field type, 1 is actual field
|
||||
oappend(F("addInfo('PIRsensorSwitch:override',1,'Cancel timer on change');")); // 0 is field type, 1 is actual field
|
||||
for (int i = 0; i < PIR_SENSOR_MAX_SENSORS; i++) {
|
||||
char str[128];
|
||||
sprintf_P(str, PSTR("addInfo('PIRsensorSwitch:pin[]',%d,'','#%d');"), i, i);
|
||||
|
||||
@@ -377,10 +377,10 @@ class St7789DisplayUsermod : public Usermod {
|
||||
|
||||
|
||||
void appendConfigData() override {
|
||||
oappend(SET_F("addInfo('ST7789:pin[]',0,'','SPI CS');"));
|
||||
oappend(SET_F("addInfo('ST7789:pin[]',1,'','SPI DC');"));
|
||||
oappend(SET_F("addInfo('ST7789:pin[]',2,'','SPI RST');"));
|
||||
oappend(SET_F("addInfo('ST7789:pin[]',3,'','SPI BL');"));
|
||||
oappend(F("addInfo('ST7789:pin[]',0,'','SPI CS');"));
|
||||
oappend(F("addInfo('ST7789:pin[]',1,'','SPI DC');"));
|
||||
oappend(F("addInfo('ST7789:pin[]',2,'','SPI RST');"));
|
||||
oappend(F("addInfo('ST7789:pin[]',3,'','SPI BL');"));
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -435,10 +435,10 @@ bool UsermodTemperature::readFromConfig(JsonObject &root) {
|
||||
}
|
||||
|
||||
void UsermodTemperature::appendConfigData() {
|
||||
oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":")); oappend(String(FPSTR(_parasite)).c_str());
|
||||
oappend(SET_F("',1,'<i>(if no Vcc connected)</i>');")); // 0 is field type, 1 is actual field
|
||||
oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":")); oappend(String(FPSTR(_parasitePin)).c_str());
|
||||
oappend(SET_F("',1,'<i>(for external MOSFET)</i>');")); // 0 is field type, 1 is actual field
|
||||
oappend(F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(F(":")); oappend(String(FPSTR(_parasite)).c_str());
|
||||
oappend(F("',1,'<i>(if no Vcc connected)</i>');")); // 0 is field type, 1 is actual field
|
||||
oappend(F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(F(":")); oappend(String(FPSTR(_parasitePin)).c_str());
|
||||
oappend(F("',1,'<i>(for external MOSFET)</i>');")); // 0 is field type, 1 is actual field
|
||||
}
|
||||
|
||||
float UsermodTemperature::getTemperature() {
|
||||
|
||||
@@ -75,7 +75,7 @@ static uint8_t soundAgc = 0; // Automagic gain control: 0 - n
|
||||
//static float volumeSmth = 0.0f; // either sampleAvg or sampleAgc depending on soundAgc; smoothed sample
|
||||
static float FFT_MajorPeak = 1.0f; // FFT: strongest (peak) frequency
|
||||
static float FFT_Magnitude = 0.0f; // FFT: volume (magnitude) of peak frequency
|
||||
static bool samplePeak = false; // Boolean flag for peak - used in effects. Responding routine may reset this flag. Auto-reset after strip.getMinShowDelay()
|
||||
static bool samplePeak = false; // Boolean flag for peak - used in effects. Responding routine may reset this flag. Auto-reset after strip.getFrameTime()
|
||||
static bool udpSamplePeak = false; // Boolean flag for peak. Set at the same time as samplePeak, but reset by transmitAudioData
|
||||
static unsigned long timeOfPeak = 0; // time of last sample peak detection.
|
||||
static uint8_t fftResult[NUM_GEQ_CHANNELS]= {0};// Our calculated freq. channel result table to be used by effects
|
||||
@@ -191,8 +191,8 @@ constexpr uint16_t samplesFFT_2 = 256; // meaningfull part of FFT resul
|
||||
#define LOG_256 5.54517744f // log(256)
|
||||
|
||||
// These are the input and output vectors. Input vectors receive computed results from FFT.
|
||||
static float vReal[samplesFFT] = {0.0f}; // FFT sample inputs / freq output - these are our raw result bins
|
||||
static float vImag[samplesFFT] = {0.0f}; // imaginary parts
|
||||
static float* vReal = nullptr; // FFT sample inputs / freq output - these are our raw result bins
|
||||
static float* vImag = nullptr; // imaginary parts
|
||||
|
||||
// Create FFT object
|
||||
// lib_deps += https://github.com/kosme/arduinoFFT#develop @ 1.9.2
|
||||
@@ -200,14 +200,9 @@ static float vImag[samplesFFT] = {0.0f}; // imaginary parts
|
||||
// #define FFT_SPEED_OVER_PRECISION // enables use of reciprocals (1/x etc) - not faster on ESP32
|
||||
// #define FFT_SQRT_APPROXIMATION // enables "quake3" style inverse sqrt - slower on ESP32
|
||||
// Below options are forcing ArduinoFFT to use sqrtf() instead of sqrt()
|
||||
#define sqrt(x) sqrtf(x) // little hack that reduces FFT time by 10-50% on ESP32
|
||||
#define sqrt_internal sqrtf // see https://github.com/kosme/arduinoFFT/pull/83
|
||||
|
||||
#include <arduinoFFT.h>
|
||||
|
||||
/* Create FFT object with weighing factor storage */
|
||||
static ArduinoFFT<float> FFT = ArduinoFFT<float>( vReal, vImag, samplesFFT, SAMPLE_RATE, true);
|
||||
// #define sqrt_internal sqrtf // see https://github.com/kosme/arduinoFFT/pull/83 - since v2.0.0 this must be done in build_flags
|
||||
|
||||
#include <arduinoFFT.h> // FFT object is created in FFTcode
|
||||
// Helper functions
|
||||
|
||||
// compute average of several FFT result bins
|
||||
@@ -226,6 +221,18 @@ void FFTcode(void * parameter)
|
||||
{
|
||||
DEBUGSR_PRINT("FFT started on core: "); DEBUGSR_PRINTLN(xPortGetCoreID());
|
||||
|
||||
// allocate FFT buffers on first call
|
||||
if (vReal == nullptr) vReal = (float*) calloc(sizeof(float), samplesFFT);
|
||||
if (vImag == nullptr) vImag = (float*) calloc(sizeof(float), samplesFFT);
|
||||
if ((vReal == nullptr) || (vImag == nullptr)) {
|
||||
// something went wrong
|
||||
if (vReal) free(vReal); vReal = nullptr;
|
||||
if (vImag) free(vImag); vImag = nullptr;
|
||||
return;
|
||||
}
|
||||
// Create FFT object with weighing factor storage
|
||||
ArduinoFFT<float> FFT = ArduinoFFT<float>( vReal, vImag, samplesFFT, SAMPLE_RATE, true);
|
||||
|
||||
// see https://www.freertos.org/vtaskdelayuntil.html
|
||||
const TickType_t xFrequency = FFT_MIN_CYCLE * portTICK_PERIOD_MS;
|
||||
|
||||
@@ -247,6 +254,7 @@ void FFTcode(void * parameter)
|
||||
|
||||
// get a fresh batch of samples from I2S
|
||||
if (audioSource) audioSource->getSamples(vReal, samplesFFT);
|
||||
memset(vImag, 0, samplesFFT * sizeof(float)); // set imaginary parts to 0
|
||||
|
||||
#if defined(WLED_DEBUG) || defined(SR_DEBUG)
|
||||
if (start < esp_timer_get_time()) { // filter out overflows
|
||||
@@ -265,8 +273,6 @@ void FFTcode(void * parameter)
|
||||
// find highest sample in the batch
|
||||
float maxSample = 0.0f; // max sample from FFT batch
|
||||
for (int i=0; i < samplesFFT; i++) {
|
||||
// set imaginary parts to 0
|
||||
vImag[i] = 0;
|
||||
// pick our our current mic sample - we take the max value from all samples that go into FFT
|
||||
if ((vReal[i] <= (INT16_MAX - 1024)) && (vReal[i] >= (INT16_MIN + 1024))) //skip extreme values - normally these are artefacts
|
||||
if (fabsf((float)vReal[i]) > maxSample) maxSample = fabsf((float)vReal[i]);
|
||||
@@ -297,7 +303,7 @@ void FFTcode(void * parameter)
|
||||
#endif
|
||||
|
||||
} else { // noise gate closed - only clear results as FFT was skipped. MIC samples are still valid when we do this.
|
||||
memset(vReal, 0, sizeof(vReal));
|
||||
memset(vReal, 0, samplesFFT * sizeof(float));
|
||||
FFT_MajorPeak = 1;
|
||||
FFT_Magnitude = 0.001;
|
||||
}
|
||||
@@ -530,8 +536,8 @@ static void detectSamplePeak(void) {
|
||||
#endif
|
||||
|
||||
static void autoResetPeak(void) {
|
||||
uint16_t MinShowDelay = MAX(50, strip.getMinShowDelay()); // Fixes private class variable compiler error. Unsure if this is the correct way of fixing the root problem. -THATDONFC
|
||||
if (millis() - timeOfPeak > MinShowDelay) { // Auto-reset of samplePeak after a complete frame has passed.
|
||||
uint16_t peakDelay = max(uint16_t(50), strip.getFrameTime());
|
||||
if (millis() - timeOfPeak > peakDelay) { // Auto-reset of samplePeak after at least one complete frame has passed.
|
||||
samplePeak = false;
|
||||
if (audioSyncEnabled == 0) udpSamplePeak = false; // this is normally reset by transmitAudioData
|
||||
}
|
||||
@@ -1879,57 +1885,59 @@ class AudioReactive : public Usermod {
|
||||
}
|
||||
|
||||
|
||||
void appendConfigData() override
|
||||
void appendConfigData(Print& uiScript) override
|
||||
{
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
oappend(SET_F("dd=addDropdown('AudioReactive','digitalmic:type');"));
|
||||
uiScript.print(F("ux='AudioReactive';")); // ux = shortcut for Audioreactive - fingers crossed that "ux" isn't already used as JS var, html post parameter or css style
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
uiScript.print(F("uxp=ux+':digitalmic:pin[]';")); // uxp = shortcut for AudioReactive:digitalmic:pin[]
|
||||
uiScript.print(F("dd=addDropdown(ux,'digitalmic:type');"));
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
oappend(SET_F("addOption(dd,'Generic Analog',0);"));
|
||||
uiScript.print(F("addOption(dd,'Generic Analog',0);"));
|
||||
#endif
|
||||
oappend(SET_F("addOption(dd,'Generic I2S',1);"));
|
||||
oappend(SET_F("addOption(dd,'ES7243',2);"));
|
||||
oappend(SET_F("addOption(dd,'SPH0654',3);"));
|
||||
oappend(SET_F("addOption(dd,'Generic I2S with Mclk',4);"));
|
||||
uiScript.print(F("addOption(dd,'Generic I2S',1);"));
|
||||
uiScript.print(F("addOption(dd,'ES7243',2);"));
|
||||
uiScript.print(F("addOption(dd,'SPH0654',3);"));
|
||||
uiScript.print(F("addOption(dd,'Generic I2S with Mclk',4);"));
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
oappend(SET_F("addOption(dd,'Generic I2S PDM',5);"));
|
||||
uiScript.print(F("addOption(dd,'Generic I2S PDM',5);"));
|
||||
#endif
|
||||
oappend(SET_F("addOption(dd,'ES8388',6);"));
|
||||
uiScript.print(F("addOption(dd,'ES8388',6);"));
|
||||
|
||||
oappend(SET_F("dd=addDropdown('AudioReactive','config:AGC');"));
|
||||
oappend(SET_F("addOption(dd,'Off',0);"));
|
||||
oappend(SET_F("addOption(dd,'Normal',1);"));
|
||||
oappend(SET_F("addOption(dd,'Vivid',2);"));
|
||||
oappend(SET_F("addOption(dd,'Lazy',3);"));
|
||||
uiScript.print(F("dd=addDropdown(ux,'config:AGC');"));
|
||||
uiScript.print(F("addOption(dd,'Off',0);"));
|
||||
uiScript.print(F("addOption(dd,'Normal',1);"));
|
||||
uiScript.print(F("addOption(dd,'Vivid',2);"));
|
||||
uiScript.print(F("addOption(dd,'Lazy',3);"));
|
||||
|
||||
oappend(SET_F("dd=addDropdown('AudioReactive','dynamics:limiter');"));
|
||||
oappend(SET_F("addOption(dd,'Off',0);"));
|
||||
oappend(SET_F("addOption(dd,'On',1);"));
|
||||
oappend(SET_F("addInfo('AudioReactive:dynamics:limiter',0,' On ');")); // 0 is field type, 1 is actual field
|
||||
oappend(SET_F("addInfo('AudioReactive:dynamics:rise',1,'ms <i>(♪ effects only)</i>');"));
|
||||
oappend(SET_F("addInfo('AudioReactive:dynamics:fall',1,'ms <i>(♪ effects only)</i>');"));
|
||||
uiScript.print(F("dd=addDropdown(ux,'dynamics:limiter');"));
|
||||
uiScript.print(F("addOption(dd,'Off',0);"));
|
||||
uiScript.print(F("addOption(dd,'On',1);"));
|
||||
uiScript.print(F("addInfo(ux+':dynamics:limiter',0,' On ');")); // 0 is field type, 1 is actual field
|
||||
uiScript.print(F("addInfo(ux+':dynamics:rise',1,'ms <i>(♪ effects only)</i>');"));
|
||||
uiScript.print(F("addInfo(ux+':dynamics:fall',1,'ms <i>(♪ effects only)</i>');"));
|
||||
|
||||
oappend(SET_F("dd=addDropdown('AudioReactive','frequency:scale');"));
|
||||
oappend(SET_F("addOption(dd,'None',0);"));
|
||||
oappend(SET_F("addOption(dd,'Linear (Amplitude)',2);"));
|
||||
oappend(SET_F("addOption(dd,'Square Root (Energy)',3);"));
|
||||
oappend(SET_F("addOption(dd,'Logarithmic (Loudness)',1);"));
|
||||
uiScript.print(F("dd=addDropdown(ux,'frequency:scale');"));
|
||||
uiScript.print(F("addOption(dd,'None',0);"));
|
||||
uiScript.print(F("addOption(dd,'Linear (Amplitude)',2);"));
|
||||
uiScript.print(F("addOption(dd,'Square Root (Energy)',3);"));
|
||||
uiScript.print(F("addOption(dd,'Logarithmic (Loudness)',1);"));
|
||||
#endif
|
||||
|
||||
oappend(SET_F("dd=addDropdown('AudioReactive','sync:mode');"));
|
||||
oappend(SET_F("addOption(dd,'Off',0);"));
|
||||
uiScript.print(F("dd=addDropdown(ux,'sync:mode');"));
|
||||
uiScript.print(F("addOption(dd,'Off',0);"));
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
oappend(SET_F("addOption(dd,'Send',1);"));
|
||||
uiScript.print(F("addOption(dd,'Send',1);"));
|
||||
#endif
|
||||
oappend(SET_F("addOption(dd,'Receive',2);"));
|
||||
uiScript.print(F("addOption(dd,'Receive',2);"));
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
oappend(SET_F("addInfo('AudioReactive:digitalmic:type',1,'<i>requires reboot!</i>');")); // 0 is field type, 1 is actual field
|
||||
oappend(SET_F("addInfo('AudioReactive:digitalmic:pin[]',0,'<i>sd/data/dout</i>','I2S SD');"));
|
||||
oappend(SET_F("addInfo('AudioReactive:digitalmic:pin[]',1,'<i>ws/clk/lrck</i>','I2S WS');"));
|
||||
oappend(SET_F("addInfo('AudioReactive:digitalmic:pin[]',2,'<i>sck/bclk</i>','I2S SCK');"));
|
||||
uiScript.print(F("addInfo(ux+':digitalmic:type',1,'<i>requires reboot!</i>');")); // 0 is field type, 1 is actual field
|
||||
uiScript.print(F("addInfo(uxp,0,'<i>sd/data/dout</i>','I2S SD');"));
|
||||
uiScript.print(F("addInfo(uxp,1,'<i>ws/clk/lrck</i>','I2S WS');"));
|
||||
uiScript.print(F("addInfo(uxp,2,'<i>sck/bclk</i>','I2S SCK');"));
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
oappend(SET_F("addInfo('AudioReactive:digitalmic:pin[]',3,'<i>only use -1, 0, 1 or 3</i>','I2S MCLK');"));
|
||||
uiScript.print(F("addInfo(uxp,3,'<i>only use -1, 0, 1 or 3</i>','I2S MCLK');"));
|
||||
#else
|
||||
oappend(SET_F("addInfo('AudioReactive:digitalmic:pin[]',3,'<i>master clock</i>','I2S MCLK');"));
|
||||
uiScript.print(F("addInfo(uxp,3,'<i>master clock</i>','I2S MCLK');"));
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ There are however plans to create a lightweight audioreactive for the 8266, with
|
||||
### using latest _arduinoFFT_ library version 2.x
|
||||
The latest arduinoFFT release version should be used for audioreactive.
|
||||
|
||||
* `build_flags` = `-D USERMOD_AUDIOREACTIVE`
|
||||
* `build_flags` = `-D USERMOD_AUDIOREACTIVE -D sqrt_internal=sqrtf`
|
||||
* `lib_deps`= `kosme/arduinoFFT @ 2.0.1`
|
||||
|
||||
## Configuration
|
||||
|
||||
@@ -305,14 +305,14 @@ class BobLightUsermod : public Usermod {
|
||||
}
|
||||
|
||||
void appendConfigData() override {
|
||||
//oappend(SET_F("dd=addDropdown('usermod','selectfield');"));
|
||||
//oappend(SET_F("addOption(dd,'1st value',0);"));
|
||||
//oappend(SET_F("addOption(dd,'2nd value',1);"));
|
||||
oappend(SET_F("addInfo('BobLight:top',1,'LEDs');")); // 0 is field type, 1 is actual field
|
||||
oappend(SET_F("addInfo('BobLight:bottom',1,'LEDs');")); // 0 is field type, 1 is actual field
|
||||
oappend(SET_F("addInfo('BobLight:left',1,'LEDs');")); // 0 is field type, 1 is actual field
|
||||
oappend(SET_F("addInfo('BobLight:right',1,'LEDs');")); // 0 is field type, 1 is actual field
|
||||
oappend(SET_F("addInfo('BobLight:pct',1,'Depth of scan [%]');")); // 0 is field type, 1 is actual field
|
||||
//oappend(F("dd=addDropdown('usermod','selectfield');"));
|
||||
//oappend(F("addOption(dd,'1st value',0);"));
|
||||
//oappend(F("addOption(dd,'2nd value',1);"));
|
||||
oappend(F("addInfo('BobLight:top',1,'LEDs');")); // 0 is field type, 1 is actual field
|
||||
oappend(F("addInfo('BobLight:bottom',1,'LEDs');")); // 0 is field type, 1 is actual field
|
||||
oappend(F("addInfo('BobLight:left',1,'LEDs');")); // 0 is field type, 1 is actual field
|
||||
oappend(F("addInfo('BobLight:right',1,'LEDs');")); // 0 is field type, 1 is actual field
|
||||
oappend(F("addInfo('BobLight:pct',1,'Depth of scan [%]');")); // 0 is field type, 1 is actual field
|
||||
}
|
||||
|
||||
void addToConfig(JsonObject& root) override {
|
||||
|
||||
@@ -264,7 +264,7 @@ void MultiRelay::handleOffTimer() {
|
||||
void MultiRelay::InitHtmlAPIHandle() { // https://github.com/me-no-dev/ESPAsyncWebServer
|
||||
DEBUG_PRINTLN(F("Relays: Initialize HTML API"));
|
||||
|
||||
server.on(SET_F("/relays"), HTTP_GET, [this](AsyncWebServerRequest *request) {
|
||||
server.on(F("/relays"), HTTP_GET, [this](AsyncWebServerRequest *request) {
|
||||
DEBUG_PRINTLN(F("Relays: HTML API"));
|
||||
String janswer;
|
||||
String error = "";
|
||||
@@ -765,10 +765,10 @@ void MultiRelay::addToConfig(JsonObject &root) {
|
||||
}
|
||||
|
||||
void MultiRelay::appendConfigData() {
|
||||
oappend(SET_F("addInfo('MultiRelay:PCF8574-address',1,'<i>(not hex!)</i>');"));
|
||||
oappend(SET_F("addInfo('MultiRelay:broadcast-sec',1,'(MQTT message)');"));
|
||||
//oappend(SET_F("addInfo('MultiRelay:relay-0:pin',1,'(use -1 for PCF8574)');"));
|
||||
oappend(SET_F("d.extra.push({'MultiRelay':{pin:[['P0',100],['P1',101],['P2',102],['P3',103],['P4',104],['P5',105],['P6',106],['P7',107]]}});"));
|
||||
oappend(F("addInfo('MultiRelay:PCF8574-address',1,'<i>(not hex!)</i>');"));
|
||||
oappend(F("addInfo('MultiRelay:broadcast-sec',1,'(MQTT message)');"));
|
||||
//oappend(F("addInfo('MultiRelay:relay-0:pin',1,'(use -1 for PCF8574)');"));
|
||||
oappend(F("d.extra.push({'MultiRelay':{pin:[['P0',100],['P1',101],['P2',102],['P3',103],['P4',104],['P5',105],['P6',106],['P7',107]]}});"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -387,23 +387,23 @@ class PixelsDiceTrayUsermod : public Usermod {
|
||||
// To work around this, add info text to the end of the preceding item.
|
||||
//
|
||||
// See addInfo in wled00/data/settings_um.htm for details on what this function does.
|
||||
oappend(SET_F(
|
||||
oappend(F(
|
||||
"addInfo('DiceTray:ble_scan_duration',1,'<br><br><i>Set to \"*\" to "
|
||||
"connect to any die.<br>Leave Blank to disable.</i><br><i "
|
||||
"class=\"warn\">Saving will replace \"*\" with die names.</i>','');"));
|
||||
#if USING_TFT_DISPLAY
|
||||
oappend(SET_F("ddr=addDropdown('DiceTray','rotation');"));
|
||||
oappend(SET_F("addOption(ddr,'0 deg',0);"));
|
||||
oappend(SET_F("addOption(ddr,'90 deg',1);"));
|
||||
oappend(SET_F("addOption(ddr,'180 deg',2);"));
|
||||
oappend(SET_F("addOption(ddr,'270 deg',3);"));
|
||||
oappend(SET_F(
|
||||
oappend(F("ddr=addDropdown('DiceTray','rotation');"));
|
||||
oappend(F("addOption(ddr,'0 deg',0);"));
|
||||
oappend(F("addOption(ddr,'90 deg',1);"));
|
||||
oappend(F("addOption(ddr,'180 deg',2);"));
|
||||
oappend(F("addOption(ddr,'270 deg',3);"));
|
||||
oappend(F(
|
||||
"addInfo('DiceTray:rotation',1,'<br><i class=\"warn\">DO NOT CHANGE "
|
||||
"SPI PINS.</i><br><i class=\"warn\">CHANGES ARE IGNORED.</i>','');"));
|
||||
oappend(SET_F("addInfo('TFT:pin[]',0,'','SPI CS');"));
|
||||
oappend(SET_F("addInfo('TFT:pin[]',1,'','SPI DC');"));
|
||||
oappend(SET_F("addInfo('TFT:pin[]',2,'','SPI RST');"));
|
||||
oappend(SET_F("addInfo('TFT:pin[]',3,'','SPI BL');"));
|
||||
oappend(F("addInfo('TFT:pin[]',0,'','SPI CS');"));
|
||||
oappend(F("addInfo('TFT:pin[]',1,'','SPI DC');"));
|
||||
oappend(F("addInfo('TFT:pin[]',2,'','SPI RST');"));
|
||||
oappend(F("addInfo('TFT:pin[]',3,'','SPI BL');"));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ The actual / original code that controls the LED modes is from Adam Zeloof. I ta
|
||||
It was quite a bit more work than I hoped, but I got there eventually :)
|
||||
|
||||
## Requirements
|
||||
* "ESP Rotary" by Lennart Hennigs, v1.5.0 or higher: https://github.com/LennartHennigs/ESPRotary
|
||||
* "ESP Rotary" by Lennart Hennigs, v2.1.1 or higher: https://github.com/LennartHennigs/ESPRotary
|
||||
|
||||
## Usermod installation
|
||||
Simply copy the below block (build task) to your `platformio_override.ini` and compile WLED using this new build task. Or use an existing one and add the buildflag `-D RGB_ROTARY_ENCODER`.
|
||||
@@ -20,7 +20,7 @@ ESP32:
|
||||
extends = env:esp32dev
|
||||
build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32 -D RGB_ROTARY_ENCODER
|
||||
lib_deps = ${esp32.lib_deps}
|
||||
lennarthennigs/ESP Rotary@^1.5.0
|
||||
lennarthennigs/ESP Rotary@^2.1.1
|
||||
```
|
||||
|
||||
ESP8266 / D1 Mini:
|
||||
@@ -29,7 +29,7 @@ ESP8266 / D1 Mini:
|
||||
extends = env:d1_mini
|
||||
build_flags = ${common.build_flags_esp8266} -D RGB_ROTARY_ENCODER
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
lennarthennigs/ESP Rotary@^1.5.0
|
||||
lennarthennigs/ESP Rotary@^2.1.1
|
||||
```
|
||||
|
||||
## How to connect the board to your ESP
|
||||
|
||||
@@ -310,22 +310,22 @@ void ShtUsermod::onMqttConnect(bool sessionPresent) {
|
||||
* @return void
|
||||
*/
|
||||
void ShtUsermod::appendConfigData() {
|
||||
oappend(SET_F("dd=addDropdown('"));
|
||||
oappend(F("dd=addDropdown('"));
|
||||
oappend(_name);
|
||||
oappend(SET_F("','"));
|
||||
oappend(F("','"));
|
||||
oappend(_shtType);
|
||||
oappend(SET_F("');"));
|
||||
oappend(SET_F("addOption(dd,'SHT30',0);"));
|
||||
oappend(SET_F("addOption(dd,'SHT31',1);"));
|
||||
oappend(SET_F("addOption(dd,'SHT35',2);"));
|
||||
oappend(SET_F("addOption(dd,'SHT85',3);"));
|
||||
oappend(SET_F("dd=addDropdown('"));
|
||||
oappend(F("');"));
|
||||
oappend(F("addOption(dd,'SHT30',0);"));
|
||||
oappend(F("addOption(dd,'SHT31',1);"));
|
||||
oappend(F("addOption(dd,'SHT35',2);"));
|
||||
oappend(F("addOption(dd,'SHT85',3);"));
|
||||
oappend(F("dd=addDropdown('"));
|
||||
oappend(_name);
|
||||
oappend(SET_F("','"));
|
||||
oappend(F("','"));
|
||||
oappend(_unitOfTemp);
|
||||
oappend(SET_F("');"));
|
||||
oappend(SET_F("addOption(dd,'Celsius',0);"));
|
||||
oappend(SET_F("addOption(dd,'Fahrenheit',1);"));
|
||||
oappend(F("');"));
|
||||
oappend(F("addOption(dd,'Celsius',0);"));
|
||||
oappend(F("addOption(dd,'Fahrenheit',1);"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -96,7 +96,7 @@ void setup() {
|
||||
jsonTransitionOnce = true;
|
||||
strip.setTransition(0); //no transition
|
||||
effectCurrent = FX_MODE_COLOR_WIPE;
|
||||
resetTimebase(); //make sure wipe starts from beginning
|
||||
strip.resetTimebase(); //make sure wipe starts from beginning
|
||||
|
||||
//set wipe direction
|
||||
Segment& seg = strip.getSegment(0);
|
||||
|
||||
@@ -86,7 +86,7 @@ void startWipe()
|
||||
bri = briLast; //turn on
|
||||
transitionDelayTemp = 0; //no transition
|
||||
effectCurrent = FX_MODE_COLOR_WIPE;
|
||||
resetTimebase(); //make sure wipe starts from beginning
|
||||
strip.resetTimebase(); //make sure wipe starts from beginning
|
||||
|
||||
//set wipe direction
|
||||
Segment& seg = strip.getSegment(0);
|
||||
|
||||
@@ -95,9 +95,9 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
fastled_col.red = col[0];
|
||||
fastled_col.green = col[1];
|
||||
fastled_col.blue = col[2];
|
||||
fastled_col.red = colPri[0];
|
||||
fastled_col.green = colPri[1];
|
||||
fastled_col.blue = colPri[2];
|
||||
prim_hsv = rgb2hsv_approximate(fastled_col);
|
||||
new_val = (int16_t)prim_hsv.h + fadeAmount;
|
||||
if (new_val > 255)
|
||||
@@ -106,9 +106,9 @@ public:
|
||||
new_val += 255; // roll-over if smaller than 0
|
||||
prim_hsv.h = (byte)new_val;
|
||||
hsv2rgb_rainbow(prim_hsv, fastled_col);
|
||||
col[0] = fastled_col.red;
|
||||
col[1] = fastled_col.green;
|
||||
col[2] = fastled_col.blue;
|
||||
colPri[0] = fastled_col.red;
|
||||
colPri[1] = fastled_col.green;
|
||||
colPri[2] = fastled_col.blue;
|
||||
}
|
||||
}
|
||||
else if (Enc_B == LOW)
|
||||
@@ -120,9 +120,9 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
fastled_col.red = col[0];
|
||||
fastled_col.green = col[1];
|
||||
fastled_col.blue = col[2];
|
||||
fastled_col.red = colPri[0];
|
||||
fastled_col.green = colPri[1];
|
||||
fastled_col.blue = colPri[2];
|
||||
prim_hsv = rgb2hsv_approximate(fastled_col);
|
||||
new_val = (int16_t)prim_hsv.h - fadeAmount;
|
||||
if (new_val > 255)
|
||||
@@ -131,9 +131,9 @@ public:
|
||||
new_val += 255; // roll-over if smaller than 0
|
||||
prim_hsv.h = (byte)new_val;
|
||||
hsv2rgb_rainbow(prim_hsv, fastled_col);
|
||||
col[0] = fastled_col.red;
|
||||
col[1] = fastled_col.green;
|
||||
col[2] = fastled_col.blue;
|
||||
colPri[0] = fastled_col.red;
|
||||
colPri[1] = fastled_col.green;
|
||||
colPri[2] = fastled_col.blue;
|
||||
}
|
||||
}
|
||||
//call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification)
|
||||
|
||||
@@ -7,11 +7,12 @@ platform = ${esp32.platform}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags =
|
||||
${common.build_flags_esp32}
|
||||
-D USERMOD_FOUR_LINE_DISPLAY -D USE_ALT_DISPlAY
|
||||
-D USERMOD_ROTARY_ENCODER_UI -D ENCODER_DT_PIN=18 -D ENCODER_CLK_PIN=5 -D ENCODER_SW_PIN=19
|
||||
upload_speed = 460800
|
||||
-D USERMOD_FOUR_LINE_DISPLAY
|
||||
-D FLD_TYPE=SH1106
|
||||
-D I2CSCLPIN=27
|
||||
-D I2CSDAPIN=26
|
||||
|
||||
lib_deps =
|
||||
${esp32.lib_deps}
|
||||
U8g2@~2.34.4
|
||||
Wire
|
||||
|
||||
@@ -1,16 +1,8 @@
|
||||
# I2C/SPI 4 Line Display Usermod ALT
|
||||
|
||||
Thank you to the authors of the original version of these usermods. It would not have been possible without them!
|
||||
"usermod_v2_four_line_display"
|
||||
"usermod_v2_rotary_encoder_ui"
|
||||
This usermod could be used in compination with `usermod_v2_rotary_encoder_ui_ALT`.
|
||||
|
||||
The core of these usermods are a copy of the originals. The main changes are to the FourLineDisplay usermod.
|
||||
The display usermod UI has been completely changed.
|
||||
|
||||
|
||||
The changes made to the RotaryEncoder usermod were made to support the new UI in the display usermod.
|
||||
Without the display, it functions identical to the original.
|
||||
The original "usermod_v2_auto_save" will not work with the display just yet.
|
||||
## Functionalities
|
||||
|
||||
Press the encoder to cycle through the options:
|
||||
* Brightness
|
||||
@@ -18,26 +10,18 @@ Press the encoder to cycle through the options:
|
||||
* Intensity
|
||||
* Palette
|
||||
* Effect
|
||||
* Main Color (only if display is used)
|
||||
* Saturation (only if display is used)
|
||||
* Main Color
|
||||
* Saturation
|
||||
|
||||
Press and hold the encoder to display Network Info. If AP is active, it will display AP, SSID and password
|
||||
Press and hold the encoder to display Network Info. If AP is active, it will display the AP, SSID and Password
|
||||
|
||||
Also shows if the timer is enabled
|
||||
Also shows if the timer is enabled.
|
||||
|
||||
[See the pair of usermods in action](https://www.youtube.com/watch?v=ulZnBt9z3TI)
|
||||
|
||||
## Installation
|
||||
|
||||
Please refer to the original `usermod_v2_rotary_encoder_ui` readme for the main instructions.
|
||||
|
||||
Copy the example `platformio_override.sample.ini` from the usermod_v2_rotary_encoder_ui_ALT folder to the root directory of your particular build and rename it to `platformio_override.ini`.
|
||||
|
||||
This file should be placed in the same directory as `platformio.ini`.
|
||||
|
||||
Then, to activate this alternative usermod, add `#define USE_ALT_DISPlAY` (NOTE: CASE SENSITIVE) to the `usermods_list.cpp` file,
|
||||
or add `-D USE_ALT_DISPlAY` to the original `platformio_override.ini.sample` file
|
||||
|
||||
Copy the example `platformio_override.sample.ini` to the root directory of your particular build.
|
||||
|
||||
## Configuration
|
||||
|
||||
|
||||
@@ -1202,21 +1202,21 @@ void FourLineDisplayUsermod::onUpdateBegin(bool init) {
|
||||
//}
|
||||
|
||||
void FourLineDisplayUsermod::appendConfigData() {
|
||||
oappend(SET_F("dd=addDropdown('4LineDisplay','type');"));
|
||||
oappend(SET_F("addOption(dd,'None',0);"));
|
||||
oappend(SET_F("addOption(dd,'SSD1306',1);"));
|
||||
oappend(SET_F("addOption(dd,'SH1106',2);"));
|
||||
oappend(SET_F("addOption(dd,'SSD1306 128x64',3);"));
|
||||
oappend(SET_F("addOption(dd,'SSD1305',4);"));
|
||||
oappend(SET_F("addOption(dd,'SSD1305 128x64',5);"));
|
||||
oappend(SET_F("addOption(dd,'SSD1309 128x64',9);"));
|
||||
oappend(SET_F("addOption(dd,'SSD1306 SPI',6);"));
|
||||
oappend(SET_F("addOption(dd,'SSD1306 SPI 128x64',7);"));
|
||||
oappend(SET_F("addOption(dd,'SSD1309 SPI 128x64',8);"));
|
||||
oappend(SET_F("addInfo('4LineDisplay:type',1,'<br><i class=\"warn\">Change may require reboot</i>','');"));
|
||||
oappend(SET_F("addInfo('4LineDisplay:pin[]',0,'','SPI CS');"));
|
||||
oappend(SET_F("addInfo('4LineDisplay:pin[]',1,'','SPI DC');"));
|
||||
oappend(SET_F("addInfo('4LineDisplay:pin[]',2,'','SPI RST');"));
|
||||
oappend(F("dd=addDropdown('4LineDisplay','type');"));
|
||||
oappend(F("addOption(dd,'None',0);"));
|
||||
oappend(F("addOption(dd,'SSD1306',1);"));
|
||||
oappend(F("addOption(dd,'SH1106',2);"));
|
||||
oappend(F("addOption(dd,'SSD1306 128x64',3);"));
|
||||
oappend(F("addOption(dd,'SSD1305',4);"));
|
||||
oappend(F("addOption(dd,'SSD1305 128x64',5);"));
|
||||
oappend(F("addOption(dd,'SSD1309 128x64',9);"));
|
||||
oappend(F("addOption(dd,'SSD1306 SPI',6);"));
|
||||
oappend(F("addOption(dd,'SSD1306 SPI 128x64',7);"));
|
||||
oappend(F("addOption(dd,'SSD1309 SPI 128x64',8);"));
|
||||
oappend(F("addInfo('4LineDisplay:type',1,'<br><i class=\"warn\">Change may require reboot</i>','');"));
|
||||
oappend(F("addInfo('4LineDisplay:pin[]',0,'','SPI CS');"));
|
||||
oappend(F("addInfo('4LineDisplay:pin[]',1,'','SPI DC');"));
|
||||
oappend(F("addInfo('4LineDisplay:pin[]',2,'','SPI RST');"));
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
[platformio]
|
||||
default_envs = esp32dev
|
||||
|
||||
[env:esp32dev]
|
||||
board = esp32dev
|
||||
platform = ${esp32.platform}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags =
|
||||
${common.build_flags_esp32}
|
||||
-D USERMOD_ROTARY_ENCODER_UI
|
||||
-D USERMOD_ROTARY_ENCODER_GPIO=INPUT
|
||||
-D ENCODER_DT_PIN=21
|
||||
-D ENCODER_CLK_PIN=23
|
||||
-D ENCODER_SW_PIN=0
|
||||
@@ -1,16 +1,8 @@
|
||||
# Rotary Encoder UI Usermod ALT
|
||||
|
||||
Thank you to the authors of the original version of these usermods. It would not have been possible without them!
|
||||
"usermod_v2_four_line_display"
|
||||
"usermod_v2_rotary_encoder_ui"
|
||||
This usermod supports the UI of the `usermod_v2_rotary_encoder_ui_ALT`.
|
||||
|
||||
The core of these usermods are a copy of the originals. The main changes are to the FourLineDisplay usermod.
|
||||
The display usermod UI has been completely changed.
|
||||
|
||||
|
||||
The changes made to the RotaryEncoder usermod were made to support the new UI in the display usermod.
|
||||
Without the display, it functions identical to the original.
|
||||
The original "usermod_v2_auto_save" will not work with the display just yet.
|
||||
## Functionalities
|
||||
|
||||
Press the encoder to cycle through the options:
|
||||
* Brightness
|
||||
@@ -21,8 +13,7 @@ Press the encoder to cycle through the options:
|
||||
* Main Color (only if display is used)
|
||||
* Saturation (only if display is used)
|
||||
|
||||
Press and hold the encoder to display Network Info
|
||||
if AP is active, it will display the AP, SSID and Password
|
||||
Press and hold the encoder to display Network Info. If AP is active, it will display the AP, SSID and Password
|
||||
|
||||
Also shows if the timer is enabled.
|
||||
|
||||
@@ -30,9 +21,7 @@ Also shows if the timer is enabled.
|
||||
|
||||
## Installation
|
||||
|
||||
Copy the example `platformio_override.sample.ini` to the root directory of your particular build and rename it to `platformio_override.ini`.
|
||||
|
||||
To activate this alternative usermod, add `#define USE_ALT_DISPlAY` (NOTE: CASE SENSITIVE) to the `usermods_list.cpp` file, or add `-D USE_ALT_DISPlAY` to your `platformio_override.ini` file
|
||||
Copy the example `platformio_override.sample.ini` to the root directory of your particular build.
|
||||
|
||||
### Define Your Options
|
||||
|
||||
@@ -40,7 +29,6 @@ To activate this alternative usermod, add `#define USE_ALT_DISPlAY` (NOTE: CASE
|
||||
* `USERMOD_FOUR_LINE_DISPLAY` - define this to have this the Four Line Display mod included wled00\usermods_list.cpp
|
||||
also tells this usermod that the display is available
|
||||
(see the Four Line Display usermod `readme.md` for more details)
|
||||
* `USE_ALT_DISPlAY` - Mandatory to use Four Line Display
|
||||
* `ENCODER_DT_PIN` - defaults to 18
|
||||
* `ENCODER_CLK_PIN` - defaults to 5
|
||||
* `ENCODER_SW_PIN` - defaults to 19
|
||||
@@ -50,7 +38,7 @@ To activate this alternative usermod, add `#define USE_ALT_DISPlAY` (NOTE: CASE
|
||||
|
||||
### PlatformIO requirements
|
||||
|
||||
Note: the Four Line Display usermod requires the libraries `U8g2` and `Wire`.
|
||||
No special requirements.
|
||||
|
||||
## Change Log
|
||||
|
||||
|
||||
@@ -518,7 +518,7 @@ void RotaryEncoderUIUsermod::setup()
|
||||
|
||||
loopTime = millis();
|
||||
|
||||
currentCCT = (approximateKelvinFromRGB(RGBW32(col[0], col[1], col[2], col[3])) - 1900) >> 5;
|
||||
currentCCT = (approximateKelvinFromRGB(RGBW32(colPri[0], colPri[1], colPri[2], colPri[3])) - 1900) >> 5;
|
||||
|
||||
if (!initDone) sortModesAndPalettes();
|
||||
|
||||
@@ -920,17 +920,17 @@ void RotaryEncoderUIUsermod::changeHue(bool increase){
|
||||
display->updateRedrawTime();
|
||||
#endif
|
||||
currentHue1 = max(min((increase ? currentHue1+fadeAmount : currentHue1-fadeAmount), 255), 0);
|
||||
colorHStoRGB(currentHue1*256, currentSat1, col);
|
||||
colorHStoRGB(currentHue1*256, currentSat1, colPri);
|
||||
stateChanged = true;
|
||||
if (applyToAll) {
|
||||
for (unsigned i=0; i<strip.getSegmentsNum(); i++) {
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive()) continue;
|
||||
seg.colors[0] = RGBW32(col[0], col[1], col[2], col[3]);
|
||||
seg.colors[0] = RGBW32(colPri[0], colPri[1], colPri[2], colPri[3]);
|
||||
}
|
||||
} else {
|
||||
Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
seg.colors[0] = RGBW32(col[0], col[1], col[2], col[3]);
|
||||
seg.colors[0] = RGBW32(colPri[0], colPri[1], colPri[2], colPri[3]);
|
||||
}
|
||||
lampUdated();
|
||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||
@@ -950,16 +950,16 @@ void RotaryEncoderUIUsermod::changeSat(bool increase){
|
||||
display->updateRedrawTime();
|
||||
#endif
|
||||
currentSat1 = max(min((increase ? currentSat1+fadeAmount : currentSat1-fadeAmount), 255), 0);
|
||||
colorHStoRGB(currentHue1*256, currentSat1, col);
|
||||
colorHStoRGB(currentHue1*256, currentSat1, colPri);
|
||||
if (applyToAll) {
|
||||
for (unsigned i=0; i<strip.getSegmentsNum(); i++) {
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive()) continue;
|
||||
seg.colors[0] = RGBW32(col[0], col[1], col[2], col[3]);
|
||||
seg.colors[0] = RGBW32(colPri[0], colPri[1], colPri[2], colPri[3]);
|
||||
}
|
||||
} else {
|
||||
Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
seg.colors[0] = RGBW32(col[0], col[1], col[2], col[3]);
|
||||
seg.colors[0] = RGBW32(colPri[0], colPri[1], colPri[2], colPri[3]);
|
||||
}
|
||||
lampUdated();
|
||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||
@@ -1090,8 +1090,8 @@ void RotaryEncoderUIUsermod::addToConfig(JsonObject &root) {
|
||||
}
|
||||
|
||||
void RotaryEncoderUIUsermod::appendConfigData() {
|
||||
oappend(SET_F("addInfo('Rotary-Encoder:PCF8574-address',1,'<i>(not hex!)</i>');"));
|
||||
oappend(SET_F("d.extra.push({'Rotary-Encoder':{pin:[['P0',100],['P1',101],['P2',102],['P3',103],['P4',104],['P5',105],['P6',106],['P7',107]]}});"));
|
||||
oappend(F("addInfo('Rotary-Encoder:PCF8574-address',1,'<i>(not hex!)</i>');"));
|
||||
oappend(F("d.extra.push({'Rotary-Encoder':{pin:[['P0',100],['P1',101],['P2',102],['P3',103],['P4',104],['P5',105],['P6',106],['P7',107]]}});"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -433,8 +433,8 @@ class WordClockUsermod : public Usermod
|
||||
|
||||
void appendConfigData()
|
||||
{
|
||||
oappend(SET_F("addInfo('WordClockUsermod:ledOffset', 1, 'Number of LEDs before the letters');"));
|
||||
oappend(SET_F("addInfo('WordClockUsermod:Norddeutsch', 1, 'Viertel vor instead of Dreiviertel');"));
|
||||
oappend(F("addInfo('WordClockUsermod:ledOffset', 1, 'Number of LEDs before the letters');"));
|
||||
oappend(F("addInfo('WordClockUsermod:Norddeutsch', 1, 'Viertel vor instead of Dreiviertel');"));
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -54,13 +54,13 @@ class WireguardUsermod : public Usermod {
|
||||
}
|
||||
|
||||
void appendConfigData() {
|
||||
oappend(SET_F("addInfo('WireGuard:host',1,'Server Hostname');")); // 0 is field type, 1 is actual field
|
||||
oappend(SET_F("addInfo('WireGuard:port',1,'Server Port');")); // 0 is field type, 1 is actual field
|
||||
oappend(SET_F("addInfo('WireGuard:ip',1,'Device IP');")); // 0 is field type, 1 is actual field
|
||||
oappend(SET_F("addInfo('WireGuard:psk',1,'Pre Shared Key (optional)');")); // 0 is field type, 1 is actual field
|
||||
oappend(SET_F("addInfo('WireGuard:pem',1,'Private Key');")); // 0 is field type, 1 is actual field
|
||||
oappend(SET_F("addInfo('WireGuard:pub',1,'Public Key');")); // 0 is field type, 1 is actual field
|
||||
oappend(SET_F("addInfo('WireGuard:tz',1,'POSIX timezone string');")); // 0 is field type, 1 is actual field
|
||||
oappend(F("addInfo('WireGuard:host',1,'Server Hostname');")); // 0 is field type, 1 is actual field
|
||||
oappend(F("addInfo('WireGuard:port',1,'Server Port');")); // 0 is field type, 1 is actual field
|
||||
oappend(F("addInfo('WireGuard:ip',1,'Device IP');")); // 0 is field type, 1 is actual field
|
||||
oappend(F("addInfo('WireGuard:psk',1,'Pre Shared Key (optional)');")); // 0 is field type, 1 is actual field
|
||||
oappend(F("addInfo('WireGuard:pem',1,'Private Key');")); // 0 is field type, 1 is actual field
|
||||
oappend(F("addInfo('WireGuard:pub',1,'Public Key');")); // 0 is field type, 1 is actual field
|
||||
oappend(F("addInfo('WireGuard:tz',1,'POSIX timezone string');")); // 0 is field type, 1 is actual field
|
||||
}
|
||||
|
||||
void addToConfig(JsonObject& root) {
|
||||
|
||||
420
wled00/FX.cpp
420
wled00/FX.cpp
File diff suppressed because it is too large
Load Diff
111
wled00/FX.h
111
wled00/FX.h
@@ -1,33 +1,23 @@
|
||||
#pragma once
|
||||
/*
|
||||
WS2812FX.h - Library for WS2812 LED effects.
|
||||
Harm Aldick - 2016
|
||||
www.aldick.org
|
||||
LICENSE
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Harm Aldick
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
Licensed under the EUPL v. 1.2 or later
|
||||
Adapted from code originally licensed under the MIT license
|
||||
|
||||
Modified for WLED
|
||||
|
||||
Segment class/struct (c) 2022 Blaz Kristan (@blazoncek)
|
||||
*/
|
||||
|
||||
#ifndef WS2812FX_h
|
||||
#define WS2812FX_h
|
||||
|
||||
#include <vector>
|
||||
#include "wled.h"
|
||||
|
||||
#include "const.h"
|
||||
|
||||
@@ -60,30 +50,42 @@
|
||||
#define WLED_FPS 42
|
||||
#define FRAMETIME_FIXED (1000/WLED_FPS)
|
||||
#define FRAMETIME strip.getFrameTime()
|
||||
#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
#define MIN_FRAME_DELAY 2 // minimum wait between repaints, to keep other functions like WiFi alive
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
#define MIN_FRAME_DELAY 3 // S2/C3 are slower than normal esp32, and only have one core
|
||||
#else
|
||||
#define MIN_FRAME_DELAY 8 // 8266 legacy MIN_SHOW_DELAY
|
||||
#endif
|
||||
#define FPS_UNLIMITED 0
|
||||
|
||||
// FPS calculation (can be defined as compile flag for debugging)
|
||||
#ifndef FPS_CALC_AVG
|
||||
#define FPS_CALC_AVG 7 // average FPS calculation over this many frames (moving average)
|
||||
#endif
|
||||
#ifndef FPS_MULTIPLIER
|
||||
#define FPS_MULTIPLIER 1 // dev option: multiplier to get sub-frame FPS without floats
|
||||
#endif
|
||||
#define FPS_CALC_SHIFT 7 // bit shift for fixed point math
|
||||
|
||||
/* each segment uses 82 bytes of SRAM memory, so if you're application fails because of
|
||||
insufficient memory, decreasing MAX_NUM_SEGMENTS may help */
|
||||
#ifdef ESP8266
|
||||
#define MAX_NUM_SEGMENTS 16
|
||||
#define MAX_NUM_SEGMENTS 16
|
||||
/* How much data bytes all segments combined may allocate */
|
||||
#define MAX_SEGMENT_DATA 5120
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
#define MAX_NUM_SEGMENTS 20
|
||||
#define MAX_SEGMENT_DATA (MAX_NUM_SEGMENTS*512) // 10k by default (S2 is short on free RAM)
|
||||
#else
|
||||
#ifndef MAX_NUM_SEGMENTS
|
||||
#define MAX_NUM_SEGMENTS 32
|
||||
#endif
|
||||
#if defined(ARDUINO_ARCH_ESP32S2)
|
||||
#define MAX_SEGMENT_DATA MAX_NUM_SEGMENTS*768 // 24k by default (S2 is short on free RAM)
|
||||
#else
|
||||
#define MAX_SEGMENT_DATA MAX_NUM_SEGMENTS*1280 // 40k by default
|
||||
#endif
|
||||
#define MAX_NUM_SEGMENTS 32 // warning: going beyond 32 may consume too much RAM for stable operation
|
||||
#define MAX_SEGMENT_DATA (MAX_NUM_SEGMENTS*1280) // 40k by default
|
||||
#endif
|
||||
|
||||
/* How much data bytes each segment should max allocate to leave enough space for other segments,
|
||||
assuming each segment uses the same amount of data. 256 for ESP8266, 640 for ESP32. */
|
||||
#define FAIR_DATA_PER_SEG (MAX_SEGMENT_DATA / strip.getMaxSegments())
|
||||
|
||||
#define MIN_SHOW_DELAY (_frametime < 16 ? 8 : 15)
|
||||
|
||||
#define NUM_COLORS 3 /* number of colors per segment */
|
||||
#define SEGMENT strip._segments[strip.getCurrSegmentId()]
|
||||
#define SEGENV strip._segments[strip.getCurrSegmentId()]
|
||||
@@ -529,6 +531,9 @@ typedef struct Segment {
|
||||
inline uint16_t length() const { return width() * height(); } // segment length (count) in physical pixels
|
||||
inline uint16_t groupLength() const { return grouping + spacing; }
|
||||
inline uint8_t getLightCapabilities() const { return _capabilities; }
|
||||
inline void deactivate() { setGeometry(0,0); }
|
||||
inline Segment &clearName() { if (name) free(name); name = nullptr; return *this; }
|
||||
inline Segment &setName(const String &name) { return setName(name.c_str()); }
|
||||
|
||||
inline static uint16_t getUsedSegmentData() { return _usedSegmentData; }
|
||||
inline static void addUsedSegmentData(int len) { _usedSegmentData += len; }
|
||||
@@ -538,14 +543,15 @@ typedef struct Segment {
|
||||
static void handleRandomPalette();
|
||||
inline static const CRGBPalette16 &getCurrentPalette() { return Segment::_currentPalette; }
|
||||
|
||||
void setUp(uint16_t i1, uint16_t i2, uint8_t grp=1, uint8_t spc=0, uint16_t ofs=UINT16_MAX, uint16_t i1Y=0, uint16_t i2Y=1);
|
||||
bool setColor(uint8_t slot, uint32_t c); //returns true if changed
|
||||
void setCCT(uint16_t k);
|
||||
void setOpacity(uint8_t o);
|
||||
void setOption(uint8_t n, bool val);
|
||||
void setMode(uint8_t fx, bool loadDefaults = false);
|
||||
void setPalette(uint8_t pal);
|
||||
uint8_t differs(Segment& b) const;
|
||||
void setGeometry(uint16_t i1, uint16_t i2, uint8_t grp=1, uint8_t spc=0, uint16_t ofs=UINT16_MAX, uint16_t i1Y=0, uint16_t i2Y=1, uint8_t m12 = 0);
|
||||
Segment &setColor(uint8_t slot, uint32_t c);
|
||||
Segment &setCCT(uint16_t k);
|
||||
Segment &setOpacity(uint8_t o);
|
||||
Segment &setOption(uint8_t n, bool val);
|
||||
Segment &setMode(uint8_t fx, bool loadDefaults = false);
|
||||
Segment &setPalette(uint8_t pal);
|
||||
Segment &setName(const char* name);
|
||||
uint8_t differs(const Segment& b) const;
|
||||
void refreshLightCapabilities();
|
||||
|
||||
// runtime data functions
|
||||
@@ -559,7 +565,7 @@ typedef struct Segment {
|
||||
* Call resetIfRequired before calling the next effect function.
|
||||
* Safe to call from interrupts and network requests.
|
||||
*/
|
||||
inline void markForReset() { reset = true; } // setOption(SEG_OPTION_RESET, true)
|
||||
inline Segment &markForReset() { reset = true; return *this; } // setOption(SEG_OPTION_RESET, true)
|
||||
|
||||
// transition functions
|
||||
void startTransition(uint16_t dur); // transition has to start before actual segment values change
|
||||
@@ -613,9 +619,15 @@ typedef struct Segment {
|
||||
}
|
||||
|
||||
// 2D matrix
|
||||
[[gnu::hot]] uint16_t virtualWidth() const; // segment width in virtual pixels (accounts for groupping and spacing)
|
||||
[[gnu::hot]] uint16_t virtualHeight() const; // segment height in virtual pixels (accounts for groupping and spacing)
|
||||
uint16_t nrOfVStrips() const; // returns number of virtual vertical strips in 2D matrix (used to expand 1D effects into 2D)
|
||||
[[gnu::hot]] unsigned virtualWidth() const; // segment width in virtual pixels (accounts for groupping and spacing)
|
||||
[[gnu::hot]] unsigned virtualHeight() const; // segment height in virtual pixels (accounts for groupping and spacing)
|
||||
inline unsigned nrOfVStrips() const { // returns number of virtual vertical strips in 2D matrix (used to expand 1D effects into 2D)
|
||||
#ifndef WLED_DISABLE_2D
|
||||
return (is2D() && map1D2D == M12_pBar) ? virtualWidth() : 1;
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
#ifndef WLED_DISABLE_2D
|
||||
[[gnu::hot]] uint16_t XY(int x, int y); // support function to get relative index within segment
|
||||
[[gnu::hot]] void setPixelColorXY(int x, int y, uint32_t c); // set relative pixel within segment with color
|
||||
@@ -720,7 +732,11 @@ class WS2812FX { // 96 bytes
|
||||
#ifndef WLED_DISABLE_2D
|
||||
panels(1),
|
||||
#endif
|
||||
#ifdef WLED_AUTOSEGMENTS
|
||||
autoSegments(true),
|
||||
#else
|
||||
autoSegments(false),
|
||||
#endif
|
||||
correctWB(false),
|
||||
cctFromRgb(false),
|
||||
// semi-private (just obscured) used in effect functions through macros
|
||||
@@ -733,7 +749,7 @@ class WS2812FX { // 96 bytes
|
||||
_transitionDur(750),
|
||||
_targetFps(WLED_FPS),
|
||||
_frametime(FRAMETIME_FIXED),
|
||||
_cumulativeFps(2),
|
||||
_cumulativeFps(50 << FPS_CALC_SHIFT),
|
||||
_isServicing(false),
|
||||
_isOffRefreshRequired(false),
|
||||
_hasWhiteChannel(false),
|
||||
@@ -743,6 +759,7 @@ class WS2812FX { // 96 bytes
|
||||
customMappingTable(nullptr),
|
||||
customMappingSize(0),
|
||||
_lastShow(0),
|
||||
_lastServiceShow(0),
|
||||
_segment_index(0),
|
||||
_mainSegment(0)
|
||||
{
|
||||
@@ -788,7 +805,8 @@ class WS2812FX { // 96 bytes
|
||||
setTargetFps(uint8_t fps),
|
||||
setupEffectData(); // add default effects to the list; defined in FX.cpp
|
||||
|
||||
inline void restartRuntime() { for (Segment &seg : _segments) seg.markForReset(); }
|
||||
inline void resetTimebase() { timebase = 0UL - millis(); }
|
||||
inline void restartRuntime() { for (Segment &seg : _segments) { seg.markForReset().resetIfRequired(); } }
|
||||
inline void setTransitionMode(bool t) { for (Segment &seg : _segments) seg.startTransition(t ? _transitionDur : 0); }
|
||||
inline void setColor(uint8_t slot, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0) { setColor(slot, RGBW32(r,g,b,w)); }
|
||||
inline void setPixelColor(unsigned n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0) { setPixelColor(n, RGBW32(r,g,b,w)); }
|
||||
@@ -840,14 +858,12 @@ class WS2812FX { // 96 bytes
|
||||
getMappedPixelIndex(uint16_t index) const;
|
||||
|
||||
inline uint16_t getFrameTime() const { return _frametime; } // returns amount of time a frame should take (in ms)
|
||||
inline uint16_t getMinShowDelay() const { return MIN_SHOW_DELAY; } // returns minimum amount of time strip.service() can be delayed (constant)
|
||||
inline uint16_t getMinShowDelay() const { return MIN_FRAME_DELAY; } // returns minimum amount of time strip.service() can be delayed (constant)
|
||||
inline uint16_t getLength() const { return _length; } // returns actual amount of LEDs on a strip (2D matrix may have less LEDs than W*H)
|
||||
inline uint16_t getTransition() const { return _transitionDur; } // returns currently set transition time (in ms)
|
||||
|
||||
uint32_t
|
||||
now,
|
||||
timebase,
|
||||
getPixelColor(uint16_t) const;
|
||||
unsigned long now, timebase;
|
||||
uint32_t getPixelColor(unsigned) const;
|
||||
|
||||
inline uint32_t getLastShow() const { return _lastShow; } // returns millis() timestamp of last strip.show() call
|
||||
inline uint32_t segColor(uint8_t i) const { return _colors_t[i]; } // returns currently valid color (for slot i) AKA SEGCOLOR(); may be blended between two colors while in transition
|
||||
@@ -954,6 +970,7 @@ class WS2812FX { // 96 bytes
|
||||
uint16_t customMappingSize;
|
||||
|
||||
unsigned long _lastShow;
|
||||
unsigned long _lastServiceShow;
|
||||
|
||||
uint8_t _segment_index;
|
||||
uint8_t _mainSegment;
|
||||
|
||||
@@ -1,24 +1,9 @@
|
||||
/*
|
||||
FX_2Dfcn.cpp contains all 2D utility functions
|
||||
|
||||
LICENSE
|
||||
The MIT License (MIT)
|
||||
Copyright (c) 2022 Blaz Kristan (https://blaz.at/home)
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
Licensed under the EUPL v. 1.2 or later
|
||||
Adapted from code originally licensed under the MIT license
|
||||
|
||||
Parts of the code adapted from WLED Sound Reactive
|
||||
*/
|
||||
@@ -171,7 +156,7 @@ uint16_t IRAM_ATTR_YN Segment::XY(int x, int y)
|
||||
void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col)
|
||||
{
|
||||
if (!isActive()) return; // not active
|
||||
if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit
|
||||
if ((unsigned)x >= virtualWidth() || (unsigned)y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit
|
||||
|
||||
uint8_t _bri_t = currentBri();
|
||||
if (_bri_t < 255) {
|
||||
@@ -266,7 +251,7 @@ void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa)
|
||||
// returns RGBW values of pixel
|
||||
uint32_t IRAM_ATTR_YN Segment::getPixelColorXY(int x, int y) const {
|
||||
if (!isActive()) return 0; // not active
|
||||
if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return 0; // if pixel would fall out of virtual segment just exit
|
||||
if ((unsigned)x >= virtualWidth() || (unsigned)y >= virtualHeight() || x<0 || y<0) return 0; // if pixel would fall out of virtual segment just exit
|
||||
if (reverse ) x = virtualWidth() - x - 1;
|
||||
if (reverse_y) y = virtualHeight() - y - 1;
|
||||
if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed
|
||||
@@ -704,11 +689,14 @@ void Segment::wu_pixel(uint32_t x, uint32_t y, CRGB c) { //awesome wu_pixel
|
||||
WU_WEIGHT(ix, yy), WU_WEIGHT(xx, yy)};
|
||||
// multiply the intensities by the colour, and saturating-add them to the pixels
|
||||
for (int i = 0; i < 4; i++) {
|
||||
CRGB led = getPixelColorXY((x >> 8) + (i & 1), (y >> 8) + ((i >> 1) & 1));
|
||||
int wu_x = (x >> 8) + (i & 1); // precalculate x
|
||||
int wu_y = (y >> 8) + ((i >> 1) & 1); // precalculate y
|
||||
CRGB led = getPixelColorXY(wu_x, wu_y);
|
||||
CRGB oldLed = led;
|
||||
led.r = qadd8(led.r, c.r * wu[i] >> 8);
|
||||
led.g = qadd8(led.g, c.g * wu[i] >> 8);
|
||||
led.b = qadd8(led.b, c.b * wu[i] >> 8);
|
||||
setPixelColorXY(int((x >> 8) + (i & 1)), int((y >> 8) + ((i >> 1) & 1)), led);
|
||||
if (led != oldLed) setPixelColorXY(wu_x, wu_y, led); // don't repaint if same color
|
||||
}
|
||||
}
|
||||
#undef WU_WEIGHT
|
||||
|
||||
@@ -2,24 +2,10 @@
|
||||
WS2812FX_fcn.cpp contains all utility functions
|
||||
Harm Aldick - 2016
|
||||
www.aldick.org
|
||||
LICENSE
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Harm Aldick
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
Licensed under the EUPL v. 1.2 or later
|
||||
Adapted from code originally licensed under the MIT license
|
||||
|
||||
Modified heavily for WLED
|
||||
*/
|
||||
@@ -452,37 +438,44 @@ void Segment::setCurrentPalette() {
|
||||
|
||||
// relies on WS2812FX::service() to call it for each frame
|
||||
void Segment::handleRandomPalette() {
|
||||
uint16_t time_ms = millis();
|
||||
uint16_t time_s = millis()/1000U;
|
||||
// is it time to generate a new palette?
|
||||
if ((uint16_t)((uint16_t)(millis() / 1000U) - _lastPaletteChange) > randomPaletteChangeTime){
|
||||
_newRandomPalette = useHarmonicRandomPalette ? generateHarmonicRandomPalette(_randomPalette) : generateRandomPalette();
|
||||
_lastPaletteChange = (uint16_t)(millis() / 1000U);
|
||||
_lastPaletteBlend = (uint16_t)((uint16_t)millis() - 512); // starts blending immediately
|
||||
if ((uint16_t)(time_s - _lastPaletteChange) > randomPaletteChangeTime) {
|
||||
_newRandomPalette = useHarmonicRandomPalette ? generateHarmonicRandomPalette(_randomPalette) : generateRandomPalette();
|
||||
_lastPaletteChange = time_s;
|
||||
_lastPaletteBlend = time_ms - 512; // starts blending immediately
|
||||
}
|
||||
|
||||
// if palette transitions is enabled, blend it according to Transition Time (if longer than minimum given by service calls)
|
||||
if (strip.paletteFade) {
|
||||
// assumes that 128 updates are sufficient to blend a palette, so shift by 7 (can be more, can be less)
|
||||
// in reality there need to be 255 blends to fully blend two entirely different palettes
|
||||
if ((uint16_t)((uint16_t)millis() - _lastPaletteBlend) < strip.getTransition() >> 7) return; // not yet time to fade, delay the update
|
||||
if ((uint16_t)(time_ms - _lastPaletteBlend) < strip.getTransition() >> 7) return; // not yet time to fade, delay the update
|
||||
_lastPaletteBlend = (uint16_t)millis();
|
||||
}
|
||||
nblendPaletteTowardPalette(_randomPalette, _newRandomPalette, 48);
|
||||
}
|
||||
|
||||
// segId is given when called from network callback, changes are queued if that segment is currently in its effect function
|
||||
void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t ofs, uint16_t i1Y, uint16_t i2Y) {
|
||||
void Segment::setGeometry(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t ofs, uint16_t i1Y, uint16_t i2Y, uint8_t m12) {
|
||||
// return if neither bounds nor grouping have changed
|
||||
bool boundsUnchanged = (start == i1 && stop == i2);
|
||||
#ifndef WLED_DISABLE_2D
|
||||
if (Segment::maxHeight>1) boundsUnchanged &= (startY == i1Y && stopY == i2Y); // 2D
|
||||
#endif
|
||||
|
||||
m12 = constrain(m12, 0, 7);
|
||||
if (stop && (spc > 0 || m12 != map1D2D)) fill(BLACK);
|
||||
if (m12 != map1D2D) map1D2D = m12;
|
||||
/*
|
||||
if (boundsUnchanged
|
||||
&& (!grp || (grouping == grp && spacing == spc))
|
||||
&& (ofs == UINT16_MAX || ofs == offset)) return;
|
||||
|
||||
&& (m12 == map1D2D)
|
||||
) return;
|
||||
*/
|
||||
stateChanged = true; // send UDP/WS broadcast
|
||||
|
||||
if (stop) fill(BLACK); // turn old segment range off (clears pixels if changing spacing)
|
||||
if (grp) { // prevent assignment of 0
|
||||
grouping = grp;
|
||||
spacing = spc;
|
||||
@@ -492,10 +485,7 @@ void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t
|
||||
}
|
||||
if (ofs < UINT16_MAX) offset = ofs;
|
||||
|
||||
DEBUG_PRINT(F("setUp segment: ")); DEBUG_PRINT(i1);
|
||||
DEBUG_PRINT(','); DEBUG_PRINT(i2);
|
||||
DEBUG_PRINT(F(" -> ")); DEBUG_PRINT(i1Y);
|
||||
DEBUG_PRINT(','); DEBUG_PRINTLN(i2Y);
|
||||
DEBUG_PRINTF_P(PSTR("Segment geometry: %d,%d -> %d,%d\n"), (int)i1, (int)i2, (int)i1Y, (int)i2Y);
|
||||
markForReset();
|
||||
if (boundsUnchanged) return;
|
||||
|
||||
@@ -523,46 +513,53 @@ void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t
|
||||
}
|
||||
|
||||
|
||||
bool Segment::setColor(uint8_t slot, uint32_t c) { //returns true if changed
|
||||
if (slot >= NUM_COLORS || c == colors[slot]) return false;
|
||||
Segment &Segment::setColor(uint8_t slot, uint32_t c) {
|
||||
if (slot >= NUM_COLORS || c == colors[slot]) return *this;
|
||||
if (!_isRGB && !_hasW) {
|
||||
if (slot == 0 && c == BLACK) return false; // on/off segment cannot have primary color black
|
||||
if (slot == 1 && c != BLACK) return false; // on/off segment cannot have secondary color non black
|
||||
if (slot == 0 && c == BLACK) return *this; // on/off segment cannot have primary color black
|
||||
if (slot == 1 && c != BLACK) return *this; // on/off segment cannot have secondary color non black
|
||||
}
|
||||
if (fadeTransition) startTransition(strip.getTransition()); // start transition prior to change
|
||||
colors[slot] = c;
|
||||
stateChanged = true; // send UDP/WS broadcast
|
||||
return true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Segment::setCCT(uint16_t k) {
|
||||
Segment &Segment::setCCT(uint16_t k) {
|
||||
if (k > 255) { //kelvin value, convert to 0-255
|
||||
if (k < 1900) k = 1900;
|
||||
if (k > 10091) k = 10091;
|
||||
k = (k - 1900) >> 5;
|
||||
}
|
||||
if (cct == k) return;
|
||||
if (fadeTransition) startTransition(strip.getTransition()); // start transition prior to change
|
||||
cct = k;
|
||||
stateChanged = true; // send UDP/WS broadcast
|
||||
if (cct != k) {
|
||||
//DEBUGFX_PRINTF_P(PSTR("- Starting CCT transition: %d\n"), k);
|
||||
startTransition(strip.getTransition()); // start transition prior to change
|
||||
cct = k;
|
||||
stateChanged = true; // send UDP/WS broadcast
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Segment::setOpacity(uint8_t o) {
|
||||
if (opacity == o) return;
|
||||
if (fadeTransition) startTransition(strip.getTransition()); // start transition prior to change
|
||||
opacity = o;
|
||||
stateChanged = true; // send UDP/WS broadcast
|
||||
Segment &Segment::setOpacity(uint8_t o) {
|
||||
if (opacity != o) {
|
||||
//DEBUGFX_PRINTF_P(PSTR("- Starting opacity transition: %d\n"), o);
|
||||
startTransition(strip.getTransition()); // start transition prior to change
|
||||
opacity = o;
|
||||
stateChanged = true; // send UDP/WS broadcast
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Segment::setOption(uint8_t n, bool val) {
|
||||
Segment &Segment::setOption(uint8_t n, bool val) {
|
||||
bool prevOn = on;
|
||||
if (fadeTransition && n == SEG_OPTION_ON && val != prevOn) startTransition(strip.getTransition()); // start transition prior to change
|
||||
if (val) options |= 0x01 << n;
|
||||
else options &= ~(0x01 << n);
|
||||
if (!(n == SEG_OPTION_SELECTED || n == SEG_OPTION_RESET)) stateChanged = true; // send UDP/WS broadcast
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Segment::setMode(uint8_t fx, bool loadDefaults) {
|
||||
Segment &Segment::setMode(uint8_t fx, bool loadDefaults) {
|
||||
// skip reserved
|
||||
while (fx < strip.getModeCount() && strncmp_P("RSVD", strip.getModeData(fx), 4) == 0) fx++;
|
||||
if (fx >= strip.getModeCount()) fx = 0; // set solid mode
|
||||
@@ -594,9 +591,10 @@ void Segment::setMode(uint8_t fx, bool loadDefaults) {
|
||||
markForReset();
|
||||
stateChanged = true; // send UDP/WS broadcast
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Segment::setPalette(uint8_t pal) {
|
||||
Segment &Segment::setPalette(uint8_t pal) {
|
||||
if (pal < 245 && pal > GRADIENT_PALETTE_COUNT+13) pal = 0; // built in palettes
|
||||
if (pal > 245 && (strip.customPalettes.size() == 0 || 255U-pal > strip.customPalettes.size()-1)) pal = 0; // custom palettes
|
||||
if (pal != palette) {
|
||||
@@ -604,37 +602,38 @@ void Segment::setPalette(uint8_t pal) {
|
||||
palette = pal;
|
||||
stateChanged = true; // send UDP/WS broadcast
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Segment &Segment::setName(const char *newName) {
|
||||
if (newName) {
|
||||
const int newLen = min(strlen(newName), (size_t)WLED_MAX_SEGNAME_LEN);
|
||||
if (newLen) {
|
||||
if (name) name = static_cast<char*>(realloc(name, newLen+1));
|
||||
else name = static_cast<char*>(malloc(newLen+1));
|
||||
if (name) strlcpy(name, newName, newLen+1);
|
||||
name[newLen] = 0;
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
return clearName();
|
||||
}
|
||||
|
||||
// 2D matrix
|
||||
uint16_t IRAM_ATTR Segment::virtualWidth() const {
|
||||
unsigned IRAM_ATTR Segment::virtualWidth() const {
|
||||
unsigned groupLen = groupLength();
|
||||
unsigned vWidth = ((transpose ? height() : width()) + groupLen - 1) / groupLen;
|
||||
if (mirror) vWidth = (vWidth + 1) /2; // divide by 2 if mirror, leave at least a single LED
|
||||
return vWidth;
|
||||
}
|
||||
|
||||
uint16_t IRAM_ATTR Segment::virtualHeight() const {
|
||||
unsigned IRAM_ATTR Segment::virtualHeight() const {
|
||||
unsigned groupLen = groupLength();
|
||||
unsigned vHeight = ((transpose ? width() : height()) + groupLen - 1) / groupLen;
|
||||
if (mirror_y) vHeight = (vHeight + 1) /2; // divide by 2 if mirror, leave at least a single LED
|
||||
return vHeight;
|
||||
}
|
||||
|
||||
uint16_t IRAM_ATTR_YN Segment::nrOfVStrips() const {
|
||||
unsigned vLen = 1;
|
||||
#ifndef WLED_DISABLE_2D
|
||||
if (is2D()) {
|
||||
switch (map1D2D) {
|
||||
case M12_pBar:
|
||||
vLen = virtualWidth();
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return vLen;
|
||||
}
|
||||
|
||||
// Constants for mapping mode "Pinwheel"
|
||||
#ifndef WLED_DISABLE_2D
|
||||
constexpr int Pinwheel_Steps_Small = 72; // no holes up to 16x16
|
||||
@@ -970,7 +969,7 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColor(int i) const
|
||||
return strip.getPixelColor(i);
|
||||
}
|
||||
|
||||
uint8_t Segment::differs(Segment& b) const {
|
||||
uint8_t Segment::differs(const Segment& b) const {
|
||||
uint8_t d = 0;
|
||||
if (start != b.start) d |= SEG_DIFFERS_BOUNDS;
|
||||
if (stop != b.stop) d |= SEG_DIFFERS_BOUNDS;
|
||||
@@ -1066,36 +1065,25 @@ void Segment::fade_out(uint8_t rate) {
|
||||
const int cols = is2D() ? virtualWidth() : virtualLength();
|
||||
const int rows = virtualHeight(); // will be 1 for 1D
|
||||
|
||||
rate = (255-rate) >> 1;
|
||||
float mappedRate = 1.0f / (float(rate) + 1.1f);
|
||||
|
||||
uint32_t color = colors[1]; // SEGCOLOR(1); // target color
|
||||
int w2 = W(color);
|
||||
int r2 = R(color);
|
||||
int g2 = G(color);
|
||||
int b2 = B(color);
|
||||
rate = (256-rate) >> 1;
|
||||
const int mappedRate = 256 / (rate + 1);
|
||||
|
||||
for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) {
|
||||
color = is2D() ? getPixelColorXY(x, y) : getPixelColor(x);
|
||||
uint32_t color = is2D() ? getPixelColorXY(x, y) : getPixelColor(x);
|
||||
if (color == colors[1]) continue; // already at target color
|
||||
int w1 = W(color);
|
||||
int r1 = R(color);
|
||||
int g1 = G(color);
|
||||
int b1 = B(color);
|
||||
|
||||
int wdelta = (w2 - w1) * mappedRate;
|
||||
int rdelta = (r2 - r1) * mappedRate;
|
||||
int gdelta = (g2 - g1) * mappedRate;
|
||||
int bdelta = (b2 - b1) * mappedRate;
|
||||
|
||||
// if fade isn't complete, make sure delta is at least 1 (fixes rounding issues)
|
||||
wdelta += (w2 == w1) ? 0 : (w2 > w1) ? 1 : -1;
|
||||
rdelta += (r2 == r1) ? 0 : (r2 > r1) ? 1 : -1;
|
||||
gdelta += (g2 == g1) ? 0 : (g2 > g1) ? 1 : -1;
|
||||
bdelta += (b2 == b1) ? 0 : (b2 > b1) ? 1 : -1;
|
||||
|
||||
if (is2D()) setPixelColorXY(x, y, r1 + rdelta, g1 + gdelta, b1 + bdelta, w1 + wdelta);
|
||||
else setPixelColor(x, r1 + rdelta, g1 + gdelta, b1 + bdelta, w1 + wdelta);
|
||||
for (int i = 0; i < 32; i += 8) {
|
||||
uint8_t c2 = (colors[1]>>i); // get background channel
|
||||
uint8_t c1 = (color>>i); // get foreground channel
|
||||
// we can't use bitshift since we are using int
|
||||
int delta = (c2 - c1) * mappedRate / 256;
|
||||
// if fade isn't complete, make sure delta is at least 1 (fixes rounding issues)
|
||||
if (delta == 0) delta += (c2 == c1) ? 0 : (c2 > c1) ? 1 : -1;
|
||||
// stuff new value back into color
|
||||
color &= ~(0xFF<<i);
|
||||
color |= ((c1 + delta) & 0xFF) << i;
|
||||
}
|
||||
if (is2D()) setPixelColorXY(x, y, color);
|
||||
else setPixelColor(x, color);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1201,10 +1189,7 @@ uint32_t Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_
|
||||
//do not call this method from system context (network callback)
|
||||
void WS2812FX::finalizeInit() {
|
||||
//reset segment runtimes
|
||||
for (segment &seg : _segments) {
|
||||
seg.markForReset();
|
||||
seg.resetIfRequired();
|
||||
}
|
||||
restartRuntime();
|
||||
|
||||
// for the lack of better place enumerate ledmaps here
|
||||
// if we do it in json.cpp (serializeInfo()) we are getting flashes on LEDs
|
||||
@@ -1214,6 +1199,40 @@ void WS2812FX::finalizeInit() {
|
||||
|
||||
_hasWhiteChannel = _isOffRefreshRequired = false;
|
||||
|
||||
unsigned digitalCount = 0;
|
||||
#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
// determine if it is sensible to use parallel I2S outputs on ESP32 (i.e. more than 5 outputs = 1 I2S + 4 RMT)
|
||||
unsigned maxLedsOnBus = 0;
|
||||
unsigned busType = 0;
|
||||
for (const auto &bus : busConfigs) {
|
||||
if (Bus::isDigital(bus.type) && !Bus::is2Pin(bus.type)) {
|
||||
digitalCount++;
|
||||
if (busType == 0) busType = bus.type; // remember first bus type
|
||||
if (busType != bus.type) {
|
||||
DEBUG_PRINTF_P(PSTR("Mixed digital bus types detected! Forcing single I2S output.\n"));
|
||||
useParallelI2S = false; // mixed bus types, no parallel I2S
|
||||
}
|
||||
if (bus.count > maxLedsOnBus) maxLedsOnBus = bus.count;
|
||||
}
|
||||
}
|
||||
DEBUG_PRINTF_P(PSTR("Maximum LEDs on a bus: %u\nDigital buses: %u\n"), maxLedsOnBus, digitalCount);
|
||||
// we may remove 600 LEDs per bus limit when NeoPixelBus is updated beyond 2.8.3
|
||||
if (digitalCount > 1 && maxLedsOnBus <= 600 && useParallelI2S) BusManager::useParallelOutput(); // must call before creating buses
|
||||
else useParallelI2S = false; // enforce single I2S
|
||||
digitalCount = 0;
|
||||
#endif
|
||||
|
||||
// create buses/outputs
|
||||
unsigned mem = 0;
|
||||
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();
|
||||
|
||||
//if busses failed to load, add default (fresh install, FS issue, ...)
|
||||
if (BusManager::getNumBusses() == 0) {
|
||||
DEBUG_PRINTLN(F("No busses, init default"));
|
||||
@@ -1229,6 +1248,7 @@ void WS2812FX::finalizeInit() {
|
||||
|
||||
unsigned prevLen = 0;
|
||||
unsigned pinsIndex = 0;
|
||||
digitalCount = 0;
|
||||
for (unsigned i = 0; i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) {
|
||||
uint8_t defPin[OUTPUT_MAX_PINS];
|
||||
// if we have less types than requested outputs and they do not align, use last known type to set current type
|
||||
@@ -1290,12 +1310,14 @@ void WS2812FX::finalizeInit() {
|
||||
// if we have less counts than pins and they do not align, use last known count to set current count
|
||||
unsigned count = defCounts[(i < defNumCounts) ? i : defNumCounts -1];
|
||||
// analog always has length 1
|
||||
if (Bus::isPWM(dataType)) count = 1;
|
||||
if (Bus::isPWM(dataType) || Bus::isOnOff(dataType)) count = 1;
|
||||
prevLen += count;
|
||||
BusConfig defCfg = BusConfig(dataType, defPin, start, count, DEFAULT_LED_COLOR_ORDER, false, 0, RGBW_MODE_MANUAL_ONLY, 0, useGlobalLedBuffer);
|
||||
mem += defCfg.memUsage(Bus::isDigital(dataType) && !Bus::is2Pin(dataType) ? digitalCount++ : 0);
|
||||
if (BusManager::add(defCfg) == -1) break;
|
||||
}
|
||||
}
|
||||
DEBUG_PRINTF_P(PSTR("LED buffer size: %uB/%uB\n"), mem, BusManager::memUsage());
|
||||
|
||||
_length = 0;
|
||||
for (int i=0; i<BusManager::getNumBusses(); i++) {
|
||||
@@ -1308,15 +1330,11 @@ void WS2812FX::finalizeInit() {
|
||||
_isOffRefreshRequired |= bus->isOffRefreshRequired() && !bus->isPWM(); // use refresh bit for phase shift with analog
|
||||
unsigned busEnd = bus->getStart() + bus->getLength();
|
||||
if (busEnd > _length) _length = busEnd;
|
||||
#ifdef ESP8266
|
||||
// why do we need to reinitialise GPIO3???
|
||||
//if (!bus->isDigital() || bus->is2Pin()) continue;
|
||||
//uint8_t pins[5];
|
||||
//if (!bus->getPins(pins)) continue;
|
||||
//BusDigital* bd = static_cast<BusDigital*>(bus);
|
||||
//if (pins[0] == 3) bd->reinit();
|
||||
#endif
|
||||
|
||||
// This must be done after all buses have been created, as some kinds (parallel I2S) interact
|
||||
bus->begin();
|
||||
}
|
||||
DEBUG_PRINTF_P(PSTR("Heap after buses: %d\n"), ESP.getFreeHeap());
|
||||
|
||||
Segment::maxWidth = _length;
|
||||
Segment::maxHeight = 1;
|
||||
@@ -1331,14 +1349,21 @@ void WS2812FX::finalizeInit() {
|
||||
void WS2812FX::service() {
|
||||
unsigned long nowUp = millis(); // Be aware, millis() rolls over every 49 days
|
||||
now = nowUp + timebase;
|
||||
if (nowUp - _lastShow < MIN_SHOW_DELAY || _suspend) return;
|
||||
if (_suspend) return;
|
||||
unsigned long elapsed = nowUp - _lastServiceShow;
|
||||
|
||||
if (elapsed <= MIN_FRAME_DELAY) return; // keep wifi alive - no matter if triggered or unlimited
|
||||
if ( !_triggered && (_targetFps != FPS_UNLIMITED)) { // unlimited mode = no frametime
|
||||
if (elapsed < _frametime) return; // too early for service
|
||||
}
|
||||
|
||||
bool doShow = false;
|
||||
|
||||
_isServicing = true;
|
||||
_segment_index = 0;
|
||||
|
||||
for (segment &seg : _segments) {
|
||||
if (_suspend) return; // immediately stop processing segments if suspend requested during service()
|
||||
if (_suspend) break; // immediately stop processing segments if suspend requested during service()
|
||||
|
||||
// process transition (mode changes in the middle of transition)
|
||||
seg.handleTransition();
|
||||
@@ -1348,10 +1373,10 @@ void WS2812FX::service() {
|
||||
if (!seg.isActive()) continue;
|
||||
|
||||
// last condition ensures all solid segments are updated at the same time
|
||||
if (nowUp > seg.next_time || _triggered || (doShow && seg.mode == FX_MODE_STATIC))
|
||||
if (nowUp >= seg.next_time || _triggered || (doShow && seg.mode == FX_MODE_STATIC))
|
||||
{
|
||||
doShow = true;
|
||||
unsigned delay = FRAMETIME;
|
||||
unsigned frameDelay = FRAMETIME;
|
||||
|
||||
if (!seg.freeze) { //only run effect function if not frozen
|
||||
int oldCCT = BusManager::getSegmentCCT(); // store original CCT value (actually it is not Segment based)
|
||||
@@ -1371,7 +1396,7 @@ void WS2812FX::service() {
|
||||
// overwritten by later effect. To enable seamless blending for every effect, additional LED buffer
|
||||
// would need to be allocated for each effect and then blended together for each pixel.
|
||||
[[maybe_unused]] uint8_t tmpMode = seg.currentMode(); // this will return old mode while in transition
|
||||
delay = (*_mode[seg.mode])(); // run new/current mode
|
||||
frameDelay = (*_mode[seg.mode])(); // run new/current mode
|
||||
#ifndef WLED_DISABLE_MODE_BLEND
|
||||
if (modeBlending && seg.mode != tmpMode) {
|
||||
Segment::tmpsegd_t _tmpSegData;
|
||||
@@ -1380,16 +1405,16 @@ void WS2812FX::service() {
|
||||
_virtualSegmentLength = seg.virtualLength(); // update SEGLEN (mapping may have changed)
|
||||
unsigned d2 = (*_mode[tmpMode])(); // run old mode
|
||||
seg.restoreSegenv(_tmpSegData); // restore mode state (will also update transitional state)
|
||||
delay = MIN(delay,d2); // use shortest delay
|
||||
frameDelay = min(frameDelay,d2); // use shortest delay
|
||||
Segment::modeBlend(false); // unset semaphore
|
||||
}
|
||||
#endif
|
||||
seg.call++;
|
||||
if (seg.isInTransition() && delay > FRAMETIME) delay = FRAMETIME; // force faster updates during transition
|
||||
if (seg.isInTransition() && frameDelay > FRAMETIME) frameDelay = FRAMETIME; // force faster updates during transition
|
||||
BusManager::setSegmentCCT(oldCCT); // restore old CCT for ABL adjustments
|
||||
}
|
||||
|
||||
seg.next_time = nowUp + delay;
|
||||
seg.next_time = nowUp + frameDelay;
|
||||
}
|
||||
_segment_index++;
|
||||
}
|
||||
@@ -1398,15 +1423,16 @@ void WS2812FX::service() {
|
||||
_triggered = false;
|
||||
|
||||
#ifdef WLED_DEBUG
|
||||
if (millis() - nowUp > _frametime) DEBUG_PRINTF_P(PSTR("Slow effects %u/%d.\n"), (unsigned)(millis()-nowUp), (int)_frametime);
|
||||
if ((_targetFps != FPS_UNLIMITED) && (millis() - nowUp > _frametime)) DEBUG_PRINTF_P(PSTR("Slow effects %u/%d.\n"), (unsigned)(millis()-nowUp), (int)_frametime);
|
||||
#endif
|
||||
if (doShow) {
|
||||
yield();
|
||||
Segment::handleRandomPalette(); // slowly transition random palette; move it into for loop when each segment has individual random palette
|
||||
show();
|
||||
_lastServiceShow = nowUp; // update timestamp, for precise FPS control
|
||||
if (!_suspend) show();
|
||||
}
|
||||
#ifdef WLED_DEBUG
|
||||
if (millis() - nowUp > _frametime) DEBUG_PRINTF_P(PSTR("Slow strip %u/%d.\n"), (unsigned)(millis()-nowUp), (int)_frametime);
|
||||
if ((_targetFps != FPS_UNLIMITED) && (millis() - nowUp > _frametime)) DEBUG_PRINTF_P(PSTR("Slow strip %u/%d.\n"), (unsigned)(millis()-nowUp), (int)_frametime);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1416,7 +1442,7 @@ void IRAM_ATTR WS2812FX::setPixelColor(unsigned i, uint32_t col) {
|
||||
BusManager::setPixelColor(i, col);
|
||||
}
|
||||
|
||||
uint32_t IRAM_ATTR WS2812FX::getPixelColor(uint16_t i) const {
|
||||
uint32_t IRAM_ATTR WS2812FX::getPixelColor(unsigned i) const {
|
||||
i = getMappedPixelIndex(i);
|
||||
if (i >= _length) return 0;
|
||||
return BusManager::getPixelColor(i);
|
||||
@@ -1426,18 +1452,20 @@ void WS2812FX::show() {
|
||||
// avoid race condition, capture _callback value
|
||||
show_callback callback = _callback;
|
||||
if (callback) callback();
|
||||
unsigned long showNow = millis();
|
||||
|
||||
// some buses send asynchronously and this method will return before
|
||||
// all of the data has been sent.
|
||||
// See https://github.com/Makuna/NeoPixelBus/wiki/ESP32-NeoMethods#neoesp32rmt-methods
|
||||
BusManager::show();
|
||||
|
||||
unsigned long showNow = millis();
|
||||
size_t diff = showNow - _lastShow;
|
||||
size_t fpsCurr = 200;
|
||||
if (diff > 0) fpsCurr = 1000 / diff;
|
||||
_cumulativeFps = (3 * _cumulativeFps + fpsCurr +2) >> 2; // "+2" for proper rounding (2/4 = 0.5)
|
||||
_lastShow = showNow;
|
||||
|
||||
if (diff > 0) { // skip calculation if no time has passed
|
||||
size_t fpsCurr = (1000 << FPS_CALC_SHIFT) / diff; // fixed point math
|
||||
_cumulativeFps = (FPS_CALC_AVG * _cumulativeFps + fpsCurr + FPS_CALC_AVG / 2) / (FPS_CALC_AVG + 1); // "+FPS_CALC_AVG/2" for proper rounding
|
||||
_lastShow = showNow;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1454,12 +1482,13 @@ bool WS2812FX::isUpdating() const {
|
||||
*/
|
||||
uint16_t WS2812FX::getFps() const {
|
||||
if (millis() - _lastShow > 2000) return 0;
|
||||
return _cumulativeFps +1;
|
||||
return (FPS_MULTIPLIER * _cumulativeFps) >> FPS_CALC_SHIFT; // _cumulativeFps is stored in fixed point
|
||||
}
|
||||
|
||||
void WS2812FX::setTargetFps(uint8_t fps) {
|
||||
if (fps > 0 && fps <= 120) _targetFps = fps;
|
||||
_frametime = 1000 / _targetFps;
|
||||
if (fps <= 250) _targetFps = fps;
|
||||
if (_targetFps > 0) _frametime = 1000 / _targetFps;
|
||||
else _frametime = MIN_FRAME_DELAY; // unlimited mode
|
||||
}
|
||||
|
||||
void WS2812FX::setMode(uint8_t segid, uint8_t m) {
|
||||
@@ -1507,7 +1536,7 @@ void WS2812FX::setBrightness(uint8_t b, bool direct) {
|
||||
BusManager::setBrightness(b);
|
||||
if (!direct) {
|
||||
unsigned long t = millis();
|
||||
if (_segments[0].next_time > t + 22 && t - _lastShow > MIN_SHOW_DELAY) trigger(); //apply brightness change immediately if no refresh soon
|
||||
if (_segments[0].next_time > t + 22 && t - _lastShow > MIN_FRAME_DELAY) trigger(); //apply brightness change immediately if no refresh soon
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1617,7 +1646,7 @@ void WS2812FX::setSegment(uint8_t segId, uint16_t i1, uint16_t i2, uint8_t group
|
||||
segId = getSegmentsNum()-1; // segments are added at the end of list
|
||||
}
|
||||
suspend();
|
||||
_segments[segId].setUp(i1, i2, grouping, spacing, offset, startY, stopY);
|
||||
_segments[segId].setGeometry(i1, i2, grouping, spacing, offset, startY, stopY);
|
||||
resume();
|
||||
if (segId > 0 && segId == getSegmentsNum()-1 && i2 <= i1) _segments.pop_back(); // if last segment was deleted remove it from vector
|
||||
}
|
||||
|
||||
@@ -18,10 +18,12 @@
|
||||
#endif
|
||||
#include "const.h"
|
||||
#include "pin_manager.h"
|
||||
#include "bus_wrapper.h"
|
||||
#include "bus_manager.h"
|
||||
#include "bus_wrapper.h"
|
||||
#include <bits/unique_ptr.h>
|
||||
|
||||
extern bool cctICused;
|
||||
extern bool useParallelI2S;
|
||||
|
||||
//colors.cpp
|
||||
uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb);
|
||||
@@ -29,28 +31,6 @@ uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb);
|
||||
//udp.cpp
|
||||
uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, byte *buffer, uint8_t bri=255, bool isRGBW=false);
|
||||
|
||||
// enable additional debug output
|
||||
#if defined(WLED_DEBUG_HOST)
|
||||
#include "net_debug.h"
|
||||
#define DEBUGOUT NetDebug
|
||||
#else
|
||||
#define DEBUGOUT Serial
|
||||
#endif
|
||||
|
||||
#ifdef WLED_DEBUG
|
||||
#ifndef ESP8266
|
||||
#include <rom/rtc.h>
|
||||
#endif
|
||||
#define DEBUG_PRINT(x) DEBUGOUT.print(x)
|
||||
#define DEBUG_PRINTLN(x) DEBUGOUT.println(x)
|
||||
#define DEBUG_PRINTF(x...) DEBUGOUT.printf(x)
|
||||
#define DEBUG_PRINTF_P(x...) DEBUGOUT.printf_P(x)
|
||||
#else
|
||||
#define DEBUG_PRINT(x)
|
||||
#define DEBUG_PRINTLN(x)
|
||||
#define DEBUG_PRINTF(x...)
|
||||
#define DEBUG_PRINTF_P(x...)
|
||||
#endif
|
||||
|
||||
//color mangling macros
|
||||
#define RGBW32(r,g,b,w) (uint32_t((byte(w) << 24) | (byte(r) << 16) | (byte(g) << 8) | (byte(b))))
|
||||
@@ -63,6 +43,7 @@ uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, byte
|
||||
bool ColorOrderMap::add(uint16_t start, uint16_t len, uint8_t colorOrder) {
|
||||
if (count() >= WLED_MAX_COLOR_ORDER_MAPPINGS || len == 0 || (colorOrder & 0x0F) > COL_ORDER_MAX) return false; // upper nibble contains W swap information
|
||||
_mappings.push_back({start,len,colorOrder});
|
||||
DEBUGBUS_PRINTF_P(PSTR("Bus: Add COM (%d,%d,%d)\n"), (int)start, (int)len, (int)colorOrder);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -116,12 +97,16 @@ uint32_t Bus::autoWhiteCalc(uint32_t c) const {
|
||||
}
|
||||
|
||||
uint8_t *Bus::allocateData(size_t size) {
|
||||
if (_data) free(_data); // should not happen, but for safety
|
||||
freeData(); // should not happen, but for safety
|
||||
return _data = (uint8_t *)(size>0 ? calloc(size, sizeof(uint8_t)) : nullptr);
|
||||
}
|
||||
|
||||
void Bus::freeData() {
|
||||
if (_data) free(_data);
|
||||
_data = nullptr;
|
||||
}
|
||||
|
||||
BusDigital::BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com)
|
||||
BusDigital::BusDigital(const BusConfig &bc, uint8_t nr, const ColorOrderMap &com)
|
||||
: Bus(bc.type, bc.start, bc.autoWhite, bc.count, bc.reversed, (bc.refreshReq || bc.type == TYPE_TM1814))
|
||||
, _skip(bc.skipAmount) //sacrificial pixels
|
||||
, _colorOrder(bc.colorOrder)
|
||||
@@ -129,42 +114,43 @@ BusDigital::BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com)
|
||||
, _milliAmpsMax(bc.milliAmpsMax)
|
||||
, _colorOrderMap(com)
|
||||
{
|
||||
if (!isDigital(bc.type) || !bc.count) return;
|
||||
if (!PinManager::allocatePin(bc.pins[0], true, PinOwner::BusDigital)) return;
|
||||
DEBUGBUS_PRINTLN(F("Bus: Creating digital bus."));
|
||||
if (!isDigital(bc.type) || !bc.count) { DEBUGBUS_PRINTLN(F("Not digial or empty bus!")); return; }
|
||||
if (!PinManager::allocatePin(bc.pins[0], true, PinOwner::BusDigital)) { DEBUGBUS_PRINTLN(F("Pin 0 allocated!")); return; }
|
||||
_frequencykHz = 0U;
|
||||
_pins[0] = bc.pins[0];
|
||||
if (is2Pin(bc.type)) {
|
||||
if (!PinManager::allocatePin(bc.pins[1], true, PinOwner::BusDigital)) {
|
||||
cleanup();
|
||||
DEBUGBUS_PRINTLN(F("Pin 1 allocated!"));
|
||||
return;
|
||||
}
|
||||
_pins[1] = bc.pins[1];
|
||||
_frequencykHz = bc.frequency ? bc.frequency : 2000U; // 2MHz clock if undefined
|
||||
}
|
||||
_iType = PolyBus::getI(bc.type, _pins, nr);
|
||||
if (_iType == I_NONE) return;
|
||||
if (_iType == I_NONE) { DEBUGBUS_PRINTLN(F("Incorrect iType!")); return; }
|
||||
_hasRgb = hasRGB(bc.type);
|
||||
_hasWhite = hasWhite(bc.type);
|
||||
_hasCCT = hasCCT(bc.type);
|
||||
if (bc.doubleBuffer && !allocateData(bc.count * Bus::getNumberOfChannels(bc.type))) return;
|
||||
if (bc.doubleBuffer && !allocateData(bc.count * Bus::getNumberOfChannels(bc.type))) { DEBUGBUS_PRINTLN(F("Buffer allocation failed!")); return; }
|
||||
//_buffering = bc.doubleBuffer;
|
||||
uint16_t lenToCreate = bc.count;
|
||||
if (bc.type == TYPE_WS2812_1CH_X3) lenToCreate = NUM_ICS_WS2812_1CH_3X(bc.count); // only needs a third of "RGB" LEDs for NeoPixelBus
|
||||
_busPtr = PolyBus::create(_iType, _pins, lenToCreate + _skip, nr, _frequencykHz);
|
||||
_busPtr = PolyBus::create(_iType, _pins, lenToCreate + _skip, nr);
|
||||
_valid = (_busPtr != nullptr);
|
||||
DEBUG_PRINTF_P(PSTR("%successfully inited strip %u (len %u) with type %u and pins %u,%u (itype %u). mA=%d/%d\n"), _valid?"S":"Uns", nr, bc.count, bc.type, _pins[0], is2Pin(bc.type)?_pins[1]:255, _iType, _milliAmpsPerLed, _milliAmpsMax);
|
||||
DEBUGBUS_PRINTF_P(PSTR("Bus: %successfully inited #%u (len:%u, type:%u (RGB:%d, W:%d, CCT:%d), pins:%u,%u [itype:%u] mA=%d/%d)\n"),
|
||||
_valid?"S":"Uns",
|
||||
(int)nr,
|
||||
(int)bc.count,
|
||||
(int)bc.type,
|
||||
(int)_hasRgb, (int)_hasWhite, (int)_hasCCT,
|
||||
(unsigned)_pins[0], is2Pin(bc.type)?(unsigned)_pins[1]:255U,
|
||||
(unsigned)_iType,
|
||||
(int)_milliAmpsPerLed, (int)_milliAmpsMax
|
||||
);
|
||||
}
|
||||
|
||||
//fine tune power estimation constants for your setup
|
||||
//you can set it to 0 if the ESP is powered by USB and the LEDs by external
|
||||
#ifndef MA_FOR_ESP
|
||||
#ifdef ESP8266
|
||||
#define MA_FOR_ESP 80 //how much mA does the ESP use (Wemos D1 about 80mA)
|
||||
#else
|
||||
#define MA_FOR_ESP 120 //how much mA does the ESP use (ESP32 about 120mA)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//DISCLAIMER
|
||||
//The following function attemps to calculate the current LED power usage,
|
||||
//and will limit the brightness to stay below a set amperage threshold.
|
||||
@@ -173,7 +159,7 @@ BusDigital::BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com)
|
||||
//I am NOT to be held liable for burned down garages or houses!
|
||||
|
||||
// To disable brightness limiter we either set output max current to 0 or single LED current to 0
|
||||
uint8_t BusDigital::estimateCurrentAndLimitBri() {
|
||||
uint8_t BusDigital::estimateCurrentAndLimitBri() const {
|
||||
bool useWackyWS2815PowerModel = false;
|
||||
byte actualMilliampsPerLed = _milliAmpsPerLed;
|
||||
|
||||
@@ -186,7 +172,7 @@ uint8_t BusDigital::estimateCurrentAndLimitBri() {
|
||||
actualMilliampsPerLed = 12; // from testing an actual strip
|
||||
}
|
||||
|
||||
size_t powerBudget = (_milliAmpsMax - MA_FOR_ESP/BusManager::getNumBusses()); //80/120mA for ESP power
|
||||
unsigned powerBudget = (_milliAmpsMax - MA_FOR_ESP/BusManager::getNumBusses()); //80/120mA for ESP power
|
||||
if (powerBudget > getLength()) { //each LED uses about 1mA in standby, exclude that from power budget
|
||||
powerBudget -= getLength();
|
||||
} else {
|
||||
@@ -211,26 +197,25 @@ uint8_t BusDigital::estimateCurrentAndLimitBri() {
|
||||
}
|
||||
|
||||
// powerSum has all the values of channels summed (max would be getLength()*765 as white is excluded) so convert to milliAmps
|
||||
busPowerSum = (busPowerSum * actualMilliampsPerLed) / 765;
|
||||
_milliAmpsTotal = busPowerSum * _bri / 255;
|
||||
BusDigital::_milliAmpsTotal = (busPowerSum * actualMilliampsPerLed * _bri) / (765*255);
|
||||
|
||||
uint8_t newBri = _bri;
|
||||
if (busPowerSum * _bri / 255 > powerBudget) { //scale brightness down to stay in current limit
|
||||
float scale = (float)(powerBudget * 255) / (float)(busPowerSum * _bri);
|
||||
if (scale >= 1.0f) return _bri;
|
||||
_milliAmpsTotal = ceilf((float)_milliAmpsTotal * scale);
|
||||
uint8_t scaleB = min((int)(scale * 255), 255);
|
||||
newBri = unsigned(_bri * scaleB) / 256 + 1;
|
||||
if (BusDigital::_milliAmpsTotal > powerBudget) {
|
||||
//scale brightness down to stay in current limit
|
||||
unsigned scaleB = powerBudget * 255 / BusDigital::_milliAmpsTotal;
|
||||
newBri = (_bri * scaleB) / 256 + 1;
|
||||
BusDigital::_milliAmpsTotal = powerBudget;
|
||||
//_milliAmpsTotal = (busPowerSum * actualMilliampsPerLed * newBri) / (765*255);
|
||||
}
|
||||
return newBri;
|
||||
}
|
||||
|
||||
void BusDigital::show() {
|
||||
_milliAmpsTotal = 0;
|
||||
BusDigital::_milliAmpsTotal = 0;
|
||||
if (!_valid) return;
|
||||
|
||||
uint8_t cctWW = 0, cctCW = 0;
|
||||
unsigned newBri = estimateCurrentAndLimitBri(); // will fill _milliAmpsTotal
|
||||
unsigned newBri = estimateCurrentAndLimitBri(); // will fill _milliAmpsTotal (TODO: could use PolyBus::CalcTotalMilliAmpere())
|
||||
if (newBri < _bri) PolyBus::setBrightness(_busPtr, _iType, newBri); // limit brightness to stay within current limits
|
||||
|
||||
if (_data) {
|
||||
@@ -256,6 +241,7 @@ void BusDigital::show() {
|
||||
// TODO: there is an issue if CCT is calculated from RGB value (_cct==-1), we cannot do that with double buffer
|
||||
Bus::_cct = _data[offset+channels-1];
|
||||
Bus::calculateCCT(c, cctWW, cctCW);
|
||||
if (_type == TYPE_WS2812_WWA) c = RGBW32(cctWW, cctCW, 0, W(c)); // may need swapping
|
||||
}
|
||||
unsigned pix = i;
|
||||
if (_reversed) pix = _len - pix -1;
|
||||
@@ -306,9 +292,8 @@ void BusDigital::setStatusPixel(uint32_t c) {
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR BusDigital::setPixelColor(uint16_t pix, uint32_t c) {
|
||||
void IRAM_ATTR BusDigital::setPixelColor(unsigned pix, uint32_t c) {
|
||||
if (!_valid) return;
|
||||
uint8_t cctWW = 0, cctCW = 0;
|
||||
if (hasWhite()) c = autoWhiteCalc(c);
|
||||
if (Bus::_cct >= 1900) c = colorBalanceFromKelvin(Bus::_cct, c); //color correction from CCT
|
||||
if (_data) {
|
||||
@@ -336,13 +321,19 @@ void IRAM_ATTR BusDigital::setPixelColor(uint16_t pix, uint32_t c) {
|
||||
case 2: c = RGBW32(R(cOld), G(cOld), W(c) , 0); break;
|
||||
}
|
||||
}
|
||||
if (hasCCT()) Bus::calculateCCT(c, cctWW, cctCW);
|
||||
PolyBus::setPixelColor(_busPtr, _iType, pix, c, co, (cctCW<<8) | cctWW);
|
||||
uint16_t wwcw = 0;
|
||||
if (hasCCT()) {
|
||||
uint8_t cctWW = 0, cctCW = 0;
|
||||
Bus::calculateCCT(c, cctWW, cctCW);
|
||||
wwcw = (cctCW<<8) | cctWW;
|
||||
if (_type == TYPE_WS2812_WWA) c = RGBW32(cctWW, cctCW, 0, W(c)); // may need swapping
|
||||
}
|
||||
PolyBus::setPixelColor(_busPtr, _iType, pix, c, co, wwcw);
|
||||
}
|
||||
}
|
||||
|
||||
// returns original color if global buffering is enabled, else returns lossly restored color from bus
|
||||
uint32_t IRAM_ATTR BusDigital::getPixelColor(uint16_t pix) const {
|
||||
uint32_t IRAM_ATTR BusDigital::getPixelColor(unsigned pix) const {
|
||||
if (!_valid) return 0;
|
||||
if (_data) {
|
||||
size_t offset = pix * getNumberOfChannels();
|
||||
@@ -368,16 +359,24 @@ uint32_t IRAM_ATTR BusDigital::getPixelColor(uint16_t pix) const {
|
||||
case 2: c = RGBW32(b, b, b, b); break;
|
||||
}
|
||||
}
|
||||
if (_type == TYPE_WS2812_WWA) {
|
||||
uint8_t w = R(c) | G(c);
|
||||
c = RGBW32(w, w, 0, w);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t BusDigital::getPins(uint8_t* pinArray) const {
|
||||
unsigned BusDigital::getPins(uint8_t* pinArray) const {
|
||||
unsigned numPins = is2Pin(_type) + 1;
|
||||
if (pinArray) for (unsigned i = 0; i < numPins; i++) pinArray[i] = _pins[i];
|
||||
return numPins;
|
||||
}
|
||||
|
||||
unsigned BusDigital::getBusSize() const {
|
||||
return sizeof(BusDigital) + (isOk() ? PolyBus::getDataSize(_busPtr, _iType) + (_data ? _len * getNumberOfChannels() : 0) : 0);
|
||||
}
|
||||
|
||||
void BusDigital::setColorOrder(uint8_t colorOrder) {
|
||||
// upper nibble contains W swap information
|
||||
if ((colorOrder & 0x0F) > 5) return;
|
||||
@@ -400,8 +399,8 @@ std::vector<LEDType> BusDigital::getLEDTypes() {
|
||||
{TYPE_WS2805, "D", PSTR("WS2805 RGBCW")},
|
||||
{TYPE_SM16825, "D", PSTR("SM16825 RGBCW")},
|
||||
{TYPE_WS2812_1CH_X3, "D", PSTR("WS2811 White")},
|
||||
//{TYPE_WS2812_2CH_X3, "D", PSTR("WS2811 CCT")}, // not implemented
|
||||
//{TYPE_WS2812_WWA, "D", PSTR("WS2811 WWA")}, // not implemented
|
||||
//{TYPE_WS2812_2CH_X3, "D", PSTR("WS281x CCT")}, // not implemented
|
||||
{TYPE_WS2812_WWA, "D", PSTR("WS281x WWA")}, // amber ignored
|
||||
{TYPE_WS2801, "2P", PSTR("WS2801")},
|
||||
{TYPE_APA102, "2P", PSTR("APA102")},
|
||||
{TYPE_LPD8806, "2P", PSTR("LPD8806")},
|
||||
@@ -410,18 +409,19 @@ std::vector<LEDType> BusDigital::getLEDTypes() {
|
||||
};
|
||||
}
|
||||
|
||||
void BusDigital::reinit() {
|
||||
void BusDigital::begin() {
|
||||
if (!_valid) return;
|
||||
PolyBus::begin(_busPtr, _iType, _pins);
|
||||
PolyBus::begin(_busPtr, _iType, _pins, _frequencykHz);
|
||||
}
|
||||
|
||||
void BusDigital::cleanup() {
|
||||
DEBUG_PRINTLN(F("Digital Cleanup."));
|
||||
DEBUGBUS_PRINTLN(F("Digital Cleanup."));
|
||||
PolyBus::cleanup(_busPtr, _iType);
|
||||
_iType = I_NONE;
|
||||
_valid = false;
|
||||
_busPtr = nullptr;
|
||||
if (_data != nullptr) freeData();
|
||||
freeData();
|
||||
//PinManager::deallocateMultiplePins(_pins, 2, PinOwner::BusDigital);
|
||||
PinManager::deallocatePin(_pins[1], PinOwner::BusDigital);
|
||||
PinManager::deallocatePin(_pins[0], PinOwner::BusDigital);
|
||||
}
|
||||
@@ -452,7 +452,7 @@ void BusDigital::cleanup() {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
BusPwm::BusPwm(BusConfig &bc)
|
||||
BusPwm::BusPwm(const BusConfig &bc)
|
||||
: Bus(bc.type, bc.start, bc.autoWhite, 1, bc.reversed, bc.refreshReq) // hijack Off refresh flag to indicate usage of dithering
|
||||
{
|
||||
if (!isPWM(bc.type)) return;
|
||||
@@ -496,12 +496,12 @@ BusPwm::BusPwm(BusConfig &bc)
|
||||
_hasRgb = hasRGB(bc.type);
|
||||
_hasWhite = hasWhite(bc.type);
|
||||
_hasCCT = hasCCT(bc.type);
|
||||
_data = _pwmdata; // avoid malloc() and use stack
|
||||
_data = _pwmdata; // avoid malloc() and use already allocated memory
|
||||
_valid = true;
|
||||
DEBUG_PRINTF_P(PSTR("%successfully inited PWM strip with type %u, frequency %u, bit depth %u and pins %u,%u,%u,%u,%u\n"), _valid?"S":"Uns", bc.type, _frequency, _depth, _pins[0], _pins[1], _pins[2], _pins[3], _pins[4]);
|
||||
DEBUGBUS_PRINTF_P(PSTR("%successfully inited PWM strip with type %u, frequency %u, bit depth %u and pins %u,%u,%u,%u,%u\n"), _valid?"S":"Uns", bc.type, _frequency, _depth, _pins[0], _pins[1], _pins[2], _pins[3], _pins[4]);
|
||||
}
|
||||
|
||||
void BusPwm::setPixelColor(uint16_t pix, uint32_t c) {
|
||||
void BusPwm::setPixelColor(unsigned pix, uint32_t c) {
|
||||
if (pix != 0 || !_valid) return; //only react to first pixel
|
||||
if (_type != TYPE_ANALOG_3CH) c = autoWhiteCalc(c);
|
||||
if (Bus::_cct >= 1900 && (_type == TYPE_ANALOG_3CH || _type == TYPE_ANALOG_4CH)) {
|
||||
@@ -538,7 +538,7 @@ void BusPwm::setPixelColor(uint16_t pix, uint32_t c) {
|
||||
}
|
||||
|
||||
//does no index check
|
||||
uint32_t BusPwm::getPixelColor(uint16_t pix) const {
|
||||
uint32_t BusPwm::getPixelColor(unsigned pix) const {
|
||||
if (!_valid) return 0;
|
||||
// TODO getting the reverse from CCT is involved (a quick approximation when CCT blending is ste to 0 implemented)
|
||||
switch (_type) {
|
||||
@@ -567,19 +567,15 @@ void BusPwm::show() {
|
||||
const unsigned maxBri = (1<<_depth); // possible values: 16384 (14), 8192 (13), 4096 (12), 2048 (11), 1024 (10), 512 (9) and 256 (8)
|
||||
[[maybe_unused]] const unsigned bitShift = dithering * 4; // if dithering, _depth is 12 bit but LEDC channel is set to 8 bit (using 4 fractional bits)
|
||||
|
||||
// use CIE brightness formula (cubic) to fit (or approximate linearity of) human eye perceived brightness
|
||||
// the formula is based on 12 bit resolution as there is no need for greater precision
|
||||
// use CIE brightness formula (linear + cubic) to approximate human eye perceived brightness
|
||||
// see: https://en.wikipedia.org/wiki/Lightness
|
||||
unsigned pwmBri = (unsigned)_bri * 100; // enlarge to use integer math for linear response
|
||||
if (pwmBri < 2040) {
|
||||
// linear response for values [0-20]
|
||||
pwmBri = ((pwmBri << 12) + 115043) / 230087; //adding '0.5' before division for correct rounding
|
||||
} else {
|
||||
// cubic response for values [21-255]
|
||||
pwmBri += 4080;
|
||||
float temp = (float)pwmBri / 29580.0f;
|
||||
temp = temp * temp * temp * (float)maxBri;
|
||||
pwmBri = (unsigned)temp; // pwmBri is in range [0-maxBri]
|
||||
unsigned pwmBri = _bri;
|
||||
if (pwmBri < 21) { // linear response for values [0-20]
|
||||
pwmBri = (pwmBri * maxBri + 2300 / 2) / 2300 ; // adding '0.5' before division for correct rounding, 2300 gives a good match to CIE curve
|
||||
} else { // cubic response for values [21-255]
|
||||
float temp = float(pwmBri + 41) / float(255 + 41); // 41 is to match offset & slope to linear part
|
||||
temp = temp * temp * temp * (float)maxBri;
|
||||
pwmBri = (unsigned)temp; // pwmBri is in range [0-maxBri] C
|
||||
}
|
||||
|
||||
[[maybe_unused]] unsigned hPoint = 0; // phase shift (0 - maxBri)
|
||||
@@ -618,7 +614,7 @@ void BusPwm::show() {
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t BusPwm::getPins(uint8_t* pinArray) const {
|
||||
unsigned BusPwm::getPins(uint8_t* pinArray) const {
|
||||
if (!_valid) return 0;
|
||||
unsigned numPins = numPWMPins(_type);
|
||||
if (pinArray) for (unsigned i = 0; i < numPins; i++) pinArray[i] = _pins[i];
|
||||
@@ -654,7 +650,7 @@ void BusPwm::deallocatePins() {
|
||||
}
|
||||
|
||||
|
||||
BusOnOff::BusOnOff(BusConfig &bc)
|
||||
BusOnOff::BusOnOff(const BusConfig &bc)
|
||||
: Bus(bc.type, bc.start, bc.autoWhite, 1, bc.reversed)
|
||||
, _onoffdata(0)
|
||||
{
|
||||
@@ -671,10 +667,10 @@ BusOnOff::BusOnOff(BusConfig &bc)
|
||||
_hasCCT = false;
|
||||
_data = &_onoffdata; // avoid malloc() and use stack
|
||||
_valid = true;
|
||||
DEBUG_PRINTF_P(PSTR("%successfully inited On/Off strip with pin %u\n"), _valid?"S":"Uns", _pin);
|
||||
DEBUGBUS_PRINTF_P(PSTR("%successfully inited On/Off strip with pin %u\n"), _valid?"S":"Uns", _pin);
|
||||
}
|
||||
|
||||
void BusOnOff::setPixelColor(uint16_t pix, uint32_t c) {
|
||||
void BusOnOff::setPixelColor(unsigned pix, uint32_t c) {
|
||||
if (pix != 0 || !_valid) return; //only react to first pixel
|
||||
c = autoWhiteCalc(c);
|
||||
uint8_t r = R(c);
|
||||
@@ -684,7 +680,7 @@ void BusOnOff::setPixelColor(uint16_t pix, uint32_t c) {
|
||||
_data[0] = bool(r|g|b|w) && bool(_bri) ? 0xFF : 0;
|
||||
}
|
||||
|
||||
uint32_t BusOnOff::getPixelColor(uint16_t pix) const {
|
||||
uint32_t BusOnOff::getPixelColor(unsigned pix) const {
|
||||
if (!_valid) return 0;
|
||||
return RGBW32(_data[0], _data[0], _data[0], _data[0]);
|
||||
}
|
||||
@@ -694,7 +690,7 @@ void BusOnOff::show() {
|
||||
digitalWrite(_pin, _reversed ? !(bool)_data[0] : (bool)_data[0]);
|
||||
}
|
||||
|
||||
uint8_t BusOnOff::getPins(uint8_t* pinArray) const {
|
||||
unsigned BusOnOff::getPins(uint8_t* pinArray) const {
|
||||
if (!_valid) return 0;
|
||||
if (pinArray) pinArray[0] = _pin;
|
||||
return 1;
|
||||
@@ -707,7 +703,7 @@ std::vector<LEDType> BusOnOff::getLEDTypes() {
|
||||
};
|
||||
}
|
||||
|
||||
BusNetwork::BusNetwork(BusConfig &bc)
|
||||
BusNetwork::BusNetwork(const BusConfig &bc)
|
||||
: Bus(bc.type, bc.start, bc.autoWhite, bc.count)
|
||||
, _broadcastLock(false)
|
||||
{
|
||||
@@ -731,10 +727,10 @@ BusNetwork::BusNetwork(BusConfig &bc)
|
||||
_UDPchannels = _hasWhite + 3;
|
||||
_client = IPAddress(bc.pins[0],bc.pins[1],bc.pins[2],bc.pins[3]);
|
||||
_valid = (allocateData(_len * _UDPchannels) != nullptr);
|
||||
DEBUG_PRINTF_P(PSTR("%successfully inited virtual strip with type %u and IP %u.%u.%u.%u\n"), _valid?"S":"Uns", bc.type, bc.pins[0], bc.pins[1], bc.pins[2], bc.pins[3]);
|
||||
DEBUGBUS_PRINTF_P(PSTR("%successfully inited virtual strip with type %u and IP %u.%u.%u.%u\n"), _valid?"S":"Uns", bc.type, bc.pins[0], bc.pins[1], bc.pins[2], bc.pins[3]);
|
||||
}
|
||||
|
||||
void BusNetwork::setPixelColor(uint16_t pix, uint32_t c) {
|
||||
void BusNetwork::setPixelColor(unsigned pix, uint32_t c) {
|
||||
if (!_valid || pix >= _len) return;
|
||||
if (_hasWhite) c = autoWhiteCalc(c);
|
||||
if (Bus::_cct >= 1900) c = colorBalanceFromKelvin(Bus::_cct, c); //color correction from CCT
|
||||
@@ -745,7 +741,7 @@ void BusNetwork::setPixelColor(uint16_t pix, uint32_t c) {
|
||||
if (_hasWhite) _data[offset+3] = W(c);
|
||||
}
|
||||
|
||||
uint32_t BusNetwork::getPixelColor(uint16_t pix) const {
|
||||
uint32_t BusNetwork::getPixelColor(unsigned pix) const {
|
||||
if (!_valid || pix >= _len) return 0;
|
||||
unsigned offset = pix * _UDPchannels;
|
||||
return RGBW32(_data[offset], _data[offset+1], _data[offset+2], (hasWhite() ? _data[offset+3] : 0));
|
||||
@@ -758,7 +754,7 @@ void BusNetwork::show() {
|
||||
_broadcastLock = false;
|
||||
}
|
||||
|
||||
uint8_t BusNetwork::getPins(uint8_t* pinArray) const {
|
||||
unsigned BusNetwork::getPins(uint8_t* pinArray) const {
|
||||
if (pinArray) for (unsigned i = 0; i < 4; i++) pinArray[i] = _client[i];
|
||||
return 4;
|
||||
}
|
||||
@@ -779,6 +775,7 @@ std::vector<LEDType> BusNetwork::getLEDTypes() {
|
||||
}
|
||||
|
||||
void BusNetwork::cleanup() {
|
||||
DEBUGBUS_PRINTLN(F("Virtual Cleanup."));
|
||||
_type = I_NONE;
|
||||
_valid = false;
|
||||
freeData();
|
||||
@@ -786,43 +783,66 @@ void BusNetwork::cleanup() {
|
||||
|
||||
|
||||
//utility to get the approx. memory usage of a given BusConfig
|
||||
uint32_t BusManager::memUsage(BusConfig &bc) {
|
||||
if (Bus::isOnOff(bc.type) || Bus::isPWM(bc.type)) return OUTPUT_MAX_PINS;
|
||||
|
||||
unsigned len = bc.count + bc.skipAmount;
|
||||
unsigned channels = Bus::getNumberOfChannels(bc.type);
|
||||
unsigned multiplier = 1;
|
||||
if (Bus::isDigital(bc.type)) { // digital types
|
||||
if (Bus::is16bit(bc.type)) len *= 2; // 16-bit LEDs
|
||||
#ifdef ESP8266
|
||||
if (bc.pins[0] == 3) { //8266 DMA uses 5x the mem
|
||||
multiplier = 5;
|
||||
}
|
||||
#else //ESP32 RMT uses double buffer, parallel I2S uses 8x buffer (3 times)
|
||||
multiplier = PolyBus::isParallelI2S1Output() ? 24 : 2;
|
||||
#endif
|
||||
}
|
||||
return (len * multiplier + bc.doubleBuffer * (bc.count + bc.skipAmount)) * channels;
|
||||
}
|
||||
|
||||
uint32_t BusManager::memUsage(unsigned maxChannels, unsigned maxCount, unsigned minBuses) {
|
||||
//ESP32 RMT uses double buffer, parallel I2S uses 8x buffer (3 times)
|
||||
unsigned multiplier = PolyBus::isParallelI2S1Output() ? 3 : 2;
|
||||
return (maxChannels * maxCount * minBuses * multiplier);
|
||||
}
|
||||
|
||||
int BusManager::add(BusConfig &bc) {
|
||||
if (getNumBusses() - getNumVirtualBusses() >= WLED_MAX_BUSSES) return -1;
|
||||
if (Bus::isVirtual(bc.type)) {
|
||||
busses[numBusses] = new BusNetwork(bc);
|
||||
} else if (Bus::isDigital(bc.type)) {
|
||||
busses[numBusses] = new BusDigital(bc, numBusses, colorOrderMap);
|
||||
} else if (Bus::isOnOff(bc.type)) {
|
||||
busses[numBusses] = new BusOnOff(bc);
|
||||
unsigned BusConfig::memUsage(unsigned nr) const {
|
||||
if (Bus::isVirtual(type)) {
|
||||
return sizeof(BusNetwork) + (count * Bus::getNumberOfChannels(type));
|
||||
} else if (Bus::isDigital(type)) {
|
||||
return sizeof(BusDigital) + PolyBus::memUsage(count + skipAmount, PolyBus::getI(type, pins, nr)) + doubleBuffer * (count + skipAmount) * Bus::getNumberOfChannels(type);
|
||||
} else if (Bus::isOnOff(type)) {
|
||||
return sizeof(BusOnOff);
|
||||
} else {
|
||||
busses[numBusses] = new BusPwm(bc);
|
||||
return sizeof(BusPwm);
|
||||
}
|
||||
return numBusses++;
|
||||
}
|
||||
|
||||
|
||||
unsigned BusManager::memUsage() {
|
||||
// when ESP32, S2 & S3 use parallel I2S only the largest bus determines the total memory requirements for back buffers
|
||||
// front buffers are always allocated per bus
|
||||
unsigned size = 0;
|
||||
unsigned maxI2S = 0;
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(ESP8266)
|
||||
unsigned digitalCount = 0;
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
#define MAX_RMT 4
|
||||
#else
|
||||
#define MAX_RMT 8
|
||||
#endif
|
||||
#endif
|
||||
for (const auto &bus : busses) {
|
||||
unsigned busSize = bus->getBusSize();
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(ESP8266)
|
||||
if (bus->isDigital() && !bus->is2Pin()) digitalCount++;
|
||||
if (PolyBus::isParallelI2S1Output() && digitalCount > MAX_RMT) {
|
||||
unsigned i2sCommonSize = 3 * bus->getLength() * bus->getNumberOfChannels() * (bus->is16bit()+1);
|
||||
if (i2sCommonSize > maxI2S) maxI2S = i2sCommonSize;
|
||||
busSize -= i2sCommonSize;
|
||||
}
|
||||
#endif
|
||||
size += busSize;
|
||||
}
|
||||
return size + maxI2S;
|
||||
}
|
||||
|
||||
int BusManager::add(const BusConfig &bc) {
|
||||
DEBUGBUS_PRINTF_P(PSTR("Bus: Adding bus (%d - %d >= %d)\n"), getNumBusses(), getNumVirtualBusses(), WLED_MAX_BUSSES);
|
||||
if (getNumBusses() - getNumVirtualBusses() >= WLED_MAX_BUSSES) return -1;
|
||||
unsigned numDigital = 0;
|
||||
for (const auto &bus : busses) if (bus->isDigital() && !bus->is2Pin()) numDigital++;
|
||||
if (Bus::isVirtual(bc.type)) {
|
||||
//busses.push_back(std::make_unique<BusNetwork>(bc)); // when C++ >11
|
||||
busses.push_back(new BusNetwork(bc));
|
||||
} else if (Bus::isDigital(bc.type)) {
|
||||
//busses.push_back(std::make_unique<BusDigital>(bc, numDigital, colorOrderMap));
|
||||
busses.push_back(new BusDigital(bc, numDigital, colorOrderMap));
|
||||
} else if (Bus::isOnOff(bc.type)) {
|
||||
//busses.push_back(std::make_unique<BusOnOff>(bc));
|
||||
busses.push_back(new BusOnOff(bc));
|
||||
} else {
|
||||
//busses.push_back(std::make_unique<BusPwm>(bc));
|
||||
busses.push_back(new BusPwm(bc));
|
||||
}
|
||||
return busses.size();
|
||||
}
|
||||
|
||||
// credit @willmmiles
|
||||
@@ -851,18 +871,21 @@ String BusManager::getLEDTypesJSONString() {
|
||||
}
|
||||
|
||||
void BusManager::useParallelOutput() {
|
||||
_parallelOutputs = 8; // hardcoded since we use NPB I2S x8 methods
|
||||
DEBUGBUS_PRINTLN(F("Bus: Enabling parallel I2S."));
|
||||
PolyBus::setParallelI2S1Output();
|
||||
}
|
||||
|
||||
bool BusManager::hasParallelOutput() {
|
||||
return PolyBus::isParallelI2S1Output();
|
||||
}
|
||||
|
||||
//do not call this method from system context (network callback)
|
||||
void BusManager::removeAll() {
|
||||
DEBUG_PRINTLN(F("Removing all."));
|
||||
DEBUGBUS_PRINTLN(F("Removing all."));
|
||||
//prevents crashes due to deleting busses while in use.
|
||||
while (!canAllShow()) yield();
|
||||
for (unsigned i = 0; i < numBusses; i++) delete busses[i];
|
||||
numBusses = 0;
|
||||
_parallelOutputs = 1;
|
||||
for (auto &bus : busses) delete bus; // needed when not using std::unique_ptr C++ >11
|
||||
busses.clear();
|
||||
PolyBus::setParallelI2S1Output(false);
|
||||
}
|
||||
|
||||
@@ -873,7 +896,9 @@ void BusManager::removeAll() {
|
||||
void BusManager::esp32RMTInvertIdle() {
|
||||
bool idle_out;
|
||||
unsigned rmt = 0;
|
||||
for (unsigned u = 0; u < numBusses(); u++) {
|
||||
unsigned u = 0;
|
||||
for (auto &bus : busses) {
|
||||
if (bus->getLength()==0 || !bus->isDigital() || bus->is2Pin()) continue;
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32C3) // 2 RMT, only has 1 I2S but NPB does not support it ATM
|
||||
if (u > 1) return;
|
||||
rmt = u;
|
||||
@@ -884,11 +909,11 @@ void BusManager::esp32RMTInvertIdle() {
|
||||
if (u > 3) return;
|
||||
rmt = u;
|
||||
#else
|
||||
if (u < _parallelOutputs) continue;
|
||||
if (u >= _parallelOutputs + 8) return; // only 8 RMT channels
|
||||
rmt = u - _parallelOutputs;
|
||||
unsigned numI2S = !PolyBus::isParallelI2S1Output(); // if using parallel I2S, RMT is used 1st
|
||||
if (numI2S > u) continue;
|
||||
if (u > 7 + numI2S) return;
|
||||
rmt = u - numI2S;
|
||||
#endif
|
||||
if (busses[u]->getLength()==0 || !busses[u]->isDigital() || busses[u]->is2Pin()) continue;
|
||||
//assumes that bus number to rmt channel mapping stays 1:1
|
||||
rmt_channel_t ch = static_cast<rmt_channel_t>(rmt);
|
||||
rmt_idle_level_t lvl;
|
||||
@@ -897,6 +922,7 @@ void BusManager::esp32RMTInvertIdle() {
|
||||
else if (lvl == RMT_IDLE_LEVEL_LOW) lvl = RMT_IDLE_LEVEL_HIGH;
|
||||
else continue;
|
||||
rmt_set_idle_level(ch, idle_out, lvl);
|
||||
u++
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -905,12 +931,12 @@ void BusManager::on() {
|
||||
#ifdef ESP8266
|
||||
//Fix for turning off onboard LED breaking bus
|
||||
if (PinManager::getPinOwner(LED_BUILTIN) == PinOwner::BusDigital) {
|
||||
for (unsigned i = 0; i < numBusses; i++) {
|
||||
for (auto &bus : busses) {
|
||||
uint8_t pins[2] = {255,255};
|
||||
if (busses[i]->isDigital() && busses[i]->getPins(pins)) {
|
||||
if (bus->isDigital() && bus->getPins(pins)) {
|
||||
if (pins[0] == LED_BUILTIN || pins[1] == LED_BUILTIN) {
|
||||
BusDigital *bus = static_cast<BusDigital*>(busses[i]);
|
||||
bus->reinit();
|
||||
BusDigital *b = static_cast<BusDigital*>(bus);
|
||||
b->begin();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -927,7 +953,7 @@ void BusManager::off() {
|
||||
// turn off built-in LED if strip is turned off
|
||||
// this will break digital bus so will need to be re-initialised on On
|
||||
if (PinManager::getPinOwner(LED_BUILTIN) == PinOwner::BusDigital) {
|
||||
for (unsigned i = 0; i < numBusses; i++) if (busses[i]->isOffRefreshRequired()) return;
|
||||
for (const auto &bus : busses) if (bus->isOffRefreshRequired()) return;
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
}
|
||||
@@ -939,31 +965,26 @@ void BusManager::off() {
|
||||
|
||||
void BusManager::show() {
|
||||
_milliAmpsUsed = 0;
|
||||
for (unsigned i = 0; i < numBusses; i++) {
|
||||
busses[i]->show();
|
||||
_milliAmpsUsed += busses[i]->getUsedCurrent();
|
||||
for (auto &bus : busses) {
|
||||
bus->show();
|
||||
_milliAmpsUsed += bus->getUsedCurrent();
|
||||
}
|
||||
if (_milliAmpsUsed) _milliAmpsUsed += MA_FOR_ESP;
|
||||
}
|
||||
|
||||
void BusManager::setStatusPixel(uint32_t c) {
|
||||
for (unsigned i = 0; i < numBusses; i++) {
|
||||
busses[i]->setStatusPixel(c);
|
||||
}
|
||||
for (auto &bus : busses) bus->setStatusPixel(c);
|
||||
}
|
||||
|
||||
void IRAM_ATTR BusManager::setPixelColor(uint16_t pix, uint32_t c) {
|
||||
for (unsigned i = 0; i < numBusses; i++) {
|
||||
unsigned bstart = busses[i]->getStart();
|
||||
if (pix < bstart || pix >= bstart + busses[i]->getLength()) continue;
|
||||
busses[i]->setPixelColor(pix - bstart, c);
|
||||
void IRAM_ATTR BusManager::setPixelColor(unsigned pix, uint32_t c) {
|
||||
for (auto &bus : busses) {
|
||||
unsigned bstart = bus->getStart();
|
||||
if (pix < bstart || pix >= bstart + bus->getLength()) continue;
|
||||
bus->setPixelColor(pix - bstart, c);
|
||||
}
|
||||
}
|
||||
|
||||
void BusManager::setBrightness(uint8_t b) {
|
||||
for (unsigned i = 0; i < numBusses; i++) {
|
||||
busses[i]->setBrightness(b);
|
||||
}
|
||||
for (auto &bus : busses) bus->setBrightness(b);
|
||||
}
|
||||
|
||||
void BusManager::setSegmentCCT(int16_t cct, bool allowWBCorrection) {
|
||||
@@ -975,35 +996,33 @@ void BusManager::setSegmentCCT(int16_t cct, bool allowWBCorrection) {
|
||||
Bus::setCCT(cct);
|
||||
}
|
||||
|
||||
uint32_t BusManager::getPixelColor(uint16_t pix) {
|
||||
for (unsigned i = 0; i < numBusses; i++) {
|
||||
unsigned bstart = busses[i]->getStart();
|
||||
if (!busses[i]->containsPixel(pix)) continue;
|
||||
return busses[i]->getPixelColor(pix - bstart);
|
||||
uint32_t BusManager::getPixelColor(unsigned pix) {
|
||||
for (auto &bus : busses) {
|
||||
unsigned bstart = bus->getStart();
|
||||
if (!bus->containsPixel(pix)) continue;
|
||||
return bus->getPixelColor(pix - bstart);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool BusManager::canAllShow() {
|
||||
for (unsigned i = 0; i < numBusses; i++) {
|
||||
if (!busses[i]->canShow()) return false;
|
||||
}
|
||||
for (const auto &bus : busses) if (!bus->canShow()) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
Bus* BusManager::getBus(uint8_t busNr) {
|
||||
if (busNr >= numBusses) return nullptr;
|
||||
if (busNr >= busses.size()) return nullptr;
|
||||
return busses[busNr];
|
||||
}
|
||||
|
||||
//semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit())
|
||||
uint16_t BusManager::getTotalLength() {
|
||||
unsigned len = 0;
|
||||
for (unsigned i=0; i<numBusses; i++) len += busses[i]->getLength();
|
||||
for (const auto &bus : busses) len += bus->getLength();
|
||||
return len;
|
||||
}
|
||||
|
||||
bool PolyBus::useParallelI2S = false;
|
||||
bool PolyBus::_useParallelI2S = false;
|
||||
|
||||
// Bus static member definition
|
||||
int16_t Bus::_cct = -1;
|
||||
@@ -1012,9 +1031,8 @@ uint8_t Bus::_gAWM = 255;
|
||||
|
||||
uint16_t BusDigital::_milliAmpsTotal = 0;
|
||||
|
||||
uint8_t BusManager::numBusses = 0;
|
||||
Bus* BusManager::busses[WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES];
|
||||
//std::vector<std::unique_ptr<Bus>> BusManager::busses;
|
||||
std::vector<Bus*> BusManager::busses;
|
||||
ColorOrderMap BusManager::colorOrderMap = {};
|
||||
uint16_t BusManager::_milliAmpsUsed = 0;
|
||||
uint16_t BusManager::_milliAmpsMax = ABL_MILLIAMPS_DEFAULT;
|
||||
uint8_t BusManager::_parallelOutputs = 1;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#pragma once
|
||||
#ifndef BusManager_h
|
||||
#define BusManager_h
|
||||
|
||||
@@ -7,6 +8,30 @@
|
||||
|
||||
#include "const.h"
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
// enable additional debug output
|
||||
#if defined(WLED_DEBUG_HOST)
|
||||
#include "net_debug.h"
|
||||
#define DEBUGOUT NetDebug
|
||||
#else
|
||||
#define DEBUGOUT Serial
|
||||
#endif
|
||||
|
||||
#ifdef WLED_DEBUG_BUS
|
||||
#ifndef ESP8266
|
||||
#include <rom/rtc.h>
|
||||
#endif
|
||||
#define DEBUGBUS_PRINT(x) DEBUGOUT.print(x)
|
||||
#define DEBUGBUS_PRINTLN(x) DEBUGOUT.println(x)
|
||||
#define DEBUGBUS_PRINTF(x...) DEBUGOUT.printf(x)
|
||||
#define DEBUGBUS_PRINTF_P(x...) DEBUGOUT.printf_P(x)
|
||||
#else
|
||||
#define DEBUGBUS_PRINT(x)
|
||||
#define DEBUGBUS_PRINTLN(x)
|
||||
#define DEBUGBUS_PRINTF(x...)
|
||||
#define DEBUGBUS_PRINTF_P(x...)
|
||||
#endif
|
||||
|
||||
//colors.cpp
|
||||
uint16_t approximateKelvinFromRGB(uint32_t rgb);
|
||||
@@ -77,49 +102,51 @@ class Bus {
|
||||
_autoWhiteMode = Bus::hasWhite(type) ? aw : RGBW_MODE_MANUAL_ONLY;
|
||||
};
|
||||
|
||||
virtual ~Bus() {} //throw the bus under the bus
|
||||
virtual ~Bus() {} //throw the bus under the bus (derived class needs to freeData())
|
||||
|
||||
virtual void begin() {};
|
||||
virtual void show() = 0;
|
||||
virtual bool canShow() const { return true; }
|
||||
virtual void setStatusPixel(uint32_t c) {}
|
||||
virtual void setPixelColor(uint16_t pix, uint32_t c) = 0;
|
||||
virtual void setBrightness(uint8_t b) { _bri = b; };
|
||||
virtual void setColorOrder(uint8_t co) {}
|
||||
virtual uint32_t getPixelColor(uint16_t pix) const { return 0; }
|
||||
virtual uint8_t getPins(uint8_t* pinArray = nullptr) const { return 0; }
|
||||
virtual uint16_t getLength() const { return isOk() ? _len : 0; }
|
||||
virtual uint8_t getColorOrder() const { return COL_ORDER_RGB; }
|
||||
virtual uint8_t skippedLeds() const { return 0; }
|
||||
virtual uint16_t getFrequency() const { return 0U; }
|
||||
virtual uint16_t getLEDCurrent() const { return 0; }
|
||||
virtual uint16_t getUsedCurrent() const { return 0; }
|
||||
virtual uint16_t getMaxCurrent() const { return 0; }
|
||||
virtual bool canShow() const { return true; }
|
||||
virtual void setStatusPixel(uint32_t c) {}
|
||||
virtual void setPixelColor(unsigned pix, uint32_t c) = 0;
|
||||
virtual void setBrightness(uint8_t b) { _bri = b; };
|
||||
virtual void setColorOrder(uint8_t co) {}
|
||||
virtual uint32_t getPixelColor(unsigned pix) const { return 0; }
|
||||
virtual unsigned getPins(uint8_t* pinArray = nullptr) const { return 0; }
|
||||
virtual uint16_t getLength() const { return isOk() ? _len : 0; }
|
||||
virtual uint8_t getColorOrder() const { return COL_ORDER_RGB; }
|
||||
virtual unsigned skippedLeds() const { return 0; }
|
||||
virtual uint16_t getFrequency() const { return 0U; }
|
||||
virtual uint16_t getLEDCurrent() const { return 0; }
|
||||
virtual uint16_t getUsedCurrent() const { return 0; }
|
||||
virtual uint16_t getMaxCurrent() const { return 0; }
|
||||
virtual unsigned getBusSize() const { return sizeof(Bus); }
|
||||
|
||||
inline bool hasRGB() const { return _hasRgb; }
|
||||
inline bool hasWhite() const { return _hasWhite; }
|
||||
inline bool hasCCT() const { return _hasCCT; }
|
||||
inline bool isDigital() const { return isDigital(_type); }
|
||||
inline bool is2Pin() const { return is2Pin(_type); }
|
||||
inline bool isOnOff() const { return isOnOff(_type); }
|
||||
inline bool isPWM() const { return isPWM(_type); }
|
||||
inline bool isVirtual() const { return isVirtual(_type); }
|
||||
inline bool is16bit() const { return is16bit(_type); }
|
||||
inline bool mustRefresh() const { return mustRefresh(_type); }
|
||||
inline void setReversed(bool reversed) { _reversed = reversed; }
|
||||
inline void setStart(uint16_t start) { _start = start; }
|
||||
inline void setAutoWhiteMode(uint8_t m) { if (m < 5) _autoWhiteMode = m; }
|
||||
inline uint8_t getAutoWhiteMode() const { return _autoWhiteMode; }
|
||||
inline uint8_t getNumberOfChannels() const { return hasWhite() + 3*hasRGB() + hasCCT(); }
|
||||
inline uint16_t getStart() const { return _start; }
|
||||
inline uint8_t getType() const { return _type; }
|
||||
inline bool isOk() const { return _valid; }
|
||||
inline bool isReversed() const { return _reversed; }
|
||||
inline bool isOffRefreshRequired() const { return _needsRefresh; }
|
||||
inline bool containsPixel(uint16_t pix) const { return pix >= _start && pix < _start + _len; }
|
||||
inline bool hasRGB() const { return _hasRgb; }
|
||||
inline bool hasWhite() const { return _hasWhite; }
|
||||
inline bool hasCCT() const { return _hasCCT; }
|
||||
inline bool isDigital() const { return isDigital(_type); }
|
||||
inline bool is2Pin() const { return is2Pin(_type); }
|
||||
inline bool isOnOff() const { return isOnOff(_type); }
|
||||
inline bool isPWM() const { return isPWM(_type); }
|
||||
inline bool isVirtual() const { return isVirtual(_type); }
|
||||
inline bool is16bit() const { return is16bit(_type); }
|
||||
inline bool mustRefresh() const { return mustRefresh(_type); }
|
||||
inline void setReversed(bool reversed) { _reversed = reversed; }
|
||||
inline void setStart(uint16_t start) { _start = start; }
|
||||
inline void setAutoWhiteMode(uint8_t m) { if (m < 5) _autoWhiteMode = m; }
|
||||
inline uint8_t getAutoWhiteMode() const { return _autoWhiteMode; }
|
||||
inline unsigned getNumberOfChannels() const { return hasWhite() + 3*hasRGB() + hasCCT(); }
|
||||
inline uint16_t getStart() const { return _start; }
|
||||
inline uint8_t getType() const { return _type; }
|
||||
inline bool isOk() const { return _valid; }
|
||||
inline bool isReversed() const { return _reversed; }
|
||||
inline bool isOffRefreshRequired() const { return _needsRefresh; }
|
||||
inline bool containsPixel(uint16_t pix) const { return pix >= _start && pix < _start + _len; }
|
||||
|
||||
static inline std::vector<LEDType> getLEDTypes() { return {{TYPE_NONE, "", PSTR("None")}}; } // not used. just for reference for derived classes
|
||||
static constexpr uint8_t getNumberOfPins(uint8_t type) { return isVirtual(type) ? 4 : isPWM(type) ? numPWMPins(type) : is2Pin(type) + 1; } // credit @PaoloTK
|
||||
static constexpr uint8_t getNumberOfChannels(uint8_t type) { return hasWhite(type) + 3*hasRGB(type) + hasCCT(type); }
|
||||
static inline std::vector<LEDType> getLEDTypes() { return {{TYPE_NONE, "", PSTR("None")}}; } // not used. just for reference for derived classes
|
||||
static constexpr unsigned getNumberOfPins(uint8_t type) { return isVirtual(type) ? 4 : isPWM(type) ? numPWMPins(type) : is2Pin(type) + 1; } // credit @PaoloTK
|
||||
static constexpr unsigned getNumberOfChannels(uint8_t type) { return hasWhite(type) + 3*hasRGB(type) + hasCCT(type); }
|
||||
static constexpr bool hasRGB(uint8_t type) {
|
||||
return !((type >= TYPE_WS2812_1CH && type <= TYPE_WS2812_WWA) || type == TYPE_ANALOG_1CH || type == TYPE_ANALOG_2CH || type == TYPE_ONOFF);
|
||||
}
|
||||
@@ -151,7 +178,7 @@ class Bus {
|
||||
static inline uint8_t getGlobalAWMode() { return _gAWM; }
|
||||
static inline void setCCT(int16_t cct) { _cct = cct; }
|
||||
static inline uint8_t getCCTBlend() { return _cctBlend; }
|
||||
static inline void setCCTBlend(uint8_t b) {
|
||||
static inline void setCCTBlend(uint8_t b) {
|
||||
_cctBlend = (std::min((int)b,100) * 127) / 100;
|
||||
//compile-time limiter for hardware that can't power both white channels at max
|
||||
#ifdef WLED_MAX_CCT_BLEND
|
||||
@@ -190,30 +217,31 @@ class Bus {
|
||||
|
||||
uint32_t autoWhiteCalc(uint32_t c) const;
|
||||
uint8_t *allocateData(size_t size = 1);
|
||||
void freeData() { if (_data != nullptr) free(_data); _data = nullptr; }
|
||||
void freeData();
|
||||
};
|
||||
|
||||
|
||||
class BusDigital : public Bus {
|
||||
public:
|
||||
BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com);
|
||||
BusDigital(const BusConfig &bc, uint8_t nr, const ColorOrderMap &com);
|
||||
~BusDigital() { cleanup(); }
|
||||
|
||||
void show() override;
|
||||
bool canShow() const override;
|
||||
void setBrightness(uint8_t b) override;
|
||||
void setStatusPixel(uint32_t c) override;
|
||||
[[gnu::hot]] void setPixelColor(uint16_t pix, uint32_t c) override;
|
||||
[[gnu::hot]] void setPixelColor(unsigned pix, uint32_t c) override;
|
||||
void setColorOrder(uint8_t colorOrder) override;
|
||||
[[gnu::hot]] uint32_t getPixelColor(uint16_t pix) const override;
|
||||
[[gnu::hot]] uint32_t getPixelColor(unsigned pix) const override;
|
||||
uint8_t getColorOrder() const override { return _colorOrder; }
|
||||
uint8_t getPins(uint8_t* pinArray = nullptr) const override;
|
||||
uint8_t skippedLeds() const override { return _skip; }
|
||||
unsigned getPins(uint8_t* pinArray = nullptr) const override;
|
||||
unsigned skippedLeds() const override { return _skip; }
|
||||
uint16_t getFrequency() const override { return _frequencykHz; }
|
||||
uint16_t getLEDCurrent() const override { return _milliAmpsPerLed; }
|
||||
uint16_t getUsedCurrent() const override { return _milliAmpsTotal; }
|
||||
uint16_t getMaxCurrent() const override { return _milliAmpsMax; }
|
||||
void reinit();
|
||||
unsigned getBusSize() const override;
|
||||
void begin() override;
|
||||
void cleanup();
|
||||
|
||||
static std::vector<LEDType> getLEDTypes();
|
||||
@@ -242,21 +270,22 @@ class BusDigital : public Bus {
|
||||
return c;
|
||||
}
|
||||
|
||||
uint8_t estimateCurrentAndLimitBri();
|
||||
uint8_t estimateCurrentAndLimitBri() const;
|
||||
};
|
||||
|
||||
|
||||
class BusPwm : public Bus {
|
||||
public:
|
||||
BusPwm(BusConfig &bc);
|
||||
BusPwm(const BusConfig &bc);
|
||||
~BusPwm() { cleanup(); }
|
||||
|
||||
void setPixelColor(uint16_t pix, uint32_t c) override;
|
||||
uint32_t getPixelColor(uint16_t pix) const override; //does no index check
|
||||
uint8_t getPins(uint8_t* pinArray = nullptr) const override;
|
||||
void setPixelColor(unsigned pix, uint32_t c) override;
|
||||
uint32_t getPixelColor(unsigned pix) const override; //does no index check
|
||||
unsigned getPins(uint8_t* pinArray = nullptr) const override;
|
||||
uint16_t getFrequency() const override { return _frequency; }
|
||||
unsigned getBusSize() const override { return sizeof(BusPwm); }
|
||||
void show() override;
|
||||
void cleanup() { deallocatePins(); }
|
||||
inline void cleanup() { deallocatePins(); _data = nullptr; }
|
||||
|
||||
static std::vector<LEDType> getLEDTypes();
|
||||
|
||||
@@ -275,14 +304,15 @@ class BusPwm : public Bus {
|
||||
|
||||
class BusOnOff : public Bus {
|
||||
public:
|
||||
BusOnOff(BusConfig &bc);
|
||||
BusOnOff(const BusConfig &bc);
|
||||
~BusOnOff() { cleanup(); }
|
||||
|
||||
void setPixelColor(uint16_t pix, uint32_t c) override;
|
||||
uint32_t getPixelColor(uint16_t pix) const override;
|
||||
uint8_t getPins(uint8_t* pinArray) const override;
|
||||
void setPixelColor(unsigned pix, uint32_t c) override;
|
||||
uint32_t getPixelColor(unsigned pix) const override;
|
||||
unsigned getPins(uint8_t* pinArray) const override;
|
||||
unsigned getBusSize() const override { return sizeof(BusOnOff); }
|
||||
void show() override;
|
||||
void cleanup() { PinManager::deallocatePin(_pin, PinOwner::BusOnOff); }
|
||||
inline void cleanup() { PinManager::deallocatePin(_pin, PinOwner::BusOnOff); _data = nullptr; }
|
||||
|
||||
static std::vector<LEDType> getLEDTypes();
|
||||
|
||||
@@ -294,13 +324,14 @@ class BusOnOff : public Bus {
|
||||
|
||||
class BusNetwork : public Bus {
|
||||
public:
|
||||
BusNetwork(BusConfig &bc);
|
||||
BusNetwork(const BusConfig &bc);
|
||||
~BusNetwork() { cleanup(); }
|
||||
|
||||
bool canShow() const override { return !_broadcastLock; } // this should be a return value from UDP routine if it is still sending data out
|
||||
void setPixelColor(uint16_t pix, uint32_t c) override;
|
||||
uint32_t getPixelColor(uint16_t pix) const override;
|
||||
uint8_t getPins(uint8_t* pinArray = nullptr) const override;
|
||||
[[gnu::hot]] void setPixelColor(unsigned pix, uint32_t c) override;
|
||||
[[gnu::hot]] uint32_t getPixelColor(unsigned pix) const override;
|
||||
unsigned getPins(uint8_t* pinArray = nullptr) const override;
|
||||
unsigned getBusSize() const override { return sizeof(BusNetwork) + (isOk() ? _len * _UDPchannels : 0); }
|
||||
void show() override;
|
||||
void cleanup();
|
||||
|
||||
@@ -346,6 +377,16 @@ struct BusConfig {
|
||||
type = busType & 0x7F; // bit 7 may be/is hacked to include refresh info (1=refresh in off state, 0=no refresh)
|
||||
size_t nPins = Bus::getNumberOfPins(type);
|
||||
for (size_t i = 0; i < nPins; i++) pins[i] = ppins[i];
|
||||
DEBUGBUS_PRINTF_P(PSTR("Bus: Config (%d-%d, type:%d, CO:%d, rev:%d, skip:%d, AW:%d kHz:%d, mA:%d/%d)\n"),
|
||||
(int)start, (int)(start+len),
|
||||
(int)type,
|
||||
(int)colorOrder,
|
||||
(int)reversed,
|
||||
(int)skipAmount,
|
||||
(int)autoWhite,
|
||||
(int)frequency,
|
||||
(int)milliAmpsPerLed, (int)milliAmpsMax
|
||||
);
|
||||
}
|
||||
|
||||
//validates start and length and extends total if needed
|
||||
@@ -359,21 +400,32 @@ struct BusConfig {
|
||||
if (start + count > total) total = start + count;
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned memUsage(unsigned nr = 0) const;
|
||||
};
|
||||
|
||||
|
||||
//fine tune power estimation constants for your setup
|
||||
//you can set it to 0 if the ESP is powered by USB and the LEDs by external
|
||||
#ifndef MA_FOR_ESP
|
||||
#ifdef ESP8266
|
||||
#define MA_FOR_ESP 80 //how much mA does the ESP use (Wemos D1 about 80mA)
|
||||
#else
|
||||
#define MA_FOR_ESP 120 //how much mA does the ESP use (ESP32 about 120mA)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
class BusManager {
|
||||
public:
|
||||
BusManager() {};
|
||||
|
||||
//utility to get the approx. memory usage of a given BusConfig
|
||||
static uint32_t memUsage(BusConfig &bc);
|
||||
static uint32_t memUsage(unsigned channels, unsigned count, unsigned buses = 1);
|
||||
static uint16_t currentMilliamps() { return _milliAmpsUsed; }
|
||||
static unsigned memUsage();
|
||||
static uint16_t currentMilliamps() { return _milliAmpsUsed + MA_FOR_ESP; }
|
||||
static uint16_t ablMilliampsMax() { return _milliAmpsMax; }
|
||||
|
||||
static int add(BusConfig &bc);
|
||||
static int add(const BusConfig &bc);
|
||||
static void useParallelOutput(); // workaround for inaccessible PolyBus
|
||||
static bool hasParallelOutput(); // workaround for inaccessible PolyBus
|
||||
|
||||
//do not call this method from system context (network callback)
|
||||
static void removeAll();
|
||||
@@ -384,38 +436,37 @@ class BusManager {
|
||||
static void show();
|
||||
static bool canAllShow();
|
||||
static void setStatusPixel(uint32_t c);
|
||||
[[gnu::hot]] static void setPixelColor(uint16_t pix, uint32_t c);
|
||||
[[gnu::hot]] static void setPixelColor(unsigned pix, uint32_t c);
|
||||
static void setBrightness(uint8_t b);
|
||||
// for setSegmentCCT(), cct can only be in [-1,255] range; allowWBCorrection will convert it to K
|
||||
// WARNING: setSegmentCCT() is a misleading name!!! much better would be setGlobalCCT() or just setCCT()
|
||||
static void setSegmentCCT(int16_t cct, bool allowWBCorrection = false);
|
||||
static inline void setMilliampsMax(uint16_t max) { _milliAmpsMax = max;}
|
||||
static uint32_t getPixelColor(uint16_t pix);
|
||||
static uint32_t getPixelColor(unsigned pix);
|
||||
static inline int16_t getSegmentCCT() { return Bus::getCCT(); }
|
||||
|
||||
static Bus* getBus(uint8_t busNr);
|
||||
|
||||
//semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit())
|
||||
static uint16_t getTotalLength();
|
||||
static inline uint8_t getNumBusses() { return numBusses; }
|
||||
static inline uint8_t getNumBusses() { return busses.size(); }
|
||||
static String getLEDTypesJSONString();
|
||||
|
||||
static inline ColorOrderMap& getColorOrderMap() { return colorOrderMap; }
|
||||
|
||||
private:
|
||||
static uint8_t numBusses;
|
||||
static Bus* busses[WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES];
|
||||
//static std::vector<std::unique_ptr<Bus>> busses; // we'd need C++ >11
|
||||
static std::vector<Bus*> busses;
|
||||
static ColorOrderMap colorOrderMap;
|
||||
static uint16_t _milliAmpsUsed;
|
||||
static uint16_t _milliAmpsMax;
|
||||
static uint8_t _parallelOutputs;
|
||||
|
||||
#ifdef ESP32_DATA_IDLE_HIGH
|
||||
static void esp32RMTInvertIdle() ;
|
||||
#endif
|
||||
static uint8_t getNumVirtualBusses() {
|
||||
int j = 0;
|
||||
for (int i=0; i<numBusses; i++) if (busses[i]->isVirtual()) j++;
|
||||
for (const auto &bus : busses) j += bus->isVirtual();
|
||||
return j;
|
||||
}
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -40,7 +40,7 @@ void longPressAction(uint8_t b)
|
||||
{
|
||||
if (!macroLongPress[b]) {
|
||||
switch (b) {
|
||||
case 0: setRandomColor(col); colorUpdated(CALL_MODE_BUTTON); break;
|
||||
case 0: setRandomColor(colPri); colorUpdated(CALL_MODE_BUTTON); break;
|
||||
case 1:
|
||||
if(buttonBriDirection) {
|
||||
if (bri == 255) break; // avoid unnecessary updates to brightness
|
||||
@@ -215,6 +215,7 @@ void handleAnalog(uint8_t b)
|
||||
briLast = bri;
|
||||
bri = 0;
|
||||
} else {
|
||||
if (bri == 0) strip.restartRuntime();
|
||||
bri = aRead;
|
||||
}
|
||||
} else if (macroDoublePress[b] == 249) {
|
||||
@@ -229,7 +230,7 @@ void handleAnalog(uint8_t b)
|
||||
effectPalette = constrain(effectPalette, 0, strip.getPaletteCount()-1); // map is allowed to "overshoot", so we need to contrain the result
|
||||
} else if (macroDoublePress[b] == 200) {
|
||||
// primary color, hue, full saturation
|
||||
colorHStoRGB(aRead*256,255,col);
|
||||
colorHStoRGB(aRead*256,255,colPri);
|
||||
} else {
|
||||
// otherwise use "double press" for segment selection
|
||||
Segment& seg = strip.getSegment(macroDoublePress[b]);
|
||||
@@ -374,6 +375,7 @@ void handleIO()
|
||||
if (rlyPin>=0) {
|
||||
pinMode(rlyPin, rlyOpenDrain ? OUTPUT_OPEN_DRAIN : OUTPUT);
|
||||
digitalWrite(rlyPin, rlyMde);
|
||||
delay(50); // wait for relay to switch and power to stabilize
|
||||
}
|
||||
offMode = false;
|
||||
}
|
||||
|
||||
@@ -118,6 +118,9 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
Bus::setCCTBlend(strip.cctBlending);
|
||||
strip.setTargetFps(hw_led["fps"]); //NOP if 0, default 42 FPS
|
||||
CJSON(useGlobalLedBuffer, hw_led[F("ld")]);
|
||||
#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
CJSON(useParallelI2S, hw_led[F("prl")]);
|
||||
#endif
|
||||
|
||||
#ifndef WLED_DISABLE_2D
|
||||
// 2D Matrix Settings
|
||||
@@ -162,34 +165,6 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
DEBUG_PRINTF_P(PSTR("Heap before buses: %d\n"), ESP.getFreeHeap());
|
||||
int s = 0; // bus iterator
|
||||
if (fromFS) BusManager::removeAll(); // can't safely manipulate busses directly in network callback
|
||||
unsigned mem = 0;
|
||||
|
||||
// determine if it is sensible to use parallel I2S outputs on ESP32 (i.e. more than 5 outputs = 1 I2S + 4 RMT)
|
||||
bool useParallel = false;
|
||||
#if defined(ARDUINO_ARCH_ESP32) && !defined(ARDUINO_ARCH_ESP32S2) && !defined(ARDUINO_ARCH_ESP32S3) && !defined(ARDUINO_ARCH_ESP32C3)
|
||||
unsigned digitalCount = 0;
|
||||
unsigned maxLedsOnBus = 0;
|
||||
unsigned maxChannels = 0;
|
||||
for (JsonObject elm : ins) {
|
||||
unsigned type = elm["type"] | TYPE_WS2812_RGB;
|
||||
unsigned len = elm["len"] | DEFAULT_LED_COUNT;
|
||||
if (!Bus::isDigital(type)) continue;
|
||||
if (!Bus::is2Pin(type)) {
|
||||
digitalCount++;
|
||||
unsigned channels = Bus::getNumberOfChannels(type);
|
||||
if (len > maxLedsOnBus) maxLedsOnBus = len;
|
||||
if (channels > maxChannels) maxChannels = channels;
|
||||
}
|
||||
}
|
||||
DEBUG_PRINTF_P(PSTR("Maximum LEDs on a bus: %u\nDigital buses: %u\n"), maxLedsOnBus, digitalCount);
|
||||
// we may remove 300 LEDs per bus limit when NeoPixelBus is updated beyond 2.9.0
|
||||
if (maxLedsOnBus <= 300 && digitalCount > 5) {
|
||||
DEBUG_PRINTLN(F("Switching to parallel I2S."));
|
||||
useParallel = true;
|
||||
BusManager::useParallelOutput();
|
||||
mem = BusManager::memUsage(maxChannels, maxLedsOnBus, 8); // use alternate memory calculation
|
||||
}
|
||||
#endif
|
||||
|
||||
for (JsonObject elm : ins) {
|
||||
if (s >= WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES) break;
|
||||
@@ -220,24 +195,11 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
maMax = 0;
|
||||
}
|
||||
ledType |= refresh << 7; // hack bit 7 to indicate strip requires off refresh
|
||||
if (fromFS) {
|
||||
BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer, maPerLed, maMax);
|
||||
if (useParallel && s < 8) {
|
||||
// if for some unexplained reason the above pre-calculation was wrong, update
|
||||
unsigned memT = BusManager::memUsage(bc); // includes x8 memory allocation for parallel I2S
|
||||
if (memT > mem) mem = memT; // if we have unequal LED count use the largest
|
||||
} else
|
||||
mem += BusManager::memUsage(bc); // includes global buffer
|
||||
if (mem <= MAX_LED_MEMORY) if (BusManager::add(bc) == -1) break; // finalization will be done in WLED::beginStrip()
|
||||
} else {
|
||||
if (busConfigs[s] != nullptr) delete busConfigs[s];
|
||||
busConfigs[s] = new BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer, maPerLed, maMax);
|
||||
doInitBusses = true; // finalization done in beginStrip()
|
||||
}
|
||||
|
||||
busConfigs.push_back(std::move(BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer, maPerLed, maMax)));
|
||||
doInitBusses = true; // finalization done in beginStrip()
|
||||
s++;
|
||||
}
|
||||
DEBUG_PRINTF_P(PSTR("LED buffer size: %uB\n"), mem);
|
||||
DEBUG_PRINTF_P(PSTR("Heap after buses: %d\n"), ESP.getFreeHeap());
|
||||
}
|
||||
if (hw_led["rev"]) BusManager::getBus(0)->setReversed(true); //set 0.11 global reversed setting for first bus
|
||||
|
||||
@@ -677,16 +639,16 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
|
||||
static const char s_cfg_json[] PROGMEM = "/cfg.json";
|
||||
|
||||
void deserializeConfigFromFS() {
|
||||
bool success = deserializeConfigSec();
|
||||
bool deserializeConfigFromFS() {
|
||||
[[maybe_unused]] bool success = deserializeConfigSec();
|
||||
#ifdef WLED_ADD_EEPROM_SUPPORT
|
||||
if (!success) { //if file does not exist, try reading from EEPROM
|
||||
deEEPSettings();
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!requestJSONBufferLock(1)) return;
|
||||
if (!requestJSONBufferLock(1)) return false;
|
||||
|
||||
DEBUG_PRINTLN(F("Reading settings from /cfg.json..."));
|
||||
|
||||
@@ -696,17 +658,11 @@ void deserializeConfigFromFS() {
|
||||
#ifdef WLED_ADD_EEPROM_SUPPORT
|
||||
deEEPSettings();
|
||||
#endif
|
||||
|
||||
// save default values to /cfg.json
|
||||
// call readFromConfig() with an empty object so that usermods can initialize to defaults prior to saving
|
||||
JsonObject empty = JsonObject();
|
||||
UsermodManager::readFromConfig(empty);
|
||||
serializeConfig();
|
||||
// init Ethernet (in case default type is set at compile time)
|
||||
#ifdef WLED_USE_ETHERNET
|
||||
WLED::instance().initEthernet();
|
||||
#endif
|
||||
return;
|
||||
return true; // config does not exist (we will need to save it once strip is initialised)
|
||||
}
|
||||
|
||||
// NOTE: This routine deserializes *and* applies the configuration
|
||||
@@ -715,7 +671,7 @@ void deserializeConfigFromFS() {
|
||||
bool needsSave = deserializeConfig(root, true);
|
||||
releaseJSONBufferLock();
|
||||
|
||||
if (needsSave) serializeConfig(); // usermods required new parameters
|
||||
return needsSave;
|
||||
}
|
||||
|
||||
void serializeConfig() {
|
||||
@@ -824,6 +780,9 @@ void serializeConfig() {
|
||||
hw_led["fps"] = strip.getTargetFps();
|
||||
hw_led[F("rgbwm")] = Bus::getGlobalAWMode(); // global auto white mode override
|
||||
hw_led[F("ld")] = useGlobalLedBuffer;
|
||||
#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
hw_led[F("prl")] = BusManager::hasParallelOutput();
|
||||
#endif
|
||||
|
||||
#ifndef WLED_DISABLE_2D
|
||||
// 2D Matrix Settings
|
||||
@@ -848,8 +807,19 @@ void serializeConfig() {
|
||||
JsonArray hw_led_ins = hw_led.createNestedArray("ins");
|
||||
|
||||
for (size_t s = 0; s < BusManager::getNumBusses(); s++) {
|
||||
DEBUG_PRINTF_P(PSTR("Cfg: Saving bus #%u\n"), s);
|
||||
Bus *bus = BusManager::getBus(s);
|
||||
if (!bus || bus->getLength()==0) break;
|
||||
DEBUG_PRINTF_P(PSTR(" (%d-%d, type:%d, CO:%d, rev:%d, skip:%d, AW:%d kHz:%d, mA:%d/%d)\n"),
|
||||
(int)bus->getStart(), (int)(bus->getStart()+bus->getLength()),
|
||||
(int)(bus->getType() & 0x7F),
|
||||
(int)bus->getColorOrder(),
|
||||
(int)bus->isReversed(),
|
||||
(int)bus->skippedLeds(),
|
||||
(int)bus->getAutoWhiteMode(),
|
||||
(int)bus->getFrequency(),
|
||||
(int)bus->getLEDCurrent(), (int)bus->getMaxCurrent()
|
||||
);
|
||||
JsonObject ins = hw_led_ins.createNestedObject();
|
||||
ins["start"] = bus->getStart();
|
||||
ins["len"] = bus->getLength();
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
#endif
|
||||
|
||||
#ifndef WLED_MAX_USERMODS
|
||||
#ifdef ESP8266
|
||||
#if defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
#define WLED_MAX_USERMODS 4
|
||||
#else
|
||||
#define WLED_MAX_USERMODS 6
|
||||
@@ -49,31 +49,31 @@
|
||||
#define WLED_MAX_DIGITAL_CHANNELS 3
|
||||
#define WLED_MAX_ANALOG_CHANNELS 5
|
||||
#define WLED_MAX_BUSSES 4 // will allow 3 digital & 1 analog RGB
|
||||
#define WLED_MIN_VIRTUAL_BUSSES 2
|
||||
#define WLED_MIN_VIRTUAL_BUSSES 3
|
||||
#else
|
||||
#define WLED_MAX_ANALOG_CHANNELS (LEDC_CHANNEL_MAX*LEDC_SPEED_MODE_MAX)
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32C3) // 2 RMT, 6 LEDC, only has 1 I2S but NPB does not support it ATM
|
||||
#define WLED_MAX_BUSSES 4 // will allow 2 digital & 2 analog RGB
|
||||
#define WLED_MAX_BUSSES 6 // will allow 2 digital & 2 analog RGB or 6 PWM white
|
||||
#define WLED_MAX_DIGITAL_CHANNELS 2
|
||||
//#define WLED_MAX_ANALOG_CHANNELS 6
|
||||
#define WLED_MIN_VIRTUAL_BUSSES 3
|
||||
#define WLED_MIN_VIRTUAL_BUSSES 4
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2) // 4 RMT, 8 LEDC, only has 1 I2S bus, supported in NPB
|
||||
// the 5th bus (I2S) will prevent Audioreactive usermod from functioning (it is last used though)
|
||||
#define WLED_MAX_BUSSES 7 // will allow 5 digital & 2 analog RGB
|
||||
#define WLED_MAX_DIGITAL_CHANNELS 5
|
||||
//#define WLED_MAX_ANALOG_CHANNELS 8
|
||||
#define WLED_MIN_VIRTUAL_BUSSES 3
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S3) // 4 RMT, 8 LEDC, has 2 I2S but NPB does not support them ATM
|
||||
#define WLED_MAX_BUSSES 6 // will allow 4 digital & 2 analog RGB
|
||||
#define WLED_MAX_DIGITAL_CHANNELS 4
|
||||
#define WLED_MAX_BUSSES 14 // will allow 12 digital & 2 analog RGB
|
||||
#define WLED_MAX_DIGITAL_CHANNELS 12 // x4 RMT + x1/x8 I2S0
|
||||
//#define WLED_MAX_ANALOG_CHANNELS 8
|
||||
#define WLED_MIN_VIRTUAL_BUSSES 4
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S3) // 4 RMT, 8 LEDC, has 2 I2S but NPB supports parallel x8 LCD on I2S1
|
||||
#define WLED_MAX_BUSSES 14 // will allow 12 digital & 2 analog RGB
|
||||
#define WLED_MAX_DIGITAL_CHANNELS 12 // x4 RMT + x8 I2S-LCD
|
||||
//#define WLED_MAX_ANALOG_CHANNELS 8
|
||||
#define WLED_MIN_VIRTUAL_BUSSES 6
|
||||
#else
|
||||
// the last digital bus (I2S0) will prevent Audioreactive usermod from functioning
|
||||
#define WLED_MAX_BUSSES 20 // will allow 17 digital & 3 analog RGB
|
||||
#define WLED_MAX_DIGITAL_CHANNELS 17
|
||||
#define WLED_MAX_BUSSES 19 // will allow 16 digital & 3 analog RGB
|
||||
#define WLED_MAX_DIGITAL_CHANNELS 16 // x1/x8 I2S1 + x8 RMT
|
||||
//#define WLED_MAX_ANALOG_CHANNELS 16
|
||||
#define WLED_MIN_VIRTUAL_BUSSES 4
|
||||
#define WLED_MIN_VIRTUAL_BUSSES 6
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
@@ -115,7 +115,7 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef ESP8266
|
||||
#if defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
#define WLED_MAX_COLOR_ORDER_MAPPINGS 5
|
||||
#else
|
||||
#define WLED_MAX_COLOR_ORDER_MAPPINGS 10
|
||||
@@ -125,7 +125,7 @@
|
||||
#undef WLED_MAX_LEDMAPS
|
||||
#endif
|
||||
#ifndef WLED_MAX_LEDMAPS
|
||||
#ifdef ESP8266
|
||||
#if defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
#define WLED_MAX_LEDMAPS 10
|
||||
#else
|
||||
#define WLED_MAX_LEDMAPS 16
|
||||
@@ -473,6 +473,8 @@
|
||||
#ifndef MAX_LEDS
|
||||
#ifdef ESP8266
|
||||
#define MAX_LEDS 1664 //can't rely on memory limit to limit this to 1600 LEDs
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
#define MAX_LEDS 2048 //due to memory constraints
|
||||
#else
|
||||
#define MAX_LEDS 8192
|
||||
#endif
|
||||
@@ -482,7 +484,9 @@
|
||||
#ifdef ESP8266
|
||||
#define MAX_LED_MEMORY 4000
|
||||
#else
|
||||
#if defined(ARDUINO_ARCH_ESP32S2) || defined(ARDUINO_ARCH_ESP32C3)
|
||||
#if defined(ARDUINO_ARCH_ESP32S2)
|
||||
#define MAX_LED_MEMORY 16000
|
||||
#elif defined(ARDUINO_ARCH_ESP32C3)
|
||||
#define MAX_LED_MEMORY 32000
|
||||
#else
|
||||
#define MAX_LED_MEMORY 64000
|
||||
|
||||
@@ -16,7 +16,7 @@ function isI(n) { return n === +n && n === (n|0); } // isInteger
|
||||
function toggle(el) { gId(el).classList.toggle("hide"); gId('No'+el).classList.toggle("hide"); }
|
||||
function tooltip(cont=null) {
|
||||
d.querySelectorAll((cont?cont+" ":"")+"[title]").forEach((element)=>{
|
||||
element.addEventListener("mouseover", ()=>{
|
||||
element.addEventListener("pointerover", ()=>{
|
||||
// save title
|
||||
element.setAttribute("data-title", element.getAttribute("title"));
|
||||
const tooltip = d.createElement("span");
|
||||
@@ -41,7 +41,7 @@ function tooltip(cont=null) {
|
||||
tooltip.classList.add("visible");
|
||||
});
|
||||
|
||||
element.addEventListener("mouseout", ()=>{
|
||||
element.addEventListener("pointerout", ()=>{
|
||||
d.querySelectorAll('.tooltip').forEach((tooltip)=>{
|
||||
tooltip.classList.remove("visible");
|
||||
d.body.removeChild(tooltip);
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
--sgp: "block";
|
||||
--bmt: 0;
|
||||
--sti: 42px;
|
||||
--stp: 42px;
|
||||
}
|
||||
|
||||
html {
|
||||
@@ -143,7 +144,7 @@ button {
|
||||
}
|
||||
|
||||
.huge {
|
||||
font-size: 42px;
|
||||
font-size: 60px !important;
|
||||
}
|
||||
|
||||
.segt, .plentry TABLE {
|
||||
@@ -468,7 +469,7 @@ button {
|
||||
padding: 4px 2px;
|
||||
position: relative;
|
||||
opacity: 1;
|
||||
transition: opacity .5s linear, height .25s, transform .25s;
|
||||
transition: opacity .25s linear, height .2s, transform .2s;
|
||||
}
|
||||
|
||||
.filter {
|
||||
@@ -583,6 +584,10 @@ button {
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
#rover .ibtn {
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
#ndlt {
|
||||
margin: 12px 0;
|
||||
}
|
||||
@@ -623,7 +628,7 @@ button {
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.infobtn {
|
||||
#info .ibtn {
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
@@ -847,7 +852,7 @@ input[type=range]::-moz-range-thumb {
|
||||
width: 135px;
|
||||
}
|
||||
|
||||
#nodes .infobtn {
|
||||
#nodes .ibtn {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@@ -1035,7 +1040,7 @@ textarea {
|
||||
|
||||
.segname .flr, .pname .flr {
|
||||
transform: rotate(0deg);
|
||||
right: -6px;
|
||||
/*right: -6px;*/
|
||||
}
|
||||
|
||||
/* segment power wrapper */
|
||||
@@ -1330,15 +1335,22 @@ TD .checkmark, TD .radiomark {
|
||||
box-shadow: 0 0 10px 4px var(--c-1);
|
||||
}
|
||||
|
||||
.lstI .flr:hover {
|
||||
background: var(--c-6);
|
||||
border-radius: 100%;
|
||||
}
|
||||
|
||||
#pcont .selected:not([class*="expanded"]) {
|
||||
bottom: 52px;
|
||||
top: 42px;
|
||||
}
|
||||
|
||||
#fxlist .lstI.selected,
|
||||
#pallist .lstI.selected {
|
||||
#fxlist .lstI.selected {
|
||||
top: calc(var(--sti) + 42px);
|
||||
}
|
||||
#pallist .lstI.selected {
|
||||
top: calc(var(--stp) + 42px);
|
||||
}
|
||||
|
||||
dialog::backdrop {
|
||||
backdrop-filter: blur(10px);
|
||||
@@ -1353,10 +1365,12 @@ dialog {
|
||||
color: var(--c-f);
|
||||
}
|
||||
|
||||
#fxlist .lstI.sticky,
|
||||
#pallist .lstI.sticky {
|
||||
#fxlist .lstI.sticky {
|
||||
top: var(--sti);
|
||||
}
|
||||
#pallist .lstI.sticky {
|
||||
top: var(--stp);
|
||||
}
|
||||
|
||||
/* list item content */
|
||||
.lstIcontent {
|
||||
@@ -1519,7 +1533,7 @@ dialog {
|
||||
#info table .btn, #nodes table .btn {
|
||||
width: 200px;
|
||||
}
|
||||
#info .infobtn, #nodes .infobtn {
|
||||
#info .ibtn, #nodes .ibtn {
|
||||
width: 145px;
|
||||
}
|
||||
#info div, #nodes div, #nodes a.btn {
|
||||
|
||||
@@ -128,7 +128,7 @@
|
||||
<div style="padding: 8px 0;" id="btns">
|
||||
<button class="btn btn-xs" title="File editor" type="button" id="edit" onclick="window.location.href=getURL('/edit')"><i class="icons btn-icon"></i></button>
|
||||
<button class="btn btn-xs" title="Pixel Magic Tool" type="button" id="pxmb" onclick="window.location.href=getURL('/pxmagic.htm')"><i class="icons btn-icon"></i></button>
|
||||
<button class="btn btn-xs" title="Add custom palette" type="button" onclick="window.location.href=getURL('/cpal.htm')"><i class="icons btn-icon"></i></button>
|
||||
<button class="btn btn-xs" title="Add custom palette" type="button" id="adPal" onclick="window.location.href=getURL('/cpal.htm')"><i class="icons btn-icon"></i></button>
|
||||
<button class="btn btn-xs" title="Remove last custom palette" type="button" id="rmPal" onclick="palettesData=null;localStorage.removeItem('wledPalx');requestJson({rmcpal:true});setTimeout(loadPalettes,250,loadPalettesData);"><i class="icons btn-icon"></i></button>
|
||||
</div>
|
||||
<p class="labels hd" id="pall"><i class="icons sel-icon" onclick="tglHex()"></i> Color palette</p>
|
||||
@@ -304,10 +304,10 @@
|
||||
</div>
|
||||
<div id="kv">Loading...</div><br>
|
||||
<div>
|
||||
<button class="btn infobtn" onclick="requestJson()">Refresh</button>
|
||||
<button class="btn infobtn" onclick="toggleNodes()">Instance List</button>
|
||||
<button class="btn infobtn" onclick="window.open(getURL('/update'),'_self');">Update WLED</button>
|
||||
<button class="btn infobtn" id="resetbtn" onclick="cnfReset()">Reboot WLED</button>
|
||||
<button class="btn ibtn" onclick="requestJson()">Refresh</button>
|
||||
<button class="btn ibtn" onclick="toggleNodes()">Instance List</button>
|
||||
<button class="btn ibtn" onclick="window.open(getURL('/update'),'_self');">Update WLED</button>
|
||||
<button class="btn ibtn" id="resetbtn" onclick="cnfReset()">Reboot WLED</button>
|
||||
</div>
|
||||
<br>
|
||||
<span class="h">Made with <span id="heart">❤︎</span> by <a href="https://github.com/Aircoookie/" target="_blank">Aircoookie</a> and the <a href="https://wled.discourse.group/" target="_blank">WLED community</a></span>
|
||||
@@ -318,7 +318,7 @@
|
||||
<div id="ndlt">WLED instances</div>
|
||||
<div id="kn">Loading...</div>
|
||||
<div style="position:sticky;bottom:0;">
|
||||
<button class="btn infobtn" onclick="loadNodes()">Refresh</button>
|
||||
<button class="btn ibtn" onclick="loadNodes()">Refresh</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -331,8 +331,8 @@
|
||||
<div id="lv">?</div><br><br>
|
||||
To use built-in effects, use an override button below.<br>
|
||||
You can return to realtime mode by pressing the star in the top left corner.<br>
|
||||
<button class="btn" onclick="setLor(1)">Override once</button>
|
||||
<button class="btn" onclick="setLor(2)">Override until reboot</button><br>
|
||||
<button class="btn ibtn" onclick="setLor(1)">Override once</button>
|
||||
<button class="btn ibtn" onclick="setLor(2)">Override until reboot</button><br>
|
||||
<span class="h">For best performance, it is recommended to turn off the streaming source when not in use.</span>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -773,8 +773,8 @@ function populateSegments(s)
|
||||
}
|
||||
|
||||
let segp = `<div id="segp${i}" class="sbs">`+
|
||||
`<i class="icons slider-icon pwr ${inst.on ? "act":""}" id="seg${i}pwr" onclick="setSegPwr(${i})"></i>`+
|
||||
`<div class="sliderwrap il">`+
|
||||
`<i class="icons slider-icon pwr ${inst.on ? "act":""}" id="seg${i}pwr" title="Power" onclick="setSegPwr(${i})"></i>`+
|
||||
`<div class="sliderwrap il" title="Opacity/Brightness">`+
|
||||
`<input id="seg${i}bri" class="noslide" onchange="setSegBri(${i})" oninput="updateTrail(this)" max="255" min="1" type="range" value="${inst.bri}" />`+
|
||||
`<div class="sliderdisplay"></div>`+
|
||||
`</div>`+
|
||||
@@ -810,7 +810,7 @@ function populateSegments(s)
|
||||
cn += `<div class="seg lstI ${i==s.mainseg && !simplifiedUI ? 'selected' : ''} ${exp ? "expanded":""}" id="seg${i}" data-set="${inst.set}">`+
|
||||
`<label class="check schkl ${smpl}">`+
|
||||
`<input type="checkbox" id="seg${i}sel" onchange="selSeg(${i})" ${inst.sel ? "checked":""}>`+
|
||||
`<span class="checkmark"></span>`+
|
||||
`<span class="checkmark" title="Select"></span>`+
|
||||
`</label>`+
|
||||
`<div class="segname ${smpl}" onclick="selSegEx(${i})">`+
|
||||
`<i class="icons e-icon frz" id="seg${i}frz" title="(un)Freeze" onclick="event.preventDefault();tglFreeze(${i});">&#x${inst.frz ? (li.live && li.liveseg==i?'e410':'e0e8') : 'e325'};</i>`+
|
||||
@@ -1659,13 +1659,17 @@ function setEffectParameters(idx)
|
||||
paOnOff[0] = paOnOff[0].substring(0,dPos);
|
||||
}
|
||||
if (paOnOff.length>0 && paOnOff[0] != "!") text = paOnOff[0];
|
||||
gId("adPal").classList.remove("hide");
|
||||
if (lastinfo.cpalcount>0) gId("rmPal").classList.remove("hide");
|
||||
} else {
|
||||
// disable palette list
|
||||
text += ' not used';
|
||||
palw.style.display = "none";
|
||||
gId("adPal").classList.add("hide");
|
||||
gId("rmPal").classList.add("hide");
|
||||
// Close palette dialog if not available
|
||||
if (gId("palw").lastElementChild.tagName == "DIALOG") {
|
||||
gId("palw").lastElementChild.close();
|
||||
if (palw.lastElementChild.tagName == "DIALOG") {
|
||||
palw.lastElementChild.close();
|
||||
}
|
||||
}
|
||||
pall.innerHTML = icon + text;
|
||||
@@ -1879,7 +1883,7 @@ function makeSeg()
|
||||
function resetUtil(off=false)
|
||||
{
|
||||
gId('segutil').innerHTML = `<div class="seg btn btn-s${off?' off':''}" style="padding:0;margin-bottom:12px;">`
|
||||
+ '<label class="check schkl"><input type="checkbox" id="selall" onchange="selSegAll(this)"><span class="checkmark"></span></label>'
|
||||
+ '<label class="check schkl"><input type="checkbox" id="selall" onchange="selSegAll(this)"><span class="checkmark" title="Select all"></span></label>'
|
||||
+ `<div class="segname" ${off?'':'onclick="makeSeg()"'}><i class="icons btn-icon"></i>Add segment</div>`
|
||||
+ '<div class="pop hide" onclick="event.stopPropagation();">'
|
||||
+ `<i class="icons g-icon" title="Select group" onclick="this.nextElementSibling.classList.toggle('hide');"></i>`
|
||||
@@ -2649,28 +2653,28 @@ function fromRgb()
|
||||
var g = gId('sliderG').value;
|
||||
var b = gId('sliderB').value;
|
||||
setPicker(`rgb(${r},${g},${b})`);
|
||||
let cd = gId('csl').children; // color slots
|
||||
cd[csel].dataset.r = r;
|
||||
cd[csel].dataset.g = g;
|
||||
cd[csel].dataset.b = b;
|
||||
setCSL(cd[csel]);
|
||||
let cd = gId('csl').children[csel]; // color slots
|
||||
cd.dataset.r = r;
|
||||
cd.dataset.g = g;
|
||||
cd.dataset.b = b;
|
||||
setCSL(cd);
|
||||
}
|
||||
|
||||
function fromW()
|
||||
{
|
||||
let w = gId('sliderW');
|
||||
let cd = gId('csl').children; // color slots
|
||||
cd[csel].dataset.w = w.value;
|
||||
setCSL(cd[csel]);
|
||||
let cd = gId('csl').children[csel]; // color slots
|
||||
cd.dataset.w = w.value;
|
||||
setCSL(cd);
|
||||
updateTrail(w);
|
||||
}
|
||||
|
||||
// sr 0: from RGB sliders, 1: from picker, 2: from hex
|
||||
function setColor(sr)
|
||||
{
|
||||
var cd = gId('csl').children; // color slots
|
||||
let cdd = cd[csel].dataset;
|
||||
let w = 0, r,g,b;
|
||||
var cd = gId('csl').children[csel]; // color slots
|
||||
let cdd = cd.dataset;
|
||||
let w = parseInt(cdd.w), r = parseInt(cdd.r), g = parseInt(cdd.g), b = parseInt(cdd.b);
|
||||
if (sr == 1 && isRgbBlack(cdd)) cpick.color.setChannel('hsv', 'v', 100);
|
||||
if (sr != 2 && hasWhite) w = parseInt(gId('sliderW').value);
|
||||
var col = cpick.color.rgb;
|
||||
@@ -2678,7 +2682,7 @@ function setColor(sr)
|
||||
cdd.g = g = hasRGB ? col.g : w;
|
||||
cdd.b = b = hasRGB ? col.b : w;
|
||||
cdd.w = w;
|
||||
setCSL(cd[csel]);
|
||||
setCSL(cd);
|
||||
var obj = {"seg": {"col": [[],[],[]]}};
|
||||
obj.seg.col[csel] = [r, g, b, w];
|
||||
requestJson(obj);
|
||||
@@ -2827,8 +2831,13 @@ function search(field, listId = null) {
|
||||
|
||||
// restore default preset sorting if no search term is entered
|
||||
if (!search) {
|
||||
if (listId === 'pcont') { populatePresets(); return; }
|
||||
if (listId === 'pallist') { populatePalettes(); return; }
|
||||
if (listId === 'pcont') { populatePresets(); return; }
|
||||
if (listId === 'pallist') {
|
||||
let id = parseInt(d.querySelector('#pallist input[name="palette"]:checked').value); // preserve selected palette
|
||||
populatePalettes();
|
||||
updateSelectedPalette(id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// clear filter if searching in fxlist
|
||||
@@ -2841,12 +2850,16 @@ function search(field, listId = null) {
|
||||
|
||||
// filter list items but leave (Default & Solid) always visible
|
||||
const listItems = gId(listId).querySelectorAll('.lstI');
|
||||
listItems.forEach((listItem,i)=>{
|
||||
if (listId!=='pcont' && i===0) return;
|
||||
listItems.forEach((listItem, i) => {
|
||||
if (listId !== 'pcont' && i === 0) return;
|
||||
const listItemName = listItem.querySelector('.lstIname').innerText.toUpperCase();
|
||||
const searchIndex = listItemName.indexOf(field.value.toUpperCase());
|
||||
listItem.style.display = (searchIndex < 0) ? 'none' : '';
|
||||
listItem.dataset.searchIndex = searchIndex;
|
||||
if (searchIndex < 0) {
|
||||
listItem.dataset.searchIndex = Number.MAX_SAFE_INTEGER;
|
||||
} else {
|
||||
listItem.dataset.searchIndex = searchIndex;
|
||||
}
|
||||
listItem.style.display = (searchIndex < 0) && !listItem.classList.contains("selected") ? 'none' : '';
|
||||
});
|
||||
|
||||
// sort list items by search index and name
|
||||
@@ -2887,18 +2900,25 @@ function initFilters() {
|
||||
|
||||
function filterFocus(e) {
|
||||
const f = gId("filters");
|
||||
if (e.type === "focus") f.classList.remove('fade'); // immediately show (still has transition)
|
||||
// compute sticky top (with delay for transition)
|
||||
setTimeout(() => {
|
||||
const sti = parseInt(getComputedStyle(d.documentElement).getPropertyValue('--sti')) + (e.type === "focus" ? 1 : -1) * f.offsetHeight;
|
||||
sCol('--sti', sti + "px");
|
||||
}, 252);
|
||||
const c = !!f.querySelectorAll("input[type=checkbox]:checked").length;
|
||||
const h = f.offsetHeight;
|
||||
const sti = parseInt(getComputedStyle(d.documentElement).getPropertyValue('--sti'));
|
||||
if (e.type === "focus") {
|
||||
// compute sticky top (with delay for transition)
|
||||
if (!h) setTimeout(() => {
|
||||
sCol('--sti', (sti+f.offsetHeight) + "px"); // has an unpleasant consequence on palette offset
|
||||
}, 255);
|
||||
f.classList.remove('fade'); // immediately show (still has transition)
|
||||
}
|
||||
if (e.type === "blur") {
|
||||
setTimeout(() => {
|
||||
if (e.target === document.activeElement && document.hasFocus()) return;
|
||||
// do not hide if filter is active
|
||||
if (gId("filters").querySelectorAll("input[type=checkbox]:checked").length) return;
|
||||
f.classList.add('fade');
|
||||
if (!c) {
|
||||
// compute sticky top
|
||||
sCol('--sti', (sti-h) + "px"); // has an unpleasant consequence on palette offset
|
||||
f.classList.add('fade');
|
||||
}
|
||||
}, 255); // wait with hiding
|
||||
}
|
||||
}
|
||||
@@ -2908,11 +2928,11 @@ function filterFx() {
|
||||
inputField.value = '';
|
||||
inputField.focus();
|
||||
clean(inputField.nextElementSibling);
|
||||
gId("fxlist").querySelectorAll('.lstI').forEach((listItem,i) => {
|
||||
gId("fxlist").querySelectorAll('.lstI').forEach((listItem, i) => {
|
||||
const listItemName = listItem.querySelector('.lstIname').innerText;
|
||||
let hide = false;
|
||||
gId("filters").querySelectorAll("input[type=checkbox]").forEach((e) => { if (e.checked && !listItemName.includes(e.dataset.flt)) hide = true; });
|
||||
listItem.style.display = hide ? 'none' : '';
|
||||
gId("filters").querySelectorAll("input[type=checkbox]").forEach((e) => { if (e.checked && !listItemName.includes(e.dataset.flt)) hide = i > 0 /*true*/; });
|
||||
listItem.style.display = hide && !listItem.classList.contains("selected") ? 'none' : '';
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3098,10 +3118,9 @@ function mergeDeep(target, ...sources)
|
||||
return mergeDeep(target, ...sources);
|
||||
}
|
||||
|
||||
function tooltip(cont=null)
|
||||
{
|
||||
function tooltip(cont=null) {
|
||||
d.querySelectorAll((cont?cont+" ":"")+"[title]").forEach((element)=>{
|
||||
element.addEventListener("mouseover", ()=>{
|
||||
element.addEventListener("pointerover", ()=>{
|
||||
// save title
|
||||
element.setAttribute("data-title", element.getAttribute("title"));
|
||||
const tooltip = d.createElement("span");
|
||||
@@ -3126,7 +3145,7 @@ function tooltip(cont=null)
|
||||
tooltip.classList.add("visible");
|
||||
});
|
||||
|
||||
element.addEventListener("mouseout", ()=>{
|
||||
element.addEventListener("pointerout", ()=>{
|
||||
d.querySelectorAll('.tooltip').forEach((tooltip)=>{
|
||||
tooltip.classList.remove("visible");
|
||||
d.body.removeChild(tooltip);
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
<title>LED Settings</title>
|
||||
<script src="common.js" async type="text/javascript"></script>
|
||||
<script>
|
||||
var laprev=55,maxB=1,maxD=1,maxA=1,maxV=0,maxM=4000,maxPB=2048,maxL=1664,maxCO=5,maxLbquot=0; //maximum bytes for LED allocation: 4kB for 8266, 32kB for 32
|
||||
var oMaxB=1;
|
||||
var maxB=1,maxD=1,maxA=1,maxV=0,maxM=4000,maxPB=2048,maxL=1664,maxCO=5; //maximum bytes for LED allocation: 4kB for 8266, 32kB for 32
|
||||
var customStarts=false,startsDirty=[];
|
||||
function off(n) { gN(n).value = -1;}
|
||||
// these functions correspond to C macros found in const.h
|
||||
@@ -24,6 +23,7 @@
|
||||
function is16b(t) { return !!(gT(t).c & 0x10); } // is digital 16 bit type
|
||||
function mustR(t) { return !!(gT(t).c & 0x20); } // Off refresh is mandatory
|
||||
function numPins(t){ return Math.max(gT(t).t.length, 1); } // type length determines number of GPIO pins
|
||||
function chrID(x) { return String.fromCharCode((x<10?48:55)+x); }
|
||||
function S() {
|
||||
getLoc();
|
||||
loadJS(getURL('/settings/s.js?p=2'), false, ()=>{
|
||||
@@ -42,16 +42,20 @@
|
||||
if (loc) d.Sf.action = getURL('/settings/leds');
|
||||
}
|
||||
function bLimits(b,v,p,m,l,o=5,d=2,a=6) {
|
||||
// maxB - max buses (can be changed if using ESP32 parallel I2S)
|
||||
// maxD - max digital channels (can be changed if using ESP32 parallel I2S)
|
||||
// maxA - max analog channels
|
||||
// maxV - min virtual buses
|
||||
// maxPB - max LEDs per bus
|
||||
// maxM - max LED memory
|
||||
// maxL - max LEDs (will serve to determine ESP >1664 == ESP32)
|
||||
// maxCO - max Color Order mappings
|
||||
oMaxB = maxB = b; maxD = d, maxA = a, maxV = v; maxM = m; maxPB = p; maxL = l; maxCO = o;
|
||||
maxB = b; // maxB - max physical (analog + digital) buses: 32 - ESP32, 14 - S3/S2, 6 - C3, 4 - 8266
|
||||
maxD = d; // maxD - max digital channels (can be changed if using ESP32 parallel I2S): 16 - ESP32, 12 - S3/S2, 2 - C3, 3 - 8266
|
||||
maxA = a; // maxA - max analog channels: 16 - ESP32, 8 - S3/S2, 6 - C3, 5 - 8266
|
||||
maxV = v; // maxV - min virtual buses: 4 - ESP32/S3, 3 - S2/C3, 2 - ESP8266
|
||||
maxPB = p; // maxPB - max LEDs per bus
|
||||
maxM = m; // maxM - max LED memory
|
||||
maxL = l; // maxL - max LEDs (will serve to determine ESP >1664 == ESP32)
|
||||
maxCO = o; // maxCO - max Color Order mappings
|
||||
}
|
||||
function is8266() { return maxA == 5 && maxD == 3; } // NOTE: see const.h
|
||||
function is32() { return maxA == 16 && maxD == 16; } // NOTE: see const.h
|
||||
function isC3() { return maxA == 6 && maxD == 2; } // NOTE: see const.h
|
||||
function isS2() { return maxA == 8 && maxD == 12 && maxV == 4; } // NOTE: see const.h
|
||||
function isS3() { return maxA == 8 && maxD == 12 && maxV == 6; } // NOTE: see const.h
|
||||
function pinsOK() {
|
||||
var ok = true;
|
||||
var nList = d.Sf.querySelectorAll("#mLC input[name^=L]");
|
||||
@@ -119,7 +123,12 @@
|
||||
var en = d.Sf.ABL.checked;
|
||||
gId('abl').style.display = (en) ? 'inline':'none';
|
||||
gId('psu2').style.display = (en) ? 'inline':'none';
|
||||
if (!en) d.Sf.PPL.checked = false;
|
||||
if (!en) {
|
||||
// limiter disabled
|
||||
d.Sf.PPL.checked = false;
|
||||
// d.Sf.querySelectorAll("#mLC select[name^=LAsel]").forEach((e)=>{e.selectedIndex = 0;}); // select default LED mA
|
||||
// d.Sf.querySelectorAll("#mLC input[name^=LA]").forEach((e)=>{e.min = 0; e.value = 0;}); // set min & value to 0
|
||||
}
|
||||
UI();
|
||||
}
|
||||
// enable per port limiter and calculate current
|
||||
@@ -132,46 +141,51 @@
|
||||
d.Sf.MA.min = abl && !ppl ? 250 : 0;
|
||||
gId("psuMA").style.display = ppl ? 'none' : 'inline';
|
||||
gId("ppldis").style.display = ppl ? 'inline' : 'none';
|
||||
// set PPL minimum value and clear actual PPL limit if ABL disabled
|
||||
// set PPL minimum value and clear actual PPL limit if ABL is disabled
|
||||
d.Sf.querySelectorAll("#mLC input[name^=MA]").forEach((i,x)=>{
|
||||
var n = String.fromCharCode((x<10?48:55)+x);
|
||||
var n = chrID(x);
|
||||
gId("PSU"+n).style.display = ppl ? "inline" : "none";
|
||||
const t = parseInt(d.Sf["LT"+n].value); // LED type SELECT
|
||||
const c = parseInt(d.Sf["LC"+n].value); //get LED count
|
||||
i.min = ppl && !(isVir(t) || isAna(t)) ? 250 : 0;
|
||||
if (!abl || isVir(t) || isAna(t)) i.value = 0;
|
||||
i.min = ppl && isDig(t) ? 250 : 0;
|
||||
if (!abl || !isDig(t)) i.value = 0;
|
||||
else if (ppl) sumMA += parseInt(i.value,10);
|
||||
else if (sDI) i.value = Math.round(parseInt(d.Sf.MA.value,10)*c/sDI);
|
||||
});
|
||||
if (ppl) d.Sf.MA.value = sumMA; // populate UI ABL value if PPL used
|
||||
}
|
||||
// enable and update LED Amps
|
||||
function enLA(s,n)
|
||||
{
|
||||
const abl = d.Sf.ABL.checked;
|
||||
const t = parseInt(d.Sf["LT"+n].value); // LED type SELECT
|
||||
gId('LAdis'+n).style.display = s.selectedIndex==5 ? "inline" : "none";
|
||||
if (s.value!=="0") d.Sf["LA"+n].value = s.value;
|
||||
d.Sf["LA"+n].min = (isVir(t) || isAna(t)) ? 0 : 1;
|
||||
gId('LAdis'+n).style.display = s.selectedIndex==5 ? "inline" : "none"; // show/hide custom mA field
|
||||
if (s.value!=="0") d.Sf["LA"+n].value = s.value; // set value from select object
|
||||
d.Sf["LA"+n].min = (!isDig(t) || !abl) ? 0 : 1; // set minimum value for validation
|
||||
}
|
||||
function setABL()
|
||||
{
|
||||
d.Sf.ABL.checked = parseInt(d.Sf.MA.value) > 0;
|
||||
let en = parseInt(d.Sf.MA.value) > 0;
|
||||
// check if ABL is enabled (max mA entered per output)
|
||||
d.Sf.querySelectorAll("#mLC input[name^=MA]").forEach((i,n)=>{
|
||||
if (parseInt(i.value) > 0) d.Sf.ABL.checked = true;
|
||||
if (parseInt(i.value) > 0) en = true;
|
||||
});
|
||||
d.Sf.ABL.checked = en;
|
||||
// select appropriate LED current
|
||||
d.Sf.querySelectorAll("#mLC select[name^=LAsel]").forEach((sel,x)=>{
|
||||
sel.value = 0; // set custom
|
||||
var n = String.fromCharCode((x<10?48:55)+x);
|
||||
switch (parseInt(d.Sf["LA"+n].value)) {
|
||||
case 0: break; // disable ABL
|
||||
case 15: sel.value = 15; break;
|
||||
case 30: sel.value = 30; break;
|
||||
case 35: sel.value = 35; break;
|
||||
case 55: sel.value = 55; break;
|
||||
case 255: sel.value = 255; break;
|
||||
}
|
||||
enLA(sel,n);
|
||||
var n = chrID(x);
|
||||
if (en)
|
||||
switch (parseInt(d.Sf["LA"+n].value)) {
|
||||
case 0: break; // disable ABL
|
||||
case 15: sel.value = 15; break;
|
||||
case 30: sel.value = 30; break;
|
||||
case 35: sel.value = 35; break;
|
||||
case 55: sel.value = 55; break;
|
||||
case 255: sel.value = 255; break;
|
||||
}
|
||||
else sel.value = 0;
|
||||
enLA(sel,n); // configure individual limiter
|
||||
});
|
||||
enABL();
|
||||
gId('m1').innerHTML = maxM;
|
||||
@@ -202,8 +216,7 @@
|
||||
let gRGBW = false, memu = 0;
|
||||
let busMA = 0;
|
||||
let sLC = 0, sPC = 0, sDI = 0, maxLC = 0;
|
||||
const ablEN = d.Sf.ABL.checked;
|
||||
maxB = oMaxB; // TODO make sure we start with all possible buses
|
||||
const abl = d.Sf.ABL.checked;
|
||||
let setPinConfig = (n,t) => {
|
||||
let p0d = "GPIO:";
|
||||
let p1d = "";
|
||||
@@ -241,6 +254,7 @@
|
||||
}
|
||||
|
||||
// enable/disable LED fields
|
||||
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)
|
||||
@@ -248,19 +262,20 @@
|
||||
var n = s.name.substring(2);
|
||||
var t = parseInt(s.value);
|
||||
memu += getMem(t, n); // calc memory
|
||||
dC += (isDig(t) && !isD2P(t));
|
||||
setPinConfig(n,t);
|
||||
gId("abl"+n).style.display = (!ablEN || isVir(t) || isAna(t)) ? "none" : "inline";
|
||||
if (change) {
|
||||
gId("abl"+n).style.display = (!abl || !isDig(t)) ? "none" : "inline"; // show/hide individual ABL settings
|
||||
if (change) { // did we change LED type?
|
||||
gId("rf"+n).checked = (gId("rf"+n).checked || t == 31); // LEDs require data in off state (mandatory for TM1814)
|
||||
if (isAna(t)) d.Sf["LC"+n].value = 1; // for sanity change analog count just to 1 LED
|
||||
d.Sf["LA"+n].min = (isVir(t) || isAna(t)) ? 0 : 1;
|
||||
d.Sf["MA"+n].min = (isVir(t) || isAna(t)) ? 0 : 250;
|
||||
d.Sf["LA"+n].min = (!isDig(t) || !abl) ? 0 : 1; // set minimum value for LED mA
|
||||
d.Sf["MA"+n].min = (!isDig(t)) ? 0 : 250; // set minimum value for PSU mA
|
||||
}
|
||||
gId("rf"+n).onclick = mustR(t) ? (()=>{return false}) : (()=>{}); // prevent change change of "Refresh" checkmark when mandatory
|
||||
gRGBW |= hasW(t); // RGBW checkbox
|
||||
gId("co"+n).style.display = (isVir(t) || isAna(t)) ? "none":"inline"; // hide color order for PWM
|
||||
gId("dig"+n+"w").style.display = (isDig(t) && hasW(t)) ? "inline":"none"; // show swap channels dropdown
|
||||
gId("dig"+n+"w").querySelector("[data-opt=CCT]").disabled = !hasCCT(t); // disable WW/CW swapping
|
||||
gId("dig"+n+"w").querySelector("[data-opt=CCT]").disabled = !hasCCT(t); // disable WW/CW swapping
|
||||
if (!(isDig(t) && hasW(t))) d.Sf["WO"+n].value = 0; // reset swapping
|
||||
gId("dig"+n+"c").style.display = (isAna(t)) ? "none":"inline"; // hide count for analog
|
||||
gId("dig"+n+"r").style.display = (isVir(t)) ? "none":"inline"; // hide reversed for virtual
|
||||
@@ -278,23 +293,27 @@
|
||||
d.Sf.CR.checked = false;
|
||||
}
|
||||
// update start indexes, max values, calculate current, etc
|
||||
let sameType = 0;
|
||||
var nList = d.Sf.querySelectorAll("#mLC input[name^=L]");
|
||||
nList.forEach((LC,i)=>{
|
||||
let nm = LC.name.substring(0,2); // field name
|
||||
let n = LC.name.substring(2); // bus number
|
||||
let t = parseInt(d.Sf["LT"+n].value); // LED type SELECT
|
||||
if (isDig(t)) {
|
||||
if (sameType == 0) sameType = t; // first bus type
|
||||
else if (sameType != t) sameType = -1; // different bus type
|
||||
}
|
||||
// do we have a led count field
|
||||
if (nm=="LC") {
|
||||
let c = parseInt(LC.value,10); //get LED count
|
||||
if (c > 300 && i < 8) maxB = oMaxB - Math.max(maxD-7,0); //TODO: hard limit for buses when using ESP32 parallel I2S
|
||||
if (!customStarts || !startsDirty[n]) gId("ls"+n).value=sLC; //update start value
|
||||
if (!customStarts || !startsDirty[n]) gId("ls"+n).value = sLC; //update start value
|
||||
gId("ls"+n).disabled = !customStarts; //enable/disable field editing
|
||||
if (c) {
|
||||
let s = parseInt(gId("ls"+n).value); //start value
|
||||
if (s+c > sLC) sLC = s+c; //update total count
|
||||
if (c > maxLC) maxLC = c; //max per output
|
||||
if (!isVir(t)) sPC += c; //virtual out busses do not count towards physical LEDs
|
||||
if (!(isVir(t) || isAna(t))) {
|
||||
if (isDig(t)) {
|
||||
sDI += c; // summarize digital LED count
|
||||
let maPL = parseInt(d.Sf["LA"+n].value);
|
||||
if (maPL == 255) maPL = 12;
|
||||
@@ -341,6 +360,13 @@
|
||||
else LC.style.color = d.ro_gpio.some((e)=>e==parseInt(LC.value)) ? "orange" : "#fff";
|
||||
}
|
||||
});
|
||||
if (is32() || isS2() || isS3()) {
|
||||
if (maxLC > 600 || dC < 2 || sameType <= 0) {
|
||||
d.Sf["PR"].checked = false;
|
||||
gId("prl").classList.add("hide");
|
||||
} else
|
||||
gId("prl").classList.remove("hide");
|
||||
} else d.Sf["PR"].checked = false;
|
||||
// distribute ABL current if not using PPL
|
||||
enPPL(sDI);
|
||||
|
||||
@@ -370,10 +396,15 @@
|
||||
gId('psu').innerHTML = s;
|
||||
gId('psu2').innerHTML = s2;
|
||||
gId("json").style.display = d.Sf.IT.value==8 ? "" : "none";
|
||||
|
||||
// show/hide FPS warning messages
|
||||
gId('fpsNone').style.display = (d.Sf.FR.value == 0) ? 'block':'none';
|
||||
gId('fpsWarn').style.display = (d.Sf.FR.value == 0) || (d.Sf.FR.value >= 80) ? 'block':'none';
|
||||
gId('fpsHigh').style.display = (d.Sf.FR.value >= 80) ? 'block':'none';
|
||||
}
|
||||
function lastEnd(i) {
|
||||
if (i-- < 1) return 0;
|
||||
var s = String.fromCharCode((i<10?48:55)+i);
|
||||
var s = chrID(i);
|
||||
v = parseInt(d.getElementsByName("LS"+s)[0].value) + parseInt(d.getElementsByName("LC"+s)[0].value);
|
||||
var t = parseInt(d.getElementsByName("LT"+s)[0].value);
|
||||
if (isPWM(t)) v = 1; //PWM busses
|
||||
@@ -396,7 +427,7 @@
|
||||
});
|
||||
|
||||
if ((n==1 && i>=maxB+maxV) || (n==-1 && i==0)) return;
|
||||
var s = String.fromCharCode((i<10?48:55)+i);
|
||||
var s = chrID(i);
|
||||
|
||||
if (n==1) {
|
||||
// npm run build has trouble minimizing spaces inside string
|
||||
@@ -452,14 +483,17 @@ mA/LED: <select name="LAsel${s}" onchange="enLA(this,'${s}');UI();">
|
||||
if (type.t != undefined && type.t != "") {
|
||||
opt.setAttribute('data-type', type.t);
|
||||
}
|
||||
sel.appendChild(opt);
|
||||
sel.appendChild(opt);
|
||||
}
|
||||
}
|
||||
});
|
||||
enLA(d.Sf["LAsel"+s],s); // update LED mA
|
||||
// disable inappropriate LED types
|
||||
let sel = d.getElementsByName("LT"+s)[0]
|
||||
if (i >= maxB || digitalB >= maxD) disable(sel,'option[data-type="D"]'); // NOTE: see isDig()
|
||||
if (i >= maxB || twopinB >= 1) disable(sel,'option[data-type="2P"]'); // NOTE: see isD2P()
|
||||
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.selectedIndex = sel.querySelector('option:not(:disabled)').index;
|
||||
}
|
||||
@@ -479,7 +513,7 @@ mA/LED: <select name="LAsel${s}" onchange="enLA(this,'${s}');UI();">
|
||||
function addCOM(start=0,len=1,co=0) {
|
||||
var i = gEBCN("com_entry").length;
|
||||
if (i >= maxCO) return;
|
||||
var s = String.fromCharCode((i<10?48:55)+i);
|
||||
var s = chrID(i);
|
||||
var b = `<div class="com_entry">
|
||||
<hr class="sml">
|
||||
${i+1}: Start: <input type="number" name="XS${s}" id="xs${s}" class="l starts" min="0" max="65535" value="${start}" oninput="UI();" required="">
|
||||
@@ -533,7 +567,7 @@ Swap: <select id="xw${s}" name="XW${s}">
|
||||
|
||||
function addBtn(i,p,t) {
|
||||
var c = gId("btns").innerHTML;
|
||||
var s = String.fromCharCode((i<10?48:55)+i);
|
||||
var s = chrID(i);
|
||||
c += `Button ${i} GPIO: <input type="number" name="BT${s}" onchange="UI()" class="xs" value="${p}">`;
|
||||
c += ` <select name="BE${s}">`
|
||||
c += `<option value="0" ${t==0?"selected":""}>Disabled</option>`;
|
||||
@@ -557,8 +591,10 @@ Swap: <select id="xw${s}" name="XW${s}">
|
||||
function checkSi() { //on load, checks whether there are custom start fields
|
||||
var cs = false;
|
||||
for (var i=1; i < gEBCN("iST").length; i++) {
|
||||
var v = parseInt(gId("ls"+(i-1)).value) + parseInt(gN("LC"+(i-1)).value);
|
||||
if (v != parseInt(gId("ls"+i).value)) {cs = true; startsDirty[i] = true;}
|
||||
var s = chrID(i);
|
||||
var p = chrID(i-1); // cover edge case 'A' previous char being '9'
|
||||
var v = parseInt(gId("ls"+p).value) + parseInt(gN("LC"+p).value);
|
||||
if (v != parseInt(gId("ls"+s).value)) {cs = true; startsDirty[i] = true;}
|
||||
}
|
||||
if (gId("ls0") && parseInt(gId("ls0").value) != 0) {cs = true; startsDirty[0] = true;}
|
||||
gId("si").checked = cs;
|
||||
@@ -587,10 +623,10 @@ Swap: <select id="xw${s}" name="XW${s}">
|
||||
|
||||
function receivedText(e) {
|
||||
let lines = e.target.result;
|
||||
var c = JSON.parse(lines);
|
||||
var c = JSON.parse(lines);
|
||||
if (c.hw) {
|
||||
if (c.hw.led) {
|
||||
for (var i=0; i<10; i++) addLEDs(-1);
|
||||
for (var i=0; i<oMaxB+maxV; i++) addLEDs(-1);
|
||||
var l = c.hw.led;
|
||||
l.ins.forEach((v,i,a)=>{
|
||||
addLEDs(1);
|
||||
@@ -762,8 +798,11 @@ Swap: <select id="xw${s}" name="XW${s}">
|
||||
</div>
|
||||
</div>
|
||||
<h3>Hardware setup</h3>
|
||||
<div id="mLC">LED outputs:</div>
|
||||
<hr class="sml">
|
||||
<div id="mLC">
|
||||
LED outputs:<br>
|
||||
<hr class="sml">
|
||||
<i>Only last output can be changed. Remove to edit others.</i><br>
|
||||
</div>
|
||||
<button type="button" id="+" onclick="addLEDs(1,false)">+</button>
|
||||
<button type="button" id="-" onclick="addLEDs(-1,false)">-</button><br>
|
||||
LED memory usage: <span id="m0">0</span> / <span id="m1">?</span> B<br>
|
||||
@@ -773,6 +812,7 @@ Swap: <select id="xw${s}" name="XW${s}">
|
||||
Use less than <span id="wreason">800 LEDs per output</span> for the best experience!<br>
|
||||
</div>
|
||||
<hr class="sml">
|
||||
<div id="prl" class="hide">Use parallel I2S: <input type="checkbox" name="PR"><br></div>
|
||||
Make a segment for each output: <input type="checkbox" name="MS"><br>
|
||||
Custom bus start indices: <input type="checkbox" onchange="tglSi(this.checked)" id="si"><br>
|
||||
Use global LED buffer: <input type="checkbox" name="LD" onchange="UI()"><br>
|
||||
@@ -860,7 +900,10 @@ Swap: <select id="xw${s}" name="XW${s}">
|
||||
<option value="2">Linear (never wrap)</option>
|
||||
<option value="3">None (not recommended)</option>
|
||||
</select><br>
|
||||
Target refresh rate: <input type="number" class="s" min="1" max="120" name="FR" required> FPS
|
||||
Target refresh rate: <input type="number" class="s" min="0" max="250" name="FR" oninput="UI()" required> FPS
|
||||
<div id="fpsNone" class="warn" style="display: none;">⚠ Unlimited FPS Mode is experimental ⚠<br></div>
|
||||
<div id="fpsHigh" class="warn" style="display: none;">⚠ High FPS Mode is experimental.<br></div>
|
||||
<div id="fpsWarn" class="warn" style="display: none;">Please <a class="lnk" href="sec#backup">backup</a> WLED configuration and presets first!<br></div>
|
||||
<hr class="sml">
|
||||
<div id="cfg">Config template: <input type="file" name="data2" accept=".json"><button type="button" class="sml" onclick="loadCfg(d.Sf.data2)">Apply</button><br></div>
|
||||
<hr>
|
||||
|
||||
@@ -57,11 +57,11 @@
|
||||
<h3>Software Update</h3>
|
||||
<button type="button" onclick="U()">Manual OTA Update</button><br>
|
||||
Enable ArduinoOTA: <input type="checkbox" name="AO">
|
||||
<hr>
|
||||
<hr id="backup">
|
||||
<h3>Backup & Restore</h3>
|
||||
<div class="warn">⚠ Restoring presets/configuration will OVERWRITE your current presets/configuration.<br>
|
||||
Incorrect upload or configuration may require a factory reset or re-flashing of your ESP.</div>
|
||||
For security reasons, passwords are not backed up.
|
||||
Incorrect upload or configuration may require a factory reset or re-flashing of your ESP.<br>
|
||||
For security reasons, passwords are not backed up.</div>
|
||||
<a class="btn lnk" id="bckcfg" href="/presets.json" download="presets">Backup presets</a><br>
|
||||
<div>Restore presets<br><input type="file" name="data" accept=".json"> <button type="button" onclick="uploadFile(d.Sf.data,'/presets.json');">Upload</button><br></div><br>
|
||||
<a class="btn lnk" id="bckpresets" href="/cfg.json" download="cfg">Backup configuration</a><br>
|
||||
@@ -72,10 +72,10 @@
|
||||
<a href="https://github.com/Aircoookie/WLED/wiki/Contributors-and-credits" target="_blank">Contributors, dependencies and special thanks</a><br>
|
||||
A huge thank you to everyone who helped me create WLED!<br><br>
|
||||
(c) 2016-2024 Christian Schwinne <br>
|
||||
<i>Licensed under the <a href="https://github.com/Aircoookie/WLED/blob/master/LICENSE" target="_blank">MIT license</a></i><br><br>
|
||||
Server message: <span class="sip"> Response error! </span><hr>
|
||||
<i>Licensed under the <a href="https://github.com/Aircoookie/WLED/blob/master/LICENSE" target="_blank">EUPL v1.2 license</a></i><br><br>
|
||||
Installed version: <span class="sip">WLED ##VERSION##</span><hr>
|
||||
<div id="toast"></div>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save</button>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -156,6 +156,7 @@
|
||||
<option value="20">AKST/AKDT (Anchorage)</option>
|
||||
<option value="21">MX-CST</option>
|
||||
<option value="22">PKT (Pakistan)</option>
|
||||
<option value="23">BRT (Brasília)</option>
|
||||
</select><br>
|
||||
UTC offset: <input name="UO" type="number" min="-65500" max="65500" required> seconds (max. 18 hours)<br>
|
||||
Current local time is <span class="times">unknown</span>.<br>
|
||||
|
||||
@@ -16,8 +16,9 @@
|
||||
<body onload="GetV()">
|
||||
<h2>WLED Software Update</h2>
|
||||
<form method='POST' action='./update' id='uf' enctype='multipart/form-data' onsubmit="U()">
|
||||
Installed version: <span class="sip">##VERSION##</span><br>
|
||||
Download the latest binary: <a href="https://github.com/Aircoookie/WLED/releases" target="_blank">
|
||||
Installed version: <span class="sip">WLED ##VERSION##</span><br>
|
||||
Download the latest binary: <a href="https://github.com/Aircoookie/WLED/releases" target="_blank"
|
||||
style="vertical-align: text-bottom; display: inline-flex;">
|
||||
<img src="https://img.shields.io/github/release/Aircoookie/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-->
|
||||
<button type="submit">Update!</button><br>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#pragma once
|
||||
#ifndef WLED_FCN_DECLARE_H
|
||||
#define WLED_FCN_DECLARE_H
|
||||
|
||||
@@ -24,7 +25,7 @@ void IRAM_ATTR touchButtonISR();
|
||||
|
||||
//cfg.cpp
|
||||
bool deserializeConfig(JsonObject doc, bool fromFS = false);
|
||||
void deserializeConfigFromFS();
|
||||
bool deserializeConfigFromFS();
|
||||
bool deserializeConfigSec();
|
||||
void serializeConfig();
|
||||
void serializeConfigSec();
|
||||
@@ -169,7 +170,6 @@ bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient = 0);
|
||||
void setValuesFromSegment(uint8_t s);
|
||||
void setValuesFromMainSeg();
|
||||
void setValuesFromFirstSelectedSeg();
|
||||
void resetTimebase();
|
||||
void toggleOnOff();
|
||||
void applyBri();
|
||||
void applyFinalBri();
|
||||
@@ -231,7 +231,8 @@ void deletePreset(byte index);
|
||||
bool getPresetName(byte index, String& name);
|
||||
|
||||
//remote.cpp
|
||||
void handleRemote(uint8_t *data, size_t len);
|
||||
void handleWiZdata(uint8_t *incomingData, size_t len);
|
||||
void handleRemote();
|
||||
|
||||
//set.cpp
|
||||
bool isAsterisksOnly(const char* str, byte maxLen);
|
||||
@@ -302,7 +303,7 @@ class Usermod {
|
||||
virtual bool handleButton(uint8_t b) { return false; } // button overrides are possible here
|
||||
virtual bool getUMData(um_data_t **data) { if (data) *data = nullptr; return false; }; // usermod data exchange [see examples for audio effects]
|
||||
virtual void connected() {} // called when WiFi is (re)connected
|
||||
virtual void appendConfigData() {} // helper function called from usermod settings page to add metadata for entry fields
|
||||
virtual void appendConfigData(Print& settingsScript); // helper function called from usermod settings page to add metadata for entry fields
|
||||
virtual void addToJsonState(JsonObject& obj) {} // add JSON objects for WLED state
|
||||
virtual void addToJsonInfo(JsonObject& obj) {} // add JSON objects for UI Info page
|
||||
virtual void readFromJsonState(JsonObject& obj) {} // process JSON messages received from web server
|
||||
@@ -314,6 +315,20 @@ class Usermod {
|
||||
virtual void onUpdateBegin(bool) {} // fired prior to and after unsuccessful firmware update
|
||||
virtual void onStateChange(uint8_t mode) {} // fired upon WLED state change
|
||||
virtual uint16_t getId() {return USERMOD_ID_UNSPECIFIED;}
|
||||
|
||||
// API shims
|
||||
private:
|
||||
static Print* oappend_shim;
|
||||
// old form of appendConfigData; called by default appendConfigData(Print&) with oappend_shim set up
|
||||
// private so it is not accidentally invoked except via Usermod::appendConfigData(Print&)
|
||||
virtual void appendConfigData() {}
|
||||
protected:
|
||||
// Shim for oappend(), which used to exist in utils.cpp
|
||||
template<typename T> static inline void oappend(const T& t) { oappend_shim->print(t); };
|
||||
#ifdef ESP8266
|
||||
// Handle print(PSTR()) without crashing by detecting PROGMEM strings
|
||||
static void oappend(const char* c) { if ((intptr_t) c >= 0x40000000) oappend_shim->print(FPSTR(c)); else oappend_shim->print(c); };
|
||||
#endif
|
||||
};
|
||||
|
||||
class UsermodManager {
|
||||
@@ -328,7 +343,7 @@ class UsermodManager {
|
||||
static bool getUMData(um_data_t **um_data, uint8_t mod_id = USERMOD_ID_RESERVED); // USERMOD_ID_RESERVED will poll all usermods
|
||||
static void setup();
|
||||
static void connected();
|
||||
static void appendConfigData();
|
||||
static void appendConfigData(Print&);
|
||||
static void addToJsonState(JsonObject& obj);
|
||||
static void addToJsonInfo(JsonObject& obj);
|
||||
static void readFromJsonState(JsonObject& obj);
|
||||
@@ -359,13 +374,14 @@ void userLoop();
|
||||
//util.cpp
|
||||
int getNumVal(const String* req, uint16_t pos);
|
||||
void parseNumber(const char* str, byte* val, byte minv=0, byte maxv=255);
|
||||
bool getVal(JsonVariant elem, byte* val, byte minv=0, byte maxv=255);
|
||||
bool getVal(JsonVariant elem, byte* val, byte minv=0, byte maxv=255); // getVal supports inc/decrementing and random ("X~Y(r|~[w][-][Z])" form)
|
||||
bool getBoolVal(JsonVariant elem, bool dflt);
|
||||
bool updateVal(const char* req, const char* key, byte* val, byte minv=0, byte maxv=255);
|
||||
bool oappend(const char* txt); // append new c string to temp buffer efficiently
|
||||
bool oappendi(int i); // append new number to temp buffer efficiently
|
||||
void sappend(char stype, const char* key, int val);
|
||||
void sappends(char stype, const char* key, char* val);
|
||||
size_t printSetFormCheckbox(Print& settingsScript, const char* key, int val);
|
||||
size_t printSetFormValue(Print& settingsScript, const char* key, int val);
|
||||
size_t printSetFormValue(Print& settingsScript, const char* key, const char* val);
|
||||
size_t printSetFormIndex(Print& settingsScript, const char* key, int index);
|
||||
size_t printSetClassElementHTML(Print& settingsScript, const char* key, const int index, const char* val);
|
||||
void prepareHostname(char* hostname);
|
||||
bool isAsterisksOnly(const char* str, byte maxLen);
|
||||
bool requestJSONBufferLock(uint8_t module=255);
|
||||
@@ -375,6 +391,9 @@ uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxL
|
||||
int16_t extractModeDefaults(uint8_t mode, const char *segVar);
|
||||
void checkSettingsPIN(const char *pin);
|
||||
uint16_t crc16(const unsigned char* data_p, size_t length);
|
||||
uint16_t beatsin88_t(accum88 beats_per_minute_88, uint16_t lowest = 0, uint16_t highest = 65535, uint32_t timebase = 0, uint16_t phase_offset = 0);
|
||||
uint16_t beatsin16_t(accum88 beats_per_minute, uint16_t lowest = 0, uint16_t highest = 65535, uint32_t timebase = 0, uint16_t phase_offset = 0);
|
||||
uint8_t beatsin8_t(accum88 beats_per_minute, uint8_t lowest = 0, uint8_t highest = 255, uint32_t timebase = 0, uint8_t phase_offset = 0);
|
||||
um_data_t* simulateSound(uint8_t simulationId);
|
||||
void enumerateLedmaps();
|
||||
uint8_t get_random_wheel_index(uint8_t pos);
|
||||
@@ -405,27 +424,37 @@ void clearEEPROM();
|
||||
#endif
|
||||
|
||||
//wled_math.cpp
|
||||
#if defined(ESP8266) && !defined(WLED_USE_REAL_MATH)
|
||||
template <typename T> T atan_t(T x);
|
||||
float cos_t(float phi);
|
||||
float sin_t(float x);
|
||||
float tan_t(float x);
|
||||
float acos_t(float x);
|
||||
float asin_t(float x);
|
||||
float floor_t(float x);
|
||||
float fmod_t(float num, float denom);
|
||||
#else
|
||||
#include <math.h>
|
||||
#define sin_t sinf
|
||||
#define cos_t cosf
|
||||
#define tan_t tanf
|
||||
#define asin_t asinf
|
||||
#define acos_t acosf
|
||||
#define atan_t atanf
|
||||
#define fmod_t fmodf
|
||||
#define floor_t floorf
|
||||
#endif
|
||||
//float cos_t(float phi); // use float math
|
||||
//float sin_t(float phi);
|
||||
//float tan_t(float x);
|
||||
int16_t sin16_t(uint16_t theta);
|
||||
int16_t cos16_t(uint16_t theta);
|
||||
uint8_t sin8_t(uint8_t theta);
|
||||
uint8_t cos8_t(uint8_t theta);
|
||||
float sin_approx(float theta); // uses integer math (converted to float), accuracy +/-0.0015 (compared to sinf())
|
||||
float cos_approx(float theta);
|
||||
float tan_approx(float x);
|
||||
float atan2_t(float y, float x);
|
||||
float acos_t(float x);
|
||||
float asin_t(float x);
|
||||
template <typename T> T atan_t(T x);
|
||||
float floor_t(float x);
|
||||
float fmod_t(float num, float denom);
|
||||
#define sin_t sin_approx
|
||||
#define cos_t cos_approx
|
||||
#define tan_t tan_approx
|
||||
|
||||
/*
|
||||
#include <math.h> // standard math functions. use a lot of flash
|
||||
#define sin_t sinf
|
||||
#define cos_t cosf
|
||||
#define tan_t tanf
|
||||
#define asin_t asinf
|
||||
#define acos_t acosf
|
||||
#define atan_t atanf
|
||||
#define fmod_t fmodf
|
||||
#define floor_t floorf
|
||||
*/
|
||||
//wled_serial.cpp
|
||||
void handleSerial();
|
||||
void updateBaudRate(uint32_t rate);
|
||||
@@ -444,7 +473,7 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
|
||||
void sendDataWs(AsyncWebSocketClient * client = nullptr);
|
||||
|
||||
//xml.cpp
|
||||
void XML_response(AsyncWebServerRequest *request, char* dest = nullptr);
|
||||
void getSettingsJS(byte subPage, char* dest);
|
||||
void XML_response(Print& dest);
|
||||
void getSettingsJS(byte subPage, Print& dest);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -433,7 +433,7 @@ bool handleFileRead(AsyncWebServerRequest* request, String path){
|
||||
}
|
||||
#endif
|
||||
if(WLED_FS.exists(path) || WLED_FS.exists(path + ".gz")) {
|
||||
request->send(WLED_FS, path, String(), request->hasArg(F("download")));
|
||||
request->send(request->beginResponse(WLED_FS, path, {}, request->hasArg(F("download")), {}));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -195,9 +195,9 @@ void onHueData(void* arg, AsyncClient* client, void *data, size_t len)
|
||||
{
|
||||
switch(hueColormode)
|
||||
{
|
||||
case 1: if (hueX != hueXLast || hueY != hueYLast) colorXYtoRGB(hueX,hueY,col); hueXLast = hueX; hueYLast = hueY; break;
|
||||
case 2: if (hueHue != hueHueLast || hueSat != hueSatLast) colorHStoRGB(hueHue,hueSat,col); hueHueLast = hueHue; hueSatLast = hueSat; break;
|
||||
case 3: if (hueCt != hueCtLast) colorCTtoRGB(hueCt,col); hueCtLast = hueCt; break;
|
||||
case 1: if (hueX != hueXLast || hueY != hueYLast) colorXYtoRGB(hueX,hueY,colPri); hueXLast = hueX; hueYLast = hueY; break;
|
||||
case 2: if (hueHue != hueHueLast || hueSat != hueSatLast) colorHStoRGB(hueHue,hueSat,colPri); hueHueLast = hueHue; hueSatLast = hueSat; break;
|
||||
case 3: if (hueCt != hueCtLast) colorCTtoRGB(hueCt,colPri); hueCtLast = hueCt; break;
|
||||
}
|
||||
}
|
||||
hueReceived = true;
|
||||
|
||||
@@ -123,6 +123,7 @@ void handleImprovPacket() {
|
||||
}
|
||||
|
||||
checksum += next;
|
||||
checksum &= 0xFF;
|
||||
packetByte++;
|
||||
}
|
||||
}
|
||||
@@ -193,24 +194,22 @@ void sendImprovIPRPCResult(ImprovRPCType type) {
|
||||
}
|
||||
|
||||
void sendImprovInfoResponse() {
|
||||
const char* bString =
|
||||
#ifdef ESP8266
|
||||
"esp8266"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
"esp32-c3"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
"esp32-s2"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
"esp32-s3";
|
||||
#else // ESP32
|
||||
"esp32";
|
||||
#endif
|
||||
;
|
||||
|
||||
char bString[32];
|
||||
#ifdef ESP8266
|
||||
strcpy(bString, "esp8266");
|
||||
#else // ESP32
|
||||
strncpy(bString, ESP.getChipModel(), 31);
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
bString[5] = '\0'; // disregard chip revision for classic ESP32
|
||||
#else
|
||||
bString[31] = '\0'; // just in case
|
||||
#endif
|
||||
strlwr(bString);
|
||||
#endif
|
||||
//Use serverDescription if it has been changed from the default "WLED", else mDNS name
|
||||
bool useMdnsName = (strcmp(serverDescription, "WLED") == 0 && strlen(cmDNS) > 0);
|
||||
char vString[20];
|
||||
sprintf_P(vString, PSTR("0.15.0-b5/%i"), VERSION);
|
||||
char vString[32];
|
||||
sprintf_P(vString, PSTR("%s/%i"), versionString, VERSION);
|
||||
const char *str[4] = {"WLED", vString, bString, useMdnsName ? cmDNS : serverDescription};
|
||||
|
||||
sendImprovRPCResult(ImprovRPCType::Request_Info, 4, str);
|
||||
|
||||
143
wled00/json.cpp
143
wled00/json.cpp
@@ -91,19 +91,20 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t grp = elem["grp"] | seg.grouping;
|
||||
uint16_t spc = elem[F("spc")] | seg.spacing;
|
||||
uint16_t of = seg.offset;
|
||||
uint8_t soundSim = elem["si"] | seg.soundSim;
|
||||
uint8_t map1D2D = elem["m12"] | seg.map1D2D;
|
||||
|
||||
if ((spc>0 && spc!=seg.spacing) || seg.map1D2D!=map1D2D) seg.fill(BLACK); // clear spacing gaps
|
||||
|
||||
seg.map1D2D = constrain(map1D2D, 0, 7);
|
||||
seg.soundSim = constrain(soundSim, 0, 3);
|
||||
|
||||
uint8_t set = elem[F("set")] | seg.set;
|
||||
seg.set = constrain(set, 0, 3);
|
||||
uint16_t grp = elem["grp"] | seg.grouping;
|
||||
uint16_t spc = elem[F("spc")] | seg.spacing;
|
||||
uint16_t of = seg.offset;
|
||||
uint8_t soundSim = elem["si"] | seg.soundSim;
|
||||
uint8_t map1D2D = elem["m12"] | seg.map1D2D;
|
||||
uint8_t set = elem[F("set")] | seg.set;
|
||||
bool selected = getBoolVal(elem["sel"], seg.selected);
|
||||
bool reverse = getBoolVal(elem["rev"], seg.reverse);
|
||||
bool mirror = getBoolVal(elem["mi"] , seg.mirror);
|
||||
#ifndef WLED_DISABLE_2D
|
||||
bool reverse_y = getBoolVal(elem["rY"] , seg.reverse_y);
|
||||
bool mirror_y = getBoolVal(elem["mY"] , seg.mirror_y);
|
||||
bool transpose = getBoolVal(elem[F("tp")], seg.transpose);
|
||||
#endif
|
||||
|
||||
int len = 1;
|
||||
if (stop > start) len = stop - start;
|
||||
@@ -117,7 +118,7 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
if (stop > start && of > len -1) of = len -1;
|
||||
|
||||
// update segment (delete if necessary)
|
||||
seg.setUp(start, stop, grp, spc, of, startY, stopY); // strip needs to be suspended for this to work without issues
|
||||
seg.setGeometry(start, stop, grp, spc, of, startY, stopY, map1D2D); // strip needs to be suspended for this to work without issues
|
||||
|
||||
if (newSeg) seg.refreshLightCapabilities(); // fix for #3403
|
||||
|
||||
@@ -206,47 +207,30 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
}
|
||||
#endif
|
||||
|
||||
//seg.map1D2D = constrain(map1D2D, 0, 7); // done in setGeometry()
|
||||
seg.set = constrain(set, 0, 3);
|
||||
seg.soundSim = constrain(soundSim, 0, 3);
|
||||
seg.selected = selected;
|
||||
seg.reverse = reverse;
|
||||
seg.mirror = mirror;
|
||||
#ifndef WLED_DISABLE_2D
|
||||
bool reverse = seg.reverse;
|
||||
bool mirror = seg.mirror;
|
||||
#endif
|
||||
seg.selected = getBoolVal(elem["sel"], seg.selected);
|
||||
seg.reverse = getBoolVal(elem["rev"], seg.reverse);
|
||||
seg.mirror = getBoolVal(elem["mi"] , seg.mirror);
|
||||
#ifndef WLED_DISABLE_2D
|
||||
bool reverse_y = seg.reverse_y;
|
||||
bool mirror_y = seg.mirror_y;
|
||||
seg.reverse_y = getBoolVal(elem["rY"] , seg.reverse_y);
|
||||
seg.mirror_y = getBoolVal(elem["mY"] , seg.mirror_y);
|
||||
seg.transpose = getBoolVal(elem[F("tp")], seg.transpose);
|
||||
if (seg.is2D() && seg.map1D2D == M12_pArc && (reverse != seg.reverse || reverse_y != seg.reverse_y || mirror != seg.mirror || mirror_y != seg.mirror_y)) seg.fill(BLACK); // clear entire segment (in case of Arc 1D to 2D expansion)
|
||||
seg.reverse_y = reverse_y;
|
||||
seg.mirror_y = mirror_y;
|
||||
seg.transpose = transpose;
|
||||
#endif
|
||||
|
||||
byte fx = seg.mode;
|
||||
byte last = strip.getModeCount();
|
||||
// partial fix for #3605
|
||||
if (!elem["fx"].isNull() && elem["fx"].is<const char*>()) {
|
||||
const char *tmp = elem["fx"].as<const char *>();
|
||||
if (strlen(tmp) > 3 && (strchr(tmp,'r') || strchr(tmp,'~') != strrchr(tmp,'~'))) last = 0; // we have "X~Y(r|[w]~[-])" form
|
||||
}
|
||||
// end fix
|
||||
if (getVal(elem["fx"], &fx, 0, last)) { //load effect ('r' random, '~' inc/dec, 0-255 exact value, 5~10r pick random between 5 & 10)
|
||||
if (getVal(elem["fx"], &fx, 0, strip.getModeCount())) {
|
||||
if (!presetId && currentPlaylist>=0) unloadPlaylist();
|
||||
if (fx != seg.mode) seg.setMode(fx, elem[F("fxdef")]);
|
||||
}
|
||||
|
||||
//getVal also supports inc/decrementing and random
|
||||
getVal(elem["sx"], &seg.speed);
|
||||
getVal(elem["ix"], &seg.intensity);
|
||||
|
||||
uint8_t pal = seg.palette;
|
||||
last = strip.getPaletteCount();
|
||||
if (!elem["pal"].isNull() && elem["pal"].is<const char*>()) {
|
||||
const char *tmp = elem["pal"].as<const char *>();
|
||||
if (strlen(tmp) > 3 && (strchr(tmp,'r') || strchr(tmp,'~') != strrchr(tmp,'~'))) last = 0; // we have "X~Y(r|[w]~[-])" form
|
||||
}
|
||||
if (seg.getLightCapabilities() & 1) { // ignore palette for White and On/Off segments
|
||||
if (getVal(elem["pal"], &pal, 0, last)) seg.setPalette(pal);
|
||||
if (getVal(elem["pal"], &pal, 0, strip.getPaletteCount())) seg.setPalette(pal);
|
||||
}
|
||||
|
||||
getVal(elem["c1"], &seg.custom1);
|
||||
@@ -346,7 +330,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
}
|
||||
}
|
||||
|
||||
int tr = -1;
|
||||
long tr = -1;
|
||||
if (!presetId || currentPlaylist < 0) { //do not apply transition time from preset if playlist active, as it would override playlist transition times
|
||||
tr = root[F("transition")] | -1;
|
||||
if (tr >= 0) {
|
||||
@@ -363,7 +347,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
}
|
||||
|
||||
tr = root[F("tb")] | -1;
|
||||
if (tr >= 0) strip.timebase = ((uint32_t)tr) - millis();
|
||||
if (tr >= 0) strip.timebase = (unsigned long)tr - millis();
|
||||
|
||||
JsonObject nl = root["nl"];
|
||||
nightlightActive = getBoolVal(nl["on"], nightlightActive);
|
||||
@@ -406,35 +390,38 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
|
||||
int it = 0;
|
||||
JsonVariant segVar = root["seg"];
|
||||
if (!segVar.isNull()) strip.suspend();
|
||||
if (segVar.is<JsonObject>())
|
||||
{
|
||||
int id = segVar["id"] | -1;
|
||||
//if "seg" is not an array and ID not specified, apply to all selected/checked segments
|
||||
if (id < 0) {
|
||||
//apply all selected segments
|
||||
//bool didSet = false;
|
||||
for (size_t s = 0; s < strip.getSegmentsNum(); s++) {
|
||||
Segment &sg = strip.getSegment(s);
|
||||
if (sg.isActive() && sg.isSelected()) {
|
||||
deserializeSegment(segVar, s, presetId);
|
||||
//didSet = true;
|
||||
if (!segVar.isNull()) {
|
||||
// we may be called during strip.service() so we must not modify segments while effects are executing
|
||||
strip.suspend();
|
||||
const unsigned long waitUntil = millis() + strip.getFrameTime();
|
||||
while (strip.isServicing() && millis() < waitUntil) delay(1); // wait until frame is over
|
||||
#ifdef WLED_DEBUG
|
||||
if (millis() >= waitUntil) DEBUG_PRINTLN(F("JSON: Waited for strip to finish servicing."));
|
||||
#endif
|
||||
if (segVar.is<JsonObject>()) {
|
||||
int id = segVar["id"] | -1;
|
||||
//if "seg" is not an array and ID not specified, apply to all selected/checked segments
|
||||
if (id < 0) {
|
||||
//apply all selected segments
|
||||
for (size_t s = 0; s < strip.getSegmentsNum(); s++) {
|
||||
Segment &sg = strip.getSegment(s);
|
||||
if (sg.isActive() && sg.isSelected()) {
|
||||
deserializeSegment(segVar, s, presetId);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
deserializeSegment(segVar, id, presetId); //apply only the segment with the specified ID
|
||||
}
|
||||
//TODO: not sure if it is good idea to change first active but unselected segment
|
||||
//if (!didSet) deserializeSegment(segVar, strip.getMainSegmentId(), presetId);
|
||||
} else {
|
||||
deserializeSegment(segVar, id, presetId); //apply only the segment with the specified ID
|
||||
size_t deleted = 0;
|
||||
JsonArray segs = segVar.as<JsonArray>();
|
||||
for (JsonObject elem : segs) {
|
||||
if (deserializeSegment(elem, it++, presetId) && !elem["stop"].isNull() && elem["stop"]==0) deleted++;
|
||||
}
|
||||
if (strip.getSegmentsNum() > 3 && deleted >= strip.getSegmentsNum()/2U) strip.purgeSegments(); // batch deleting more than half segments
|
||||
}
|
||||
} else {
|
||||
size_t deleted = 0;
|
||||
JsonArray segs = segVar.as<JsonArray>();
|
||||
for (JsonObject elem : segs) {
|
||||
if (deserializeSegment(elem, it++, presetId) && !elem["stop"].isNull() && elem["stop"]==0) deleted++;
|
||||
}
|
||||
if (strip.getSegmentsNum() > 3 && deleted >= strip.getSegmentsNum()/2U) strip.purgeSegments(); // batch deleting more than half segments
|
||||
strip.resume();
|
||||
}
|
||||
strip.resume();
|
||||
|
||||
UsermodManager::readFromJsonState(root);
|
||||
|
||||
@@ -454,21 +441,25 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
handleSet(nullptr, apireq, false); // may set stateChanged
|
||||
}
|
||||
|
||||
// applying preset (2 cases: a) API call includes all preset values ("pd"), b) API only specifies preset ID ("ps"))
|
||||
// Applying preset from JSON API has 2 cases: a) "pd" AKA "preset direct" and b) "ps" AKA "preset select"
|
||||
// a) "preset direct" can only be an integer value representing preset ID. "preset direct" assumes JSON API contains the rest of preset content (i.e. from UI call)
|
||||
// "preset direct" JSON can contain "ps" API (i.e. call from UI to cycle presets) in such case stateChanged has to be false (i.e. no "win" or "seg" API)
|
||||
// b) "preset select" can be cycling ("1~5~""), random ("r" or "1~5r"), ID, etc. value allowed from JSON API. This type of call assumes no state changing content in API call
|
||||
byte presetToRestore = 0;
|
||||
// a) already applied preset content (requires "seg" or "win" but will ignore the rest)
|
||||
if (!root[F("pd")].isNull() && stateChanged) {
|
||||
// a) already applied preset content (requires "seg" or "win" but will ignore the rest)
|
||||
currentPreset = root[F("pd")] | currentPreset;
|
||||
if (root["win"].isNull()) presetCycCurr = currentPreset; // otherwise it was set in handleSet() [set.cpp]
|
||||
if (root["win"].isNull()) presetCycCurr = currentPreset; // otherwise presetCycCurr was set in handleSet() [set.cpp]
|
||||
presetToRestore = currentPreset; // stateUpdated() will clear the preset, so we need to restore it after
|
||||
DEBUG_PRINTF_P(PSTR("Preset direct: %d\n"), currentPreset);
|
||||
} else if (!root["ps"].isNull()) {
|
||||
ps = presetCycCurr;
|
||||
if (root["win"].isNull() && getVal(root["ps"], &ps, 0, 0) && ps > 0 && ps < 251 && ps != currentPreset) {
|
||||
// we have "ps" call (i.e. from button or external API call) or "pd" that includes "ps" (i.e. from UI call)
|
||||
if (root["win"].isNull() && getVal(root["ps"], &presetCycCurr, 1, 250) && presetCycCurr > 0 && presetCycCurr < 251 && presetCycCurr != currentPreset) {
|
||||
DEBUG_PRINTF_P(PSTR("Preset select: %d\n"), presetCycCurr);
|
||||
// b) preset ID only or preset that does not change state (use embedded cycling limits if they exist in getVal())
|
||||
presetCycCurr = ps;
|
||||
applyPreset(ps, callMode); // async load from file system (only preset ID was specified)
|
||||
applyPreset(presetCycCurr, callMode); // async load from file system (only preset ID was specified)
|
||||
return stateResponse;
|
||||
}
|
||||
} else presetCycCurr = currentPreset; // restore presetCycCurr
|
||||
}
|
||||
|
||||
JsonObject playlist = root[F("playlist")];
|
||||
|
||||
@@ -9,10 +9,10 @@ void setValuesFromFirstSelectedSeg() { setValuesFromSegment(strip.getFirstSelect
|
||||
void setValuesFromSegment(uint8_t s)
|
||||
{
|
||||
Segment& seg = strip.getSegment(s);
|
||||
col[0] = R(seg.colors[0]);
|
||||
col[1] = G(seg.colors[0]);
|
||||
col[2] = B(seg.colors[0]);
|
||||
col[3] = W(seg.colors[0]);
|
||||
colPri[0] = R(seg.colors[0]);
|
||||
colPri[1] = G(seg.colors[0]);
|
||||
colPri[2] = B(seg.colors[0]);
|
||||
colPri[3] = W(seg.colors[0]);
|
||||
colSec[0] = R(seg.colors[1]);
|
||||
colSec[1] = G(seg.colors[1]);
|
||||
colSec[2] = B(seg.colors[1]);
|
||||
@@ -39,7 +39,7 @@ void applyValuesToSelectedSegs()
|
||||
if (effectIntensity != selsegPrev.intensity) {seg.intensity = effectIntensity; stateChanged = true;}
|
||||
if (effectPalette != selsegPrev.palette) {seg.setPalette(effectPalette);}
|
||||
if (effectCurrent != selsegPrev.mode) {seg.setMode(effectCurrent);}
|
||||
uint32_t col0 = RGBW32( col[0], col[1], col[2], col[3]);
|
||||
uint32_t col0 = RGBW32(colPri[0], colPri[1], colPri[2], colPri[3]);
|
||||
uint32_t col1 = RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]);
|
||||
if (col0 != selsegPrev.colors[0]) {seg.setColor(0, col0);}
|
||||
if (col1 != selsegPrev.colors[1]) {seg.setColor(1, col1);}
|
||||
@@ -47,17 +47,12 @@ void applyValuesToSelectedSegs()
|
||||
}
|
||||
|
||||
|
||||
void resetTimebase()
|
||||
{
|
||||
strip.timebase = 0 - millis();
|
||||
}
|
||||
|
||||
|
||||
void toggleOnOff()
|
||||
{
|
||||
if (bri == 0)
|
||||
{
|
||||
bri = briLast;
|
||||
strip.restartRuntime();
|
||||
} else
|
||||
{
|
||||
briLast = bri;
|
||||
@@ -78,8 +73,8 @@ byte scaledBri(byte in)
|
||||
|
||||
//applies global brightness
|
||||
void applyBri() {
|
||||
if (!realtimeMode || !arlsForceMaxBri)
|
||||
{
|
||||
if (!(realtimeMode && arlsForceMaxBri)) {
|
||||
//DEBUG_PRINTF_P(PSTR("Applying strip brightness: %d (%d,%d)\n"), (int)briT, (int)bri, (int)briOld);
|
||||
strip.setBrightness(scaledBri(briT));
|
||||
}
|
||||
}
|
||||
@@ -90,6 +85,7 @@ void applyFinalBri() {
|
||||
briOld = bri;
|
||||
briT = bri;
|
||||
applyBri();
|
||||
strip.trigger();
|
||||
}
|
||||
|
||||
|
||||
@@ -122,7 +118,7 @@ void stateUpdated(byte callMode) {
|
||||
nightlightStartTime = millis();
|
||||
}
|
||||
if (briT == 0) {
|
||||
if (callMode != CALL_MODE_NOTIFICATION) resetTimebase(); //effect start from beginning
|
||||
if (callMode != CALL_MODE_NOTIFICATION) strip.resetTimebase(); //effect start from beginning
|
||||
}
|
||||
|
||||
if (bri > 0) briLast = bri;
|
||||
@@ -151,7 +147,6 @@ void stateUpdated(byte callMode) {
|
||||
transitionStartTime = millis();
|
||||
} else {
|
||||
applyFinalBri();
|
||||
strip.trigger();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,14 +157,14 @@ void updateInterfaces(uint8_t callMode)
|
||||
|
||||
sendDataWs();
|
||||
lastInterfaceUpdate = millis();
|
||||
interfaceUpdateCallMode = 0; //disable further updates
|
||||
interfaceUpdateCallMode = CALL_MODE_INIT; //disable further updates
|
||||
|
||||
if (callMode == CALL_MODE_WS_SEND) return;
|
||||
|
||||
#ifndef WLED_DISABLE_ALEXA
|
||||
if (espalexaDevice != nullptr && callMode != CALL_MODE_ALEXA) {
|
||||
espalexaDevice->setValue(bri);
|
||||
espalexaDevice->setColor(col[0], col[1], col[2]);
|
||||
espalexaDevice->setColor(colPri[0], colPri[1], colPri[2]);
|
||||
}
|
||||
#endif
|
||||
#ifndef WLED_DISABLE_MQTT
|
||||
@@ -226,7 +221,7 @@ void handleNightlight()
|
||||
nightlightDelayMs = (unsigned)(nightlightDelayMins*60000);
|
||||
nightlightActiveOld = true;
|
||||
briNlT = bri;
|
||||
for (unsigned i=0; i<4; i++) colNlT[i] = col[i]; // remember starting color
|
||||
for (unsigned i=0; i<4; i++) colNlT[i] = colPri[i]; // remember starting color
|
||||
if (nightlightMode == NL_MODE_SUN)
|
||||
{
|
||||
//save current
|
||||
@@ -251,7 +246,7 @@ void handleNightlight()
|
||||
bri = briNlT + ((nightlightTargetBri - briNlT)*nper);
|
||||
if (nightlightMode == NL_MODE_COLORFADE) // color fading only is enabled with "NF=2"
|
||||
{
|
||||
for (unsigned i=0; i<4; i++) col[i] = colNlT[i]+ ((colSec[i] - colNlT[i])*nper); // fading from actual color to secondary color
|
||||
for (unsigned i=0; i<4; i++) colPri[i] = colNlT[i]+ ((colSec[i] - colNlT[i])*nper); // fading from actual color to secondary color
|
||||
}
|
||||
colorUpdated(CALL_MODE_NO_NOTIFY);
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ static void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProp
|
||||
//Prefix is stripped from the topic at this point
|
||||
|
||||
if (strcmp_P(topic, PSTR("/col")) == 0) {
|
||||
colorFromDecOrHexString(col, payloadStr);
|
||||
colorFromDecOrHexString(colPri, payloadStr);
|
||||
colorUpdated(CALL_MODE_DIRECT_CHANGE);
|
||||
} else if (strcmp_P(topic, PSTR("/api")) == 0) {
|
||||
if (requestJSONBufferLock(15)) {
|
||||
@@ -124,6 +124,32 @@ static void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProp
|
||||
payloadStr = nullptr;
|
||||
}
|
||||
|
||||
// Print adapter for flat buffers
|
||||
namespace {
|
||||
class bufferPrint : public Print {
|
||||
char* _buf;
|
||||
size_t _size, _offset;
|
||||
public:
|
||||
|
||||
bufferPrint(char* buf, size_t size) : _buf(buf), _size(size), _offset(0) {};
|
||||
|
||||
size_t write(const uint8_t *buffer, size_t size) {
|
||||
size = std::min(size, _size - _offset);
|
||||
memcpy(_buf + _offset, buffer, size);
|
||||
_offset += size;
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t write(uint8_t c) {
|
||||
return this->write(&c, 1);
|
||||
}
|
||||
|
||||
char* data() const { return _buf; }
|
||||
size_t size() const { return _offset; }
|
||||
size_t capacity() const { return _size; }
|
||||
};
|
||||
}; // anonymous namespace
|
||||
|
||||
|
||||
void publishMqtt()
|
||||
{
|
||||
@@ -139,7 +165,7 @@ void publishMqtt()
|
||||
strcat_P(subuf, PSTR("/g"));
|
||||
mqtt->publish(subuf, 0, retainMqttMsg, s); // optionally retain message (#2263)
|
||||
|
||||
sprintf_P(s, PSTR("#%06X"), (col[3] << 24) | (col[0] << 16) | (col[1] << 8) | (col[2]));
|
||||
sprintf_P(s, PSTR("#%06X"), (colPri[3] << 24) | (colPri[0] << 16) | (colPri[1] << 8) | (colPri[2]));
|
||||
strlcpy(subuf, mqttDeviceTopic, 33);
|
||||
strcat_P(subuf, PSTR("/c"));
|
||||
mqtt->publish(subuf, 0, retainMqttMsg, s); // optionally retain message (#2263)
|
||||
@@ -148,11 +174,13 @@ void publishMqtt()
|
||||
strcat_P(subuf, PSTR("/status"));
|
||||
mqtt->publish(subuf, 0, true, "online"); // retain message for a LWT
|
||||
|
||||
char apires[1024]; // allocating 1024 bytes from stack can be risky
|
||||
XML_response(nullptr, apires);
|
||||
// TODO: use a DynamicBufferList. Requires a list-read-capable MQTT client API.
|
||||
DynamicBuffer buf(1024);
|
||||
bufferPrint pbuf(buf.data(), buf.size());
|
||||
XML_response(pbuf);
|
||||
strlcpy(subuf, mqttDeviceTopic, 33);
|
||||
strcat_P(subuf, PSTR("/v"));
|
||||
mqtt->publish(subuf, 0, retainMqttMsg, apires); // optionally retain message (#2263)
|
||||
mqtt->publish(subuf, 0, retainMqttMsg, buf.data(), pbuf.size()); // optionally retain message (#2263)
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -207,6 +207,7 @@ void WiFiEvent(WiFiEvent_t event)
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
DEBUG_PRINTF_P(PSTR("Network event: %d\n"), (int)event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,8 +36,9 @@ Timezone* tz;
|
||||
#define TZ_ANCHORAGE 20
|
||||
#define TZ_MX_CENTRAL 21
|
||||
#define TZ_PAKISTAN 22
|
||||
#define TZ_BRASILIA 23
|
||||
|
||||
#define TZ_COUNT 23
|
||||
#define TZ_COUNT 24
|
||||
#define TZ_INIT 255
|
||||
|
||||
byte tzCurrent = TZ_INIT; //uninitialized
|
||||
@@ -135,6 +136,10 @@ static const std::pair<TimeChangeRule, TimeChangeRule> TZ_TABLE[] PROGMEM = {
|
||||
/* TZ_PAKISTAN */ {
|
||||
{Last, Sun, Mar, 1, 300}, //Pakistan Standard Time = UTC + 5 hours
|
||||
{Last, Sun, Mar, 1, 300}
|
||||
},
|
||||
/* TZ_BRASILIA */ {
|
||||
{Last, Sun, Mar, 1, -180}, //Brasília Standard Time = UTC - 3 hours
|
||||
{Last, Sun, Mar, 1, -180}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -201,7 +201,12 @@ bool PinManager::isPinOk(byte gpio, bool output)
|
||||
if (gpio > 18 && gpio < 21) return false; // 19 + 20 = USB-JTAG. Not recommended for other uses.
|
||||
#endif
|
||||
if (gpio > 21 && gpio < 33) return false; // 22 to 32: not connected + SPI FLASH
|
||||
if (gpio > 32 && gpio < 38) return !psramFound(); // 33 to 37: not available if using _octal_ SPI Flash or _octal_ PSRAM
|
||||
#if CONFIG_ESPTOOLPY_FLASHMODE_OPI // 33-37: never available if using _octal_ Flash (opi_opi)
|
||||
if (gpio > 32 && gpio < 38) return false;
|
||||
#endif
|
||||
#if CONFIG_SPIRAM_MODE_OCT // 33-37: not available if using _octal_ PSRAM (qio_opi), but free to use on _quad_ PSRAM (qio_qspi)
|
||||
if (gpio > 32 && gpio < 38) return !psramFound();
|
||||
#endif
|
||||
// 38 to 48 are for general use. Be careful about straping pins GPIO45 and GPIO46 - these may be pull-up or pulled-down on your board.
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
// strapping pins: 0, 45 & 46
|
||||
@@ -209,8 +214,20 @@ bool PinManager::isPinOk(byte gpio, bool output)
|
||||
// JTAG: GPIO39-42 are usually used for inline debugging
|
||||
// GPIO46 is input only and pulled down
|
||||
#else
|
||||
if (gpio > 5 && gpio < 12) return false; //SPI flash pins
|
||||
if (strncmp_P(PSTR("ESP32-PICO"), ESP.getChipModel(), 10) == 0 && (gpio == 16 || gpio == 17)) return false; // PICO-D4: gpio16+17 are in use for onboard SPI FLASH
|
||||
|
||||
if ((strncmp_P(PSTR("ESP32-U4WDH"), ESP.getChipModel(), 11) == 0) || // this is the correct identifier, but....
|
||||
(strncmp_P(PSTR("ESP32-PICO-D2"), ESP.getChipModel(), 13) == 0)) { // https://github.com/espressif/arduino-esp32/issues/10683
|
||||
// this chip has 4 MB of internal Flash and different packaging, so available pins are different!
|
||||
if (((gpio > 5) && (gpio < 9)) || (gpio == 11))
|
||||
return false;
|
||||
} else {
|
||||
// for classic ESP32 (non-mini) modules, these are the SPI flash pins
|
||||
if (gpio > 5 && gpio < 12) return false; //SPI flash pins
|
||||
}
|
||||
|
||||
if (((strncmp_P(PSTR("ESP32-PICO"), ESP.getChipModel(), 10) == 0) ||
|
||||
(strncmp_P(PSTR("ESP32-U4WDH"), ESP.getChipModel(), 11) == 0))
|
||||
&& (gpio == 16 || gpio == 17)) return false; // PICO-D4/U4WDH: gpio16+17 are in use for onboard SPI FLASH
|
||||
if (gpio == 16 || gpio == 17) return !psramFound(); //PSRAM pins on ESP32 (these are IO)
|
||||
#endif
|
||||
if (output) return digitalPinCanOutput(gpio);
|
||||
|
||||
@@ -143,6 +143,7 @@ void applyPresetWithFallback(uint8_t index, uint8_t callMode, uint8_t effectID,
|
||||
|
||||
void handlePresets()
|
||||
{
|
||||
byte presetErrFlag = ERR_NONE;
|
||||
if (presetToSave) {
|
||||
strip.suspend();
|
||||
doSaveState();
|
||||
@@ -163,17 +164,24 @@ void handlePresets()
|
||||
|
||||
DEBUG_PRINTF_P(PSTR("Applying preset: %u\n"), (unsigned)tmpPreset);
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32S3) || defined(ARDUINO_ARCH_ESP32S2) || defined(ARDUINO_ARCH_ESP32C3)
|
||||
unsigned long start = millis();
|
||||
while (strip.isUpdating() && millis() - start < FRAMETIME_FIXED) yield(); // wait for strip to finish updating, accessing FS during sendout causes glitches
|
||||
#endif
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
if (tmpPreset==255 && tmpRAMbuffer!=nullptr) {
|
||||
deserializeJson(*pDoc,tmpRAMbuffer);
|
||||
errorFlag = ERR_NONE;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
errorFlag = readObjectFromFileUsingId(getPresetsFileName(tmpPreset < 255), tmpPreset, pDoc) ? ERR_NONE : ERR_FS_PLOAD;
|
||||
presetErrFlag = readObjectFromFileUsingId(getPresetsFileName(tmpPreset < 255), tmpPreset, pDoc) ? ERR_NONE : ERR_FS_PLOAD;
|
||||
}
|
||||
fdo = pDoc->as<JsonObject>();
|
||||
|
||||
// only reset errorflag if previous error was preset-related
|
||||
if ((errorFlag == ERR_NONE) || (errorFlag == ERR_FS_PLOAD)) errorFlag = presetErrFlag;
|
||||
|
||||
//HTTP API commands
|
||||
const char* httpwin = fdo["win"];
|
||||
if (httpwin) {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "wled.h"
|
||||
#ifndef WLED_DISABLE_ESPNOW
|
||||
|
||||
#define ESPNOW_BUSWAIT_TIMEOUT 24 // one frame timeout to wait for bus to finish updating
|
||||
|
||||
#define NIGHT_MODE_DEACTIVATED -1
|
||||
#define NIGHT_MODE_BRIGHTNESS 5
|
||||
|
||||
@@ -38,6 +40,7 @@ typedef struct WizMoteMessageStructure {
|
||||
|
||||
static uint32_t last_seq = UINT32_MAX;
|
||||
static int brightnessBeforeNightMode = NIGHT_MODE_DEACTIVATED;
|
||||
static int16_t ESPNowButton = -1; // set in callback if new button value is received
|
||||
|
||||
// Pulled from the IR Remote logic but reduced to 10 steps with a constant of 3
|
||||
static const byte brightnessSteps[] = {
|
||||
@@ -121,6 +124,9 @@ static bool remoteJson(int button)
|
||||
|
||||
sprintf_P(objKey, PSTR("\"%d\":"), button);
|
||||
|
||||
unsigned long start = millis();
|
||||
while (strip.isUpdating() && millis()-start < ESPNOW_BUSWAIT_TIMEOUT) yield(); // wait for strip to finish updating, accessing FS during sendout causes glitches
|
||||
|
||||
// attempt to read command from remote.json
|
||||
readObjectFromFile(PSTR("/remote.json"), objKey, pDoc);
|
||||
JsonObject fdo = pDoc->as<JsonObject>();
|
||||
@@ -176,7 +182,7 @@ static bool remoteJson(int button)
|
||||
}
|
||||
|
||||
// Callback function that will be executed when data is received
|
||||
void handleRemote(uint8_t *incomingData, size_t len) {
|
||||
void handleWiZdata(uint8_t *incomingData, size_t len) {
|
||||
message_structure_t *incoming = reinterpret_cast<message_structure_t *>(incomingData);
|
||||
|
||||
if (strcmp(last_signal_src, linked_remote) != 0) {
|
||||
@@ -202,8 +208,15 @@ void handleRemote(uint8_t *incomingData, size_t len) {
|
||||
DEBUG_PRINT(F("] button: "));
|
||||
DEBUG_PRINTLN(incoming->button);
|
||||
|
||||
if (!remoteJson(incoming->button))
|
||||
switch (incoming->button) {
|
||||
ESPNowButton = incoming->button; // save state, do not process in callback (can cause glitches)
|
||||
last_seq = cur_seq;
|
||||
}
|
||||
|
||||
// process ESPNow button data (acesses FS, should not be called while update to avoid glitches)
|
||||
void handleRemote() {
|
||||
if(ESPNowButton >= 0) {
|
||||
if (!remoteJson(ESPNowButton))
|
||||
switch (ESPNowButton) {
|
||||
case WIZMOTE_BUTTON_ON : setOn(); break;
|
||||
case WIZMOTE_BUTTON_OFF : setOff(); break;
|
||||
case WIZMOTE_BUTTON_ONE : presetWithFallback(1, FX_MODE_STATIC, 0); break;
|
||||
@@ -219,9 +232,10 @@ void handleRemote(uint8_t *incomingData, size_t len) {
|
||||
case WIZ_SMART_BUTTON_BRIGHT_DOWN : brightnessDown(); break;
|
||||
default: break;
|
||||
}
|
||||
last_seq = cur_seq;
|
||||
}
|
||||
ESPNowButton = -1;
|
||||
}
|
||||
|
||||
#else
|
||||
void handleRemote(uint8_t *incomingData, size_t len) {}
|
||||
void handleRemote() {}
|
||||
#endif
|
||||
|
||||
@@ -134,15 +134,17 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
strip.correctWB = request->hasArg(F("CCT"));
|
||||
strip.cctFromRgb = request->hasArg(F("CR"));
|
||||
cctICused = request->hasArg(F("IC"));
|
||||
strip.cctBlending = request->arg(F("CB")).toInt();
|
||||
Bus::setCCTBlend(strip.cctBlending);
|
||||
Bus::setCCTBlend(request->arg(F("CB")).toInt());
|
||||
Bus::setGlobalAWMode(request->arg(F("AW")).toInt());
|
||||
strip.setTargetFps(request->arg(F("FR")).toInt());
|
||||
useGlobalLedBuffer = request->hasArg(F("LD"));
|
||||
#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
useParallelI2S = request->hasArg(F("PR"));
|
||||
#endif
|
||||
|
||||
bool busesChanged = false;
|
||||
for (int s = 0; s < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; s++) {
|
||||
int offset = s < 10 ? 48 : 55;
|
||||
int offset = s < 10 ? '0' : 'A' - 10;
|
||||
char lp[4] = "L0"; lp[2] = offset+s; lp[3] = 0; //ascii 0-9 //strip data pin
|
||||
char lc[4] = "LC"; lc[2] = offset+s; lc[3] = 0; //strip length
|
||||
char co[4] = "CO"; co[2] = offset+s; co[3] = 0; //strip color order
|
||||
@@ -161,7 +163,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
break;
|
||||
}
|
||||
for (int i = 0; i < 5; i++) {
|
||||
lp[1] = offset+i;
|
||||
lp[1] = '0'+i;
|
||||
if (!request->hasArg(lp)) break;
|
||||
pins[i] = (request->arg(lp).length() > 0) ? request->arg(lp).toInt() : 255;
|
||||
}
|
||||
@@ -208,15 +210,15 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
type |= request->hasArg(rf) << 7; // off refresh override
|
||||
// actual finalization is done in WLED::loop() (removing old busses and adding new)
|
||||
// this may happen even before this loop is finished so we do "doInitBusses" after the loop
|
||||
if (busConfigs[s] != nullptr) delete busConfigs[s];
|
||||
busConfigs[s] = new BusConfig(type, pins, start, length, colorOrder | (channelSwap<<4), request->hasArg(cv), skip, awmode, freq, useGlobalLedBuffer, maPerLed, maMax);
|
||||
busConfigs.push_back(std::move(BusConfig(type, pins, start, length, colorOrder | (channelSwap<<4), request->hasArg(cv), skip, awmode, freq, useGlobalLedBuffer, maPerLed, maMax)));
|
||||
busesChanged = true;
|
||||
}
|
||||
//doInitBusses = busesChanged; // we will do that below to ensure all input data is processed
|
||||
|
||||
// we will not bother with pre-allocating ColorOrderMappings vector
|
||||
BusManager::getColorOrderMap().reset();
|
||||
for (int s = 0; s < WLED_MAX_COLOR_ORDER_MAPPINGS; s++) {
|
||||
int offset = s < 10 ? 48 : 55;
|
||||
int offset = s < 10 ? '0' : 'A' - 10;
|
||||
char xs[4] = "XS"; xs[2] = offset+s; xs[3] = 0; //start LED
|
||||
char xc[4] = "XC"; xc[2] = offset+s; xc[3] = 0; //strip length
|
||||
char xo[4] = "XO"; xo[2] = offset+s; xo[3] = 0; //color order
|
||||
@@ -255,7 +257,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
disablePullUp = (bool)request->hasArg(F("IP"));
|
||||
touchThreshold = request->arg(F("TT")).toInt();
|
||||
for (int i = 0; i < WLED_MAX_BUTTONS; i++) {
|
||||
int offset = i < 10 ? 48 : 55;
|
||||
int offset = i < 10 ? '0' : 'A' - 10;
|
||||
char bt[4] = "BT"; bt[2] = offset+i; bt[3] = 0; // button pin (use A,B,C,... if WLED_MAX_BUTTONS>10)
|
||||
char be[4] = "BE"; be[2] = offset+i; be[3] = 0; // button type (use A,B,C,... if WLED_MAX_BUTTONS>10)
|
||||
int hw_btn_pin = request->arg(bt).toInt();
|
||||
@@ -1183,7 +1185,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
}
|
||||
// you can add more if you need
|
||||
|
||||
// global col[], effectCurrent, ... are updated in stateChanged()
|
||||
// global colPri[], effectCurrent, ... are updated in stateChanged()
|
||||
if (!apply) return true; // when called by JSON API, do not call colorUpdated() here
|
||||
|
||||
pos = req.indexOf(F("&NN")); //do not send UDP notifications this time
|
||||
@@ -1191,7 +1193,11 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
|
||||
// internal call, does not send XML response
|
||||
pos = req.indexOf(F("IN"));
|
||||
if (pos < 1) XML_response(request);
|
||||
if ((request != nullptr) && (pos < 1)) {
|
||||
auto response = request->beginResponseStream("text/xml");
|
||||
XML_response(*response);
|
||||
request->send(response);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -34,8 +34,8 @@ static const int enablePin = -1; // disable the enable pin because it is not ne
|
||||
static const int rxPin = -1; // disable the receiving pin because it is not needed - softhack007: Pin=-1 means "use default" not "disable"
|
||||
static const int txPin = 2; // transmit DMX data over this pin (default is pin 2)
|
||||
|
||||
//DMX value array and size. Entry 0 will hold startbyte
|
||||
static uint8_t dmxData[dmxMaxChannel] = { 0 };
|
||||
//DMX value array and size. Entry 0 will hold startbyte, so we need 512+1 elements
|
||||
static uint8_t dmxData[dmxMaxChannel+1] = { 0 };
|
||||
static int chanSize = 0;
|
||||
#if !defined(DMX_SEND_ONLY)
|
||||
static int currentChannel = 0;
|
||||
|
||||
@@ -120,10 +120,8 @@ private:
|
||||
|
||||
void encodeLightId(uint8_t idx, char* out)
|
||||
{
|
||||
uint8_t mac[6];
|
||||
WiFi.macAddress(mac);
|
||||
|
||||
sprintf_P(out, PSTR("%02X:%02X:%02X:%02X:%02X:%02X:00:11-%02X"), mac[0],mac[1],mac[2],mac[3],mac[4],mac[5], idx);
|
||||
String mymac = WiFi.macAddress();
|
||||
sprintf_P(out, PSTR("%02X:%s:AB-%02X"), idx, mymac.c_str(), idx);
|
||||
}
|
||||
|
||||
// construct 'globally unique' Json dict key fitting into signed int
|
||||
|
||||
@@ -300,7 +300,7 @@ void parseNotifyPacket(uint8_t *udpIn) {
|
||||
if (!receiveSegmentOptions) {
|
||||
DEBUG_PRINTF_P(PSTR("Set segment w/o options: %d [%d,%d;%d,%d]\n"), id, (int)start, (int)stop, (int)startY, (int)stopY);
|
||||
strip.suspend(); //should not be needed as UDP handling is not done in ISR callbacks but still added "just in case"
|
||||
selseg.setUp(start, stop, selseg.grouping, selseg.spacing, offset, startY, stopY);
|
||||
selseg.setGeometry(start, stop, selseg.grouping, selseg.spacing, offset, startY, stopY);
|
||||
strip.resume();
|
||||
continue; // we do receive bounds, but not options
|
||||
}
|
||||
@@ -342,12 +342,12 @@ void parseNotifyPacket(uint8_t *udpIn) {
|
||||
if (receiveSegmentBounds) {
|
||||
DEBUG_PRINTF_P(PSTR("Set segment w/ options: %d [%d,%d;%d,%d]\n"), id, (int)start, (int)stop, (int)startY, (int)stopY);
|
||||
strip.suspend(); //should not be needed as UDP handling is not done in ISR callbacks but still added "just in case"
|
||||
selseg.setUp(start, stop, udpIn[5+ofs], udpIn[6+ofs], offset, startY, stopY);
|
||||
selseg.setGeometry(start, stop, udpIn[5+ofs], udpIn[6+ofs], offset, startY, stopY);
|
||||
strip.resume();
|
||||
} else {
|
||||
DEBUG_PRINTF_P(PSTR("Set segment grouping: %d [%d,%d]\n"), id, (int)udpIn[5+ofs], (int)udpIn[6+ofs]);
|
||||
strip.suspend(); //should not be needed as UDP handling is not done in ISR callbacks but still added "just in case"
|
||||
selseg.setUp(selseg.start, selseg.stop, udpIn[5+ofs], udpIn[6+ofs], selseg.offset, selseg.startY, selseg.stopY);
|
||||
selseg.setGeometry(selseg.start, selseg.stop, udpIn[5+ofs], udpIn[6+ofs], selseg.offset, selseg.startY, selseg.stopY);
|
||||
strip.resume();
|
||||
}
|
||||
}
|
||||
@@ -974,14 +974,12 @@ void espNowReceiveCB(uint8_t* address, uint8_t* data, uint8_t len, signed int rs
|
||||
DEBUG_PRINTLN();
|
||||
#endif
|
||||
|
||||
#ifndef WLED_DISABLE_ESPNOW
|
||||
// usermods hook can override processing
|
||||
if (UsermodManager::onEspNowMessage(address, data, len)) return;
|
||||
#endif
|
||||
|
||||
// handle WiZ Mote data
|
||||
if (data[0] == 0x91 || data[0] == 0x81 || data[0] == 0x80) {
|
||||
handleRemote(data, len);
|
||||
handleWiZdata(data, len);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ void UsermodManager::setup() { for (unsigned i = 0; i < numMods; i++
|
||||
void UsermodManager::connected() { for (unsigned i = 0; i < numMods; i++) ums[i]->connected(); }
|
||||
void UsermodManager::loop() { for (unsigned i = 0; i < numMods; i++) ums[i]->loop(); }
|
||||
void UsermodManager::handleOverlayDraw() { for (unsigned i = 0; i < numMods; i++) ums[i]->handleOverlayDraw(); }
|
||||
void UsermodManager::appendConfigData() { for (unsigned i = 0; i < numMods; i++) ums[i]->appendConfigData(); }
|
||||
void UsermodManager::appendConfigData(Print& dest) { for (unsigned i = 0; i < numMods; i++) ums[i]->appendConfigData(dest); }
|
||||
bool UsermodManager::handleButton(uint8_t b) {
|
||||
bool overrideIO = false;
|
||||
for (unsigned i = 0; i < numMods; i++) {
|
||||
@@ -71,3 +71,13 @@ bool UsermodManager::add(Usermod* um)
|
||||
|
||||
Usermod* UsermodManager::ums[WLED_MAX_USERMODS] = {nullptr};
|
||||
byte UsermodManager::numMods = 0;
|
||||
|
||||
/* Usermod v2 interface shim for oappend */
|
||||
Print* Usermod::oappend_shim = nullptr;
|
||||
|
||||
void Usermod::appendConfigData(Print& settingsScript) {
|
||||
assert(!oappend_shim);
|
||||
oappend_shim = &settingsScript;
|
||||
this->appendConfigData();
|
||||
oappend_shim = nullptr;
|
||||
}
|
||||
|
||||
141
wled00/util.cpp
141
wled00/util.cpp
@@ -52,7 +52,7 @@ void parseNumber(const char* str, byte* val, byte minv, byte maxv)
|
||||
*val = atoi(str);
|
||||
}
|
||||
|
||||
|
||||
//getVal supports inc/decrementing and random ("X~Y(r|~[w][-][Z])" form)
|
||||
bool getVal(JsonVariant elem, byte* val, byte vmin, byte vmax) {
|
||||
if (elem.is<int>()) {
|
||||
if (elem < 0) return false; //ignore e.g. {"ps":-1}
|
||||
@@ -60,8 +60,12 @@ bool getVal(JsonVariant elem, byte* val, byte vmin, byte vmax) {
|
||||
return true;
|
||||
} else if (elem.is<const char*>()) {
|
||||
const char* str = elem;
|
||||
size_t len = strnlen(str, 12);
|
||||
if (len == 0 || len > 10) return false;
|
||||
size_t len = strnlen(str, 14);
|
||||
if (len == 0 || len > 12) return false;
|
||||
// fix for #3605 & #4346
|
||||
// ignore vmin and vmax and use as specified in API
|
||||
if (len > 3 && (strchr(str,'r') || strchr(str,'~') != strrchr(str,'~'))) vmax = vmin = 0; // we have "X~Y(r|~[w][-][Z])" form
|
||||
// end fix
|
||||
parseNumber(str, val, vmin, vmax);
|
||||
return true;
|
||||
}
|
||||
@@ -87,90 +91,30 @@ bool updateVal(const char* req, const char* key, byte* val, byte minv, byte maxv
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//append a numeric setting to string buffer
|
||||
void sappend(char stype, const char* key, int val)
|
||||
{
|
||||
char ds[] = "d.Sf.";
|
||||
|
||||
switch(stype)
|
||||
{
|
||||
case 'c': //checkbox
|
||||
oappend(ds);
|
||||
oappend(key);
|
||||
oappend(".checked=");
|
||||
oappendi(val);
|
||||
oappend(";");
|
||||
break;
|
||||
case 'v': //numeric
|
||||
oappend(ds);
|
||||
oappend(key);
|
||||
oappend(".value=");
|
||||
oappendi(val);
|
||||
oappend(";");
|
||||
break;
|
||||
case 'i': //selectedIndex
|
||||
oappend(ds);
|
||||
oappend(key);
|
||||
oappend(SET_F(".selectedIndex="));
|
||||
oappendi(val);
|
||||
oappend(";");
|
||||
break;
|
||||
}
|
||||
static size_t printSetFormInput(Print& settingsScript, const char* key, const char* selector, int value) {
|
||||
return settingsScript.printf_P(PSTR("d.Sf.%s.%s=%d;"), key, selector, value);
|
||||
}
|
||||
|
||||
|
||||
//append a string setting to buffer
|
||||
void sappends(char stype, const char* key, char* val)
|
||||
{
|
||||
switch(stype)
|
||||
{
|
||||
case 's': {//string (we can interpret val as char*)
|
||||
String buf = val;
|
||||
//convert "%" to "%%" to make EspAsyncWebServer happy
|
||||
//buf.replace("%","%%");
|
||||
oappend("d.Sf.");
|
||||
oappend(key);
|
||||
oappend(".value=\"");
|
||||
oappend(buf.c_str());
|
||||
oappend("\";");
|
||||
break;}
|
||||
case 'm': //message
|
||||
oappend(SET_F("d.getElementsByClassName"));
|
||||
oappend(key);
|
||||
oappend(SET_F(".innerHTML=\""));
|
||||
oappend(val);
|
||||
oappend("\";");
|
||||
break;
|
||||
}
|
||||
size_t printSetFormCheckbox(Print& settingsScript, const char* key, int val) {
|
||||
return printSetFormInput(settingsScript, key, PSTR("checked"), val);
|
||||
}
|
||||
size_t printSetFormValue(Print& settingsScript, const char* key, int val) {
|
||||
return printSetFormInput(settingsScript, key, PSTR("value"), val);
|
||||
}
|
||||
size_t printSetFormIndex(Print& settingsScript, const char* key, int index) {
|
||||
return printSetFormInput(settingsScript, key, PSTR("selectedIndex"), index);
|
||||
}
|
||||
|
||||
|
||||
bool oappendi(int i)
|
||||
{
|
||||
char s[12]; // 32bit signed number can have 10 digits plus - sign
|
||||
sprintf(s, "%d", i);
|
||||
return oappend(s);
|
||||
size_t printSetFormValue(Print& settingsScript, const char* key, const char* val) {
|
||||
return settingsScript.printf_P(PSTR("d.Sf.%s.value=\"%s\";"),key,val);
|
||||
}
|
||||
|
||||
|
||||
bool oappend(const char* txt)
|
||||
{
|
||||
unsigned len = strlen(txt);
|
||||
if ((obuf == nullptr) || (olen + len >= SETTINGS_STACK_BUF_SIZE)) { // sanity checks
|
||||
#ifdef WLED_DEBUG
|
||||
DEBUG_PRINT(F("oappend() buffer overflow. Cannot append "));
|
||||
DEBUG_PRINT(len); DEBUG_PRINT(F(" bytes \t\""));
|
||||
DEBUG_PRINT(txt); DEBUG_PRINTLN(F("\""));
|
||||
#endif
|
||||
return false; // buffer full
|
||||
}
|
||||
strcpy(obuf + olen, txt);
|
||||
olen += len;
|
||||
return true;
|
||||
size_t printSetClassElementHTML(Print& settingsScript, const char* key, const int index, const char* val) {
|
||||
return settingsScript.printf_P(PSTR("d.getElementsByClassName(\"%s\")[%d].innerHTML=\"%s\";"), key, index, val);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void prepareHostname(char* hostname)
|
||||
{
|
||||
sprintf_P(hostname, PSTR("wled-%*s"), 6, escapedMac.c_str() + 6);
|
||||
@@ -432,6 +376,39 @@ uint16_t crc16(const unsigned char* data_p, size_t length) {
|
||||
return crc;
|
||||
}
|
||||
|
||||
// fastled beatsin: 1:1 replacements to remove the use of fastled sin16()
|
||||
// Generates a 16-bit sine wave at a given BPM that oscillates within a given range. see fastled for details.
|
||||
uint16_t beatsin88_t(accum88 beats_per_minute_88, uint16_t lowest, uint16_t highest, uint32_t timebase, uint16_t phase_offset)
|
||||
{
|
||||
uint16_t beat = beat88( beats_per_minute_88, timebase);
|
||||
uint16_t beatsin (sin16_t( beat + phase_offset) + 32768);
|
||||
uint16_t rangewidth = highest - lowest;
|
||||
uint16_t scaledbeat = scale16( beatsin, rangewidth);
|
||||
uint16_t result = lowest + scaledbeat;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Generates a 16-bit sine wave at a given BPM that oscillates within a given range. see fastled for details.
|
||||
uint16_t beatsin16_t(accum88 beats_per_minute, uint16_t lowest, uint16_t highest, uint32_t timebase, uint16_t phase_offset)
|
||||
{
|
||||
uint16_t beat = beat16( beats_per_minute, timebase);
|
||||
uint16_t beatsin = (sin16_t( beat + phase_offset) + 32768);
|
||||
uint16_t rangewidth = highest - lowest;
|
||||
uint16_t scaledbeat = scale16( beatsin, rangewidth);
|
||||
uint16_t result = lowest + scaledbeat;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Generates an 8-bit sine wave at a given BPM that oscillates within a given range. see fastled for details.
|
||||
uint8_t beatsin8_t(accum88 beats_per_minute, uint8_t lowest, uint8_t highest, uint32_t timebase, uint8_t phase_offset)
|
||||
{
|
||||
uint8_t beat = beat8( beats_per_minute, timebase);
|
||||
uint8_t beatsin = sin8_t( beat + phase_offset);
|
||||
uint8_t rangewidth = highest - lowest;
|
||||
uint8_t scaledbeat = scale8( beatsin, rangewidth);
|
||||
uint8_t result = lowest + scaledbeat;
|
||||
return result;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Begin simulateSound (to enable audio enhanced effects to display something)
|
||||
@@ -491,8 +468,8 @@ um_data_t* simulateSound(uint8_t simulationId)
|
||||
default:
|
||||
case UMS_BeatSin:
|
||||
for (int i = 0; i<16; i++)
|
||||
fftResult[i] = beatsin8(120 / (i+1), 0, 255);
|
||||
// fftResult[i] = (beatsin8(120, 0, 255) + (256/16 * i)) % 256;
|
||||
fftResult[i] = beatsin8_t(120 / (i+1), 0, 255);
|
||||
// fftResult[i] = (beatsin8_t(120, 0, 255) + (256/16 * i)) % 256;
|
||||
volumeSmth = fftResult[8];
|
||||
break;
|
||||
case UMS_WeWillRockYou:
|
||||
@@ -529,12 +506,12 @@ um_data_t* simulateSound(uint8_t simulationId)
|
||||
break;
|
||||
case UMS_10_13:
|
||||
for (int i = 0; i<16; i++)
|
||||
fftResult[i] = inoise8(beatsin8(90 / (i+1), 0, 200)*15 + (ms>>10), ms>>3);
|
||||
fftResult[i] = inoise8(beatsin8_t(90 / (i+1), 0, 200)*15 + (ms>>10), ms>>3);
|
||||
volumeSmth = fftResult[8];
|
||||
break;
|
||||
case UMS_14_3:
|
||||
for (int i = 0; i<16; i++)
|
||||
fftResult[i] = inoise8(beatsin8(120 / (i+1), 10, 30)*10 + (ms>>14), ms>>3);
|
||||
fftResult[i] = inoise8(beatsin8_t(120 / (i+1), 10, 30)*10 + (ms>>14), ms>>3);
|
||||
volumeSmth = fftResult[8];
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -84,6 +84,9 @@ void WLED::loop()
|
||||
#ifndef WLED_DISABLE_INFRARED
|
||||
handleIR();
|
||||
#endif
|
||||
#ifndef WLED_DISABLE_ESPNOW
|
||||
handleRemote();
|
||||
#endif
|
||||
#ifndef WLED_DISABLE_ALEXA
|
||||
handleAlexa();
|
||||
#endif
|
||||
@@ -179,48 +182,10 @@ void WLED::loop()
|
||||
DEBUG_PRINTLN(F("Re-init busses."));
|
||||
bool aligned = strip.checkSegmentAlignment(); //see if old segments match old bus(ses)
|
||||
BusManager::removeAll();
|
||||
unsigned mem = 0;
|
||||
// determine if it is sensible to use parallel I2S outputs on ESP32 (i.e. more than 5 outputs = 1 I2S + 4 RMT)
|
||||
bool useParallel = false;
|
||||
#if defined(ARDUINO_ARCH_ESP32) && !defined(ARDUINO_ARCH_ESP32S2) && !defined(ARDUINO_ARCH_ESP32S3) && !defined(ARDUINO_ARCH_ESP32C3)
|
||||
unsigned digitalCount = 0;
|
||||
unsigned maxLedsOnBus = 0;
|
||||
unsigned maxChannels = 0;
|
||||
for (unsigned i = 0; i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) {
|
||||
if (busConfigs[i] == nullptr) break;
|
||||
if (!Bus::isDigital(busConfigs[i]->type)) continue;
|
||||
if (!Bus::is2Pin(busConfigs[i]->type)) {
|
||||
digitalCount++;
|
||||
unsigned channels = Bus::getNumberOfChannels(busConfigs[i]->type);
|
||||
if (busConfigs[i]->count > maxLedsOnBus) maxLedsOnBus = busConfigs[i]->count;
|
||||
if (channels > maxChannels) maxChannels = channels;
|
||||
}
|
||||
}
|
||||
DEBUG_PRINTF_P(PSTR("Maximum LEDs on a bus: %u\nDigital buses: %u\n"), maxLedsOnBus, digitalCount);
|
||||
// we may remove 300 LEDs per bus limit when NeoPixelBus is updated beyond 2.9.0
|
||||
if (maxLedsOnBus <= 300 && digitalCount > 5) {
|
||||
DEBUG_PRINTF_P(PSTR("Switching to parallel I2S."));
|
||||
useParallel = true;
|
||||
BusManager::useParallelOutput();
|
||||
mem = BusManager::memUsage(maxChannels, maxLedsOnBus, 8); // use alternate memory calculation (hse to be used *after* useParallelOutput())
|
||||
}
|
||||
#endif
|
||||
// create buses/outputs
|
||||
for (unsigned i = 0; i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) {
|
||||
if (busConfigs[i] == nullptr || (!useParallel && i > 10)) break;
|
||||
if (useParallel && i < 8) {
|
||||
// if for some unexplained reason the above pre-calculation was wrong, update
|
||||
unsigned memT = BusManager::memUsage(*busConfigs[i]); // includes x8 memory allocation for parallel I2S
|
||||
if (memT > mem) mem = memT; // if we have unequal LED count use the largest
|
||||
} else
|
||||
mem += BusManager::memUsage(*busConfigs[i]); // includes global buffer
|
||||
if (mem <= MAX_LED_MEMORY) BusManager::add(*busConfigs[i]);
|
||||
delete busConfigs[i];
|
||||
busConfigs[i] = nullptr;
|
||||
}
|
||||
strip.finalizeInit(); // also loads default ledmap if present
|
||||
strip.finalizeInit(); // will create buses and also load default ledmap if present
|
||||
if (aligned) strip.makeAutoSegments();
|
||||
else strip.fixInvalidSegments();
|
||||
BusManager::setBrightness(scaledBri(bri)); // fix re-initialised bus' brightness #4005 and #4824
|
||||
doSerializeConfig = true;
|
||||
}
|
||||
if (loadLedmap >= 0) {
|
||||
@@ -379,6 +344,12 @@ void WLED::setup()
|
||||
case FM_QOUT: DEBUG_PRINT(F("(QOUT)"));break;
|
||||
case FM_DIO: DEBUG_PRINT(F("(DIO)")); break;
|
||||
case FM_DOUT: DEBUG_PRINT(F("(DOUT)"));break;
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32S3) && CONFIG_ESPTOOLPY_FLASHMODE_OPI
|
||||
case FM_FAST_READ: DEBUG_PRINT(F("(OPI)")); break;
|
||||
#else
|
||||
case FM_FAST_READ: DEBUG_PRINT(F("(fast_read)")); break;
|
||||
#endif
|
||||
case FM_SLOW_READ: DEBUG_PRINT(F("(slow_read)")); break;
|
||||
default: break;
|
||||
}
|
||||
#endif
|
||||
@@ -448,7 +419,7 @@ void WLED::setup()
|
||||
multiWiFi.push_back(WiFiConfig(CLIENT_SSID,CLIENT_PASS)); // initialise vector with default WiFi
|
||||
|
||||
DEBUG_PRINTLN(F("Reading config"));
|
||||
deserializeConfigFromFS();
|
||||
bool needsCfgSave = deserializeConfigFromFS();
|
||||
DEBUG_PRINTF_P(PSTR("heap %u\n"), ESP.getFreeHeap());
|
||||
|
||||
#if defined(STATUSLED) && STATUSLED>=0
|
||||
@@ -468,13 +439,12 @@ void WLED::setup()
|
||||
UsermodManager::setup();
|
||||
DEBUG_PRINTF_P(PSTR("heap %u\n"), ESP.getFreeHeap());
|
||||
|
||||
if (needsCfgSave) serializeConfig(); // usermods required new parameters; need to wait for strip to be initialised #4752
|
||||
|
||||
if (strcmp(multiWiFi[0].clientSSID, DEFAULT_CLIENT_SSID) == 0)
|
||||
showWelcomePage = true;
|
||||
WiFi.persistent(false);
|
||||
#ifdef WLED_USE_ETHERNET
|
||||
WiFi.onEvent(WiFiEvent);
|
||||
#endif
|
||||
|
||||
WiFi.mode(WIFI_STA); // enable scanning
|
||||
findWiFi(true); // start scanning for available WiFi-s
|
||||
|
||||
@@ -491,7 +461,7 @@ void WLED::setup()
|
||||
#endif
|
||||
|
||||
// fill in unique mdns default
|
||||
if (strcmp(cmDNS, "x") == 0) sprintf_P(cmDNS, PSTR("wled-%*s"), 6, escapedMac.c_str() + 6);
|
||||
if (strcmp(cmDNS, DEFAULT_MDNS_NAME) == 0) sprintf_P(cmDNS, PSTR("wled-%*s"), 6, escapedMac.c_str() + 6);
|
||||
#ifndef WLED_DISABLE_MQTT
|
||||
if (mqttDeviceTopic[0] == 0) sprintf_P(mqttDeviceTopic, PSTR("wled/%*s"), 6, escapedMac.c_str() + 6);
|
||||
if (mqttClientID[0] == 0) sprintf_P(mqttClientID, PSTR("WLED-%*s"), 6, escapedMac.c_str() + 6);
|
||||
@@ -564,6 +534,7 @@ void WLED::beginStrip()
|
||||
strip.makeAutoSegments();
|
||||
strip.setBrightness(0);
|
||||
strip.setShowCallback(handleOverlayDraw);
|
||||
doInitBusses = false;
|
||||
|
||||
if (turnOnAtBoot) {
|
||||
if (briS > 0) bri = briS;
|
||||
@@ -571,11 +542,12 @@ void WLED::beginStrip()
|
||||
} else {
|
||||
// fix for #3196
|
||||
if (bootPreset > 0) {
|
||||
bool oldTransition = fadeTransition; // workaround if transitions are enabled
|
||||
fadeTransition = false; // ignore transitions temporarily
|
||||
strip.setColor(0, BLACK); // set all segments black
|
||||
fadeTransition = oldTransition; // restore transitions
|
||||
col[0] = col[1] = col[2] = col[3] = 0; // needed for colorUpdated()
|
||||
// set all segments black (no transition)
|
||||
for (unsigned i = 0; i < strip.getSegmentsNum(); i++) {
|
||||
Segment &seg = strip.getSegment(i);
|
||||
if (seg.isActive()) seg.colors[0] = BLACK;
|
||||
}
|
||||
colPri[0] = colPri[1] = colPri[2] = colPri[3] = 0; // needed for colorUpdated()
|
||||
}
|
||||
briLast = briS; bri = 0;
|
||||
strip.fill(BLACK);
|
||||
@@ -774,7 +746,7 @@ int8_t WLED::findWiFi(bool doScan) {
|
||||
|
||||
void WLED::initConnection()
|
||||
{
|
||||
DEBUG_PRINTLN(F("initConnection() called."));
|
||||
DEBUG_PRINTF_P(PSTR("initConnection() called @ %lus.\n"), millis()/1000);
|
||||
|
||||
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||
ws.onEvent(wsEvent);
|
||||
@@ -789,6 +761,7 @@ void WLED::initConnection()
|
||||
#endif
|
||||
|
||||
WiFi.disconnect(true); // close old connections
|
||||
delay(5); // wait for hardware to be ready
|
||||
#ifdef ESP8266
|
||||
WiFi.setPhyMode(force802_3g ? WIFI_PHY_MODE_11G : WIFI_PHY_MODE_11N);
|
||||
#endif
|
||||
@@ -818,9 +791,7 @@ void WLED::initConnection()
|
||||
if (WLED_WIFI_CONFIGURED) {
|
||||
showWelcomePage = false;
|
||||
|
||||
DEBUG_PRINT(F("Connecting to "));
|
||||
DEBUG_PRINT(multiWiFi[selectedWiFi].clientSSID);
|
||||
DEBUG_PRINTLN(F("..."));
|
||||
DEBUG_PRINTF_P(PSTR("Connecting to %s...\n"), multiWiFi[selectedWiFi].clientSSID);
|
||||
|
||||
// convert the "serverDescription" into a valid DNS hostname (alphanumeric)
|
||||
char hostname[25];
|
||||
@@ -919,7 +890,8 @@ void WLED::handleConnection()
|
||||
{
|
||||
static bool scanDone = true;
|
||||
static byte stacO = 0;
|
||||
unsigned long now = millis();
|
||||
const unsigned long now = millis();
|
||||
const unsigned long nowS = now/1000;
|
||||
const bool wifiConfigured = WLED_WIFI_CONFIGURED;
|
||||
|
||||
// ignore connection handling if WiFi is configured and scan still running
|
||||
@@ -928,7 +900,7 @@ void WLED::handleConnection()
|
||||
return;
|
||||
|
||||
if (lastReconnectAttempt == 0 || forceReconnect) {
|
||||
DEBUG_PRINTLN(F("Initial connect or forced reconnect."));
|
||||
DEBUG_PRINTF_P(PSTR("Initial connect or forced reconnect (@ %lus).\n"), nowS);
|
||||
selectedWiFi = findWiFi(); // find strongest WiFi
|
||||
initConnection();
|
||||
interfacesInited = false;
|
||||
@@ -948,8 +920,7 @@ void WLED::handleConnection()
|
||||
#endif
|
||||
if (stac != stacO) {
|
||||
stacO = stac;
|
||||
DEBUG_PRINT(F("Connected AP clients: "));
|
||||
DEBUG_PRINTLN(stac);
|
||||
DEBUG_PRINTF_P(PSTR("Connected AP clients: %d\n"), (int)stac);
|
||||
if (!WLED_CONNECTED && wifiConfigured) { // trying to connect, but not connected
|
||||
if (stac)
|
||||
WiFi.disconnect(); // disable search so that AP can work
|
||||
@@ -972,6 +943,7 @@ void WLED::handleConnection()
|
||||
initConnection();
|
||||
interfacesInited = false;
|
||||
scanDone = true;
|
||||
return;
|
||||
}
|
||||
//send improv failed 6 seconds after second init attempt (24 sec. after provisioning)
|
||||
if (improvActive > 2 && now - lastReconnectAttempt > 6000) {
|
||||
@@ -980,13 +952,13 @@ void WLED::handleConnection()
|
||||
}
|
||||
if (now - lastReconnectAttempt > ((stac) ? 300000 : 18000) && wifiConfigured) {
|
||||
if (improvActive == 2) improvActive = 3;
|
||||
DEBUG_PRINTLN(F("Last reconnect too old."));
|
||||
DEBUG_PRINTF_P(PSTR("Last reconnect (%lus) too old (@ %lus).\n"), lastReconnectAttempt/1000, nowS);
|
||||
if (++selectedWiFi >= multiWiFi.size()) selectedWiFi = 0; // we couldn't connect, try with another network from the list
|
||||
initConnection();
|
||||
}
|
||||
if (!apActive && now - lastReconnectAttempt > 12000 && (!wasConnected || apBehavior == AP_BEHAVIOR_NO_CONN)) {
|
||||
if (!(apBehavior == AP_BEHAVIOR_TEMPORARY && now > WLED_AP_TIMEOUT)) {
|
||||
DEBUG_PRINTLN(F("Not connected AP."));
|
||||
DEBUG_PRINTF_P(PSTR("Not connected AP (@ %lus).\n"), nowS);
|
||||
initAP(); // start AP only within first 5min
|
||||
}
|
||||
}
|
||||
@@ -996,7 +968,7 @@ void WLED::handleConnection()
|
||||
dnsServer.stop();
|
||||
WiFi.softAPdisconnect(true);
|
||||
apActive = false;
|
||||
DEBUG_PRINTLN(F("Temporary AP disabled."));
|
||||
DEBUG_PRINTF_P(PSTR("Temporary AP disabled (@ %lus).\n"), nowS);
|
||||
}
|
||||
}
|
||||
} else if (!interfacesInited) { //newly connected
|
||||
|
||||
@@ -3,12 +3,11 @@
|
||||
/*
|
||||
Main sketch, global variable declarations
|
||||
@title WLED project sketch
|
||||
@version 0.15.0-b5
|
||||
@author Christian Schwinne
|
||||
*/
|
||||
|
||||
// version code in format yymmddb (b = daily build)
|
||||
#define VERSION 2409170
|
||||
#define VERSION 2508020
|
||||
|
||||
//uncomment this if you have a "my_config.h" file you'd like to use
|
||||
//#define WLED_USE_MY_CONFIG
|
||||
@@ -36,12 +35,13 @@
|
||||
#undef WLED_ENABLE_ADALIGHT // disable has priority over enable
|
||||
#endif
|
||||
//#define WLED_ENABLE_DMX // uses 3.5kb
|
||||
//#define WLED_ENABLE_JSONLIVE // peek LED output via /json/live (WS binary peek is always enabled)
|
||||
#ifndef WLED_DISABLE_LOXONE
|
||||
#define WLED_ENABLE_LOXONE // uses 1.2kb
|
||||
#endif
|
||||
#ifndef WLED_DISABLE_WEBSOCKETS
|
||||
#define WLED_ENABLE_WEBSOCKETS
|
||||
#else
|
||||
#define WLED_ENABLE_JSONLIVE // peek LED output via /json/live (WS binary peek is always enabled)
|
||||
#endif
|
||||
|
||||
//#define WLED_DISABLE_ESPNOW // Removes dependence on esp now
|
||||
@@ -263,12 +263,12 @@ using PSRAMDynamicJsonDocument = BasicJsonDocument<PSRAM_Allocator>;
|
||||
#define WLED_VERSION dev
|
||||
#endif
|
||||
#ifndef WLED_RELEASE_NAME
|
||||
#define WLED_RELEASE_NAME dev_release
|
||||
#define WLED_RELEASE_NAME "Custom"
|
||||
#endif
|
||||
|
||||
// Global Variable definitions
|
||||
WLED_GLOBAL char versionString[] _INIT(TOSTRING(WLED_VERSION));
|
||||
WLED_GLOBAL char releaseString[] _INIT(TOSTRING(WLED_RELEASE_NAME)); // somehow this will not work if using "const char releaseString[]
|
||||
WLED_GLOBAL char releaseString[] _INIT(WLED_RELEASE_NAME); // must include the quotes when defining, e.g -D WLED_RELEASE_NAME=\"ESP32_MULTI_USREMODS\"
|
||||
#define WLED_CODENAME "Kōsen"
|
||||
|
||||
// AP and OTA default passwords (for maximum security change them!)
|
||||
@@ -316,8 +316,6 @@ WLED_GLOBAL bool rlyOpenDrain _INIT(RLYODRAIN);
|
||||
constexpr uint8_t hardwareTX = 1;
|
||||
#endif
|
||||
|
||||
//WLED_GLOBAL byte presetToApply _INIT(0);
|
||||
|
||||
WLED_GLOBAL char ntpServerName[33] _INIT("0.wled.pool.ntp.org"); // NTP server to use
|
||||
|
||||
// WiFi CONFIG (all these can be changed via web UI, no need to set them here)
|
||||
@@ -369,7 +367,7 @@ WLED_GLOBAL bool noWifiSleep _INIT(false);
|
||||
WLED_GLOBAL bool force802_3g _INIT(false);
|
||||
#endif // WLED_SAVE_RAM
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#if defined(LOLIN_WIFI_FIX) && (defined(ARDUINO_ARCH_ESP32C3) || defined(ARDUINO_ARCH_ESP32S2) || defined(ARDUINO_ARCH_ESP32S3))
|
||||
#if defined(LOLIN_WIFI_FIX) && (defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3))
|
||||
WLED_GLOBAL uint8_t txPower _INIT(WIFI_POWER_8_5dBm);
|
||||
#else
|
||||
WLED_GLOBAL uint8_t txPower _INIT(WIFI_POWER_19_5dBm);
|
||||
@@ -396,6 +394,9 @@ WLED_GLOBAL byte bootPreset _INIT(0); // save preset to load
|
||||
WLED_GLOBAL bool useGlobalLedBuffer _INIT(false); // double buffering disabled on ESP8266
|
||||
#else
|
||||
WLED_GLOBAL bool useGlobalLedBuffer _INIT(true); // double buffering enabled on ESP32
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
WLED_GLOBAL bool useParallelI2S _INIT(true); // parallel I2S for ESP32
|
||||
#endif
|
||||
#endif
|
||||
#ifdef WLED_USE_IC_CCT
|
||||
WLED_GLOBAL bool cctICused _INIT(true); // CCT IC used (Athom 15W bulbs)
|
||||
@@ -406,7 +407,7 @@ WLED_GLOBAL bool gammaCorrectCol _INIT(true); // use gamma correction on col
|
||||
WLED_GLOBAL bool gammaCorrectBri _INIT(false); // use gamma correction on brightness
|
||||
WLED_GLOBAL float gammaCorrectVal _INIT(2.8f); // gamma correction value
|
||||
|
||||
WLED_GLOBAL byte col[] _INIT_N(({ 255, 160, 0, 0 })); // current RGB(W) primary color. col[] should be updated if you want to change the color.
|
||||
WLED_GLOBAL byte colPri[] _INIT_N(({ 255, 160, 0, 0 })); // current RGB(W) primary color. colPri[] should be updated if you want to change the color.
|
||||
WLED_GLOBAL byte colSec[] _INIT_N(({ 0, 0, 0, 0 })); // current RGB(W) secondary color
|
||||
|
||||
WLED_GLOBAL byte nightlightTargetBri _INIT(0); // brightness after nightlight is over
|
||||
@@ -696,10 +697,10 @@ WLED_GLOBAL bool receiveNotificationPalette _INIT(true); // apply palet
|
||||
WLED_GLOBAL bool receiveSegmentOptions _INIT(false); // apply segment options
|
||||
WLED_GLOBAL bool receiveSegmentBounds _INIT(false); // apply segment bounds (start, stop, offset)
|
||||
WLED_GLOBAL bool receiveDirect _INIT(true); // receive UDP/Hyperion realtime
|
||||
WLED_GLOBAL bool notifyDirect _INIT(false); // send notification if change via UI or HTTP API
|
||||
WLED_GLOBAL bool notifyButton _INIT(false); // send if updated by button or infrared remote
|
||||
WLED_GLOBAL bool notifyDirect _INIT(true); // send notification if change via UI or HTTP API
|
||||
WLED_GLOBAL bool notifyButton _INIT(true); // send if updated by button or infrared remote
|
||||
WLED_GLOBAL bool notifyAlexa _INIT(false); // send notification if updated via Alexa
|
||||
WLED_GLOBAL bool notifyHue _INIT(true); // send notification if Hue light changes
|
||||
WLED_GLOBAL bool notifyHue _INIT(false); // send notification if Hue light changes
|
||||
#endif
|
||||
|
||||
// effects
|
||||
@@ -839,10 +840,6 @@ WLED_GLOBAL time_t sunrise _INIT(0);
|
||||
WLED_GLOBAL time_t sunset _INIT(0);
|
||||
WLED_GLOBAL Toki toki _INIT(Toki());
|
||||
|
||||
// Temp buffer
|
||||
WLED_GLOBAL char* obuf;
|
||||
WLED_GLOBAL uint16_t olen _INIT(0);
|
||||
|
||||
// General filesystem
|
||||
WLED_GLOBAL size_t fsBytesUsed _INIT(0);
|
||||
WLED_GLOBAL size_t fsBytesTotal _INIT(0);
|
||||
@@ -889,7 +886,7 @@ WLED_GLOBAL bool e131NewData _INIT(false);
|
||||
// led fx library object
|
||||
WLED_GLOBAL BusManager busses _INIT(BusManager());
|
||||
WLED_GLOBAL WS2812FX strip _INIT(WS2812FX());
|
||||
WLED_GLOBAL BusConfig* busConfigs[WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES] _INIT({nullptr}); //temporary, to remember values from network callback until after
|
||||
WLED_GLOBAL std::vector<BusConfig> busConfigs; //temporary, to remember values from network callback until after
|
||||
WLED_GLOBAL bool doInitBusses _INIT(false);
|
||||
WLED_GLOBAL int8_t loadLedmap _INIT(-1);
|
||||
WLED_GLOBAL uint8_t currentLedmap _INIT(0);
|
||||
|
||||
@@ -10,16 +10,25 @@
|
||||
|
||||
//#define WLED_DEBUG_MATH
|
||||
|
||||
// Note: cos_t, sin_t and tan_t are very accurate but slow
|
||||
// the math.h functions use several kB of flash and are to be avoided if possible
|
||||
// sin16_t / cos16_t are faster and much more accurate than the fastled variants
|
||||
// sin_approx and cos_approx are float wrappers for sin16_t/cos16_t and have an accuracy better than +/-0.0015 compared to sinf()
|
||||
// sin8_t / cos8_t are fastled replacements and use sin16_t / cos16_t. Slightly slower than fastled version but very accurate
|
||||
|
||||
|
||||
// Taylor series approximations, replaced with Bhaskara I's approximation
|
||||
/*
|
||||
#define modd(x, y) ((x) - (int)((x) / (y)) * (y))
|
||||
|
||||
float cos_t(float phi)
|
||||
{
|
||||
float x = modd(phi, TWO_PI);
|
||||
float x = modd(phi, M_TWOPI);
|
||||
if (x < 0) x = -1 * x;
|
||||
int8_t sign = 1;
|
||||
if (x > PI)
|
||||
if (x > M_PI)
|
||||
{
|
||||
x -= PI;
|
||||
x -= M_PI;
|
||||
sign = -1;
|
||||
}
|
||||
float xx = x * x;
|
||||
@@ -31,8 +40,8 @@ float cos_t(float phi)
|
||||
return res;
|
||||
}
|
||||
|
||||
float sin_t(float x) {
|
||||
float res = cos_t(HALF_PI - x);
|
||||
float sin_t(float phi) {
|
||||
float res = cos_t(M_PI_2 - phi);
|
||||
#ifdef WLED_DEBUG_MATH
|
||||
Serial.printf("sin: %f,%f,%f,(%f)\n",x,res,sin(x),res-sin(x));
|
||||
#endif
|
||||
@@ -48,6 +57,80 @@ float tan_t(float x) {
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
*/
|
||||
|
||||
// 16-bit, integer based Bhaskara I's sine approximation: 16*x*(pi - x) / (5*pi^2 - 4*x*(pi - x))
|
||||
// input is 16bit unsigned (0-65535), output is 16bit signed (-32767 to +32767)
|
||||
// optimized integer implementation by @dedehai
|
||||
int16_t sin16_t(uint16_t theta) {
|
||||
int scale = 1;
|
||||
if (theta > 0x7FFF) {
|
||||
theta = 0xFFFF - theta;
|
||||
scale = -1; // second half of the sine function is negative (pi - 2*pi)
|
||||
}
|
||||
uint32_t precal = theta * (0x7FFF - theta);
|
||||
uint64_t numerator = (uint64_t)precal * (4 * 0x7FFF); // 64bit required
|
||||
int32_t denominator = 1342095361 - precal; // 1342095361 is 5 * 0x7FFF^2 / 4
|
||||
int16_t result = numerator / denominator;
|
||||
return result * scale;
|
||||
}
|
||||
|
||||
int16_t cos16_t(uint16_t theta) {
|
||||
return sin16_t(theta + 0x4000); //cos(x) = sin(x+pi/2)
|
||||
}
|
||||
|
||||
uint8_t sin8_t(uint8_t theta) {
|
||||
int32_t sin16 = sin16_t((uint16_t)theta * 257); // 255 * 257 = 0xFFFF
|
||||
sin16 += 0x7FFF + 128; //shift result to range 0-0xFFFF, +128 for rounding
|
||||
return min(sin16, int32_t(0xFFFF)) >> 8; // min performs saturation, and prevents overflow
|
||||
}
|
||||
|
||||
uint8_t cos8_t(uint8_t theta) {
|
||||
return sin8_t(theta + 64); //cos(x) = sin(x+pi/2)
|
||||
}
|
||||
|
||||
float sin_approx(float theta) {
|
||||
uint16_t scaled_theta = (int)(theta * (float)(0xFFFF / M_TWOPI)); // note: do not cast negative float to uint! cast to int first (undefined on C3)
|
||||
int32_t result = sin16_t(scaled_theta);
|
||||
float sin = float(result) / 0x7FFF;
|
||||
return sin;
|
||||
}
|
||||
|
||||
float cos_approx(float theta) {
|
||||
uint16_t scaled_theta = (int)(theta * (float)(0xFFFF / M_TWOPI)); // note: do not cast negative float to uint! cast to int first (undefined on C3)
|
||||
int32_t result = sin16_t(scaled_theta + 0x4000);
|
||||
float cos = float(result) / 0x7FFF;
|
||||
return cos;
|
||||
}
|
||||
|
||||
float tan_approx(float x) {
|
||||
float c = cos_approx(x);
|
||||
if (c==0.0f) return 0;
|
||||
float res = sin_approx(x) / c;
|
||||
return res;
|
||||
}
|
||||
|
||||
#define ATAN2_CONST_A 0.1963f
|
||||
#define ATAN2_CONST_B 0.9817f
|
||||
|
||||
// atan2_t approximation, with the idea from https://gist.github.com/volkansalma/2972237?permalink_comment_id=3872525#gistcomment-3872525
|
||||
float atan2_t(float y, float x) {
|
||||
float abs_y = fabs(y);
|
||||
float abs_x = fabs(x);
|
||||
float r = (abs_x - abs_y) / (abs_y + abs_x + 1e-10f); // avoid division by zero by adding a small nubmer
|
||||
float angle;
|
||||
if(x < 0) {
|
||||
r = -r;
|
||||
angle = M_PI_2 + M_PI_4;
|
||||
}
|
||||
else
|
||||
angle = M_PI_2 - M_PI_4;
|
||||
|
||||
float add = (ATAN2_CONST_A * (r * r) - ATAN2_CONST_B) * r;
|
||||
angle += add;
|
||||
angle = y < 0 ? -angle : angle;
|
||||
return angle;
|
||||
}
|
||||
|
||||
//https://stackoverflow.com/questions/3380628
|
||||
// Absolute error <= 6.7e-5
|
||||
@@ -60,10 +143,10 @@ float acos_t(float x) {
|
||||
ret = ret * xabs;
|
||||
ret = ret - 0.2121144f;
|
||||
ret = ret * xabs;
|
||||
ret = ret + HALF_PI;
|
||||
ret = ret + M_PI_2;
|
||||
ret = ret * sqrt(1.0f-xabs);
|
||||
ret = ret - 2 * negate * ret;
|
||||
float res = negate * PI + ret;
|
||||
float res = negate * M_PI + ret;
|
||||
#ifdef WLED_DEBUG_MATH
|
||||
Serial.printf("acos: %f,%f,%f,(%f)\n",x,res,acos(x),res-acos(x));
|
||||
#endif
|
||||
@@ -71,7 +154,7 @@ float acos_t(float x) {
|
||||
}
|
||||
|
||||
float asin_t(float x) {
|
||||
float res = HALF_PI - acos_t(x);
|
||||
float res = M_PI_2 - acos_t(x);
|
||||
#ifdef WLED_DEBUG_MATH
|
||||
Serial.printf("asin: %f,%f,%f,(%f)\n",x,res,asin(x),res-asin(x));
|
||||
#endif
|
||||
@@ -87,7 +170,7 @@ float atan_t(float x) {
|
||||
//For A/B/C, see https://stackoverflow.com/a/42542593
|
||||
static const double A { 0.0776509570923569 };
|
||||
static const double B { -0.287434475393028 };
|
||||
static const double C { ((HALF_PI/2) - A - B) };
|
||||
static const double C { ((M_PI_4) - A - B) };
|
||||
// polynominal factors for approximation between 1 and 5
|
||||
static const float C0 { 0.089494f };
|
||||
static const float C1 { 0.974207f };
|
||||
@@ -102,7 +185,7 @@ float atan_t(float x) {
|
||||
x = std::abs(x);
|
||||
float res;
|
||||
if (x > 5.0f) { // atan(x) converges to pi/2 - (1/x) for large values
|
||||
res = HALF_PI - (1.0f/x);
|
||||
res = M_PI_2 - (1.0f/x);
|
||||
} else if (x > 1.0f) { //1 < x < 5
|
||||
float xx = x * x;
|
||||
res = (C4*xx*xx)+(C3*xx*x)+(C2*xx)+(C1*x)+C0;
|
||||
|
||||
@@ -193,12 +193,12 @@ void createEditHandler(bool enable) {
|
||||
editHandler = &server.addHandler(new SPIFFSEditor("","",WLED_FS));//http_username,http_password));
|
||||
#endif
|
||||
#else
|
||||
editHandler = &server.on(SET_F("/edit"), HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
editHandler = &server.on(F("/edit"), HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
serveMessage(request, 501, FPSTR(s_notimplemented), F("The FS editor is disabled in this build."), 254);
|
||||
});
|
||||
#endif
|
||||
} else {
|
||||
editHandler = &server.on(SET_F("/edit"), HTTP_ANY, [](AsyncWebServerRequest *request){
|
||||
editHandler = &server.on(F("/edit"), HTTP_ANY, [](AsyncWebServerRequest *request){
|
||||
serveMessage(request, 401, FPSTR(s_accessdenied), FPSTR(s_unlock_cfg), 254);
|
||||
});
|
||||
}
|
||||
@@ -427,11 +427,11 @@ void initServer()
|
||||
|
||||
|
||||
#ifdef WLED_ENABLE_DMX
|
||||
server.on(SET_F("/dmxmap"), HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
server.on(F("/dmxmap"), HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
request->send_P(200, FPSTR(CONTENT_TYPE_HTML), PAGE_dmxmap , dmxProcessor);
|
||||
});
|
||||
#else
|
||||
server.on(SET_F("/dmxmap"), HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
server.on(F("/dmxmap"), HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
serveMessage(request, 501, FPSTR(s_notimplemented), F("DMX support is not enabled in this build."), 254);
|
||||
});
|
||||
#endif
|
||||
@@ -520,27 +520,23 @@ void serveSettingsJS(AsyncWebServerRequest* request)
|
||||
handleStaticContent(request, FPSTR(_common_js), 200, FPSTR(CONTENT_TYPE_JAVASCRIPT), JS_common, JS_common_length);
|
||||
return;
|
||||
}
|
||||
char buf[SETTINGS_STACK_BUF_SIZE+37];
|
||||
buf[0] = 0;
|
||||
byte subPage = request->arg(F("p")).toInt();
|
||||
if (subPage > 10) {
|
||||
strcpy_P(buf, PSTR("alert('Settings for this request are not implemented.');"));
|
||||
request->send(501, FPSTR(CONTENT_TYPE_JAVASCRIPT), buf);
|
||||
request->send_P(501, FPSTR(CONTENT_TYPE_JAVASCRIPT), PSTR("alert('Settings for this request are not implemented.');"));
|
||||
return;
|
||||
}
|
||||
if (subPage > 0 && !correctPIN && strlen(settingsPIN)>0) {
|
||||
strcpy_P(buf, PSTR("alert('PIN incorrect.');"));
|
||||
request->send(401, FPSTR(CONTENT_TYPE_JAVASCRIPT), buf);
|
||||
request->send_P(401, FPSTR(CONTENT_TYPE_JAVASCRIPT), PSTR("alert('PIN incorrect.');"));
|
||||
return;
|
||||
}
|
||||
strcat_P(buf,PSTR("function GetV(){var d=document;"));
|
||||
getSettingsJS(subPage, buf+strlen(buf)); // this may overflow by 35bytes!!!
|
||||
strcat_P(buf,PSTR("}"));
|
||||
|
||||
AsyncWebServerResponse *response;
|
||||
response = request->beginResponse(200, FPSTR(CONTENT_TYPE_JAVASCRIPT), buf);
|
||||
AsyncResponseStream *response = request->beginResponseStream(FPSTR(CONTENT_TYPE_JAVASCRIPT));
|
||||
response->addHeader(F("Cache-Control"), F("no-store"));
|
||||
response->addHeader(F("Expires"), F("0"));
|
||||
|
||||
response->print(F("function GetV(){var d=document;"));
|
||||
getSettingsJS(subPage, *response);
|
||||
response->print(F("}"));
|
||||
request->send(response);
|
||||
}
|
||||
|
||||
|
||||
812
wled00/xml.cpp
812
wled00/xml.cpp
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user