mirror of
https://github.com/wled/WLED.git
synced 2025-04-25 07:17:18 +00:00
Merge branch '0_15' into main
This commit is contained in:
commit
fa5d60ca26
4
.github/workflows/wled-ci.yml
vendored
4
.github/workflows/wled-ci.yml
vendored
@ -37,7 +37,7 @@ jobs:
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
cache: 'npm'
|
||||
- run: npm install
|
||||
- run: npm ci
|
||||
- name: Cache PlatformIO
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
@ -61,7 +61,7 @@ jobs:
|
||||
name: firmware-${{ matrix.environment }}
|
||||
path: |
|
||||
build_output/release/*.bin
|
||||
build_output/release/*_ESP02.bin.gz
|
||||
build_output/release/*_ESP02*.bin.gz
|
||||
release:
|
||||
name: Create Release
|
||||
runs-on: ubuntu-latest
|
||||
|
58
CHANGELOG.md
58
CHANGELOG.md
@ -1,5 +1,43 @@
|
||||
## WLED changelog
|
||||
|
||||
#### Build 2403280
|
||||
- Individual color channel control for JSON API (fixes #3860)
|
||||
- "col":[int|string|object|array, int|string|object|array, int|string|object|array]
|
||||
int = Kelvin temperature or 0 for black
|
||||
string = hex representation of [WW]RRGGBB
|
||||
object = individual channel control {"r":0,"g":127,"b":255,"w":255}, each being optional (valid to send {})
|
||||
array = direct channel values [r,g,b,w] (w element being optional)
|
||||
- runtime selection for CCT IC (Athom 15W bulb)
|
||||
- #3850 (by @w00000dy)
|
||||
- Rotary encoder palette count bugfix
|
||||
- bugfixes and optimisations
|
||||
|
||||
#### Build 2403240
|
||||
- v0.15.0-b2
|
||||
- WS2805 support (RGB + WW + CW, 600kbps)
|
||||
- Unified PSRAM use
|
||||
- NeoPixelBus v2.7.9 (for future WS2805 support)
|
||||
- Ubiquitous PSRAM mode for all variants of ESP32
|
||||
- SSD1309_64 I2C Support for FLD Usermod (#3836 by @THATDONFC)
|
||||
- Palette cycling fix (add support for `{"seg":[{"pal":"X~Y~"}]}` or `{"seg":[{"pal":"X~Yr"}]}`)
|
||||
- FW1906 Support (#3810 by @deece and @Robert-github-com)
|
||||
- ESPAsyncWebServer 2.2.0 (#3828 by @willmmiles)
|
||||
- Bugfixes: #3843, #3844
|
||||
|
||||
#### Build 2403190
|
||||
- limit max PWM frequency (fix incorrect PWM resolution)
|
||||
- Segment UI bugfix
|
||||
- Updated AsyncWebServer (by @wlillmmiles)
|
||||
- Simpler boot preset (fix for #3806)
|
||||
- Effect: Fix for 2D Drift animation (#3816 by @BaptisteHudyma)
|
||||
- Effect: Add twin option to 2D Drift
|
||||
- MQTT cleanup
|
||||
- DDP: Support sources that don't push (#3833 by @willmmiles)
|
||||
- Usermod: Tetris AI usermod (#3711 by @muebau)
|
||||
|
||||
#### Build 2403171
|
||||
- merge 0.14.2 changes into 0.15
|
||||
|
||||
#### Build 2403070
|
||||
- Add additional segment options when controlling over e1.31 (#3616 by @demophoon)
|
||||
- LockedJsonResponse: Release early if possible (#3760 by @willmmiles)
|
||||
@ -120,6 +158,26 @@
|
||||
- send UDP/WS on segment change
|
||||
- pop_back() when removing last segment
|
||||
|
||||
#### Build 2403170
|
||||
- WLED 0.14.2 release
|
||||
|
||||
#### Build 2403110
|
||||
- Beta WLED 0.14.2-b2
|
||||
- New AsyncWebServer (improved performance and reduced memory use)
|
||||
- New builds for ESP8266 with 160MHz CPU clock
|
||||
- Fixing stairway usermod and adding buildflags (#3758 by @lost-hope)
|
||||
- Fixing a potential array bounds violation in ESPDMX
|
||||
- Reduced RAM usage (moved strings and TZ data (by @willmmiles) to PROGMEM)
|
||||
- LockedJsonResponse: Release early if possible (by @willmmiles)
|
||||
|
||||
#### Build 2402120
|
||||
- Beta WLED 0.14.2-b1
|
||||
- Possible fix for #3589 & partial fix for #3605
|
||||
- Prevent JSON buffer clear after failed lock attempt
|
||||
- Multiple analog button fix for #3549
|
||||
- UM Audioreactive: add two compiler options (#3732 by @wled-install)
|
||||
- Fix for #3693
|
||||
|
||||
#### Build 2401141
|
||||
- Official release of WLED 0.14.1
|
||||
- Fix for #3566, #3665, #3672
|
||||
|
@ -2,6 +2,20 @@
|
||||
|
||||
Here are a few suggestions to make it easier for you to contribute!
|
||||
|
||||
### Describe your PR
|
||||
|
||||
Please add a description of your proposed code changes. It does not need to be an exhaustive essay, however a PR with no description or just a few words might not get accepted, simply because very basic information is missing.
|
||||
|
||||
A good description helps us to review and understand your proposed changes. For example, you could say a few words about
|
||||
* what you try to achieve (new feature, fixing a bug, refactoring, security enhancements, etc.)
|
||||
* how your code works (short technical summary - focus on important aspects that might not be obvious when reading the code)
|
||||
* testing you performed, known limitations, open ends you possibly could not solve.
|
||||
* any areas where you like to get help from an experienced maintainer (yes WLED has become big 😉)
|
||||
|
||||
### Target branch for pull requests
|
||||
|
||||
Please make all PRs against the `0_15` branch.
|
||||
|
||||
### Code style
|
||||
|
||||
When in doubt, it is easiest to replicate the code style you find in the files you want to edit :)
|
||||
@ -73,6 +87,6 @@ Good:
|
||||
<!-- This is an HTML comment -->
|
||||
```
|
||||
|
||||
There is no set character limit for a comment within a line,
|
||||
though as a rule of thumb you should wrap your comment if it exceeds the width of your editor window.
|
||||
There is no hard character limit for a comment within a line,
|
||||
though as a rule of thumb consider wrapping after 120 characters.
|
||||
Inline comments are OK if they describe that line only and are not exceedingly wide.
|
102
package-lock.json
generated
102
package-lock.json
generated
@ -1,57 +1,56 @@
|
||||
{
|
||||
"name": "wled",
|
||||
"version": "0.15.0-b1",
|
||||
"version": "0.15.0-b2",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "wled",
|
||||
"version": "0.15.0-b1",
|
||||
"version": "0.15.0-b2",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"clean-css": "^5.3.3",
|
||||
"html-minifier-terser": "^7.2.0",
|
||||
"inliner": "^1.13.1",
|
||||
"nodemon": "^3.0.2",
|
||||
"zlib": "^1.0.5"
|
||||
"nodemon": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/gen-mapping": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
|
||||
"integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
|
||||
"version": "0.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
|
||||
"integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
|
||||
"dependencies": {
|
||||
"@jridgewell/set-array": "^1.0.1",
|
||||
"@jridgewell/set-array": "^1.2.1",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.10",
|
||||
"@jridgewell/trace-mapping": "^0.3.9"
|
||||
"@jridgewell/trace-mapping": "^0.3.24"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/resolve-uri": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz",
|
||||
"integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==",
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
|
||||
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/set-array": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
|
||||
"integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
|
||||
"integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/source-map": {
|
||||
"version": "0.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz",
|
||||
"integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==",
|
||||
"version": "0.3.6",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz",
|
||||
"integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==",
|
||||
"dependencies": {
|
||||
"@jridgewell/gen-mapping": "^0.3.0",
|
||||
"@jridgewell/trace-mapping": "^0.3.9"
|
||||
"@jridgewell/gen-mapping": "^0.3.5",
|
||||
"@jridgewell/trace-mapping": "^0.3.25"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/sourcemap-codec": {
|
||||
@ -60,9 +59,9 @@
|
||||
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
|
||||
},
|
||||
"node_modules/@jridgewell/trace-mapping": {
|
||||
"version": "0.3.21",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.21.tgz",
|
||||
"integrity": "sha512-SRfKmRe1KvYnxjEMtxEr+J4HIeMX5YBg/qhRHpxEIGjhX1rshcHlnFUE9K0GazhVKWM7B+nARSkV8LuvJdJ5/g==",
|
||||
"version": "0.3.25",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
|
||||
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
|
||||
"dependencies": {
|
||||
"@jridgewell/resolve-uri": "^3.1.0",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||
@ -209,11 +208,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/binary-extensions": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
||||
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
|
||||
"integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/boolbase": {
|
||||
@ -324,15 +326,9 @@
|
||||
"integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w=="
|
||||
},
|
||||
"node_modules/chokidar": {
|
||||
"version": "3.5.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
|
||||
"integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
],
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
|
||||
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
|
||||
"dependencies": {
|
||||
"anymatch": "~3.1.2",
|
||||
"braces": "~3.0.2",
|
||||
@ -345,6 +341,9 @@
|
||||
"engines": {
|
||||
"node": ">= 8.10.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
@ -1376,9 +1375,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/nodemon": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.3.tgz",
|
||||
"integrity": "sha512-7jH/NXbFPxVaMwmBCC2B9F/V6X1VkEdNgx3iu9jji8WxWcvhMWkmhNWhI5077zknOnZnBzba9hZP6bCPJLSReQ==",
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.0.tgz",
|
||||
"integrity": "sha512-xqlktYlDMCepBJd43ZQhjWwMw2obW/JRvkrLxq5RCNcuDDX1DbcPT+qT1IlIIdf+DhnWs90JpTMe+Y5KxOchvA==",
|
||||
"dependencies": {
|
||||
"chokidar": "^3.5.2",
|
||||
"debug": "^4",
|
||||
@ -1827,9 +1826,9 @@
|
||||
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.5.4",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
|
||||
"integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
|
||||
"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"
|
||||
},
|
||||
@ -1925,9 +1924,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/stream-shift": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.2.tgz",
|
||||
"integrity": "sha512-rV4Bovi9xx0BFzOb/X0B2GqoIjvqPCttZdu0Wgtx2Dxkj7ETyWl9gmqJ4EutWRLvtZWm8dxE+InQZX1IryZn/w=="
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz",
|
||||
"integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ=="
|
||||
},
|
||||
"node_modules/string_decoder": {
|
||||
"version": "0.10.31",
|
||||
@ -1994,9 +1993,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/terser": {
|
||||
"version": "5.27.0",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.27.0.tgz",
|
||||
"integrity": "sha512-bi1HRwVRskAjheeYl291n3JC4GgO/Ty4z1nVs5AAsmonJulGxpSektecnNedrwK9C7vpvVtcX3cw00VSLt7U2A==",
|
||||
"version": "5.29.2",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.29.2.tgz",
|
||||
"integrity": "sha512-ZiGkhUBIM+7LwkNjXYJq8svgkd+QK3UUr0wJqY4MieaezBSAIPgbSPZyIx0idM6XWK5CMzSWa8MJIzmRcB8Caw==",
|
||||
"dependencies": {
|
||||
"@jridgewell/source-map": "^0.3.3",
|
||||
"acorn": "^8.8.2",
|
||||
@ -2245,15 +2244,6 @@
|
||||
"decamelize": "^1.0.0",
|
||||
"window-size": "0.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/zlib": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/zlib/-/zlib-1.0.5.tgz",
|
||||
"integrity": "sha512-40fpE2II+Cd3k8HWTWONfeKE2jL+P42iWJ1zzps5W51qcTsOUKM5Q5m2PFb0CLxlmFAaUuUdJGc3OfZy947v0w==",
|
||||
"hasInstallScript": true,
|
||||
"engines": {
|
||||
"node": ">=0.2.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wled",
|
||||
"version": "0.15.0-b1",
|
||||
"version": "0.15.0-b2",
|
||||
"description": "Tools for WLED project",
|
||||
"main": "tools/cdata.js",
|
||||
"directories": {
|
||||
@ -26,7 +26,6 @@
|
||||
"clean-css": "^5.3.3",
|
||||
"html-minifier-terser": "^7.2.0",
|
||||
"inliner": "^1.13.1",
|
||||
"nodemon": "^3.0.2",
|
||||
"zlib": "^1.0.5"
|
||||
"nodemon": "^3.0.2"
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ import os
|
||||
import shutil
|
||||
import gzip
|
||||
|
||||
OUTPUT_DIR = "build_output{}".format(os.path.sep)
|
||||
OUTPUT_DIR = os.path.join("build_output")
|
||||
|
||||
def _get_cpp_define_value(env, define):
|
||||
define_list = [item[-1] for item in env["CPPDEFINES"] if item[0] == define]
|
||||
@ -13,24 +13,19 @@ def _get_cpp_define_value(env, define):
|
||||
|
||||
return None
|
||||
|
||||
def _create_dirs(dirs=["firmware", "map"]):
|
||||
# check if output directories exist and create if necessary
|
||||
if not os.path.isdir(OUTPUT_DIR):
|
||||
os.mkdir(OUTPUT_DIR)
|
||||
|
||||
def _create_dirs(dirs=["map", "release"]):
|
||||
for d in dirs:
|
||||
if not os.path.isdir("{}{}".format(OUTPUT_DIR, d)):
|
||||
os.mkdir("{}{}".format(OUTPUT_DIR, d))
|
||||
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:
|
||||
_create_dirs(["release"])
|
||||
version = _get_cpp_define_value(env, "WLED_VERSION")
|
||||
# get file extension of source file (.bin or .bin.gz)
|
||||
ext = source.split(".", 1)[1]
|
||||
release_file = "{}release{}WLED_{}_{}.{}".format(OUTPUT_DIR, os.path.sep, version, release_name, ext)
|
||||
release_file = os.path.join(OUTPUT_DIR, "release", f"WLED_{version}_{release_name}.bin")
|
||||
release_gz_file = release_file + ".gz"
|
||||
print(f"Copying {source} to {release_file}")
|
||||
shutil.copy(source, release_file)
|
||||
bin_gzip(release_file, release_gz_file)
|
||||
|
||||
def bin_rename_copy(source, target, env):
|
||||
_create_dirs()
|
||||
@ -38,38 +33,21 @@ def bin_rename_copy(source, target, env):
|
||||
|
||||
# create string with location and file names based on variant
|
||||
map_file = "{}map{}{}.map".format(OUTPUT_DIR, os.path.sep, variant)
|
||||
bin_file = "{}firmware{}{}.bin".format(OUTPUT_DIR, os.path.sep, variant)
|
||||
|
||||
# check if new target files exist and remove if necessary
|
||||
for f in [map_file, bin_file]:
|
||||
if os.path.isfile(f):
|
||||
os.remove(f)
|
||||
|
||||
# copy firmware.bin to firmware/<variant>.bin
|
||||
shutil.copy(str(target[0]), bin_file)
|
||||
|
||||
create_release(bin_file)
|
||||
create_release(str(target[0]))
|
||||
|
||||
# copy firmware.map to map/<variant>.map
|
||||
if os.path.isfile("firmware.map"):
|
||||
shutil.move("firmware.map", map_file)
|
||||
|
||||
def bin_gzip(source, target, env):
|
||||
_create_dirs()
|
||||
variant = env["PIOENV"]
|
||||
|
||||
# create string with location and file names based on variant
|
||||
bin_file = "{}firmware{}{}.bin".format(OUTPUT_DIR, os.path.sep, variant)
|
||||
gzip_file = "{}firmware{}{}.bin.gz".format(OUTPUT_DIR, os.path.sep, variant)
|
||||
|
||||
# check if new target files exist and remove if necessary
|
||||
if os.path.isfile(gzip_file): os.remove(gzip_file)
|
||||
|
||||
# write gzip firmware file
|
||||
with open(bin_file,"rb") as fp:
|
||||
with gzip.open(gzip_file, "wb", compresslevel = 9) as f:
|
||||
def bin_gzip(source, target):
|
||||
# only create gzip for esp8266
|
||||
if not env["PIOPLATFORM"] == "espressif8266":
|
||||
return
|
||||
|
||||
print(f"Creating gzip file {target} from {source}")
|
||||
with open(source,"rb") as fp:
|
||||
with gzip.open(target, "wb", compresslevel = 9) as f:
|
||||
shutil.copyfileobj(fp, f)
|
||||
|
||||
create_release(gzip_file)
|
||||
|
||||
env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", [bin_rename_copy, bin_gzip])
|
||||
env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", bin_rename_copy)
|
||||
|
@ -10,7 +10,7 @@
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# CI/release binaries
|
||||
default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth, esp32dev_audioreactive, lolin_s2_mini, esp32c3dev, esp32s3dev_8MB, esp32s3dev_8MB_PSRAM_opi, esp32_wrover
|
||||
default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, nodemcuv2_160, esp8266_2m_160, esp01_1m_full_160, esp32dev, esp32_eth, esp32dev_audioreactive, lolin_s2_mini, esp32c3dev, esp32s3dev_8MB, esp32s3dev_8MB_PSRAM_opi, esp32_wrover
|
||||
|
||||
src_dir = ./wled00
|
||||
data_dir = ./wled00/data
|
||||
@ -41,14 +41,13 @@ arduino_core_git = https://github.com/platformio/platform-espressif8266#feature/
|
||||
platform_wled_default = ${common.arduino_core_3_1_2}
|
||||
# We use 2.7.4.7 for all, includes PWM flicker fix and Wstring optimization
|
||||
#platform_packages = tasmota/framework-arduinoespressif8266 @ 3.20704.7
|
||||
platform_packages = platformio/framework-arduinoespressif8266
|
||||
platformio/toolchain-xtensa @ ~2.100300.220621 #2.40802.200502
|
||||
platform_packages = platformio/toolchain-xtensa @ ~2.100300.220621 #2.40802.200502
|
||||
platformio/tool-esptool #@ ~1.413.0
|
||||
platformio/tool-esptoolpy #@ ~1.30000.0
|
||||
|
||||
## previous platform for 8266, in case of problems with the new one
|
||||
## you'll need makuna/NeoPixelBus@ 2.6.9 for arduino_core_3_2_0, which does not support Ucs890x
|
||||
;; platform_wled_default = ${common.arduino_core_3_2_0}
|
||||
## you'll need makuna/NeoPixelBus@ 2.6.9 for arduino_core_3_0_2, which does not support Ucs890x
|
||||
;; platform_wled_default = ${common.arduino_core_3_0_2}
|
||||
;; platform_packages = tasmota/framework-arduinoespressif8266 @ 3.20704.7
|
||||
;; platformio/toolchain-xtensa @ ~2.40802.200502
|
||||
;; platformio/tool-esptool @ ~1.413.0
|
||||
@ -143,8 +142,8 @@ lib_compat_mode = strict
|
||||
lib_deps =
|
||||
fastled/FastLED @ 3.6.0
|
||||
IRremoteESP8266 @ 2.8.2
|
||||
makuna/NeoPixelBus @ 2.7.5
|
||||
https://github.com/Aircoookie/ESPAsyncWebServer.git @ ~2.0.7
|
||||
makuna/NeoPixelBus @ 2.7.9
|
||||
https://github.com/Aircoookie/ESPAsyncWebServer.git @ ^2.2.0
|
||||
# for I2C interface
|
||||
;Wire
|
||||
# ESP-NOW library
|
||||
@ -317,6 +316,11 @@ build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=ESP8266 #-DWLED
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
monitor_filters = esp8266_exception_decoder
|
||||
|
||||
[env:nodemcuv2_160]
|
||||
extends = env:nodemcuv2
|
||||
board_build.f_cpu = 160000000L
|
||||
build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=ESP8266_160 #-DWLED_DISABLE_2D
|
||||
|
||||
[env:esp8266_2m]
|
||||
board = esp_wroom_02
|
||||
platform = ${common.platform_wled_default}
|
||||
@ -326,6 +330,11 @@ build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=ESP02
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
|
||||
[env:esp8266_2m_160]
|
||||
extends = env:esp8266_2m
|
||||
board_build.f_cpu = 160000000L
|
||||
build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=ESP02_160
|
||||
|
||||
[env:esp01_1m_full]
|
||||
board = esp01_1m
|
||||
platform = ${common.platform_wled_default}
|
||||
@ -336,6 +345,12 @@ build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=ESP01 -D WLED_D
|
||||
; -D WLED_USE_UNREAL_MATH ;; may cause wrong sunset/sunrise times, but saves 7064 bytes FLASH and 975 bytes RAM
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
|
||||
[env:esp01_1m_full_160]
|
||||
extends = env:esp01_1m_full
|
||||
board_build.f_cpu = 160000000L
|
||||
build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=ESP01_160 -D WLED_DISABLE_OTA
|
||||
; -D WLED_USE_UNREAL_MATH ;; may cause wrong sunset/sunrise times, but saves 7064 bytes FLASH and 975 bytes RAM
|
||||
|
||||
[env:esp32dev]
|
||||
board = esp32dev
|
||||
platform = ${esp32.platform}
|
||||
@ -376,11 +391,10 @@ platform = ${esp32.platform}
|
||||
board = ttgo-t7-v14-mini32
|
||||
board_build.f_flash = 80000000L
|
||||
board_build.flash_mode = qio
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
board_build.partitions = tools/WLED_ESP32-wrover_4MB.csv
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32_WROVER
|
||||
-DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue
|
||||
-D WLED_USE_PSRAM
|
||||
-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 LEDPIN=25
|
||||
lib_deps = ${esp32.lib_deps}
|
||||
|
||||
@ -432,7 +446,6 @@ build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=
|
||||
;-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")
|
||||
; -D WLED_RELEASE_NAME=ESP32-S3_PSRAM
|
||||
-D WLED_USE_PSRAM -DBOARD_HAS_PSRAM ; tells WLED that PSRAM shall be used
|
||||
lib_deps = ${esp32s3.lib_deps}
|
||||
board_build.partitions = tools/WLED_ESP32_8MB.csv
|
||||
board_build.f_flash = 80000000L
|
||||
@ -448,12 +461,10 @@ board_build.partitions = tools/WLED_ESP32_4MB_1MB_FS.csv
|
||||
;board_build.f_flash = 80000000L
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32s2.build_flags} -D WLED_RELEASE_NAME=ESP32-S2
|
||||
-DBOARD_HAS_PSRAM
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1
|
||||
-DARDUINO_USB_MSC_ON_BOOT=0
|
||||
-DARDUINO_USB_DFU_ON_BOOT=0
|
||||
-DLOLIN_WIFI_FIX ; seems to work much better with this
|
||||
-D WLED_USE_PSRAM
|
||||
-D WLED_WATCHDOG_TIMEOUT=0
|
||||
-D CONFIG_ASYNC_TCP_USE_WDT=0
|
||||
-D LEDPIN=16
|
||||
|
@ -155,9 +155,8 @@ build_flags = ${common.build_flags_esp8266}
|
||||
; set default color order of your led strip
|
||||
; -D DEFAULT_LED_COLOR_ORDER=COL_ORDER_GRB
|
||||
;
|
||||
; use PSRAM if a device (ESP) has one
|
||||
; -DBOARD_HAS_PSRAM
|
||||
; -D WLED_USE_PSRAM
|
||||
; use PSRAM on classic ESP32 rev.1 (rev.3 or above has no issues)
|
||||
; -DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue
|
||||
;
|
||||
; configure I2C and SPI interface (for various hardware)
|
||||
; -D I2CSDAPIN=33 # initialise interface
|
||||
|
@ -36,7 +36,7 @@ marshmallow==3.19.0
|
||||
# via platformio
|
||||
packaging==23.1
|
||||
# via marshmallow
|
||||
platformio==6.1.6
|
||||
platformio==6.1.14
|
||||
# via -r requirements.in
|
||||
pyelftools==0.29
|
||||
# via platformio
|
||||
|
@ -1,6 +1,6 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x5000,
|
||||
otadata, data, ota, 0xe000, 0x2000,
|
||||
app0, app, ota_0, 0x10000, 0x180000,
|
||||
app1, app, ota_1, 0x190000,0x180000,
|
||||
spiffs, data, spiffs, 0x310000,0xF0000,
|
||||
app0, app, ota_0, 0x10000, 0x1A0000,
|
||||
app1, app, ota_1, 0x1B0000,0x1A0000,
|
||||
spiffs, data, spiffs, 0x350000,0xB0000,
|
||||
|
|
@ -15,10 +15,10 @@
|
||||
* It uses NodeJS packages to inline, minify and GZIP files. See writeHtmlGzipped and writeChunks invocations at the bottom of the page.
|
||||
*/
|
||||
|
||||
const fs = require("fs");
|
||||
const fs = require("node:fs");
|
||||
const path = require("path");
|
||||
const inliner = require("inliner");
|
||||
const zlib = require("zlib");
|
||||
const zlib = require("node:zlib");
|
||||
const CleanCSS = require("clean-css");
|
||||
const minifyHtml = require("html-minifier-terser").minify;
|
||||
const packageJson = require("../package.json");
|
||||
@ -30,14 +30,12 @@ const output = ["wled00/html_ui.h", "wled00/html_pixart.h", "wled00/html_cpal.h"
|
||||
|
||||
// \x1b[34m is blue, \x1b[36m is cyan, \x1b[0m is reset
|
||||
const wledBanner = `
|
||||
\t\x1b[34m## ## ## ######## ########
|
||||
\t\x1b[34m## ## ## ## ## ## ##
|
||||
\t\x1b[34m## ## ## ## ## ## ##
|
||||
\t\x1b[34m## ## ## ## ###### ## ##
|
||||
\t\x1b[34m## ## ## ## ## ## ##
|
||||
\t\x1b[34m## ## ## ## ## ## ##
|
||||
\t\x1b[34m ### ### ######## ######## ########
|
||||
\t\t\x1b[36mbuild script for web UI
|
||||
\t\x1b[34m ## ## ## ###### ######
|
||||
\t\x1b[34m## ## ## ## ## ## ##
|
||||
\t\x1b[34m## ## ## ## ###### ## ##
|
||||
\t\x1b[34m## ## ## ## ## ## ##
|
||||
\t\x1b[34m ## ## ###### ###### ######
|
||||
\t\t\x1b[36m build script for web UI
|
||||
\x1b[0m`;
|
||||
|
||||
const singleHeader = `/*
|
||||
|
117
usermods/TetrisAI_v2/gridbw.h
Normal file
117
usermods/TetrisAI_v2/gridbw.h
Normal file
@ -0,0 +1,117 @@
|
||||
/******************************************************************************
|
||||
* @file : gridbw.h
|
||||
* @brief : contains the tetris grid as binary so black and white version
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) muebau 2023
|
||||
* All rights reserved.</center></h2>
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef __GRIDBW_H__
|
||||
#define __GRIDBW_H__
|
||||
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
#include "pieces.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class GridBW
|
||||
{
|
||||
private:
|
||||
public:
|
||||
uint8_t width;
|
||||
uint8_t height;
|
||||
std::vector<uint32_t> pixels;
|
||||
|
||||
GridBW(uint8_t width, uint8_t height):
|
||||
width(width),
|
||||
height(height),
|
||||
pixels(height)
|
||||
{
|
||||
if (width > 32)
|
||||
{
|
||||
throw std::invalid_argument("maximal width is 32");
|
||||
}
|
||||
}
|
||||
|
||||
void placePiece(Piece* piece, uint8_t x, uint8_t y)
|
||||
{
|
||||
for (uint8_t row = 4 - piece->getRotation().height; row < 4; row++)
|
||||
{
|
||||
pixels[y + (row - (4 - piece->getRotation().height))] |= piece->getGridRow(x, row, width);
|
||||
}
|
||||
}
|
||||
|
||||
void erasePiece(Piece* piece, uint8_t x, uint8_t y)
|
||||
{
|
||||
for (uint8_t row = 4 - piece->getRotation().height; row < 4; row++)
|
||||
{
|
||||
pixels[y + (row - (4 - piece->getRotation().height))] &= ~piece->getGridRow(x, row, width);
|
||||
}
|
||||
}
|
||||
|
||||
bool noCollision(Piece* piece, uint8_t x, uint8_t y)
|
||||
{
|
||||
//if it touches a wall it is a collision
|
||||
if (x > (this->width - piece->getRotation().width) || y > this->height - piece->getRotation().height)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint8_t row = 4 - piece->getRotation().height; row < 4; row++)
|
||||
{
|
||||
if (piece->getGridRow(x, row, width) & pixels[y + (row - (4 - piece->getRotation().height))])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void findLandingPosition(Piece* piece)
|
||||
{
|
||||
// move down until the piece bumps into some occupied pixels or the 'wall'
|
||||
while (noCollision(piece, piece->x, piece->landingY))
|
||||
{
|
||||
piece->landingY++;
|
||||
}
|
||||
|
||||
//at this point the positon is 'in the wall' or 'over some occupied pixel'
|
||||
//so the previous position was the last correct one (clamped to 0 as minimum).
|
||||
piece->landingY = piece->landingY > 0 ? piece->landingY - 1 : 0;
|
||||
}
|
||||
|
||||
void cleanupFullLines()
|
||||
{
|
||||
uint8_t offset = 0;
|
||||
|
||||
//from "height - 1" to "0", so from bottom row to top
|
||||
for (uint8_t row = height; row-- > 0; )
|
||||
{
|
||||
//full line?
|
||||
if (isLineFull(row))
|
||||
{
|
||||
offset++;
|
||||
pixels[row] = 0x0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (offset > 0)
|
||||
{
|
||||
pixels[row + offset] = pixels[row];
|
||||
pixels[row] = 0x0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool isLineFull(uint8_t y)
|
||||
{
|
||||
return pixels[y] == (uint32_t)((1 << width) - 1);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* __GRIDBW_H__ */
|
132
usermods/TetrisAI_v2/gridcolor.h
Normal file
132
usermods/TetrisAI_v2/gridcolor.h
Normal file
@ -0,0 +1,132 @@
|
||||
/******************************************************************************
|
||||
* @file : gridcolor.h
|
||||
* @brief : contains the tetris grid as 8bit indexed color version
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) muebau 2023
|
||||
* All rights reserved.</center></h2>
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef __GRIDCOLOR_H__
|
||||
#define __GRIDCOLOR_H__
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <vector>
|
||||
#include "gridbw.h"
|
||||
#include "gridcolor.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class GridColor
|
||||
{
|
||||
private:
|
||||
public:
|
||||
uint8_t width;
|
||||
uint8_t height;
|
||||
GridBW gridBW;
|
||||
std::vector<uint8_t> pixels;
|
||||
|
||||
GridColor(uint8_t width, uint8_t height):
|
||||
width(width),
|
||||
height(height),
|
||||
gridBW(width, height),
|
||||
pixels(width* height)
|
||||
{}
|
||||
|
||||
void clear()
|
||||
{
|
||||
for (uint8_t y = 0; y < height; y++)
|
||||
{
|
||||
gridBW.pixels[y] = 0x0;
|
||||
for (int8_t x = 0; x < width; x++)
|
||||
{
|
||||
*getPixel(x, y) = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void placePiece(Piece* piece, uint8_t x, uint8_t y)
|
||||
{
|
||||
for (uint8_t pieceY = 0; pieceY < piece->getRotation().height; pieceY++)
|
||||
{
|
||||
for (uint8_t pieceX = 0; pieceX < piece->getRotation().width; pieceX++)
|
||||
{
|
||||
if (piece->getPixel(pieceX, pieceY))
|
||||
{
|
||||
*getPixel(x + pieceX, y + pieceY) = piece->pieceData->colorIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void erasePiece(Piece* piece, uint8_t x, uint8_t y)
|
||||
{
|
||||
for (uint8_t pieceY = 0; pieceY < piece->getRotation().height; pieceY++)
|
||||
{
|
||||
for (uint8_t pieceX = 0; pieceX < piece->getRotation().width; pieceX++)
|
||||
{
|
||||
if (piece->getPixel(pieceX, pieceY))
|
||||
{
|
||||
*getPixel(x + pieceX, y + pieceY) = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cleanupFullLines()
|
||||
{
|
||||
uint8_t offset = 0;
|
||||
//from "height - 1" to "0", so from bottom row to top
|
||||
for (uint8_t y = height; y-- > 0; )
|
||||
{
|
||||
if (gridBW.isLineFull(y))
|
||||
{
|
||||
offset++;
|
||||
for (uint8_t x = 0; x < width; x++)
|
||||
{
|
||||
pixels[y * width + x] = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (offset > 0)
|
||||
{
|
||||
if (gridBW.pixels[y])
|
||||
{
|
||||
for (uint8_t x = 0; x < width; x++)
|
||||
{
|
||||
pixels[(y + offset) * width + x] = pixels[y * width + x];
|
||||
pixels[y * width + x] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
gridBW.cleanupFullLines();
|
||||
}
|
||||
|
||||
uint8_t* getPixel(uint8_t x, uint8_t y)
|
||||
{
|
||||
return &pixels[y * width + x];
|
||||
}
|
||||
|
||||
void sync()
|
||||
{
|
||||
for (uint8_t y = 0; y < height; y++)
|
||||
{
|
||||
gridBW.pixels[y] = 0x0;
|
||||
for (int8_t x = 0; x < width; x++)
|
||||
{
|
||||
gridBW.pixels[y] <<= 1;
|
||||
if (*getPixel(x, y) != 0)
|
||||
{
|
||||
gridBW.pixels[y] |= 0x1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* __GRIDCOLOR_H__ */
|
184
usermods/TetrisAI_v2/pieces.h
Normal file
184
usermods/TetrisAI_v2/pieces.h
Normal file
@ -0,0 +1,184 @@
|
||||
/******************************************************************************
|
||||
* @file : pieces.h
|
||||
* @brief : contains the tetris pieces with their colors indecies
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) muebau 2022
|
||||
* All rights reserved.</center></h2>
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef __PIECES_H__
|
||||
#define __PIECES_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <bitset>
|
||||
#include <cstddef>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
#define numPieces 7
|
||||
|
||||
struct PieceRotation
|
||||
{
|
||||
uint8_t width;
|
||||
uint8_t height;
|
||||
uint16_t rows;
|
||||
};
|
||||
|
||||
struct PieceData
|
||||
{
|
||||
uint8_t rotCount;
|
||||
uint8_t colorIndex;
|
||||
PieceRotation rotations[4];
|
||||
};
|
||||
|
||||
PieceData piecesData[numPieces] = {
|
||||
// I
|
||||
{
|
||||
2,
|
||||
1,
|
||||
{
|
||||
{ 1, 4, 0b0001000100010001},
|
||||
{ 4, 1, 0b0000000000001111}
|
||||
}
|
||||
},
|
||||
// O
|
||||
{
|
||||
1,
|
||||
2,
|
||||
{
|
||||
{ 2, 2, 0b0000000000110011}
|
||||
}
|
||||
},
|
||||
// Z
|
||||
{
|
||||
2,
|
||||
3,
|
||||
{
|
||||
{ 3, 2, 0b0000000001100011},
|
||||
{ 2, 3, 0b0000000100110010}
|
||||
}
|
||||
},
|
||||
// S
|
||||
{
|
||||
2,
|
||||
4,
|
||||
{
|
||||
{ 3, 2, 0b0000000000110110},
|
||||
{ 2, 3, 0b0000001000110001}
|
||||
}
|
||||
},
|
||||
// L
|
||||
{
|
||||
4,
|
||||
5,
|
||||
{
|
||||
{ 2, 3, 0b0000001000100011},
|
||||
{ 3, 2, 0b0000000001110100},
|
||||
{ 2, 3, 0b0000001100010001},
|
||||
{ 3, 2, 0b0000000000010111}
|
||||
}
|
||||
},
|
||||
// J
|
||||
{
|
||||
4,
|
||||
6,
|
||||
{
|
||||
{ 2, 3, 0b0000000100010011},
|
||||
{ 3, 2, 0b0000000001000111},
|
||||
{ 2, 3, 0b0000001100100010},
|
||||
{ 3, 2, 0b0000000001110001}
|
||||
}
|
||||
},
|
||||
// T
|
||||
{
|
||||
4,
|
||||
7,
|
||||
{
|
||||
{ 3, 2, 0b0000000001110010},
|
||||
{ 2, 3, 0b0000000100110001},
|
||||
{ 3, 2, 0b0000000000100111},
|
||||
{ 2, 3, 0b0000001000110010}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
class Piece
|
||||
{
|
||||
private:
|
||||
public:
|
||||
uint8_t x;
|
||||
uint8_t y;
|
||||
PieceData* pieceData;
|
||||
uint8_t rotation;
|
||||
uint8_t landingY;
|
||||
|
||||
Piece(uint8_t pieceIndex = 0):
|
||||
x(0),
|
||||
y(0),
|
||||
rotation(0),
|
||||
landingY(0)
|
||||
{
|
||||
this->pieceData = &piecesData[pieceIndex];
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
this->rotation = 0;
|
||||
this->x = 0;
|
||||
this->y = 0;
|
||||
this->landingY = 0;
|
||||
}
|
||||
|
||||
uint32_t getGridRow(uint8_t x, uint8_t y, uint8_t width)
|
||||
{
|
||||
if (x < width)
|
||||
{
|
||||
//shift the row with the "top-left" position to the "x" position
|
||||
auto shiftx = (width - 1) - x;
|
||||
auto topleftx = (getRotation().width - 1);
|
||||
|
||||
auto finalShift = shiftx - topleftx;
|
||||
auto row = getRow(y);
|
||||
auto finalResult = row << finalShift;
|
||||
|
||||
return finalResult;
|
||||
}
|
||||
return 0xffffffff;
|
||||
}
|
||||
|
||||
uint8_t getRow(uint8_t y)
|
||||
{
|
||||
if (y < 4)
|
||||
{
|
||||
return (getRotation().rows >> (12 - (4 * y))) & 0xf;
|
||||
}
|
||||
return 0xf;
|
||||
}
|
||||
|
||||
bool getPixel(uint8_t x, uint8_t y)
|
||||
{
|
||||
if(x > getRotation().width - 1 || y > getRotation().height - 1 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (x < 4 && y < 4)
|
||||
{
|
||||
return (getRow((4 - getRotation().height) + y) >> (3 - ((4 - getRotation().width) + x))) & 0x1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
PieceRotation getRotation()
|
||||
{
|
||||
return this->pieceData->rotations[rotation];
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* __PIECES_H__ */
|
64
usermods/TetrisAI_v2/rating.h
Normal file
64
usermods/TetrisAI_v2/rating.h
Normal file
@ -0,0 +1,64 @@
|
||||
/******************************************************************************
|
||||
* @file : rating.h
|
||||
* @brief : contains the tetris rating of a grid
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) muebau 2022
|
||||
* All rights reserved.</center></h2>
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef __RATING_H__
|
||||
#define __RATING_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <float.h>
|
||||
#include <stdbool.h>
|
||||
#include <math.h>
|
||||
#include <vector>
|
||||
#include "rating.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class Rating
|
||||
{
|
||||
private:
|
||||
public:
|
||||
uint8_t minHeight;
|
||||
uint8_t maxHeight;
|
||||
uint16_t holes;
|
||||
uint8_t fullLines;
|
||||
uint16_t bumpiness;
|
||||
uint16_t aggregatedHeight;
|
||||
double score;
|
||||
uint8_t width;
|
||||
std::vector<uint8_t> lineHights;
|
||||
|
||||
Rating(uint8_t width):
|
||||
width(width),
|
||||
lineHights(width)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
this->minHeight = 0;
|
||||
this->maxHeight = 0;
|
||||
|
||||
for (uint8_t line = 0; line < this->width; line++)
|
||||
{
|
||||
this->lineHights[line] = 0;
|
||||
}
|
||||
|
||||
this->holes = 0;
|
||||
this->fullLines = 0;
|
||||
this->bumpiness = 0;
|
||||
this->aggregatedHeight = 0;
|
||||
this->score = -DBL_MAX;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* __RATING_H__ */
|
33
usermods/TetrisAI_v2/readme.md
Normal file
33
usermods/TetrisAI_v2/readme.md
Normal file
@ -0,0 +1,33 @@
|
||||
# Tetris AI effect usermod
|
||||
|
||||
This usermod brings you a effect brings a self playing Tetris game. The mod needs version 0.14 or above as it is based on matrix support. The effect was tested on an ESP32 with a WS2812B 16x16 matrix.
|
||||
|
||||
Version 1.0
|
||||
|
||||
## Installation
|
||||
|
||||
Just activate the usermod with `-D USERMOD_TETRISAI` and the effect will become available under the name 'Tetris AI'.
|
||||
|
||||
## Usage
|
||||
|
||||
It is best to set the background color to black, the border color to light grey and the game over color (foreground) to dark grey.
|
||||
|
||||
### Sliders and boxes
|
||||
|
||||
#### Sliders
|
||||
|
||||
* speed: speed the game plays
|
||||
* look ahead: how many pieces is the AI allowed to know the next pieces (0 - 2)
|
||||
* intelligence: how good the AI will play
|
||||
* Rotate color: make the colors shift (rotate) every few cicles
|
||||
* Mistakes free: how many good moves between mistakes (if activated)
|
||||
|
||||
#### Checkboxes
|
||||
|
||||
* show next: if true a space of 5 pixels from the right is used to show the next pieces. The whole segment is used for the grid otherwise.
|
||||
* show border: if true an additional column of 1 pixel is used to draw a border between the grid and the next pieces
|
||||
* mistakes: if true the worst instead of the best move is choosen every few moves (read above)
|
||||
|
||||
## Best results
|
||||
|
||||
If the speed is set to be a little bit faster than a good human could play with maximal intelligence and very few mistakes it makes people furious/happy at a party.
|
302
usermods/TetrisAI_v2/tetrisai.h
Normal file
302
usermods/TetrisAI_v2/tetrisai.h
Normal file
@ -0,0 +1,302 @@
|
||||
/******************************************************************************
|
||||
* @file : ai.h
|
||||
* @brief : contains the heuristic
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) muebau 2023
|
||||
* All rights reserved.</center></h2>
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef __AI_H__
|
||||
#define __AI_H__
|
||||
|
||||
#include "gridbw.h"
|
||||
#include "rating.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class TetrisAI
|
||||
{
|
||||
private:
|
||||
public:
|
||||
double aHeight;
|
||||
double fullLines;
|
||||
double holes;
|
||||
double bumpiness;
|
||||
bool findWorstMove = false;
|
||||
|
||||
uint8_t countOnes(uint32_t vector)
|
||||
{
|
||||
uint8_t count = 0;
|
||||
while (vector)
|
||||
{
|
||||
vector &= (vector - 1);
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
void updateRating(GridBW grid, Rating* rating)
|
||||
{
|
||||
rating->minHeight = 0;
|
||||
rating->maxHeight = 0;
|
||||
rating->holes = 0;
|
||||
rating->fullLines = 0;
|
||||
rating->bumpiness = 0;
|
||||
rating->aggregatedHeight = 0;
|
||||
fill(rating->lineHights.begin(), rating->lineHights.end(), 0);
|
||||
|
||||
uint32_t columnvector = 0x0;
|
||||
uint32_t lastcolumnvector = 0x0;
|
||||
for (uint8_t row = 0; row < grid.height; row++)
|
||||
{
|
||||
columnvector |= grid.pixels[row];
|
||||
|
||||
//first (highest) column makes it
|
||||
if (rating->maxHeight == 0 && columnvector)
|
||||
{
|
||||
rating->maxHeight = grid.height - row;
|
||||
}
|
||||
|
||||
//if column vector is full we found the minimal height (or it stays zero)
|
||||
if (rating->minHeight == 0 && (columnvector == (uint32_t)((1 << grid.width) - 1)))
|
||||
{
|
||||
rating->minHeight = grid.height - row;
|
||||
}
|
||||
|
||||
//line full if all ones in mask :-)
|
||||
if (grid.isLineFull(row))
|
||||
{
|
||||
rating->fullLines++;
|
||||
}
|
||||
|
||||
//holes are basically a XOR with the "full" columns
|
||||
rating->holes += countOnes(columnvector ^ grid.pixels[row]);
|
||||
|
||||
//calculate the difference (XOR) between the current column vector and the last one
|
||||
uint32_t columnDelta = columnvector ^ lastcolumnvector;
|
||||
|
||||
//process every new column
|
||||
uint8_t index = 0;
|
||||
while (columnDelta)
|
||||
{
|
||||
//if this is a new column
|
||||
if (columnDelta & 0x1)
|
||||
{
|
||||
//update hight of this column
|
||||
rating->lineHights[(grid.width - 1) - index] = grid.height - row;
|
||||
|
||||
// update aggregatedHeight
|
||||
rating->aggregatedHeight += grid.height - row;
|
||||
}
|
||||
index++;
|
||||
columnDelta >>= 1;
|
||||
}
|
||||
lastcolumnvector = columnvector;
|
||||
}
|
||||
|
||||
//compare every two columns to get the difference and add them up
|
||||
for (uint8_t column = 1; column < grid.width; column++)
|
||||
{
|
||||
rating->bumpiness += abs(rating->lineHights[column - 1] - rating->lineHights[column]);
|
||||
}
|
||||
|
||||
rating->score = (aHeight * (rating->aggregatedHeight)) + (fullLines * (rating->fullLines)) + (holes * (rating->holes)) + (bumpiness * (rating->bumpiness));
|
||||
}
|
||||
|
||||
TetrisAI(): TetrisAI(-0.510066, 0.760666, -0.35663, -0.184483)
|
||||
{}
|
||||
|
||||
TetrisAI(double aHeight, double fullLines, double holes, double bumpiness):
|
||||
aHeight(aHeight),
|
||||
fullLines(fullLines),
|
||||
holes(holes),
|
||||
bumpiness(bumpiness)
|
||||
{}
|
||||
|
||||
void findBestMove(GridBW grid, Piece *piece)
|
||||
{
|
||||
vector<Piece> pieces = {*piece};
|
||||
findBestMove(grid, &pieces);
|
||||
*piece = pieces[0];
|
||||
}
|
||||
|
||||
void findBestMove(GridBW grid, std::vector<Piece> *pieces)
|
||||
{
|
||||
findBestMove(grid, pieces->begin(), pieces->end());
|
||||
}
|
||||
|
||||
void findBestMove(GridBW grid, std::vector<Piece>::iterator start, std::vector<Piece>::iterator end)
|
||||
{
|
||||
Rating bestRating(grid.width);
|
||||
findBestMove(grid, start, end, &bestRating);
|
||||
}
|
||||
|
||||
void findBestMove(GridBW grid, std::vector<Piece>::iterator start, std::vector<Piece>::iterator end, Rating* bestRating)
|
||||
{
|
||||
grid.cleanupFullLines();
|
||||
Rating curRating(grid.width);
|
||||
Rating deeperRating(grid.width);
|
||||
Piece piece = *start;
|
||||
|
||||
// for every rotation of the piece
|
||||
for (piece.rotation = 0; piece.rotation < piece.pieceData->rotCount; piece.rotation++)
|
||||
{
|
||||
// put piece to top left corner
|
||||
piece.x = 0;
|
||||
piece.y = 0;
|
||||
|
||||
//test for every column
|
||||
for (piece.x = 0; piece.x <= grid.width - piece.getRotation().width; piece.x++)
|
||||
{
|
||||
//todo optimise by the use of the previous grids height
|
||||
piece.landingY = 0;
|
||||
//will set landingY to final position
|
||||
grid.findLandingPosition(&piece);
|
||||
|
||||
// draw piece
|
||||
grid.placePiece(&piece, piece.x, piece.landingY);
|
||||
|
||||
if(start == end - 1)
|
||||
{
|
||||
//at the deepest level
|
||||
updateRating(grid, &curRating);
|
||||
}
|
||||
else
|
||||
{
|
||||
//go deeper to take another piece into account
|
||||
findBestMove(grid, start + 1, end, &deeperRating);
|
||||
curRating = deeperRating;
|
||||
}
|
||||
|
||||
// eraese piece
|
||||
grid.erasePiece(&piece, piece.x, piece.landingY);
|
||||
|
||||
if(findWorstMove)
|
||||
{
|
||||
//init rating for worst
|
||||
if(bestRating->score == -DBL_MAX)
|
||||
{
|
||||
bestRating->score = DBL_MAX;
|
||||
}
|
||||
|
||||
// update if we found a worse one
|
||||
if (bestRating->score > curRating.score)
|
||||
{
|
||||
*bestRating = curRating;
|
||||
(*start) = piece;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// update if we found a better one
|
||||
if (bestRating->score < curRating.score)
|
||||
{
|
||||
*bestRating = curRating;
|
||||
(*start) = piece;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool findBestMoveNonBlocking(GridBW grid, std::vector<Piece>::iterator start, std::vector<Piece>::iterator end, Rating* bestRating)
|
||||
{
|
||||
//vector with pieces
|
||||
//for every piece
|
||||
//for every
|
||||
switch (expression)
|
||||
{
|
||||
case INIT:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool findBestMoveNonBlocking(GridBW grid, std::vector<Piece>::iterator start, std::vector<Piece>::iterator end, Rating* bestRating)
|
||||
{
|
||||
//INIT
|
||||
grid.cleanupFullLines();
|
||||
Rating curRating(grid.width);
|
||||
Rating deeperRating(grid.width);
|
||||
Piece piece = *start;
|
||||
|
||||
// for every rotation of the piece
|
||||
piece.rotation = 0;
|
||||
|
||||
//HANDLE
|
||||
while (piece.rotation < piece.pieceData->rotCount)
|
||||
{
|
||||
// put piece to top left corner
|
||||
piece.x = 0;
|
||||
piece.y = 0;
|
||||
|
||||
//test for every column
|
||||
piece.x = 0;
|
||||
while (piece.x <= grid.width - piece.getRotation().width)
|
||||
{
|
||||
|
||||
//todo optimise by the use of the previous grids height
|
||||
piece.landingY = 0;
|
||||
//will set landingY to final position
|
||||
grid.findLandingPosition(&piece);
|
||||
|
||||
// draw piece
|
||||
grid.placePiece(&piece, piece.x, piece.landingY);
|
||||
|
||||
if(start == end - 1)
|
||||
{
|
||||
//at the deepest level
|
||||
updateRating(grid, &curRating);
|
||||
}
|
||||
else
|
||||
{
|
||||
//go deeper to take another piece into account
|
||||
findBestMove(grid, start + 1, end, &deeperRating);
|
||||
curRating = deeperRating;
|
||||
}
|
||||
|
||||
// eraese piece
|
||||
grid.erasePiece(&piece, piece.x, piece.landingY);
|
||||
|
||||
if(findWorstMove)
|
||||
{
|
||||
//init rating for worst
|
||||
if(bestRating->score == -DBL_MAX)
|
||||
{
|
||||
bestRating->score = DBL_MAX;
|
||||
}
|
||||
|
||||
// update if we found a worse one
|
||||
if (bestRating->score > curRating.score)
|
||||
{
|
||||
*bestRating = curRating;
|
||||
(*start) = piece;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// update if we found a better one
|
||||
if (bestRating->score < curRating.score)
|
||||
{
|
||||
*bestRating = curRating;
|
||||
(*start) = piece;
|
||||
}
|
||||
}
|
||||
piece.x++;
|
||||
}
|
||||
piece.rotation++;
|
||||
}
|
||||
|
||||
//EXIT
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* __AI_H__ */
|
150
usermods/TetrisAI_v2/tetrisaigame.h
Normal file
150
usermods/TetrisAI_v2/tetrisaigame.h
Normal file
@ -0,0 +1,150 @@
|
||||
/******************************************************************************
|
||||
* @file : tetrisaigame.h
|
||||
* @brief : main tetris functions
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) muebau 2022
|
||||
* All rights reserved.</center></h2>
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef __TETRISAIGAME_H__
|
||||
#define __TETRISAIGAME_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <vector>
|
||||
#include "pieces.h"
|
||||
#include "gridcolor.h"
|
||||
#include "tetrisbag.h"
|
||||
#include "tetrisai.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class TetrisAIGame
|
||||
{
|
||||
private:
|
||||
bool animateFallOfPiece(Piece* piece, bool skip)
|
||||
{
|
||||
if (skip || piece->y >= piece->landingY)
|
||||
{
|
||||
piece->y = piece->landingY;
|
||||
grid.gridBW.placePiece(piece, piece->x, piece->landingY);
|
||||
grid.placePiece(piece, piece->x, piece->y);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// eraese last drawing
|
||||
grid.erasePiece(piece, piece->x, piece->y);
|
||||
|
||||
//move piece down
|
||||
piece->y++;
|
||||
|
||||
// draw piece
|
||||
grid.placePiece(piece, piece->x, piece->y);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
uint8_t width;
|
||||
uint8_t height;
|
||||
uint8_t nLookAhead;
|
||||
TetrisBag bag;
|
||||
GridColor grid;
|
||||
TetrisAI ai;
|
||||
Piece curPiece;
|
||||
PieceData* piecesData;
|
||||
enum States { INIT, TEST_GAME_OVER, GET_NEXT_PIECE, FIND_BEST_MOVE, ANIMATE_MOVE, ANIMATE_GAME_OVER } state = INIT;
|
||||
|
||||
TetrisAIGame(uint8_t width, uint8_t height, uint8_t nLookAhead, PieceData* piecesData, uint8_t nPieces):
|
||||
width(width),
|
||||
height(height),
|
||||
nLookAhead(nLookAhead),
|
||||
bag(nPieces, 1, nLookAhead),
|
||||
grid(width, height + 4),
|
||||
ai(),
|
||||
piecesData(piecesData)
|
||||
{
|
||||
}
|
||||
|
||||
void nextPiece()
|
||||
{
|
||||
grid.cleanupFullLines();
|
||||
bag.queuePiece();
|
||||
}
|
||||
|
||||
void findBestMove()
|
||||
{
|
||||
ai.findBestMove(grid.gridBW, &bag.piecesQueue);
|
||||
}
|
||||
|
||||
bool animateFall(bool skip)
|
||||
{
|
||||
return animateFallOfPiece(&(bag.piecesQueue[0]), skip);
|
||||
}
|
||||
|
||||
bool isGameOver()
|
||||
{
|
||||
//if there is something in the 4 lines of the hidden area the game is over
|
||||
return grid.gridBW.pixels[0] || grid.gridBW.pixels[1] || grid.gridBW.pixels[2] || grid.gridBW.pixels[3];
|
||||
}
|
||||
|
||||
void poll()
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case INIT:
|
||||
reset();
|
||||
state = TEST_GAME_OVER;
|
||||
break;
|
||||
case TEST_GAME_OVER:
|
||||
if (isGameOver())
|
||||
{
|
||||
state = ANIMATE_GAME_OVER;
|
||||
}
|
||||
else
|
||||
{
|
||||
state = GET_NEXT_PIECE;
|
||||
}
|
||||
break;
|
||||
case GET_NEXT_PIECE:
|
||||
nextPiece();
|
||||
state = FIND_BEST_MOVE;
|
||||
break;
|
||||
case FIND_BEST_MOVE:
|
||||
findBestMove();
|
||||
state = ANIMATE_MOVE;
|
||||
break;
|
||||
case ANIMATE_MOVE:
|
||||
if (!animateFall(false))
|
||||
{
|
||||
state = TEST_GAME_OVER;
|
||||
}
|
||||
break;
|
||||
case ANIMATE_GAME_OVER:
|
||||
static auto curPixel = grid.pixels.size();
|
||||
grid.pixels[curPixel] = 254;
|
||||
|
||||
if (curPixel == 0)
|
||||
{
|
||||
state = INIT;
|
||||
curPixel = grid.pixels.size();
|
||||
}
|
||||
curPixel--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
grid.clear();
|
||||
bag.init();
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* __TETRISAIGAME_H__ */
|
100
usermods/TetrisAI_v2/tetrisbag.h
Normal file
100
usermods/TetrisAI_v2/tetrisbag.h
Normal file
@ -0,0 +1,100 @@
|
||||
/******************************************************************************
|
||||
* @file : tetrisbag.h
|
||||
* @brief : the tetris implementation of a random piece generator
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) muebau 2022
|
||||
* All rights reserved.</center></h2>
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef __TETRISBAG_H__
|
||||
#define __TETRISBAG_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include "tetrisbag.h"
|
||||
|
||||
class TetrisBag
|
||||
{
|
||||
private:
|
||||
public:
|
||||
uint8_t nPieces;
|
||||
uint8_t nBagLength;
|
||||
uint8_t bagIdx;
|
||||
std::vector<uint8_t> bag;
|
||||
std::vector<Piece> piecesQueue;
|
||||
|
||||
TetrisBag(uint8_t nPieces, uint8_t nBagLength, uint8_t queueLength):
|
||||
nPieces(nPieces),
|
||||
nBagLength(nBagLength),
|
||||
bag(nPieces * nBagLength),
|
||||
piecesQueue(queueLength)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
//will shuffle the bag at first use
|
||||
bagIdx = nPieces - 1;
|
||||
|
||||
for (uint8_t bagIndex = 0; bagIndex < nPieces * nBagLength; bagIndex++)
|
||||
{
|
||||
bag[bagIndex] = bagIndex % nPieces;
|
||||
}
|
||||
|
||||
//will init the queue
|
||||
for (uint8_t index = 0; index < piecesQueue.size(); index++)
|
||||
{
|
||||
queuePiece();
|
||||
}
|
||||
}
|
||||
|
||||
void shuffleBag()
|
||||
{
|
||||
uint8_t temp;
|
||||
uint8_t swapIdx;
|
||||
for (int index = nPieces - 1; index > 0; index--)
|
||||
{
|
||||
//get candidate to swap
|
||||
swapIdx = rand() % index;
|
||||
|
||||
//swap it!
|
||||
temp = bag[swapIdx];
|
||||
bag[swapIdx] = bag[index];
|
||||
bag[index] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
Piece getNextPiece()
|
||||
{
|
||||
bagIdx++;
|
||||
if (bagIdx >= nPieces)
|
||||
{
|
||||
shuffleBag();
|
||||
bagIdx = 0;
|
||||
}
|
||||
return Piece(bag[bagIdx]);
|
||||
}
|
||||
|
||||
void queuePiece()
|
||||
{
|
||||
//move vector to left
|
||||
std::rotate(piecesQueue.begin(), piecesQueue.begin() + 1, piecesQueue.end());
|
||||
piecesQueue[piecesQueue.size() - 1] = getNextPiece();
|
||||
}
|
||||
|
||||
void queuePiece(uint8_t idx)
|
||||
{
|
||||
//move vector to left
|
||||
std::rotate(piecesQueue.begin(), piecesQueue.begin() + 1, piecesQueue.end());
|
||||
piecesQueue[piecesQueue.size() - 1] = Piece(idx % nPieces);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* __TETRISBAG_H__ */
|
222
usermods/TetrisAI_v2/usermod_v2_tetrisai.h
Normal file
222
usermods/TetrisAI_v2/usermod_v2_tetrisai.h
Normal file
@ -0,0 +1,222 @@
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
#include "FX.h"
|
||||
#include "fcn_declare.h"
|
||||
|
||||
#include "tetrisaigame.h"
|
||||
// By: muebau
|
||||
|
||||
typedef struct TetrisAI_data
|
||||
{
|
||||
unsigned long lastTime = 0;
|
||||
TetrisAIGame tetris;
|
||||
uint8_t intelligence;
|
||||
uint8_t rotate;
|
||||
bool showNext;
|
||||
bool showBorder;
|
||||
uint8_t colorOffset;
|
||||
uint8_t colorInc;
|
||||
uint8_t mistaceCountdown;
|
||||
} tetrisai_data;
|
||||
|
||||
void drawGrid(TetrisAIGame* tetris, TetrisAI_data* tetrisai_data)
|
||||
{
|
||||
SEGMENT.fill(SEGCOLOR(1));
|
||||
|
||||
//GRID
|
||||
for (auto index_y = 4; index_y < tetris->grid.height; index_y++)
|
||||
{
|
||||
for (auto index_x = 0; index_x < tetris->grid.width; index_x++)
|
||||
{
|
||||
CRGB color;
|
||||
if (*tetris->grid.getPixel(index_x, index_y) == 0)
|
||||
{
|
||||
//BG color
|
||||
color = SEGCOLOR(1);
|
||||
}
|
||||
//game over animation
|
||||
else if(*tetris->grid.getPixel(index_x, index_y) == 254)
|
||||
{
|
||||
//use fg
|
||||
color = SEGCOLOR(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
//spread the color over the whole palette
|
||||
uint8_t colorIndex = *tetris->grid.getPixel(index_x, index_y) * 32;
|
||||
colorIndex += tetrisai_data->colorOffset;
|
||||
color = ColorFromPalette(SEGPALETTE, colorIndex, 255, NOBLEND);
|
||||
}
|
||||
|
||||
SEGMENT.setPixelColorXY(index_x, index_y - 4, color);
|
||||
}
|
||||
}
|
||||
tetrisai_data->colorOffset += tetrisai_data->colorInc;
|
||||
|
||||
//NEXT PIECE AREA
|
||||
if (tetrisai_data->showNext)
|
||||
{
|
||||
//BORDER
|
||||
if (tetrisai_data->showBorder)
|
||||
{
|
||||
//draw a line 6 pixels from right with the border color
|
||||
for (auto index_y = 0; index_y < SEGMENT.virtualHeight(); index_y++)
|
||||
{
|
||||
SEGMENT.setPixelColorXY(SEGMENT.virtualWidth() - 6, index_y, SEGCOLOR(2));
|
||||
}
|
||||
}
|
||||
|
||||
//NEXT PIECE
|
||||
int piecesOffsetX = SEGMENT.virtualWidth() - 4;
|
||||
int piecesOffsetY = 1;
|
||||
for (uint8_t nextPieceIdx = 1; nextPieceIdx < tetris->nLookAhead; nextPieceIdx++)
|
||||
{
|
||||
uint8_t pieceNbrOffsetY = (nextPieceIdx - 1) * 5;
|
||||
|
||||
Piece piece(tetris->bag.piecesQueue[nextPieceIdx]);
|
||||
|
||||
for (uint8_t pieceY = 0; pieceY < piece.getRotation().height; pieceY++)
|
||||
{
|
||||
for (uint8_t pieceX = 0; pieceX < piece.getRotation().width; pieceX++)
|
||||
{
|
||||
if (piece.getPixel(pieceX, pieceY))
|
||||
{
|
||||
uint8_t colIdx = ((piece.pieceData->colorIndex * 32) + tetrisai_data->colorOffset);
|
||||
SEGMENT.setPixelColorXY(piecesOffsetX + pieceX, piecesOffsetY + pieceNbrOffsetY + pieceY, ColorFromPalette(SEGPALETTE, colIdx, 255, NOBLEND));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
// 2D Tetris AI //
|
||||
////////////////////////////
|
||||
uint16_t mode_2DTetrisAI()
|
||||
{
|
||||
if (!strip.isMatrix || !SEGENV.allocateData(sizeof(tetrisai_data)))
|
||||
{
|
||||
// not a 2D set-up
|
||||
SEGMENT.fill(SEGCOLOR(0));
|
||||
return 350;
|
||||
}
|
||||
TetrisAI_data* tetrisai_data = reinterpret_cast<TetrisAI_data*>(SEGENV.data);
|
||||
|
||||
const uint16_t cols = SEGMENT.virtualWidth();
|
||||
const uint16_t rows = SEGMENT.virtualHeight();
|
||||
|
||||
//range 0 - 1024ms => 1024/255 ~ 4
|
||||
uint16_t msDelayMove = 1024 - (4 * SEGMENT.speed);
|
||||
int16_t msDelayGameOver = msDelayMove / 4;
|
||||
|
||||
//range 0 - 2 (not including current)
|
||||
uint8_t nLookAhead = SEGMENT.intensity ? (SEGMENT.intensity >> 7) + 2 : 1;
|
||||
//range 0 - 16
|
||||
tetrisai_data->colorInc = SEGMENT.custom2 >> 4;
|
||||
|
||||
if (!tetrisai_data->tetris || (tetrisai_data->tetris.nLookAhead != nLookAhead
|
||||
|| tetrisai_data->showNext != SEGMENT.check1
|
||||
|| tetrisai_data->showBorder != SEGMENT.check2
|
||||
)
|
||||
)
|
||||
{
|
||||
tetrisai_data->showNext = SEGMENT.check1;
|
||||
tetrisai_data->showBorder = SEGMENT.check2;
|
||||
|
||||
//not more than 32 as this is the limit of this implementation
|
||||
uint8_t gridWidth = cols < 32 ? cols : 32;
|
||||
uint8_t gridHeight = rows;
|
||||
|
||||
// do we need space for the 'next' section?
|
||||
if (tetrisai_data->showNext)
|
||||
{
|
||||
// make space for the piece and one pixel of space
|
||||
gridWidth = gridWidth - 5;
|
||||
|
||||
// do we need space for a border?
|
||||
if (tetrisai_data->showBorder)
|
||||
{
|
||||
gridWidth = gridWidth - 1;
|
||||
}
|
||||
}
|
||||
|
||||
tetrisai_data->tetris = TetrisAIGame(gridWidth, gridHeight, nLookAhead, piecesData, numPieces);
|
||||
SEGMENT.fill(SEGCOLOR(1));
|
||||
}
|
||||
|
||||
if (tetrisai_data->intelligence != SEGMENT.custom1)
|
||||
{
|
||||
tetrisai_data->intelligence = SEGMENT.custom1;
|
||||
double dui = 0.2 - (0.2 * (tetrisai_data->intelligence / 255.0));
|
||||
|
||||
tetrisai_data->tetris.ai.aHeight = -0.510066 + dui;
|
||||
tetrisai_data->tetris.ai.fullLines = 0.760666 - dui;
|
||||
tetrisai_data->tetris.ai.holes = -0.35663 + dui;
|
||||
tetrisai_data->tetris.ai.bumpiness = -0.184483 + dui;
|
||||
}
|
||||
|
||||
if (tetrisai_data->tetris.state == TetrisAIGame::ANIMATE_MOVE)
|
||||
{
|
||||
if (millis() - tetrisai_data->lastTime > msDelayMove)
|
||||
{
|
||||
drawGrid(&tetrisai_data->tetris, tetrisai_data);
|
||||
tetrisai_data->lastTime = millis();
|
||||
tetrisai_data->tetris.poll();
|
||||
}
|
||||
}
|
||||
else if (tetrisai_data->tetris.state == TetrisAIGame::ANIMATE_GAME_OVER)
|
||||
{
|
||||
if (millis() - tetrisai_data->lastTime > msDelayGameOver)
|
||||
{
|
||||
drawGrid(&tetrisai_data->tetris, tetrisai_data);
|
||||
tetrisai_data->lastTime = millis();
|
||||
tetrisai_data->tetris.poll();
|
||||
}
|
||||
}
|
||||
else if (tetrisai_data->tetris.state == TetrisAIGame::FIND_BEST_MOVE)
|
||||
{
|
||||
if (SEGMENT.check3)
|
||||
{
|
||||
if(tetrisai_data->mistaceCountdown == 0)
|
||||
{
|
||||
tetrisai_data->tetris.ai.findWorstMove = true;
|
||||
tetrisai_data->tetris.poll();
|
||||
tetrisai_data->tetris.ai.findWorstMove = false;
|
||||
tetrisai_data->mistaceCountdown = SEGMENT.custom3;
|
||||
}
|
||||
tetrisai_data->mistaceCountdown--;
|
||||
}
|
||||
tetrisai_data->tetris.poll();
|
||||
}
|
||||
else
|
||||
{
|
||||
tetrisai_data->tetris.poll();
|
||||
}
|
||||
|
||||
return FRAMETIME;
|
||||
} // mode_2DTetrisAI()
|
||||
static const char _data_FX_MODE_2DTETRISAI[] PROGMEM = "Tetris AI@!,Look ahead,Intelligence,Rotate color,Mistake free,Show next,Border,Mistakes;Game Over,!,Border;!;2;sx=127,ix=64,c1=255,c2=0,c3=31,o1=1,o2=1,o3=0,pal=11";
|
||||
|
||||
class TetrisAIUsermod : public Usermod
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
public:
|
||||
void setup()
|
||||
{
|
||||
strip.addEffect(255, &mode_2DTetrisAI, _data_FX_MODE_2DTETRISAI);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
uint16_t getId()
|
||||
{
|
||||
return USERMOD_ID_TETRISAI;
|
||||
}
|
||||
};
|
@ -1,4 +1,4 @@
|
||||
# I2C 4 Line Display Usermod ALT
|
||||
# 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"
|
||||
@ -8,21 +8,20 @@ The core of these usermods are a copy of the originals. The main changes are to
|
||||
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 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.
|
||||
|
||||
Press the encoder to cycle through the options:
|
||||
*Brightness
|
||||
*Speed
|
||||
*Intensity
|
||||
*Palette
|
||||
*Effect
|
||||
*Main Color (only if display is used)
|
||||
*Saturation (only if display is used)
|
||||
* Brightness
|
||||
* Speed
|
||||
* Intensity
|
||||
* Palette
|
||||
* Effect
|
||||
* 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 AP, SSID and password
|
||||
Press and hold the encoder to display Network Info. If AP is active, it will display AP, SSID and password
|
||||
|
||||
Also shows if the timer is enabled
|
||||
|
||||
@ -30,11 +29,47 @@ Also shows if the timer is enabled
|
||||
|
||||
## Installation
|
||||
|
||||
Please refer to the original `usermod_v2_rotary_encoder_ui` readme for the main instructions
|
||||
Then to activate this alternative usermod add `#define USE_ALT_DISPlAY` to the `usermods_list.cpp` file,
|
||||
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
|
||||
|
||||
|
||||
## Configuration
|
||||
|
||||
These options are configurable in Config > Usermods
|
||||
|
||||
### Usermod Setup
|
||||
|
||||
* Global I2C GPIOs (HW) - Set the SDA and SCL pins
|
||||
|
||||
### 4LineDisplay
|
||||
|
||||
* `enabled` - enable/disable usermod
|
||||
* `type` - display type in numeric format
|
||||
* 1 = I2C SSD1306 128x32
|
||||
* 2 = I2C SH1106 128x32
|
||||
* 3 = I2C SSD1306 128x64 (4 double-height lines)
|
||||
* 4 = I2C SSD1305 128x32
|
||||
* 5 = I2C SSD1305 128x64 (4 double-height lines)
|
||||
* 6 = SPI SSD1306 128x32
|
||||
* 7 = SPI SSD1306 128x64 (4 double-height lines)
|
||||
* 8 = SPI SSD1309 128x64 (4 double-height lines)
|
||||
* 9 = I2C SSD1309 128x64 (4 double-height lines)
|
||||
* `pin` - GPIO pins used for display; SPI displays can use SCK, MOSI, CS, DC & RST
|
||||
* `flip` - flip/rotate display 180°
|
||||
* `contrast` - set display contrast (higher contrast may reduce display lifetime)
|
||||
* `screenTimeOutSec` - screen saver time-out in seconds
|
||||
* `sleepMode` - enable/disable screen saver
|
||||
* `clockMode` - enable/disable clock display in screen saver mode
|
||||
* `showSeconds` - Show seconds on the clock display
|
||||
* `i2c-freq-kHz` - I2C clock frequency in kHz (may help reduce dropped frames, range: 400-3400)
|
||||
|
||||
|
||||
### PlatformIO requirements
|
||||
|
||||
Note: the Four Line Display usermod requires the libraries `U8g2` and `Wire`.
|
||||
|
@ -17,7 +17,7 @@
|
||||
// for WLED.
|
||||
//
|
||||
// Dependencies
|
||||
// * This Usermod works best, by far, when coupled
|
||||
// * This Usermod works best, by far, when coupled
|
||||
// with RotaryEncoderUI ALT Usermod.
|
||||
//
|
||||
// Make sure to enable NTP and set your time zone in WLED Config | Time.
|
||||
@ -89,7 +89,8 @@ typedef enum {
|
||||
SSD1305_64, // U8X8_SSD1305_128X64_ADAFRUIT_HW_I2C
|
||||
SSD1306_SPI, // U8X8_SSD1306_128X32_NONAME_HW_SPI
|
||||
SSD1306_SPI64, // U8X8_SSD1306_128X64_NONAME_HW_SPI
|
||||
SSD1309_SPI64 // U8X8_SSD1309_128X64_NONAME0_4W_HW_SPI
|
||||
SSD1309_SPI64, // U8X8_SSD1309_128X64_NONAME0_4W_HW_SPI
|
||||
SSD1309_64 // U8X8_SSD1309_128X64_NONAME0_HW_I2C
|
||||
} DisplayType;
|
||||
|
||||
|
||||
@ -235,7 +236,7 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
void updateSpeed();
|
||||
void updateIntensity();
|
||||
void drawStatusIcons();
|
||||
|
||||
|
||||
/**
|
||||
* marks the position of the arrow showing
|
||||
* the current setting being changed
|
||||
@ -246,8 +247,8 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
//Draw the arrow for the current setting being changed
|
||||
void drawArrow();
|
||||
|
||||
//Display the current effect or palette (desiredEntry)
|
||||
// on the appropriate line (row).
|
||||
//Display the current effect or palette (desiredEntry)
|
||||
// on the appropriate line (row).
|
||||
void showCurrentEffectOrPalette(int inputEffPal, const char *qstring, uint8_t row);
|
||||
|
||||
/**
|
||||
@ -314,14 +315,14 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
* addToConfig() can be used to add custom persistent settings to the cfg.json file in the "um" (usermod) object.
|
||||
* It will be called by WLED when settings are actually saved (for example, LED settings are saved)
|
||||
* If you want to force saving the current state, use serializeConfig() in your loop().
|
||||
*
|
||||
*
|
||||
* CAUTION: serializeConfig() will initiate a filesystem write operation.
|
||||
* It might cause the LEDs to stutter and will cause flash wear if called too often.
|
||||
* Use it sparingly and always in the loop, never in network callbacks!
|
||||
*
|
||||
*
|
||||
* addToConfig() will also not yet add your setting to one of the settings pages automatically.
|
||||
* To make that work you still have to add the setting to the HTML, xml.cpp and set.cpp manually.
|
||||
*
|
||||
*
|
||||
* I highly recommend checking out the basics of ArduinoJson serialization and deserialization in order to use custom settings!
|
||||
*/
|
||||
void addToConfig(JsonObject& root) override;
|
||||
@ -329,7 +330,7 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
/*
|
||||
* readFromConfig() can be used to read back the custom settings you added with addToConfig().
|
||||
* This is called by WLED when settings are loaded (currently this only happens once immediately after boot)
|
||||
*
|
||||
*
|
||||
* readFromConfig() is called BEFORE setup(). This means you can use your persistent values in setup() (e.g. pin assignments, buffer sizes),
|
||||
* but also that if you want to write persistent values to a dynamic buffer, you'd need to allocate it here instead of in setup.
|
||||
* If you don't know what that is, don't fret. It most likely doesn't affect your use case :)
|
||||
@ -494,7 +495,7 @@ void FourLineDisplayUsermod::showTime() {
|
||||
}
|
||||
if (knownHour != hourCurrent) {
|
||||
// only update date when hour changes
|
||||
sprintf_P(lineBuffer, PSTR("%s %2d "), monthShortStr(month(localTime)), day(localTime));
|
||||
sprintf_P(lineBuffer, PSTR("%s %2d "), monthShortStr(month(localTime)), day(localTime));
|
||||
draw2x2String(2, lineHeight==1 ? 0 : lineHeight, lineBuffer); // adjust for 8 line displays, draw month and day
|
||||
}
|
||||
sprintf_P(lineBuffer,PSTR("%2d:%02d"), (useAMPM ? AmPmHour : hourCurrent), minuteCurrent);
|
||||
@ -556,6 +557,7 @@ void FourLineDisplayUsermod::setup() {
|
||||
case SSD1306_64: u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_HW_I2C(); break;
|
||||
case SSD1305: u8x8 = (U8X8 *) new U8X8_SSD1305_128X32_ADAFRUIT_HW_I2C(); break;
|
||||
case SSD1305_64: u8x8 = (U8X8 *) new U8X8_SSD1305_128X64_ADAFRUIT_HW_I2C(); break;
|
||||
case SSD1309_64: u8x8 = (U8X8 *) new U8X8_SSD1309_128X64_NONAME0_HW_I2C(); break;
|
||||
// U8X8 uses global SPI variable that is attached to VSPI bus on ESP32
|
||||
case SSD1306_SPI: u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_4W_HW_SPI(ioPin[0], ioPin[1], ioPin[2]); break; // Pins are cs, dc, reset
|
||||
case SSD1306_SPI64: u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_4W_HW_SPI(ioPin[0], ioPin[1], ioPin[2]); break; // Pins are cs, dc, reset
|
||||
@ -581,7 +583,7 @@ void FourLineDisplayUsermod::setup() {
|
||||
// gets called every time WiFi is (re-)connected. Initialize own network
|
||||
// interfaces here
|
||||
void FourLineDisplayUsermod::connected() {
|
||||
knownSsid = WiFi.SSID(); //apActive ? apSSID : WiFi.SSID(); //apActive ? WiFi.softAPSSID() :
|
||||
knownSsid = WiFi.SSID(); //apActive ? apSSID : WiFi.SSID(); //apActive ? WiFi.softAPSSID() :
|
||||
knownIp = Network.localIP(); //apActive ? IPAddress(4, 3, 2, 1) : Network.localIP();
|
||||
networkOverlay(PSTR("NETWORK INFO"),7000);
|
||||
}
|
||||
@ -637,7 +639,7 @@ void FourLineDisplayUsermod::redraw(bool forceRedraw) {
|
||||
powerON = !powerON;
|
||||
drawStatusIcons();
|
||||
return;
|
||||
} else if (knownnightlight != nightlightActive) { //trigger moon icon
|
||||
} else if (knownnightlight != nightlightActive) { //trigger moon icon
|
||||
knownnightlight = nightlightActive;
|
||||
drawStatusIcons();
|
||||
if (knownnightlight) {
|
||||
@ -652,7 +654,7 @@ void FourLineDisplayUsermod::redraw(bool forceRedraw) {
|
||||
return;
|
||||
} else if (knownMode != effectCurrent || knownPalette != effectPalette) {
|
||||
if (displayTurnedOff) needRedraw = true;
|
||||
else {
|
||||
else {
|
||||
if (knownPalette != effectPalette) { showCurrentEffectOrPalette(effectPalette, JSON_palette_names, 2); knownPalette = effectPalette; }
|
||||
if (knownMode != effectCurrent) { showCurrentEffectOrPalette(effectCurrent, JSON_mode_names, 3); knownMode = effectCurrent; }
|
||||
lastRedraw = now;
|
||||
@ -703,7 +705,7 @@ void FourLineDisplayUsermod::redraw(bool forceRedraw) {
|
||||
drawArrow();
|
||||
drawStatusIcons();
|
||||
|
||||
// Second row
|
||||
// Second row
|
||||
updateBrightness();
|
||||
updateSpeed();
|
||||
updateIntensity();
|
||||
@ -805,8 +807,8 @@ void FourLineDisplayUsermod::drawArrow() {
|
||||
lockRedraw = false;
|
||||
}
|
||||
|
||||
//Display the current effect or palette (desiredEntry)
|
||||
// on the appropriate line (row).
|
||||
//Display the current effect or palette (desiredEntry)
|
||||
// on the appropriate line (row).
|
||||
void FourLineDisplayUsermod::showCurrentEffectOrPalette(int inputEffPal, const char *qstring, uint8_t row) {
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS)
|
||||
unsigned long now = millis();
|
||||
@ -857,7 +859,7 @@ void FourLineDisplayUsermod::showCurrentEffectOrPalette(int inputEffPal, const c
|
||||
while (smallChars1 < (MAX_MODE_LINE_SPACE-1)) smallBuffer1[smallChars1++]=' ';
|
||||
smallBuffer1[smallChars1] = 0;
|
||||
drawString(1, row*lineHeight, smallBuffer1, true);
|
||||
while (smallChars2 < (MAX_MODE_LINE_SPACE-1)) smallBuffer2[smallChars2++]=' ';
|
||||
while (smallChars2 < (MAX_MODE_LINE_SPACE-1)) smallBuffer2[smallChars2++]=' ';
|
||||
smallBuffer2[smallChars2] = 0;
|
||||
drawString(1, row*lineHeight+1, smallBuffer2, true);
|
||||
}
|
||||
@ -1150,7 +1152,7 @@ void FourLineDisplayUsermod::onUpdateBegin(bool init) {
|
||||
xTaskCreatePinnedToCore(
|
||||
[](void * par) { // Function to implement the task
|
||||
// see https://www.freertos.org/vtaskdelayuntil.html
|
||||
const TickType_t xFrequency = REFRESH_RATE_MS * portTICK_PERIOD_MS / 2;
|
||||
const TickType_t xFrequency = REFRESH_RATE_MS * portTICK_PERIOD_MS / 2;
|
||||
TickType_t xLastWakeTime = xTaskGetTickCount();
|
||||
for(;;) {
|
||||
delay(1); // DO NOT DELETE THIS LINE! It is needed to give the IDLE(0) task enough time and to keep the watchdog happy.
|
||||
@ -1205,6 +1207,7 @@ void FourLineDisplayUsermod::appendConfigData() {
|
||||
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);"));
|
||||
@ -1218,14 +1221,14 @@ void FourLineDisplayUsermod::appendConfigData() {
|
||||
* addToConfig() can be used to add custom persistent settings to the cfg.json file in the "um" (usermod) object.
|
||||
* It will be called by WLED when settings are actually saved (for example, LED settings are saved)
|
||||
* If you want to force saving the current state, use serializeConfig() in your loop().
|
||||
*
|
||||
*
|
||||
* CAUTION: serializeConfig() will initiate a filesystem write operation.
|
||||
* It might cause the LEDs to stutter and will cause flash wear if called too often.
|
||||
* Use it sparingly and always in the loop, never in network callbacks!
|
||||
*
|
||||
*
|
||||
* addToConfig() will also not yet add your setting to one of the settings pages automatically.
|
||||
* To make that work you still have to add the setting to the HTML, xml.cpp and set.cpp manually.
|
||||
*
|
||||
*
|
||||
* I highly recommend checking out the basics of ArduinoJson serialization and deserialization in order to use custom settings!
|
||||
*/
|
||||
void FourLineDisplayUsermod::addToConfig(JsonObject& root) {
|
||||
@ -1252,7 +1255,7 @@ void FourLineDisplayUsermod::addToConfig(JsonObject& root) {
|
||||
/*
|
||||
* readFromConfig() can be used to read back the custom settings you added with addToConfig().
|
||||
* This is called by WLED when settings are loaded (currently this only happens once immediately after boot)
|
||||
*
|
||||
*
|
||||
* readFromConfig() is called BEFORE setup(). This means you can use your persistent values in setup() (e.g. pin assignments, buffer sizes),
|
||||
* but also that if you want to write persistent values to a dynamic buffer, you'd need to allocate it here instead of in setup.
|
||||
* If you don't know what that is, don't fret. It most likely doesn't affect your use case :)
|
||||
@ -1346,6 +1349,10 @@ bool FourLineDisplayUsermod::readFromConfig(JsonObject& root) {
|
||||
u8x8_Setup(u8x8->getU8x8(), u8x8_d_ssd1305_128x64_adafruit, u8x8_cad_ssd13xx_fast_i2c, u8x8_byte_arduino_hw_i2c, u8x8_gpio_and_delay_arduino);
|
||||
u8x8_SetPin_HW_I2C(u8x8->getU8x8(), U8X8_PIN_NONE, U8X8_PIN_NONE, U8X8_PIN_NONE);
|
||||
break;
|
||||
case SSD1309_64:
|
||||
u8x8_Setup(u8x8->getU8x8(), u8x8_d_ssd1309_128x64_noname0, u8x8_cad_ssd13xx_fast_i2c, u8x8_byte_arduino_hw_i2c, u8x8_gpio_and_delay_arduino);
|
||||
u8x8_SetPin_HW_I2C(u8x8->getU8x8(), U8X8_PIN_NONE, U8X8_PIN_NONE, U8X8_PIN_NONE);
|
||||
break;
|
||||
case SSD1306_SPI:
|
||||
u8x8_Setup(u8x8->getU8x8(), u8x8_d_ssd1306_128x32_univision, u8x8_cad_001, u8x8_byte_arduino_hw_spi, u8x8_gpio_and_delay_arduino);
|
||||
u8x8_SetPin_4Wire_HW_SPI(u8x8->getU8x8(), ioPin[0], ioPin[1], ioPin[2]); // Pins are cs, dc, reset
|
||||
|
@ -0,0 +1,17 @@
|
||||
[platformio]
|
||||
default_envs = esp32dev
|
||||
|
||||
[env:esp32dev]
|
||||
board = esp32dev
|
||||
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
|
||||
lib_deps =
|
||||
${esp32.lib_deps}
|
||||
U8g2@~2.34.4
|
||||
Wire
|
||||
|
@ -8,18 +8,18 @@ The core of these usermods are a copy of the originals. The main changes are to
|
||||
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.
|
||||
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.
|
||||
|
||||
Press the encoder to cycle through the options:
|
||||
*Brightness
|
||||
*Speed
|
||||
*Intensity
|
||||
*Palette
|
||||
*Effect
|
||||
*Main Color (only if display is used)
|
||||
*Saturation (only if display is used)
|
||||
* Brightness
|
||||
* Speed
|
||||
* Intensity
|
||||
* Palette
|
||||
* Effect
|
||||
* 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
|
||||
@ -30,10 +30,23 @@ Also shows if the timer is enabled.
|
||||
|
||||
## Installation
|
||||
|
||||
Please refer to the original `usermod_v2_rotary_encoder_ui` readme for the main instructions.<br/>
|
||||
To activate this alternative usermod, add `#define USE_ALT_DISPlAY` 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 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
|
||||
|
||||
### Define Your Options
|
||||
|
||||
* `USERMOD_ROTARY_ENCODER_UI` - define this to have this user mod included wled00\usermods_list.cpp
|
||||
* `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
|
||||
* `USERMOD_ROTARY_ENCODER_GPIO` - GPIO functionality:
|
||||
`INPUT_PULLUP` to use internal pull-up
|
||||
`INPUT` to use pull-up on the PCB
|
||||
|
||||
### PlatformIO requirements
|
||||
|
||||
|
@ -392,26 +392,26 @@ byte RotaryEncoderUIUsermod::readPin(uint8_t pin) {
|
||||
* modes_alpha_indexes and palettes_alpha_indexes.
|
||||
*/
|
||||
void RotaryEncoderUIUsermod::sortModesAndPalettes() {
|
||||
DEBUG_PRINTLN(F("Sorting modes and palettes."));
|
||||
DEBUG_PRINT(F("Sorting modes: ")); DEBUG_PRINTLN(strip.getModeCount());
|
||||
//modes_qstrings = re_findModeStrings(JSON_mode_names, strip.getModeCount());
|
||||
modes_qstrings = strip.getModeDataSrc();
|
||||
modes_alpha_indexes = re_initIndexArray(strip.getModeCount());
|
||||
re_sortModes(modes_qstrings, modes_alpha_indexes, strip.getModeCount(), MODE_SORT_SKIP_COUNT);
|
||||
|
||||
palettes_qstrings = re_findModeStrings(JSON_palette_names, strip.getPaletteCount()+strip.customPalettes.size());
|
||||
palettes_alpha_indexes = re_initIndexArray(strip.getPaletteCount()+strip.customPalettes.size());
|
||||
DEBUG_PRINT(F("Sorting palettes: ")); DEBUG_PRINT(strip.getPaletteCount()); DEBUG_PRINT('/'); DEBUG_PRINTLN(strip.customPalettes.size());
|
||||
palettes_qstrings = re_findModeStrings(JSON_palette_names, strip.getPaletteCount());
|
||||
palettes_alpha_indexes = re_initIndexArray(strip.getPaletteCount());
|
||||
if (strip.customPalettes.size()) {
|
||||
for (int i=0; i<strip.customPalettes.size(); i++) {
|
||||
palettes_alpha_indexes[strip.getPaletteCount()+i] = 255-i;
|
||||
palettes_qstrings[strip.getPaletteCount()+i] = PSTR("~Custom~");
|
||||
palettes_alpha_indexes[strip.getPaletteCount()-strip.customPalettes.size()+i] = 255-i;
|
||||
palettes_qstrings[strip.getPaletteCount()-strip.customPalettes.size()+i] = PSTR("~Custom~");
|
||||
}
|
||||
}
|
||||
|
||||
// How many palette names start with '*' and should not be sorted?
|
||||
// (Also skipping the first one, 'Default').
|
||||
int skipPaletteCount = 1;
|
||||
while (pgm_read_byte_near(palettes_qstrings[skipPaletteCount++]) == '*') ;
|
||||
re_sortModes(palettes_qstrings, palettes_alpha_indexes, strip.getPaletteCount(), skipPaletteCount);
|
||||
while (pgm_read_byte_near(palettes_qstrings[skipPaletteCount]) == '*') skipPaletteCount++;
|
||||
re_sortModes(palettes_qstrings, palettes_alpha_indexes, strip.getPaletteCount()-strip.customPalettes.size(), skipPaletteCount);
|
||||
}
|
||||
|
||||
byte *RotaryEncoderUIUsermod::re_initIndexArray(int numModes) {
|
||||
|
@ -5011,21 +5011,25 @@ uint16_t mode_2DDrift() { // By: Stepko https://editor.soulmateli
|
||||
const uint16_t cols = SEGMENT.virtualWidth();
|
||||
const uint16_t rows = SEGMENT.virtualHeight();
|
||||
|
||||
const uint16_t colsCenter = (cols>>1) + (cols%2);
|
||||
const uint16_t rowsCenter = (rows>>1) + (rows%2);
|
||||
|
||||
SEGMENT.fadeToBlackBy(128);
|
||||
const uint16_t maxDim = MAX(cols, rows)/2;
|
||||
unsigned long t = strip.now / (32 - (SEGMENT.speed>>3));
|
||||
unsigned long t_20 = t/20; // softhack007: pre-calculating this gives about 10% speedup
|
||||
for (float i = 1; i < maxDim; i += 0.25) {
|
||||
for (float i = 1.0f; i < maxDim; i += 0.25f) {
|
||||
float angle = radians(t * (maxDim - i));
|
||||
uint16_t myX = (cols>>1) + (uint16_t)(sin_t(angle) * i) + (cols%2);
|
||||
uint16_t myY = (rows>>1) + (uint16_t)(cos_t(angle) * i) + (rows%2);
|
||||
SEGMENT.setPixelColorXY(myX, myY, ColorFromPalette(SEGPALETTE, (i * 20) + t_20, 255, LINEARBLEND));
|
||||
int16_t mySin = sin_t(angle) * i;
|
||||
int16_t myCos = cos_t(angle) * i;
|
||||
SEGMENT.setPixelColorXY(colsCenter + mySin, rowsCenter + myCos, ColorFromPalette(SEGPALETTE, (i * 20) + t_20, 255, LINEARBLEND));
|
||||
if (SEGMENT.check1) SEGMENT.setPixelColorXY(colsCenter + myCos, rowsCenter + mySin, ColorFromPalette(SEGPALETTE, (i * 20) + t_20, 255, LINEARBLEND));
|
||||
}
|
||||
SEGMENT.blur(SEGMENT.intensity>>3);
|
||||
|
||||
return FRAMETIME;
|
||||
} // mode_2DDrift()
|
||||
static const char _data_FX_MODE_2DDRIFT[] PROGMEM = "Drift@Rotation speed,Blur amount;;!;2";
|
||||
static const char _data_FX_MODE_2DDRIFT[] PROGMEM = "Drift@Rotation speed,Blur amount,,,,Twin;;!;2";
|
||||
|
||||
|
||||
//////////////////////////
|
||||
@ -6198,8 +6202,9 @@ uint16_t mode_2Ddriftrose(void) {
|
||||
|
||||
SEGMENT.fadeToBlackBy(32+(SEGMENT.speed>>3));
|
||||
for (size_t i = 1; i < 37; i++) {
|
||||
uint32_t x = (CX + (sin_t(radians(i * 10)) * (beatsin8(i, 0, L*2)-L))) * 255.f;
|
||||
uint32_t y = (CY + (cos_t(radians(i * 10)) * (beatsin8(i, 0, L*2)-L))) * 255.f;
|
||||
float angle = radians(i * 10);
|
||||
uint32_t x = (CX + (sin_t(angle) * (beatsin8(i, 0, L*2)-L))) * 255.f;
|
||||
uint32_t y = (CY + (cos_t(angle) * (beatsin8(i, 0, L*2)-L))) * 255.f;
|
||||
SEGMENT.wu_pixel(x, y, CHSV(i * 10, 255, 255));
|
||||
}
|
||||
SEGMENT.blur((SEGMENT.intensity>>4)+1);
|
||||
|
11
wled00/FX.h
11
wled00/FX.h
@ -59,13 +59,12 @@
|
||||
/* Not used in all effects yet */
|
||||
#define WLED_FPS 42
|
||||
#define FRAMETIME_FIXED (1000/WLED_FPS)
|
||||
//#define FRAMETIME _frametime
|
||||
#define FRAMETIME strip.getFrameTime()
|
||||
|
||||
/* 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 12
|
||||
#define MAX_NUM_SEGMENTS 16
|
||||
/* How much data bytes all segments combined may allocate */
|
||||
#define MAX_SEGMENT_DATA 5120
|
||||
#else
|
||||
@ -73,11 +72,7 @@
|
||||
#define MAX_NUM_SEGMENTS 32
|
||||
#endif
|
||||
#if defined(ARDUINO_ARCH_ESP32S2)
|
||||
#if defined(BOARD_HAS_PSRAM) && defined(WLED_USE_PSRAM)
|
||||
#define MAX_SEGMENT_DATA MAX_NUM_SEGMENTS*1024 // 32k by default
|
||||
#else
|
||||
#define MAX_SEGMENT_DATA MAX_NUM_SEGMENTS*768 // 24k by default
|
||||
#endif
|
||||
#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
|
||||
@ -810,7 +805,7 @@ class WS2812FX { // 96 bytes
|
||||
inline uint8_t getSegmentsNum(void) { return _segments.size(); } // returns currently present segments
|
||||
inline uint8_t getCurrSegmentId(void) { return _segment_index; } // returns current segment index (only valid while strip.isServicing())
|
||||
inline uint8_t getMainSegmentId(void) { return _mainSegment; } // returns main segment index
|
||||
inline uint8_t getPaletteCount() { return 13 + GRADIENT_PALETTE_COUNT; } // will only return built-in palette count
|
||||
inline uint8_t getPaletteCount() { return 13 + GRADIENT_PALETTE_COUNT + customPalettes.size(); }
|
||||
inline uint8_t getTargetFps() { return _targetFps; } // returns rough FPS value for las 2s interval
|
||||
inline uint8_t getModeCount() { return _modeCount; } // returns number of registered modes/effects
|
||||
|
||||
|
@ -1098,6 +1098,12 @@ void WS2812FX::finalizeInit(void) {
|
||||
uint16_t prevLen = 0;
|
||||
for (int i = 0; i < defNumBusses && i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) {
|
||||
uint8_t defPin[] = {defDataPins[i]};
|
||||
// when booting without config (1st boot) we need to make sure GPIOs defined for LED output don't clash with hardware
|
||||
// i.e. DEBUG (GPIO1), DMX (2), SPI RAM/FLASH (16&17 on ESP32-WROVER/PICO), etc
|
||||
if (pinManager.isPinAllocated(defPin[0])) {
|
||||
defPin[0] = 1; // start with GPIO1 and work upwards
|
||||
while (pinManager.isPinAllocated(defPin[0]) && defPin[0] < WLED_NUM_PINS) defPin[0]++;
|
||||
}
|
||||
uint16_t start = prevLen;
|
||||
uint16_t count = defCounts[(i < defNumCounts) ? i : defNumCounts -1];
|
||||
prevLen += count;
|
||||
@ -1162,12 +1168,16 @@ void WS2812FX::service() {
|
||||
uint16_t delay = FRAMETIME;
|
||||
|
||||
if (!seg.freeze) { //only run effect function if not frozen
|
||||
int16_t oldCCT = BusManager::getSegmentCCT(); // store original CCT value (actually it is not Segment based)
|
||||
_virtualSegmentLength = seg.virtualLength(); //SEGLEN
|
||||
_colors_t[0] = gamma32(seg.currentColor(0));
|
||||
_colors_t[1] = gamma32(seg.currentColor(1));
|
||||
_colors_t[2] = gamma32(seg.currentColor(2));
|
||||
seg.currentPalette(_currentPalette, seg.palette); // we need to pass reference
|
||||
if (!cctFromRgb || correctWB) BusManager::setSegmentCCT(seg.currentBri(true), correctWB);
|
||||
// when correctWB is true we need to correct/adjust RGB value according to desired CCT value, but it will also affect actual WW/CW ratio
|
||||
// when cctFromRgb is true we implicitly calculate WW and CW from RGB values
|
||||
if (cctFromRgb) BusManager::setSegmentCCT(-1);
|
||||
else BusManager::setSegmentCCT(seg.currentBri(true), correctWB);
|
||||
// Effect blending
|
||||
// When two effects are being blended, each may have different segment data, this
|
||||
// data needs to be saved first and then restored before running previous mode.
|
||||
@ -1190,20 +1200,19 @@ void WS2812FX::service() {
|
||||
#endif
|
||||
seg.call++;
|
||||
if (seg.isInTransition() && delay > FRAMETIME) delay = FRAMETIME; // force faster updates during transition
|
||||
BusManager::setSegmentCCT(oldCCT); // restore old CCT for ABL adjustments
|
||||
}
|
||||
|
||||
seg.next_time = nowUp + delay;
|
||||
}
|
||||
// if (_segment_index == _queuedChangesSegId) setUpSegmentFromQueuedChanges();
|
||||
_segment_index++;
|
||||
}
|
||||
_virtualSegmentLength = 0;
|
||||
BusManager::setSegmentCCT(-1);
|
||||
_isServicing = false;
|
||||
_triggered = false;
|
||||
|
||||
#ifdef WLED_DEBUG
|
||||
if (millis() - nowUp > _frametime) DEBUG_PRINTLN(F("Slow effects."));
|
||||
if (millis() - nowUp > _frametime) DEBUG_PRINTF_P(PSTR("Slow effects %u/%d.\n"), (unsigned)(millis()-nowUp), (int)_frametime);
|
||||
#endif
|
||||
if (doShow) {
|
||||
yield();
|
||||
@ -1211,7 +1220,7 @@ void WS2812FX::service() {
|
||||
show();
|
||||
}
|
||||
#ifdef WLED_DEBUG
|
||||
if (millis() - nowUp > _frametime) DEBUG_PRINTLN(F("Slow strip."));
|
||||
if (millis() - nowUp > _frametime) DEBUG_PRINTF_P(PSTR("Slow strip %u/%d.\n"), (unsigned)(millis()-nowUp), (int)_frametime);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -1390,11 +1399,7 @@ bool WS2812FX::hasCCTBus(void) {
|
||||
for (size_t b = 0; b < BusManager::getNumBusses(); b++) {
|
||||
Bus *bus = BusManager::getBus(b);
|
||||
if (bus == nullptr || bus->getLength()==0) break;
|
||||
switch (bus->getType()) {
|
||||
case TYPE_ANALOG_5CH:
|
||||
case TYPE_ANALOG_2CH:
|
||||
return true;
|
||||
}
|
||||
if (bus->hasCCT()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -1425,31 +1430,12 @@ void WS2812FX::setSegment(uint8_t segId, uint16_t i1, uint16_t i2, uint8_t group
|
||||
appendSegment(Segment(0, strip.getLengthTotal()));
|
||||
segId = getSegmentsNum()-1; // segments are added at the end of list
|
||||
}
|
||||
/*
|
||||
if (_queuedChangesSegId == segId) _queuedChangesSegId = 255; // cancel queued change if already queued for this segment
|
||||
|
||||
if (segId < getMaxSegments() && segId == getCurrSegmentId() && isServicing()) { // queue change to prevent concurrent access
|
||||
// queuing a change for a second segment will lead to the loss of the first change if not yet applied
|
||||
// however this is not a problem as the queued change is applied immediately after the effect function in that segment returns
|
||||
_qStart = i1; _qStop = i2; _qStartY = startY; _qStopY = stopY;
|
||||
_qGrouping = grouping; _qSpacing = spacing; _qOffset = offset;
|
||||
_queuedChangesSegId = segId;
|
||||
DEBUG_PRINT(F("Segment queued: ")); DEBUG_PRINTLN(segId);
|
||||
return; // queued changes are applied immediately after effect function returns
|
||||
}
|
||||
*/
|
||||
suspend();
|
||||
_segments[segId].setUp(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
|
||||
}
|
||||
/*
|
||||
void WS2812FX::setUpSegmentFromQueuedChanges() {
|
||||
if (_queuedChangesSegId >= getSegmentsNum()) return;
|
||||
_segments[_queuedChangesSegId].setUp(_qStart, _qStop, _qGrouping, _qSpacing, _qOffset, _qStartY, _qStopY);
|
||||
_queuedChangesSegId = 255;
|
||||
}
|
||||
*/
|
||||
|
||||
void WS2812FX::resetSegments() {
|
||||
_segments.clear(); // destructs all Segment as part of clearing
|
||||
#ifndef WLED_DISABLE_2D
|
||||
|
@ -9,9 +9,10 @@
|
||||
#include "bus_wrapper.h"
|
||||
#include "bus_manager.h"
|
||||
|
||||
extern bool cctICused;
|
||||
|
||||
//colors.cpp
|
||||
uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb);
|
||||
uint16_t approximateKelvinFromRGB(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);
|
||||
@ -122,13 +123,13 @@ BusDigital::BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com)
|
||||
}
|
||||
_iType = PolyBus::getI(bc.type, _pins, nr);
|
||||
if (_iType == I_NONE) return;
|
||||
if (bc.doubleBuffer && !allocData(bc.count * (Bus::hasWhite(_type) + 3*Bus::hasRGB(_type)))) return; //warning: hardcoded channel count
|
||||
if (bc.doubleBuffer && !allocData(bc.count * Bus::getNumberOfChannels(bc.type))) 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);
|
||||
_valid = (_busPtr != nullptr);
|
||||
DEBUG_PRINTF("%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], _pins[1], _iType, _milliAmpsPerLed, _milliAmpsMax);
|
||||
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], IS_2PIN(bc.type)?_pins[1]:255, _iType, _milliAmpsPerLed, _milliAmpsMax);
|
||||
}
|
||||
|
||||
//fine tune power estimation constants for your setup
|
||||
@ -205,13 +206,15 @@ void BusDigital::show() {
|
||||
_milliAmpsTotal = 0;
|
||||
if (!_valid) return;
|
||||
|
||||
uint8_t cctWW = 0, cctCW = 0;
|
||||
uint8_t newBri = estimateCurrentAndLimitBri(); // will fill _milliAmpsTotal
|
||||
if (newBri < _bri) PolyBus::setBrightness(_busPtr, _iType, newBri); // limit brightness to stay within current limits
|
||||
|
||||
if (_data) { // use _buffering this causes ~20% FPS drop
|
||||
size_t channels = Bus::hasWhite(_type) + 3*Bus::hasRGB(_type);
|
||||
if (_data) {
|
||||
size_t channels = getNumberOfChannels();
|
||||
int16_t oldCCT = Bus::_cct; // temporarily save bus CCT
|
||||
for (size_t i=0; i<_len; i++) {
|
||||
size_t offset = i*channels;
|
||||
size_t offset = i * channels;
|
||||
uint8_t co = _colorOrderMap.getPixelColorOrder(i+_start, _colorOrder);
|
||||
uint32_t c;
|
||||
if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs (_len is always a multiple of 3)
|
||||
@ -221,17 +224,26 @@ void BusDigital::show() {
|
||||
case 2: c = RGBW32(_data[offset-2], _data[offset-1], _data[offset] , 0); break;
|
||||
}
|
||||
} else {
|
||||
c = RGBW32(_data[offset],_data[offset+1],_data[offset+2],(Bus::hasWhite(_type)?_data[offset+3]:0));
|
||||
if (hasRGB()) c = RGBW32(_data[offset], _data[offset+1], _data[offset+2], hasWhite() ? _data[offset+3] : 0);
|
||||
else c = RGBW32(0, 0, 0, _data[offset]);
|
||||
}
|
||||
if (hasCCT()) {
|
||||
// unfortunately as a segment may span multiple buses or a bus may contain multiple segments and each segment may have different CCT
|
||||
// we need to extract and appy CCT value for each pixel individually even though all buses share the same _cct variable
|
||||
// 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);
|
||||
}
|
||||
uint16_t pix = i;
|
||||
if (_reversed) pix = _len - pix -1;
|
||||
pix += _skip;
|
||||
PolyBus::setPixelColor(_busPtr, _iType, pix, c, co);
|
||||
PolyBus::setPixelColor(_busPtr, _iType, pix, c, co, (cctCW<<8) | cctWW);
|
||||
}
|
||||
#if !defined(STATUSLED) || STATUSLED>=0
|
||||
if (_skip) PolyBus::setPixelColor(_busPtr, _iType, 0, 0, _colorOrderMap.getPixelColorOrder(_start, _colorOrder)); // paint skipped pixels black
|
||||
#endif
|
||||
for (int i=1; i<_skip; i++) PolyBus::setPixelColor(_busPtr, _iType, i, 0, _colorOrderMap.getPixelColorOrder(_start, _colorOrder)); // paint skipped pixels black
|
||||
Bus::_cct = oldCCT;
|
||||
} else {
|
||||
if (newBri < _bri) {
|
||||
uint16_t hwLen = _len;
|
||||
@ -239,7 +251,8 @@ void BusDigital::show() {
|
||||
for (unsigned i = 0; i < hwLen; i++) {
|
||||
// use 0 as color order, actual order does not matter here as we just update the channel values as-is
|
||||
uint32_t c = restoreColorLossy(PolyBus::getPixelColor(_busPtr, _iType, i, 0), _bri);
|
||||
PolyBus::setPixelColor(_busPtr, _iType, i, c, 0); // repaint all pixels with new brightness
|
||||
if (hasCCT()) Bus::calculateCCT(c, cctWW, cctCW); // this will unfortunately corrupt (segment) CCT data on every bus
|
||||
PolyBus::setPixelColor(_busPtr, _iType, i, c, 0, (cctCW<<8) | cctWW); // repaint all pixels with new brightness
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -278,17 +291,20 @@ void BusDigital::setStatusPixel(uint32_t c) {
|
||||
|
||||
void IRAM_ATTR BusDigital::setPixelColor(uint16_t pix, uint32_t c) {
|
||||
if (!_valid) return;
|
||||
if (Bus::hasWhite(_type)) c = autoWhiteCalc(c);
|
||||
if (_cct >= 1900) c = colorBalanceFromKelvin(_cct, c); //color correction from CCT
|
||||
if (_data) { // use _buffering this causes ~20% FPS drop
|
||||
size_t channels = Bus::hasWhite(_type) + 3*Bus::hasRGB(_type);
|
||||
size_t offset = pix*channels;
|
||||
if (Bus::hasRGB(_type)) {
|
||||
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) {
|
||||
size_t offset = pix * getNumberOfChannels();
|
||||
if (hasRGB()) {
|
||||
_data[offset++] = R(c);
|
||||
_data[offset++] = G(c);
|
||||
_data[offset++] = B(c);
|
||||
}
|
||||
if (Bus::hasWhite(_type)) _data[offset] = W(c);
|
||||
if (hasWhite()) _data[offset++] = W(c);
|
||||
// unfortunately as a segment may span multiple buses or a bus may contain multiple segments and each segment may have different CCT
|
||||
// we need to store CCT value for each pixel (if there is a color correction in play, convert K in CCT ratio)
|
||||
if (hasCCT()) _data[offset] = Bus::_cct >= 1900 ? (Bus::_cct - 1900) >> 5 : (Bus::_cct < 0 ? 127 : Bus::_cct); // TODO: if _cct == -1 we simply ignore it
|
||||
} else {
|
||||
if (_reversed) pix = _len - pix -1;
|
||||
pix += _skip;
|
||||
@ -303,21 +319,21 @@ void IRAM_ATTR BusDigital::setPixelColor(uint16_t pix, uint32_t c) {
|
||||
case 2: c = RGBW32(R(cOld), G(cOld), W(c) , 0); break;
|
||||
}
|
||||
}
|
||||
PolyBus::setPixelColor(_busPtr, _iType, pix, c, co);
|
||||
if (hasCCT()) Bus::calculateCCT(c, cctWW, cctCW);
|
||||
PolyBus::setPixelColor(_busPtr, _iType, pix, c, co, (cctCW<<8) | cctWW);
|
||||
}
|
||||
}
|
||||
|
||||
// returns original color if global buffering is enabled, else returns lossly restored color from bus
|
||||
uint32_t IRAM_ATTR BusDigital::getPixelColor(uint16_t pix) {
|
||||
if (!_valid) return 0;
|
||||
if (_data) { // use _buffering this causes ~20% FPS drop
|
||||
size_t channels = Bus::hasWhite(_type) + 3*Bus::hasRGB(_type);
|
||||
size_t offset = pix*channels;
|
||||
if (_data) {
|
||||
size_t offset = pix * getNumberOfChannels();
|
||||
uint32_t c;
|
||||
if (!Bus::hasRGB(_type)) {
|
||||
if (!hasRGB()) {
|
||||
c = RGBW32(_data[offset], _data[offset], _data[offset], _data[offset]);
|
||||
} else {
|
||||
c = RGBW32(_data[offset], _data[offset+1], _data[offset+2], Bus::hasWhite(_type) ? _data[offset+3] : 0);
|
||||
c = RGBW32(_data[offset], _data[offset+1], _data[offset+2], hasWhite() ? _data[offset+3] : 0);
|
||||
}
|
||||
return c;
|
||||
} else {
|
||||
@ -414,48 +430,31 @@ BusPwm::BusPwm(BusConfig &bc)
|
||||
void BusPwm::setPixelColor(uint16_t pix, uint32_t c) {
|
||||
if (pix != 0 || !_valid) return; //only react to first pixel
|
||||
if (_type != TYPE_ANALOG_3CH) c = autoWhiteCalc(c);
|
||||
if (_cct >= 1900 && (_type == TYPE_ANALOG_3CH || _type == TYPE_ANALOG_4CH)) {
|
||||
c = colorBalanceFromKelvin(_cct, c); //color correction from CCT
|
||||
if (Bus::_cct >= 1900 && (_type == TYPE_ANALOG_3CH || _type == TYPE_ANALOG_4CH)) {
|
||||
c = colorBalanceFromKelvin(Bus::_cct, c); //color correction from CCT
|
||||
}
|
||||
uint8_t r = R(c);
|
||||
uint8_t g = G(c);
|
||||
uint8_t b = B(c);
|
||||
uint8_t w = W(c);
|
||||
uint8_t cct = 0; //0 - full warm white, 255 - full cold white
|
||||
if (_cct > -1) {
|
||||
if (_cct >= 1900) cct = (_cct - 1900) >> 5;
|
||||
else if (_cct < 256) cct = _cct;
|
||||
} else {
|
||||
cct = (approximateKelvinFromRGB(c) - 1900) >> 5;
|
||||
}
|
||||
|
||||
uint8_t ww, cw;
|
||||
#ifdef WLED_USE_IC_CCT
|
||||
ww = w;
|
||||
cw = cct;
|
||||
#else
|
||||
//0 - linear (CCT 127 = 50% warm, 50% cold), 127 - additive CCT blending (CCT 127 = 100% warm, 100% cold)
|
||||
if (cct < _cctBlend) ww = 255;
|
||||
else ww = ((255-cct) * 255) / (255 - _cctBlend);
|
||||
|
||||
if ((255-cct) < _cctBlend) cw = 255;
|
||||
else cw = (cct * 255) / (255 - _cctBlend);
|
||||
|
||||
ww = (w * ww) / 255; //brightness scaling
|
||||
cw = (w * cw) / 255;
|
||||
#endif
|
||||
|
||||
switch (_type) {
|
||||
case TYPE_ANALOG_1CH: //one channel (white), relies on auto white calculation
|
||||
_data[0] = w;
|
||||
break;
|
||||
case TYPE_ANALOG_2CH: //warm white + cold white
|
||||
_data[1] = cw;
|
||||
_data[0] = ww;
|
||||
if (cctICused) {
|
||||
_data[0] = w;
|
||||
_data[1] = Bus::_cct < 0 || Bus::_cct > 255 ? 127 : Bus::_cct;
|
||||
} else {
|
||||
Bus::calculateCCT(c, _data[0], _data[1]);
|
||||
}
|
||||
break;
|
||||
case TYPE_ANALOG_5CH: //RGB + warm white + cold white
|
||||
_data[4] = cw;
|
||||
w = ww;
|
||||
if (cctICused)
|
||||
_data[4] = Bus::_cct < 0 || Bus::_cct > 255 ? 127 : Bus::_cct;
|
||||
else
|
||||
Bus::calculateCCT(c, w, _data[4]);
|
||||
case TYPE_ANALOG_4CH: //RGBW
|
||||
_data[3] = w;
|
||||
case TYPE_ANALOG_3CH: //standard dumb RGB
|
||||
@ -620,7 +619,7 @@ BusNetwork::BusNetwork(BusConfig &bc)
|
||||
void BusNetwork::setPixelColor(uint16_t pix, uint32_t c) {
|
||||
if (!_valid || pix >= _len) return;
|
||||
if (_rgbw) c = autoWhiteCalc(c);
|
||||
if (_cct >= 1900) c = colorBalanceFromKelvin(_cct, c); //color correction from CCT
|
||||
if (Bus::_cct >= 1900) c = colorBalanceFromKelvin(Bus::_cct, c); //color correction from CCT
|
||||
uint16_t offset = pix * _UDPchannels;
|
||||
_data[offset] = R(c);
|
||||
_data[offset+1] = G(c);
|
||||
@ -660,25 +659,18 @@ uint32_t BusManager::memUsage(BusConfig &bc) {
|
||||
if (bc.type == TYPE_ONOFF || IS_PWM(bc.type)) return 5;
|
||||
|
||||
uint16_t len = bc.count + bc.skipAmount;
|
||||
uint16_t channels = 3;
|
||||
uint16_t channels = Bus::getNumberOfChannels(bc.type);
|
||||
uint16_t multiplier = 1;
|
||||
if (IS_DIGITAL(bc.type)) { // digital types
|
||||
if (IS_16BIT(bc.type)) len *= 2; // 16-bit LEDs
|
||||
#ifdef ESP8266
|
||||
if (bc.type > 28) channels = 4; //RGBW
|
||||
if (bc.pins[0] == 3) { //8266 DMA uses 5x the mem
|
||||
multiplier = 5;
|
||||
}
|
||||
#else //ESP32 RMT uses double buffer, I2S uses 5x buffer
|
||||
if (bc.type > 28) channels = 4; //RGBW
|
||||
multiplier = 2;
|
||||
#endif
|
||||
}
|
||||
if (IS_VIRTUAL(bc.type)) {
|
||||
switch (bc.type) {
|
||||
case TYPE_NET_DDP_RGBW: channels = 4; break;
|
||||
}
|
||||
}
|
||||
return len * channels * multiplier; //RGB
|
||||
}
|
||||
|
||||
@ -740,7 +732,7 @@ void BusManager::setSegmentCCT(int16_t cct, bool allowWBCorrection) {
|
||||
if (cct >= 0) {
|
||||
//if white balance correction allowed, save as kelvin value instead of 0-255
|
||||
if (allowWBCorrection) cct = 1900 + (cct << 5);
|
||||
} else cct = -1;
|
||||
} else cct = -1; // will use kelvin approximation from RGB
|
||||
Bus::setCCT(cct);
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,9 @@
|
||||
|
||||
#include "const.h"
|
||||
|
||||
//colors.cpp
|
||||
uint16_t approximateKelvinFromRGB(uint32_t rgb);
|
||||
|
||||
#define GET_BIT(var,bit) (((var)>>(bit))&0x01)
|
||||
#define SET_BIT(var,bit) ((var)|=(uint16_t)(0x0001<<(bit)))
|
||||
#define UNSET_BIT(var,bit) ((var)&=(~(uint16_t)(0x0001<<(bit))))
|
||||
@ -32,7 +35,7 @@ struct BusConfig {
|
||||
uint8_t skipAmount;
|
||||
bool refreshReq;
|
||||
uint8_t autoWhite;
|
||||
uint8_t pins[5] = {LEDPIN, 255, 255, 255, 255};
|
||||
uint8_t pins[5] = {255, 255, 255, 255, 255};
|
||||
uint16_t frequency;
|
||||
bool doubleBuffer;
|
||||
uint8_t milliAmpsPerLed;
|
||||
@ -53,9 +56,9 @@ struct BusConfig {
|
||||
refreshReq = (bool) GET_BIT(busType,7);
|
||||
type = busType & 0x7F; // bit 7 may be/is hacked to include refresh info (1=refresh in off state, 0=no refresh)
|
||||
size_t nPins = 1;
|
||||
if (type >= TYPE_NET_DDP_RGB && type < 96) nPins = 4; //virtual network bus. 4 "pins" store IP address
|
||||
else if (type > 47) nPins = 2;
|
||||
else if (type > 40 && type < 46) nPins = NUM_PWM_PINS(type);
|
||||
if (IS_VIRTUAL(type)) nPins = 4; //virtual network bus. 4 "pins" store IP address
|
||||
else if (IS_2PIN(type)) nPins = 2;
|
||||
else if (IS_PWM(type)) nPins = NUM_PWM_PINS(type);
|
||||
for (size_t i = 0; i < nPins; i++) pins[i] = ppins[i];
|
||||
}
|
||||
|
||||
@ -138,6 +141,8 @@ class Bus {
|
||||
virtual uint16_t getLEDCurrent() { return 0; }
|
||||
virtual uint16_t getUsedCurrent() { return 0; }
|
||||
virtual uint16_t getMaxCurrent() { return 0; }
|
||||
virtual uint8_t getNumberOfChannels() { return hasWhite(_type) + 3*hasRGB(_type) + hasCCT(_type); }
|
||||
static inline uint8_t getNumberOfChannels(uint8_t type) { return hasWhite(type) + 3*hasRGB(type) + hasCCT(type); }
|
||||
inline void setReversed(bool reversed) { _reversed = reversed; }
|
||||
inline uint16_t getStart() { return _start; }
|
||||
inline void setStart(uint16_t start) { _start = start; }
|
||||
@ -154,18 +159,22 @@ class Bus {
|
||||
}
|
||||
virtual bool hasWhite(void) { return Bus::hasWhite(_type); }
|
||||
static bool hasWhite(uint8_t type) {
|
||||
if ((type >= TYPE_WS2812_1CH && type <= TYPE_WS2812_WWA) || type == TYPE_SK6812_RGBW || type == TYPE_TM1814 || type == TYPE_UCS8904) return true; // digital types with white channel
|
||||
if ((type >= TYPE_WS2812_1CH && type <= TYPE_WS2812_WWA) ||
|
||||
type == TYPE_SK6812_RGBW || type == TYPE_TM1814 || type == TYPE_UCS8904 ||
|
||||
type == TYPE_FW1906 || type == TYPE_WS2805) return true; // digital types with white channel
|
||||
if (type > TYPE_ONOFF && type <= TYPE_ANALOG_5CH && type != TYPE_ANALOG_3CH) return true; // analog types with white channel
|
||||
if (type == TYPE_NET_DDP_RGBW) return true; // network types with white channel
|
||||
if (type == TYPE_NET_DDP_RGBW || type == TYPE_NET_ARTNET_RGBW) return true; // network types with white channel
|
||||
return false;
|
||||
}
|
||||
virtual bool hasCCT(void) { return Bus::hasCCT(_type); }
|
||||
static bool hasCCT(uint8_t type) {
|
||||
if (type == TYPE_WS2812_2CH_X3 || type == TYPE_WS2812_WWA ||
|
||||
type == TYPE_ANALOG_2CH || type == TYPE_ANALOG_5CH) return true;
|
||||
type == TYPE_ANALOG_2CH || type == TYPE_ANALOG_5CH ||
|
||||
type == TYPE_FW1906 || type == TYPE_WS2805 ) return true;
|
||||
return false;
|
||||
}
|
||||
static void setCCT(uint16_t cct) {
|
||||
static int16_t getCCT() { return _cct; }
|
||||
static void setCCT(int16_t cct) {
|
||||
_cct = cct;
|
||||
}
|
||||
static void setCCTBlend(uint8_t b) {
|
||||
@ -176,6 +185,26 @@ class Bus {
|
||||
if (_cctBlend > WLED_MAX_CCT_BLEND) _cctBlend = WLED_MAX_CCT_BLEND;
|
||||
#endif
|
||||
}
|
||||
static void calculateCCT(uint32_t c, uint8_t &ww, uint8_t &cw) {
|
||||
uint8_t cct = 0; //0 - full warm white, 255 - full cold white
|
||||
uint8_t w = byte(c >> 24);
|
||||
|
||||
if (_cct > -1) {
|
||||
if (_cct >= 1900) cct = (_cct - 1900) >> 5;
|
||||
else if (_cct < 256) cct = _cct;
|
||||
} else {
|
||||
cct = (approximateKelvinFromRGB(c) - 1900) >> 5;
|
||||
}
|
||||
|
||||
//0 - linear (CCT 127 = 50% warm, 50% cold), 127 - additive CCT blending (CCT 127 = 100% warm, 100% cold)
|
||||
if (cct < _cctBlend) ww = 255;
|
||||
else ww = ((255-cct) * 255) / (255 - _cctBlend);
|
||||
if ((255-cct) < _cctBlend) cw = 255;
|
||||
else cw = (cct * 255) / (255 - _cctBlend);
|
||||
|
||||
ww = (w * ww) / 255; //brightness scaling
|
||||
cw = (w * cw) / 255;
|
||||
}
|
||||
inline void setAutoWhiteMode(uint8_t m) { if (m < 5) _autoWhiteMode = m; }
|
||||
inline uint8_t getAutoWhiteMode() { return _autoWhiteMode; }
|
||||
inline static void setGlobalAWMode(uint8_t m) { if (m < 5) _gAWM = m; else _gAWM = AW_GLOBAL_DISABLED; }
|
||||
@ -191,8 +220,17 @@ class Bus {
|
||||
bool _needsRefresh;
|
||||
uint8_t _autoWhiteMode;
|
||||
uint8_t *_data;
|
||||
// global Auto White Calculation override
|
||||
static uint8_t _gAWM;
|
||||
// _cct has the following menaings (see calculateCCT() & BusManager::setSegmentCCT()):
|
||||
// -1 means to extract approximate CCT value in K from RGB (in calcualteCCT())
|
||||
// [0,255] is the exact CCT value where 0 means warm and 255 cold
|
||||
// [1900,10060] only for color correction expressed in K (colorBalanceFromKelvin())
|
||||
static int16_t _cct;
|
||||
// _cctBlend determines WW/CW blending:
|
||||
// 0 - linear (CCT 127 => 50% warm, 50% cold)
|
||||
// 63 - semi additive/nonlinear (CCT 127 => 66% warm, 66% cold)
|
||||
// 127 - additive CCT blending (CCT 127 => 100% warm, 100% cold)
|
||||
static uint8_t _cctBlend;
|
||||
|
||||
uint32_t autoWhiteCalc(uint32_t c);
|
||||
@ -334,9 +372,12 @@ class BusManager {
|
||||
static void setStatusPixel(uint32_t c);
|
||||
static void setPixelColor(uint16_t 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 void setMilliampsMax(uint16_t max) { _milliAmpsMax = max;}
|
||||
static uint32_t getPixelColor(uint16_t pix);
|
||||
static inline int16_t getSegmentCCT() { return Bus::getCCT(); }
|
||||
|
||||
static Bus* getBus(uint8_t busNr);
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define BusWrapper_h
|
||||
|
||||
#include "NeoPixelBusLg.h"
|
||||
#include "bus_manager.h"
|
||||
|
||||
// temporary - these defines should actually be set in platformio.ini
|
||||
// C3: I2S0 and I2S1 methods not supported (has one I2S bus)
|
||||
@ -63,52 +64,64 @@
|
||||
#define I_8266_U1_UCS_4 54
|
||||
#define I_8266_DM_UCS_4 55
|
||||
#define I_8266_BB_UCS_4 56
|
||||
//FW1906 GRBCW
|
||||
#define I_8266_U0_FW6_5 66
|
||||
#define I_8266_U1_FW6_5 67
|
||||
#define I_8266_DM_FW6_5 68
|
||||
#define I_8266_BB_FW6_5 69
|
||||
//ESP8266 APA106
|
||||
#define I_8266_U0_APA106_3 81
|
||||
#define I_8266_U1_APA106_3 82
|
||||
#define I_8266_DM_APA106_3 83
|
||||
#define I_8266_BB_APA106_3 84
|
||||
//WS2805
|
||||
#define I_8266_U0_2805_5 89
|
||||
#define I_8266_U1_2805_5 90
|
||||
#define I_8266_DM_2805_5 91
|
||||
#define I_8266_BB_2805_5 92
|
||||
|
||||
/*** ESP32 Neopixel methods ***/
|
||||
//RGB
|
||||
#define I_32_RN_NEO_3 21
|
||||
#define I_32_I0_NEO_3 22
|
||||
#define I_32_I1_NEO_3 23
|
||||
#define I_32_BB_NEO_3 24 // bitbanging on ESP32 not recommended
|
||||
//RGBW
|
||||
#define I_32_RN_NEO_4 25
|
||||
#define I_32_I0_NEO_4 26
|
||||
#define I_32_I1_NEO_4 27
|
||||
#define I_32_BB_NEO_4 28 // bitbanging on ESP32 not recommended
|
||||
//400Kbps
|
||||
#define I_32_RN_400_3 29
|
||||
#define I_32_I0_400_3 30
|
||||
#define I_32_I1_400_3 31
|
||||
#define I_32_BB_400_3 32 // bitbanging on ESP32 not recommended
|
||||
//TM1814 (RGBW)
|
||||
#define I_32_RN_TM1_4 33
|
||||
#define I_32_I0_TM1_4 34
|
||||
#define I_32_I1_TM1_4 35
|
||||
//Bit Bang theoratically possible, but very undesirable and not needed (no pin restrictions on RMT and I2S)
|
||||
//TM1829 (RGB)
|
||||
#define I_32_RN_TM2_3 36
|
||||
#define I_32_I0_TM2_3 37
|
||||
#define I_32_I1_TM2_3 38
|
||||
//Bit Bang theoratically possible, but very undesirable and not needed (no pin restrictions on RMT and I2S)
|
||||
//UCS8903 (RGB)
|
||||
#define I_32_RN_UCS_3 57
|
||||
#define I_32_I0_UCS_3 58
|
||||
#define I_32_I1_UCS_3 59
|
||||
//Bit Bang theoratically possible, but very undesirable and not needed (no pin restrictions on RMT and I2S)
|
||||
//UCS8904 (RGBW)
|
||||
#define I_32_RN_UCS_4 60
|
||||
#define I_32_I0_UCS_4 61
|
||||
#define I_32_I1_UCS_4 62
|
||||
//Bit Bang theoratically possible, but very undesirable and not needed (no pin restrictions on RMT and I2S)
|
||||
//FW1906 GRBCW
|
||||
#define I_32_RN_FW6_5 63
|
||||
#define I_32_I0_FW6_5 64
|
||||
#define I_32_I1_FW6_5 65
|
||||
//APA106
|
||||
#define I_32_RN_APA106_3 85
|
||||
#define I_32_I0_APA106_3 86
|
||||
#define I_32_I1_APA106_3 87
|
||||
#define I_32_BB_APA106_3 88 // bitbangging on ESP32 not recommended
|
||||
//WS2805
|
||||
#define I_32_RN_2805_5 93
|
||||
#define I_32_I0_2805_5 94
|
||||
#define I_32_I1_2805_5 95
|
||||
|
||||
|
||||
//APA102
|
||||
#define I_HS_DOT_3 39 //hardware SPI
|
||||
@ -176,6 +189,16 @@
|
||||
#define B_8266_U1_APA106_3 NeoPixelBusLg<NeoRbgFeature, NeoEsp8266Uart1Apa106Method, NeoGammaNullMethod> //3 chan, esp8266, gpio2
|
||||
#define B_8266_DM_APA106_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp8266DmaApa106Method, NeoGammaNullMethod> //3 chan, esp8266, gpio3
|
||||
#define B_8266_BB_APA106_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp8266BitBangApa106Method, NeoGammaNullMethod> //3 chan, esp8266, bb (any pin but 16)
|
||||
//FW1906 GRBCW
|
||||
#define B_8266_U0_FW6_5 NeoPixelBusLg<NeoGrbcwxFeature, NeoEsp8266Uart0Ws2813Method, NeoGammaNullMethod> //esp8266, gpio1
|
||||
#define B_8266_U1_FW6_5 NeoPixelBusLg<NeoGrbcwxFeature, NeoEsp8266Uart1Ws2813Method, NeoGammaNullMethod> //esp8266, gpio2
|
||||
#define B_8266_DM_FW6_5 NeoPixelBusLg<NeoGrbcwxFeature, NeoEsp8266Dma800KbpsMethod, NeoGammaNullMethod> //esp8266, gpio3
|
||||
#define B_8266_BB_FW6_5 NeoPixelBusLg<NeoGrbcwxFeature, NeoEsp8266BitBang800KbpsMethod, NeoGammaNullMethod> //esp8266, bb
|
||||
//WS2805 GRBCW
|
||||
#define B_8266_U0_2805_5 NeoPixelBusLg<NeoGrbwwFeature, NeoEsp8266Uart0Ws2805Method, NeoGammaNullMethod> //esp8266, gpio1
|
||||
#define B_8266_U1_2805_5 NeoPixelBusLg<NeoGrbwwFeature, NeoEsp8266Uart1Ws2805Method, NeoGammaNullMethod> //esp8266, gpio2
|
||||
#define B_8266_DM_2805_5 NeoPixelBusLg<NeoGrbwwFeature, NeoEsp8266DmaWs2805Method, NeoGammaNullMethod> //esp8266, gpio3
|
||||
#define B_8266_BB_2805_5 NeoPixelBusLg<NeoGrbwwFeature, NeoEsp8266BitBangWs2805Method, NeoGammaNullMethod> //esp8266, bb
|
||||
#endif
|
||||
|
||||
/*** ESP32 Neopixel methods ***/
|
||||
@ -183,75 +206,102 @@
|
||||
//RGB
|
||||
#define B_32_RN_NEO_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32RmtNWs2812xMethod, NeoGammaNullMethod>
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
#define B_32_I0_NEO_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s0800KbpsMethod, NeoGammaNullMethod>
|
||||
#define B_32_I0_NEO_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s0Ws2812xMethod, NeoGammaNullMethod>
|
||||
//#define B_32_I0_NEO_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s0X8Ws2812xMethod, NeoGammaNullMethod> // parallel I2S
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
#define B_32_I1_NEO_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s1800KbpsMethod, NeoGammaNullMethod>
|
||||
#define B_32_I1_NEO_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s1Ws2812xMethod, NeoGammaNullMethod>
|
||||
//#define B_32_I1_NEO_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s1X8Ws2812xMethod, NeoGammaNullMethod> // parallel I2S
|
||||
#endif
|
||||
//#define B_32_BB_NEO_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32BitBang800KbpsMethod, NeoGammaNullMethod> // NeoEsp8266BitBang800KbpsMethod
|
||||
//RGBW
|
||||
#define B_32_RN_NEO_4 NeoPixelBusLg<NeoGrbwFeature, NeoEsp32RmtNWs2812xMethod, NeoGammaNullMethod>
|
||||
#define B_32_RN_NEO_4 NeoPixelBusLg<NeoGrbwFeature, NeoEsp32RmtNSk6812Method, NeoGammaNullMethod>
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
#define B_32_I0_NEO_4 NeoPixelBusLg<NeoGrbwFeature, NeoEsp32I2s0800KbpsMethod, NeoGammaNullMethod>
|
||||
#define B_32_I0_NEO_4 NeoPixelBusLg<NeoGrbwFeature, NeoEsp32I2s0Sk6812Method, NeoGammaNullMethod>
|
||||
//#define B_32_I0_NEO_4 NeoPixelBusLg<NeoGrbwFeature, NeoEsp32I2s0X8Sk6812Method, NeoGammaNullMethod> // parallel I2S
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
#define B_32_I1_NEO_4 NeoPixelBusLg<NeoGrbwFeature, NeoEsp32I2s1800KbpsMethod, NeoGammaNullMethod>
|
||||
#define B_32_I1_NEO_4 NeoPixelBusLg<NeoGrbwFeature, NeoEsp32I2s1Sk6812Method, NeoGammaNullMethod>
|
||||
//#define B_32_I1_NEO_4 NeoPixelBusLg<NeoGrbwFeature, NeoEsp32I2s1X8Sk6812Method, NeoGammaNullMethod> // parallel I2S
|
||||
#endif
|
||||
//#define B_32_BB_NEO_4 NeoPixelBusLg<NeoGrbwFeature, NeoEsp32BitBang800KbpsMethod, NeoGammaNullMethod> // NeoEsp8266BitBang800KbpsMethod
|
||||
//400Kbps
|
||||
#define B_32_RN_400_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32RmtN400KbpsMethod, NeoGammaNullMethod>
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
#define B_32_I0_400_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s0400KbpsMethod, NeoGammaNullMethod>
|
||||
//#define B_32_I0_400_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s0X8400KbpsMethod, NeoGammaNullMethod> // parallel I2S
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
#define B_32_I1_400_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s1400KbpsMethod, NeoGammaNullMethod>
|
||||
//#define B_32_I1_400_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s1X8400KbpsMethod, NeoGammaNullMethod> // parallel I2S
|
||||
#endif
|
||||
//#define B_32_BB_400_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32BitBang400KbpsMethod, NeoGammaNullMethod> // NeoEsp8266BitBang400KbpsMethod
|
||||
//TM1814 (RGBW)
|
||||
#define B_32_RN_TM1_4 NeoPixelBusLg<NeoWrgbTm1814Feature, NeoEsp32RmtNTm1814Method, NeoGammaNullMethod>
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
#define B_32_I0_TM1_4 NeoPixelBusLg<NeoWrgbTm1814Feature, NeoEsp32I2s0Tm1814Method, NeoGammaNullMethod>
|
||||
//#define B_32_I0_TM1_4 NeoPixelBusLg<NeoWrgbTm1814Feature, NeoEsp32I2s0X8Tm1814Method, NeoGammaNullMethod> // parallel I2S
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
#define B_32_I1_TM1_4 NeoPixelBusLg<NeoWrgbTm1814Feature, NeoEsp32I2s1Tm1814Method, NeoGammaNullMethod>
|
||||
//#define B_32_I1_TM1_4 NeoPixelBusLg<NeoWrgbTm1814Feature, NeoEsp32I2s1X8Tm1814Method, NeoGammaNullMethod> // parallel I2S
|
||||
#endif
|
||||
//Bit Bang theoratically possible, but very undesirable and not needed (no pin restrictions on RMT and I2S)
|
||||
//TM1829 (RGB)
|
||||
#define B_32_RN_TM2_3 NeoPixelBusLg<NeoBrgFeature, NeoEsp32RmtNTm1829Method, NeoGammaNullMethod>
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
#define B_32_I0_TM2_3 NeoPixelBusLg<NeoBrgFeature, NeoEsp32I2s0Tm1829Method, NeoGammaNullMethod>
|
||||
//#define B_32_I0_TM2_3 NeoPixelBusLg<NeoBrgFeature, NeoEsp32I2s0X8Tm1829Method, NeoGammaNullMethod> // parallel I2S
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
#define B_32_I1_TM2_3 NeoPixelBusLg<NeoBrgFeature, NeoEsp32I2s1Tm1829Method, NeoGammaNullMethod>
|
||||
//#define B_32_I1_TM2_3 NeoPixelBusLg<NeoBrgFeature, NeoEsp32I2s1X8Tm1829Method, NeoGammaNullMethod> // parallel I2S
|
||||
#endif
|
||||
//Bit Bang theoratically possible, but very undesirable and not needed (no pin restrictions on RMT and I2S)
|
||||
//UCS8903
|
||||
#define B_32_RN_UCS_3 NeoPixelBusLg<NeoRgbUcs8903Feature, NeoEsp32RmtNWs2812xMethod, NeoGammaNullMethod>
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
#define B_32_I0_UCS_3 NeoPixelBusLg<NeoRgbUcs8903Feature, NeoEsp32I2s0800KbpsMethod, NeoGammaNullMethod>
|
||||
//#define B_32_I0_UCS_3 NeoPixelBusLg<NeoRgbUcs8903Feature, NeoEsp32I2s0X8800KbpsMethod, NeoGammaNullMethod> // parallel I2S
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
#define B_32_I1_UCS_3 NeoPixelBusLg<NeoRgbUcs8903Feature, NeoEsp32I2s1800KbpsMethod, NeoGammaNullMethod>
|
||||
//#define B_32_I1_UCS_3 NeoPixelBusLg<NeoRgbUcs8903Feature, NeoEsp32I2s1X8800KbpsMethod, NeoGammaNullMethod> // parallel I2S
|
||||
#endif
|
||||
//Bit Bang theoratically possible, but very undesirable and not needed (no pin restrictions on RMT and I2S)
|
||||
//UCS8904
|
||||
#define B_32_RN_UCS_4 NeoPixelBusLg<NeoRgbwUcs8904Feature, NeoEsp32RmtNWs2812xMethod, NeoGammaNullMethod>
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
#define B_32_I0_UCS_4 NeoPixelBusLg<NeoRgbwUcs8904Feature, NeoEsp32I2s0800KbpsMethod, NeoGammaNullMethod>
|
||||
//#define B_32_I0_UCS_4 NeoPixelBusLg<NeoRgbwUcs8904Feature, NeoEsp32I2s0X8800KbpsMethod, NeoGammaNullMethod>// parallel I2S
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
#define B_32_I1_UCS_4 NeoPixelBusLg<NeoRgbwUcs8904Feature, NeoEsp32I2s1800KbpsMethod, NeoGammaNullMethod>
|
||||
//#define B_32_I1_UCS_4 NeoPixelBusLg<NeoRgbwUcs8904Feature, NeoEsp32I2s1X8800KbpsMethod, NeoGammaNullMethod>// parallel I2S
|
||||
#endif
|
||||
//Bit Bang theoratically possible, but very undesirable and not needed (no pin restrictions on RMT and I2S)
|
||||
#define B_32_RN_APA106_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32RmtNApa106Method, NeoGammaNullMethod>
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
#define B_32_I0_APA106_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s0Apa106Method, NeoGammaNullMethod>
|
||||
//#define B_32_I0_APA106_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s0X8Apa106Method, NeoGammaNullMethod> // parallel I2S
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
#define B_32_I1_APA106_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s1Apa106Method, NeoGammaNullMethod>
|
||||
//#define B_32_I1_APA106_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s1X8Apa106Method, NeoGammaNullMethod> // parallel I2S
|
||||
#endif
|
||||
//FW1906 GRBCW
|
||||
#define B_32_RN_FW6_5 NeoPixelBusLg<NeoGrbcwxFeature, NeoEsp32RmtNWs2812xMethod, NeoGammaNullMethod>
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
#define B_32_I0_FW6_5 NeoPixelBusLg<NeoGrbcwxFeature, NeoEsp32I2s0800KbpsMethod, NeoGammaNullMethod>
|
||||
//#define B_32_I0_FW6_5 NeoPixelBusLg<NeoGrbcwxFeature, NeoEsp32I2s0X8800KbpsMethod, NeoGammaNullMethod> // parallel I2S
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
#define B_32_I1_FW6_5 NeoPixelBusLg<NeoGrbcwxFeature, NeoEsp32I2s1800KbpsMethod, NeoGammaNullMethod>
|
||||
//#define B_32_I1_FW6_5 NeoPixelBusLg<NeoGrbcwxFeature, NeoEsp32I2s1X8800KbpsMethod, NeoGammaNullMethod> // parallel I2S
|
||||
#endif
|
||||
//WS2805 RGBWC
|
||||
#define B_32_RN_2805_5 NeoPixelBusLg<NeoGrbwwFeature, NeoEsp32RmtNWs2805Method, NeoGammaNullMethod>
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
#define B_32_I0_2805_5 NeoPixelBusLg<NeoGrbwwFeature, NeoEsp32I2s0Ws2805Method, NeoGammaNullMethod>
|
||||
//#define B_32_I0_2805_5 NeoPixelBusLg<NeoGrbwwFeature, NeoEsp32I2s0X8Ws2805Method, NeoGammaNullMethod> // parallel I2S
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
#define B_32_I1_2805_5 NeoPixelBusLg<NeoGrbwwFeature, NeoEsp32I2s1Ws2805Method, NeoGammaNullMethod>
|
||||
//#define B_32_I1_2805_5 NeoPixelBusLg<NeoGrbwwFeature, NeoEsp32I2s1X8Ws2805Method, NeoGammaNullMethod> // parallel I2S
|
||||
#endif
|
||||
//#define B_32_BB_APA106_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp8266BitBangApa106Method, NeoGammaNullMethod> // NeoEsp8266BitBang800KbpsMethod
|
||||
|
||||
#endif
|
||||
|
||||
//APA102
|
||||
@ -290,6 +340,7 @@
|
||||
//handles pointer type conversion for all possible bus types
|
||||
class PolyBus {
|
||||
public:
|
||||
|
||||
// initialize SPI bus speed for DotStar methods
|
||||
template <class T>
|
||||
static void beginDotStar(void* busPtr, int8_t sck, int8_t miso, int8_t mosi, int8_t ss, uint16_t clock_kHz = 0U) {
|
||||
@ -353,6 +404,14 @@ class PolyBus {
|
||||
case I_8266_U1_APA106_3: (static_cast<B_8266_U1_APA106_3*>(busPtr))->Begin(); break;
|
||||
case I_8266_DM_APA106_3: (static_cast<B_8266_DM_APA106_3*>(busPtr))->Begin(); break;
|
||||
case I_8266_BB_APA106_3: (static_cast<B_8266_BB_APA106_3*>(busPtr))->Begin(); break;
|
||||
case I_8266_U0_FW6_5: (static_cast<B_8266_U0_FW6_5*>(busPtr))->Begin(); break;
|
||||
case I_8266_U1_FW6_5: (static_cast<B_8266_U1_FW6_5*>(busPtr))->Begin(); break;
|
||||
case I_8266_DM_FW6_5: (static_cast<B_8266_DM_FW6_5*>(busPtr))->Begin(); break;
|
||||
case I_8266_BB_FW6_5: (static_cast<B_8266_BB_FW6_5*>(busPtr))->Begin(); break;
|
||||
case I_8266_U0_2805_5: (static_cast<B_8266_U0_2805_5*>(busPtr))->Begin(); break;
|
||||
case I_8266_U1_2805_5: (static_cast<B_8266_U1_2805_5*>(busPtr))->Begin(); break;
|
||||
case I_8266_DM_2805_5: (static_cast<B_8266_DM_2805_5*>(busPtr))->Begin(); break;
|
||||
case I_8266_BB_2805_5: (static_cast<B_8266_BB_2805_5*>(busPtr))->Begin(); break;
|
||||
#endif
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
case I_32_RN_NEO_3: (static_cast<B_32_RN_NEO_3*>(busPtr))->Begin(); break;
|
||||
@ -362,7 +421,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_NEO_3: (static_cast<B_32_I1_NEO_3*>(busPtr))->Begin(); break;
|
||||
#endif
|
||||
// case I_32_BB_NEO_3: (static_cast<B_32_BB_NEO_3*>(busPtr))->Begin(); break;
|
||||
case I_32_RN_NEO_4: (static_cast<B_32_RN_NEO_4*>(busPtr))->Begin(); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_NEO_4: (static_cast<B_32_I0_NEO_4*>(busPtr))->Begin(); break;
|
||||
@ -370,7 +428,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_NEO_4: (static_cast<B_32_I1_NEO_4*>(busPtr))->Begin(); break;
|
||||
#endif
|
||||
// case I_32_BB_NEO_4: (static_cast<B_32_BB_NEO_4*>(busPtr))->Begin(); break;
|
||||
case I_32_RN_400_3: (static_cast<B_32_RN_400_3*>(busPtr))->Begin(); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_400_3: (static_cast<B_32_I0_400_3*>(busPtr))->Begin(); break;
|
||||
@ -378,7 +435,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_400_3: (static_cast<B_32_I1_400_3*>(busPtr))->Begin(); break;
|
||||
#endif
|
||||
// case I_32_BB_400_3: (static_cast<B_32_BB_400_3*>(busPtr))->Begin(); break;
|
||||
case I_32_RN_TM1_4: beginTM1814<B_32_RN_TM1_4*>(busPtr); break;
|
||||
case I_32_RN_TM2_3: (static_cast<B_32_RN_TM2_3*>(busPtr))->Begin(); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
@ -396,7 +452,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_UCS_3: (static_cast<B_32_I1_UCS_3*>(busPtr))->Begin(); break;
|
||||
#endif
|
||||
// case I_32_BB_UCS_3: (static_cast<B_32_BB_UCS_3*>(busPtr))->Begin(); break;
|
||||
case I_32_RN_UCS_4: (static_cast<B_32_RN_UCS_4*>(busPtr))->Begin(); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_UCS_4: (static_cast<B_32_I0_UCS_4*>(busPtr))->Begin(); break;
|
||||
@ -404,7 +459,13 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_UCS_4: (static_cast<B_32_I1_UCS_4*>(busPtr))->Begin(); break;
|
||||
#endif
|
||||
// case I_32_BB_UCS_4: (static_cast<B_32_BB_UCS_4*>(busPtr))->Begin(); break;
|
||||
case I_32_RN_FW6_5: (static_cast<B_32_RN_FW6_5*>(busPtr))->Begin(); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_FW6_5: (static_cast<B_32_I0_FW6_5*>(busPtr))->Begin(); break;
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_FW6_5: (static_cast<B_32_I1_FW6_5*>(busPtr))->Begin(); break;
|
||||
#endif
|
||||
case I_32_RN_APA106_3: (static_cast<B_32_RN_APA106_3*>(busPtr))->Begin(); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_APA106_3: (static_cast<B_32_I0_APA106_3*>(busPtr))->Begin(); break;
|
||||
@ -412,7 +473,13 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_APA106_3: (static_cast<B_32_I1_APA106_3*>(busPtr))->Begin(); break;
|
||||
#endif
|
||||
// case I_32_BB_APA106_3: (static_cast<B_32_BB_APA106_3*>(busPtr))->Begin(); break;
|
||||
case I_32_RN_2805_5: (static_cast<B_32_RN_2805_5*>(busPtr))->Begin(); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_2805_5: (static_cast<B_32_I0_2805_5*>(busPtr))->Begin(); break;
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_2805_5: (static_cast<B_32_I1_2805_5*>(busPtr))->Begin(); break;
|
||||
#endif
|
||||
// ESP32 can (and should, to avoid inadvertantly driving the chip select signal) specify the pins used for SPI, but only in begin()
|
||||
case I_HS_DOT_3: beginDotStar<B_HS_DOT_3*>(busPtr, pins[1], -1, pins[0], -1, clock_kHz); break;
|
||||
case I_HS_LPD_3: beginDotStar<B_HS_LPD_3*>(busPtr, pins[1], -1, pins[0], -1, clock_kHz); break;
|
||||
@ -465,6 +532,14 @@ class PolyBus {
|
||||
case I_8266_U1_APA106_3: busPtr = new B_8266_U1_APA106_3(len, pins[0]); break;
|
||||
case I_8266_DM_APA106_3: busPtr = new B_8266_DM_APA106_3(len, pins[0]); break;
|
||||
case I_8266_BB_APA106_3: busPtr = new B_8266_BB_APA106_3(len, pins[0]); break;
|
||||
case I_8266_U0_FW6_5: busPtr = new B_8266_U0_FW6_5(len, pins[0]); break;
|
||||
case I_8266_U1_FW6_5: busPtr = new B_8266_U1_FW6_5(len, pins[0]); break;
|
||||
case I_8266_DM_FW6_5: busPtr = new B_8266_DM_FW6_5(len, pins[0]); break;
|
||||
case I_8266_BB_FW6_5: busPtr = new B_8266_BB_FW6_5(len, pins[0]); break;
|
||||
case I_8266_U0_2805_5: busPtr = new B_8266_U0_2805_5(len, pins[0]); break;
|
||||
case I_8266_U1_2805_5: busPtr = new B_8266_U1_2805_5(len, pins[0]); break;
|
||||
case I_8266_DM_2805_5: busPtr = new B_8266_DM_2805_5(len, pins[0]); break;
|
||||
case I_8266_BB_2805_5: busPtr = new B_8266_BB_2805_5(len, pins[0]); break;
|
||||
#endif
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
case I_32_RN_NEO_3: busPtr = new B_32_RN_NEO_3(len, pins[0], (NeoBusChannel)channel); break;
|
||||
@ -474,7 +549,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_NEO_3: busPtr = new B_32_I1_NEO_3(len, pins[0]); break;
|
||||
#endif
|
||||
// case I_32_BB_NEO_3: busPtr = new B_32_BB_NEO_3(len, pins[0], (NeoBusChannel)channel); break;
|
||||
case I_32_RN_NEO_4: busPtr = new B_32_RN_NEO_4(len, pins[0], (NeoBusChannel)channel); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_NEO_4: busPtr = new B_32_I0_NEO_4(len, pins[0]); break;
|
||||
@ -482,7 +556,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_NEO_4: busPtr = new B_32_I1_NEO_4(len, pins[0]); break;
|
||||
#endif
|
||||
// case I_32_BB_NEO_4: busPtr = new B_32_BB_NEO_4(len, pins[0], (NeoBusChannel)channel); break;
|
||||
case I_32_RN_400_3: busPtr = new B_32_RN_400_3(len, pins[0], (NeoBusChannel)channel); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_400_3: busPtr = new B_32_I0_400_3(len, pins[0]); break;
|
||||
@ -490,7 +563,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_400_3: busPtr = new B_32_I1_400_3(len, pins[0]); break;
|
||||
#endif
|
||||
// case I_32_BB_400_3: busPtr = new B_32_BB_400_3(len, pins[0], (NeoBusChannel)channel); break;
|
||||
case I_32_RN_TM1_4: busPtr = new B_32_RN_TM1_4(len, pins[0], (NeoBusChannel)channel); break;
|
||||
case I_32_RN_TM2_3: busPtr = new B_32_RN_TM2_3(len, pins[0], (NeoBusChannel)channel); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
@ -508,7 +580,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_UCS_3: busPtr = new B_32_I1_UCS_3(len, pins[0]); break;
|
||||
#endif
|
||||
// case I_32_BB_UCS_3: busPtr = new B_32_BB_UCS_3(len, pins[0], (NeoBusChannel)channel); break;
|
||||
case I_32_RN_UCS_4: busPtr = new B_32_RN_UCS_4(len, pins[0], (NeoBusChannel)channel); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_UCS_4: busPtr = new B_32_I0_UCS_4(len, pins[0]); break;
|
||||
@ -516,7 +587,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_UCS_4: busPtr = new B_32_I1_UCS_4(len, pins[0]); break;
|
||||
#endif
|
||||
// case I_32_BB_UCS_4: busPtr = new B_32_BB_UCS_4(len, pins[0], (NeoBusChannel)channel); break;
|
||||
case I_32_RN_APA106_3: busPtr = new B_32_RN_APA106_3(len, pins[0], (NeoBusChannel)channel); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_APA106_3: busPtr = new B_32_I0_APA106_3(len, pins[0]); break;
|
||||
@ -524,7 +594,20 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_APA106_3: busPtr = new B_32_I1_APA106_3(len, pins[0]); break;
|
||||
#endif
|
||||
// case I_32_BB_APA106_3: busPtr = new B_32_BB_APA106_3(len, pins[0], (NeoBusChannel)channel); break;
|
||||
case I_32_RN_FW6_5: busPtr = new B_32_RN_FW6_5(len, pins[0], (NeoBusChannel)channel); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_FW6_5: busPtr = new B_32_I0_FW6_5(len, pins[0]); break;
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_FW6_5: busPtr = new B_32_I1_FW6_5(len, pins[0]); break;
|
||||
#endif
|
||||
case I_32_RN_2805_5: busPtr = new B_32_RN_2805_5(len, pins[0], (NeoBusChannel)channel); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_2805_5: busPtr = new B_32_I0_2805_5(len, pins[0]); break;
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_2805_5: busPtr = new B_32_I1_2805_5(len, pins[0]); break;
|
||||
#endif
|
||||
#endif
|
||||
// for 2-wire: pins[1] is clk, pins[0] is dat. begin expects (len, clk, dat)
|
||||
case I_HS_DOT_3: busPtr = new B_HS_DOT_3(len, pins[1], pins[0]); break;
|
||||
@ -578,6 +661,14 @@ class PolyBus {
|
||||
case I_8266_U1_APA106_3: (static_cast<B_8266_U1_APA106_3*>(busPtr))->Show(consistent); break;
|
||||
case I_8266_DM_APA106_3: (static_cast<B_8266_DM_APA106_3*>(busPtr))->Show(consistent); break;
|
||||
case I_8266_BB_APA106_3: (static_cast<B_8266_BB_APA106_3*>(busPtr))->Show(consistent); break;
|
||||
case I_8266_U0_FW6_5: (static_cast<B_8266_U0_FW6_5*>(busPtr))->Show(consistent); break;
|
||||
case I_8266_U1_FW6_5: (static_cast<B_8266_U1_FW6_5*>(busPtr))->Show(consistent); break;
|
||||
case I_8266_DM_FW6_5: (static_cast<B_8266_DM_FW6_5*>(busPtr))->Show(consistent); break;
|
||||
case I_8266_BB_FW6_5: (static_cast<B_8266_BB_FW6_5*>(busPtr))->Show(consistent); break;
|
||||
case I_8266_U0_2805_5: (static_cast<B_8266_U0_2805_5*>(busPtr))->Show(consistent); break;
|
||||
case I_8266_U1_2805_5: (static_cast<B_8266_U1_2805_5*>(busPtr))->Show(consistent); break;
|
||||
case I_8266_DM_2805_5: (static_cast<B_8266_DM_2805_5*>(busPtr))->Show(consistent); break;
|
||||
case I_8266_BB_2805_5: (static_cast<B_8266_BB_2805_5*>(busPtr))->Show(consistent); break;
|
||||
#endif
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
case I_32_RN_NEO_3: (static_cast<B_32_RN_NEO_3*>(busPtr))->Show(consistent); break;
|
||||
@ -587,7 +678,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_NEO_3: (static_cast<B_32_I1_NEO_3*>(busPtr))->Show(consistent); break;
|
||||
#endif
|
||||
// case I_32_BB_NEO_3: (static_cast<B_32_BB_NEO_3*>(busPtr))->Show(consistent); break;
|
||||
case I_32_RN_NEO_4: (static_cast<B_32_RN_NEO_4*>(busPtr))->Show(consistent); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_NEO_4: (static_cast<B_32_I0_NEO_4*>(busPtr))->Show(consistent); break;
|
||||
@ -595,7 +685,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_NEO_4: (static_cast<B_32_I1_NEO_4*>(busPtr))->Show(consistent); break;
|
||||
#endif
|
||||
// case I_32_BB_NEO_4: (static_cast<B_32_BB_NEO_4*>(busPtr))->Show(consistent); break;
|
||||
case I_32_RN_400_3: (static_cast<B_32_RN_400_3*>(busPtr))->Show(consistent); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_400_3: (static_cast<B_32_I0_400_3*>(busPtr))->Show(consistent); break;
|
||||
@ -603,7 +692,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_400_3: (static_cast<B_32_I1_400_3*>(busPtr))->Show(consistent); break;
|
||||
#endif
|
||||
// case I_32_BB_400_3: (static_cast<B_32_BB_400_3*>(busPtr))->Show(consistent); break;
|
||||
case I_32_RN_TM1_4: (static_cast<B_32_RN_TM1_4*>(busPtr))->Show(consistent); break;
|
||||
case I_32_RN_TM2_3: (static_cast<B_32_RN_TM2_3*>(busPtr))->Show(consistent); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
@ -621,7 +709,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_UCS_3: (static_cast<B_32_I1_UCS_3*>(busPtr))->Show(consistent); break;
|
||||
#endif
|
||||
// case I_32_BB_UCS_3: (static_cast<B_32_BB_NEO_3*>(busPtr))->Show(consistent); break;
|
||||
case I_32_RN_UCS_4: (static_cast<B_32_RN_UCS_4*>(busPtr))->Show(consistent); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_UCS_4: (static_cast<B_32_I0_UCS_4*>(busPtr))->Show(consistent); break;
|
||||
@ -629,7 +716,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_UCS_4: (static_cast<B_32_I1_UCS_4*>(busPtr))->Show(consistent); break;
|
||||
#endif
|
||||
// case I_32_BB_UCS_4: (static_cast<B_32_BB_UCS_4*>(busPtr))->Show(consistent); break;
|
||||
case I_32_RN_APA106_3: (static_cast<B_32_RN_APA106_3*>(busPtr))->Show(consistent); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_APA106_3: (static_cast<B_32_I0_APA106_3*>(busPtr))->Show(consistent); break;
|
||||
@ -637,7 +723,20 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_APA106_3: (static_cast<B_32_I1_APA106_3*>(busPtr))->Show(consistent); break;
|
||||
#endif
|
||||
// case I_32_BB_APA106_3: (static_cast<B_32_BB_APA106_3*>(busPtr))->Show(consistent); break;
|
||||
case I_32_RN_FW6_5: (static_cast<B_32_RN_FW6_5*>(busPtr))->Show(consistent); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_FW6_5: (static_cast<B_32_I0_FW6_5*>(busPtr))->Show(consistent); break;
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_FW6_5: (static_cast<B_32_I1_FW6_5*>(busPtr))->Show(consistent); break;
|
||||
#endif
|
||||
case I_32_RN_2805_5: (static_cast<B_32_RN_2805_5*>(busPtr))->Show(consistent); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_2805_5: (static_cast<B_32_I0_2805_5*>(busPtr))->Show(consistent); break;
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_2805_5: (static_cast<B_32_I1_2805_5*>(busPtr))->Show(consistent); break;
|
||||
#endif
|
||||
#endif
|
||||
case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->Show(consistent); break;
|
||||
case I_SS_DOT_3: (static_cast<B_SS_DOT_3*>(busPtr))->Show(consistent); break;
|
||||
@ -687,6 +786,14 @@ class PolyBus {
|
||||
case I_8266_U1_APA106_3: return (static_cast<B_8266_U1_APA106_3*>(busPtr))->CanShow(); break;
|
||||
case I_8266_DM_APA106_3: return (static_cast<B_8266_DM_APA106_3*>(busPtr))->CanShow(); break;
|
||||
case I_8266_BB_APA106_3: return (static_cast<B_8266_BB_APA106_3*>(busPtr))->CanShow(); break;
|
||||
case I_8266_U0_FW6_5: return (static_cast<B_8266_U0_FW6_5*>(busPtr))->CanShow(); break;
|
||||
case I_8266_U1_FW6_5: return (static_cast<B_8266_U1_FW6_5*>(busPtr))->CanShow(); break;
|
||||
case I_8266_DM_FW6_5: return (static_cast<B_8266_DM_FW6_5*>(busPtr))->CanShow(); break;
|
||||
case I_8266_BB_FW6_5: return (static_cast<B_8266_BB_FW6_5*>(busPtr))->CanShow(); break;
|
||||
case I_8266_U0_2805_5: return (static_cast<B_8266_U0_2805_5*>(busPtr))->CanShow(); break;
|
||||
case I_8266_U1_2805_5: return (static_cast<B_8266_U1_2805_5*>(busPtr))->CanShow(); break;
|
||||
case I_8266_DM_2805_5: return (static_cast<B_8266_DM_2805_5*>(busPtr))->CanShow(); break;
|
||||
case I_8266_BB_2805_5: return (static_cast<B_8266_BB_2805_5*>(busPtr))->CanShow(); break;
|
||||
#endif
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
case I_32_RN_NEO_3: return (static_cast<B_32_RN_NEO_3*>(busPtr))->CanShow(); break;
|
||||
@ -696,7 +803,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_NEO_3: return (static_cast<B_32_I1_NEO_3*>(busPtr))->CanShow(); break;
|
||||
#endif
|
||||
// case I_32_BB_NEO_3: return (static_cast<B_32_BB_NEO_3*>(busPtr))->CanShow(); break;
|
||||
case I_32_RN_NEO_4: return (static_cast<B_32_RN_NEO_4*>(busPtr))->CanShow(); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_NEO_4: return (static_cast<B_32_I0_NEO_4*>(busPtr))->CanShow(); break;
|
||||
@ -704,7 +810,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_NEO_4: return (static_cast<B_32_I1_NEO_4*>(busPtr))->CanShow(); break;
|
||||
#endif
|
||||
// case I_32_BB_NEO_4: return (static_cast<B_32_BB_NEO_4*>(busPtr))->CanShow(); break;
|
||||
case I_32_RN_400_3: return (static_cast<B_32_RN_400_3*>(busPtr))->CanShow(); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_400_3: return (static_cast<B_32_I0_400_3*>(busPtr))->CanShow(); break;
|
||||
@ -712,7 +817,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_400_3: return (static_cast<B_32_I1_400_3*>(busPtr))->CanShow(); break;
|
||||
#endif
|
||||
// case I_32_BB_400_3: return (static_cast<B_32_BB_400_3*>(busPtr))->CanShow(); break;
|
||||
case I_32_RN_TM1_4: return (static_cast<B_32_RN_TM1_4*>(busPtr))->CanShow(); break;
|
||||
case I_32_RN_TM2_3: return (static_cast<B_32_RN_TM2_3*>(busPtr))->CanShow(); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
@ -730,7 +834,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_UCS_3: return (static_cast<B_32_I1_UCS_3*>(busPtr))->CanShow(); break;
|
||||
#endif
|
||||
// case I_32_BB_UCS_3: return (static_cast<B_32_BB_UCS_3*>(busPtr))->CanShow(); break;
|
||||
case I_32_RN_UCS_4: return (static_cast<B_32_RN_UCS_4*>(busPtr))->CanShow(); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_UCS_4: return (static_cast<B_32_I0_UCS_4*>(busPtr))->CanShow(); break;
|
||||
@ -738,7 +841,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_UCS_4: return (static_cast<B_32_I1_UCS_4*>(busPtr))->CanShow(); break;
|
||||
#endif
|
||||
// case I_32_BB_UCS_4: return (static_cast<B_32_BB_UCS_4*>(busPtr))->CanShow(); break;
|
||||
case I_32_RN_APA106_3: return (static_cast<B_32_RN_APA106_3*>(busPtr))->CanShow(); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_APA106_3: return (static_cast<B_32_I0_APA106_3*>(busPtr))->CanShow(); break;
|
||||
@ -746,7 +848,20 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_APA106_3: return (static_cast<B_32_I1_APA106_3*>(busPtr))->CanShow(); break;
|
||||
#endif
|
||||
// case I_32_BB_APA106_3: return (static_cast<B_32_BB_APA106_3*>(busPtr))->CanShow(); break;
|
||||
case I_32_RN_FW6_5: return (static_cast<B_32_RN_FW6_5*>(busPtr))->CanShow(); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_FW6_5: return (static_cast<B_32_I0_FW6_5*>(busPtr))->CanShow(); break;
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_FW6_5: return (static_cast<B_32_I1_FW6_5*>(busPtr))->CanShow(); break;
|
||||
#endif
|
||||
case I_32_RN_2805_5: return (static_cast<B_32_RN_2805_5*>(busPtr))->CanShow(); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_2805_5: return (static_cast<B_32_I0_2805_5*>(busPtr))->CanShow(); break;
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_2805_5: return (static_cast<B_32_I1_2805_5*>(busPtr))->CanShow(); break;
|
||||
#endif
|
||||
#endif
|
||||
case I_HS_DOT_3: return (static_cast<B_HS_DOT_3*>(busPtr))->CanShow(); break;
|
||||
case I_SS_DOT_3: return (static_cast<B_SS_DOT_3*>(busPtr))->CanShow(); break;
|
||||
@ -762,12 +877,13 @@ class PolyBus {
|
||||
return true;
|
||||
}
|
||||
|
||||
static void setPixelColor(void* busPtr, uint8_t busType, uint16_t pix, uint32_t c, uint8_t co) {
|
||||
static void setPixelColor(void* busPtr, uint8_t busType, uint16_t pix, uint32_t c, uint8_t co, uint16_t wwcw = 0) {
|
||||
uint8_t r = c >> 16;
|
||||
uint8_t g = c >> 8;
|
||||
uint8_t b = c >> 0;
|
||||
uint8_t w = c >> 24;
|
||||
RgbwColor col;
|
||||
uint8_t cctWW = wwcw & 0xFF, cctCW = (wwcw>>8) & 0xFF;
|
||||
|
||||
// reorder channels to selected order
|
||||
switch (co & 0x0F) {
|
||||
@ -821,6 +937,14 @@ class PolyBus {
|
||||
case I_8266_U1_APA106_3: (static_cast<B_8266_U1_APA106_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break;
|
||||
case I_8266_DM_APA106_3: (static_cast<B_8266_DM_APA106_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break;
|
||||
case I_8266_BB_APA106_3: (static_cast<B_8266_BB_APA106_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break;
|
||||
case I_8266_U0_FW6_5: (static_cast<B_8266_U0_FW6_5*>(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break;
|
||||
case I_8266_U1_FW6_5: (static_cast<B_8266_U1_FW6_5*>(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break;
|
||||
case I_8266_DM_FW6_5: (static_cast<B_8266_DM_FW6_5*>(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break;
|
||||
case I_8266_BB_FW6_5: (static_cast<B_8266_BB_FW6_5*>(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break;
|
||||
case I_8266_U0_2805_5: (static_cast<B_8266_U0_2805_5*>(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break;
|
||||
case I_8266_U1_2805_5: (static_cast<B_8266_U1_2805_5*>(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break;
|
||||
case I_8266_DM_2805_5: (static_cast<B_8266_DM_2805_5*>(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break;
|
||||
case I_8266_BB_2805_5: (static_cast<B_8266_BB_2805_5*>(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break;
|
||||
#endif
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
case I_32_RN_NEO_3: (static_cast<B_32_RN_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break;
|
||||
@ -830,7 +954,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_NEO_3: (static_cast<B_32_I1_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break;
|
||||
#endif
|
||||
// case I_32_BB_NEO_3: (static_cast<B_32_BB_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break;
|
||||
case I_32_RN_NEO_4: (static_cast<B_32_RN_NEO_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_NEO_4: (static_cast<B_32_I0_NEO_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
@ -838,7 +961,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_NEO_4: (static_cast<B_32_I1_NEO_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
#endif
|
||||
// case I_32_BB_NEO_4: (static_cast<B_32_BB_NEO_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
case I_32_RN_400_3: (static_cast<B_32_RN_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_400_3: (static_cast<B_32_I0_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break;
|
||||
@ -846,7 +968,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_400_3: (static_cast<B_32_I1_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break;
|
||||
#endif
|
||||
// case I_32_BB_400_3: (static_cast<B_32_BB_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(colB)); break;
|
||||
case I_32_RN_TM1_4: (static_cast<B_32_RN_TM1_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
case I_32_RN_TM2_3: (static_cast<B_32_RN_TM2_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
@ -864,7 +985,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_UCS_3: (static_cast<B_32_I1_UCS_3*>(busPtr))->SetPixelColor(pix, Rgb48Color(RgbColor(col))); break;
|
||||
#endif
|
||||
// case I_32_BB_UCS_3: (static_cast<B_32_BB_UCS_3*>(busPtr))->SetPixelColor(pix, Rgb48Color(RgbColor(col))); break;
|
||||
case I_32_RN_UCS_4: (static_cast<B_32_RN_UCS_4*>(busPtr))->SetPixelColor(pix, Rgbw64Color(col)); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_UCS_4: (static_cast<B_32_I0_UCS_4*>(busPtr))->SetPixelColor(pix, Rgbw64Color(col)); break;
|
||||
@ -872,7 +992,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_UCS_4: (static_cast<B_32_I1_UCS_4*>(busPtr))->SetPixelColor(pix, Rgbw64Color(col)); break;
|
||||
#endif
|
||||
// case I_32_BB_UCS_4: (static_cast<B_32_BB_UCS_4*>(busPtr))->SetPixelColor(pix, Rgbw64Color(col)); break;
|
||||
case I_32_RN_APA106_3: (static_cast<B_32_RN_APA106_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_APA106_3: (static_cast<B_32_I0_APA106_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break;
|
||||
@ -880,7 +999,20 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_APA106_3: (static_cast<B_32_I1_APA106_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break;
|
||||
#endif
|
||||
// case I_32_BB_APA106_3: (static_cast<B_32_BB_APA106_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break;
|
||||
case I_32_RN_FW6_5: (static_cast<B_32_RN_FW6_5*>(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_FW6_5: (static_cast<B_32_I0_FW6_5*>(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break;
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_FW6_5: (static_cast<B_32_I1_FW6_5*>(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break;
|
||||
#endif
|
||||
case I_32_RN_2805_5: (static_cast<B_32_RN_2805_5*>(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_2805_5: (static_cast<B_32_I0_2805_5*>(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break;
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_2805_5: (static_cast<B_32_I1_2805_5*>(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break;
|
||||
#endif
|
||||
#endif
|
||||
case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break;
|
||||
case I_SS_DOT_3: (static_cast<B_SS_DOT_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break;
|
||||
@ -931,6 +1063,14 @@ class PolyBus {
|
||||
case I_8266_U1_APA106_3: (static_cast<B_8266_U1_APA106_3*>(busPtr))->SetLuminance(b); break;
|
||||
case I_8266_DM_APA106_3: (static_cast<B_8266_DM_APA106_3*>(busPtr))->SetLuminance(b); break;
|
||||
case I_8266_BB_APA106_3: (static_cast<B_8266_BB_APA106_3*>(busPtr))->SetLuminance(b); break;
|
||||
case I_8266_U0_FW6_5: (static_cast<B_8266_U0_FW6_5*>(busPtr))->SetLuminance(b); break;
|
||||
case I_8266_U1_FW6_5: (static_cast<B_8266_U1_FW6_5*>(busPtr))->SetLuminance(b); break;
|
||||
case I_8266_DM_FW6_5: (static_cast<B_8266_DM_FW6_5*>(busPtr))->SetLuminance(b); break;
|
||||
case I_8266_BB_FW6_5: (static_cast<B_8266_BB_FW6_5*>(busPtr))->SetLuminance(b); break;
|
||||
case I_8266_U0_2805_5: (static_cast<B_8266_U0_2805_5*>(busPtr))->SetLuminance(b); break;
|
||||
case I_8266_U1_2805_5: (static_cast<B_8266_U1_2805_5*>(busPtr))->SetLuminance(b); break;
|
||||
case I_8266_DM_2805_5: (static_cast<B_8266_DM_2805_5*>(busPtr))->SetLuminance(b); break;
|
||||
case I_8266_BB_2805_5: (static_cast<B_8266_BB_2805_5*>(busPtr))->SetLuminance(b); break;
|
||||
#endif
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
case I_32_RN_NEO_3: (static_cast<B_32_RN_NEO_3*>(busPtr))->SetLuminance(b); break;
|
||||
@ -940,7 +1080,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_NEO_3: (static_cast<B_32_I1_NEO_3*>(busPtr))->SetLuminance(b); break;
|
||||
#endif
|
||||
// case I_32_BB_NEO_3: (static_cast<B_32_BB_NEO_3*>(busPtr))->SetLuminance(b); break;
|
||||
case I_32_RN_NEO_4: (static_cast<B_32_RN_NEO_4*>(busPtr))->SetLuminance(b); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_NEO_4: (static_cast<B_32_I0_NEO_4*>(busPtr))->SetLuminance(b); break;
|
||||
@ -948,7 +1087,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_NEO_4: (static_cast<B_32_I1_NEO_4*>(busPtr))->SetLuminance(b); break;
|
||||
#endif
|
||||
// case I_32_BB_NEO_4: (static_cast<B_32_BB_NEO_4*>(busPtr))->SetLuminance(b); break;
|
||||
case I_32_RN_400_3: (static_cast<B_32_RN_400_3*>(busPtr))->SetLuminance(b); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_400_3: (static_cast<B_32_I0_400_3*>(busPtr))->SetLuminance(b); break;
|
||||
@ -956,7 +1094,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_400_3: (static_cast<B_32_I1_400_3*>(busPtr))->SetLuminance(b); break;
|
||||
#endif
|
||||
// case I_32_BB_400_3: (static_cast<B_32_BB_400_3*>(busPtr))->SetLuminance(b); break;
|
||||
case I_32_RN_TM1_4: (static_cast<B_32_RN_TM1_4*>(busPtr))->SetLuminance(b); break;
|
||||
case I_32_RN_TM2_3: (static_cast<B_32_RN_TM2_3*>(busPtr))->SetLuminance(b); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
@ -974,7 +1111,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_UCS_3: (static_cast<B_32_I1_UCS_3*>(busPtr))->SetLuminance(b); break;
|
||||
#endif
|
||||
// case I_32_BB_UCS_3: (static_cast<B_32_BB_UCS_3*>(busPtr))->SetLuminance(b); break;
|
||||
case I_32_RN_UCS_4: (static_cast<B_32_RN_UCS_4*>(busPtr))->SetLuminance(b); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_UCS_4: (static_cast<B_32_I0_UCS_4*>(busPtr))->SetLuminance(b); break;
|
||||
@ -982,7 +1118,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_UCS_4: (static_cast<B_32_I1_UCS_4*>(busPtr))->SetLuminance(b); break;
|
||||
#endif
|
||||
// case I_32_BB_UCS_4: (static_cast<B_32_BB_UCS_4*>(busPtr))->SetLuminance(b); break;
|
||||
case I_32_RN_APA106_3: (static_cast<B_32_RN_APA106_3*>(busPtr))->SetLuminance(b); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_APA106_3: (static_cast<B_32_I0_APA106_3*>(busPtr))->SetLuminance(b); break;
|
||||
@ -990,7 +1125,20 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_APA106_3: (static_cast<B_32_I1_APA106_3*>(busPtr))->SetLuminance(b); break;
|
||||
#endif
|
||||
// case I_32_BB_APA106_3: (static_cast<B_32_BB_APA106_3*>(busPtr))->SetLuminance(b); break;
|
||||
case I_32_RN_FW6_5: (static_cast<B_32_RN_FW6_5*>(busPtr))->SetLuminance(b); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_FW6_5: (static_cast<B_32_I0_FW6_5*>(busPtr))->SetLuminance(b); break;
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_FW6_5: (static_cast<B_32_I1_FW6_5*>(busPtr))->SetLuminance(b); break;
|
||||
#endif
|
||||
case I_32_RN_2805_5: (static_cast<B_32_RN_2805_5*>(busPtr))->SetLuminance(b); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_2805_5: (static_cast<B_32_I0_2805_5*>(busPtr))->SetLuminance(b); break;
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_2805_5: (static_cast<B_32_I1_2805_5*>(busPtr))->SetLuminance(b); break;
|
||||
#endif
|
||||
#endif
|
||||
case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->SetLuminance(b); break;
|
||||
case I_SS_DOT_3: (static_cast<B_SS_DOT_3*>(busPtr))->SetLuminance(b); break;
|
||||
@ -1042,6 +1190,14 @@ class PolyBus {
|
||||
case I_8266_U1_APA106_3: col = (static_cast<B_8266_U1_APA106_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_8266_DM_APA106_3: col = (static_cast<B_8266_DM_APA106_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_8266_BB_APA106_3: col = (static_cast<B_8266_BB_APA106_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_8266_U0_FW6_5: { RgbwwColor c = (static_cast<B_8266_U0_FW6_5*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W
|
||||
case I_8266_U1_FW6_5: { RgbwwColor c = (static_cast<B_8266_U1_FW6_5*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W
|
||||
case I_8266_DM_FW6_5: { RgbwwColor c = (static_cast<B_8266_DM_FW6_5*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W
|
||||
case I_8266_BB_FW6_5: { RgbwwColor c = (static_cast<B_8266_BB_FW6_5*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W
|
||||
case I_8266_U0_2805_5: { RgbwwColor c = (static_cast<B_8266_U0_2805_5*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W
|
||||
case I_8266_U1_2805_5: { RgbwwColor c = (static_cast<B_8266_U1_2805_5*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W
|
||||
case I_8266_DM_2805_5: { RgbwwColor c = (static_cast<B_8266_DM_2805_5*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W
|
||||
case I_8266_BB_2805_5: { RgbwwColor c = (static_cast<B_8266_BB_2805_5*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W
|
||||
#endif
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
case I_32_RN_NEO_3: col = (static_cast<B_32_RN_NEO_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
@ -1051,7 +1207,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_NEO_3: col = (static_cast<B_32_I1_NEO_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
#endif
|
||||
// case I_32_BB_NEO_3: col = (static_cast<B_32_BB_NEO_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_RN_NEO_4: col = (static_cast<B_32_RN_NEO_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_NEO_4: col = (static_cast<B_32_I0_NEO_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
@ -1059,7 +1214,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_NEO_4: col = (static_cast<B_32_I1_NEO_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
#endif
|
||||
// case I_32_BB_NEO_4: col = (static_cast<B_32_BB_NEO_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_RN_400_3: col = (static_cast<B_32_RN_400_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_400_3: col = (static_cast<B_32_I0_400_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
@ -1067,7 +1221,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_400_3: col = (static_cast<B_32_I1_400_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
#endif
|
||||
// case I_32_BB_400_3: col = (static_cast<B_32_BB_400_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_RN_TM1_4: col = (static_cast<B_32_RN_TM1_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_RN_TM2_3: col = (static_cast<B_32_RN_TM2_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
@ -1085,7 +1238,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_UCS_3: { Rgb48Color c = (static_cast<B_32_I1_UCS_3*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R>>8,c.G>>8,c.B>>8,0); } break;
|
||||
#endif
|
||||
// case I_32_BB_UCS_3: col = (static_cast<B_32_BB_UCS_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_RN_UCS_4: { Rgbw64Color c = (static_cast<B_32_RN_UCS_4*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R>>8,c.G>>8,c.B>>8,c.W>>8); } break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_UCS_4: { Rgbw64Color c = (static_cast<B_32_I0_UCS_4*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R>>8,c.G>>8,c.B>>8,c.W>>8); } break;
|
||||
@ -1093,7 +1245,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_UCS_4: { Rgbw64Color c = (static_cast<B_32_I1_UCS_4*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R>>8,c.G>>8,c.B>>8,c.W>>8); } break;
|
||||
#endif
|
||||
// case I_32_BB_UCS_4: col = (static_cast<B_32_BB_UCS_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_RN_APA106_3: col = (static_cast<B_32_RN_APA106_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_APA106_3: col = (static_cast<B_32_I0_APA106_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
@ -1101,7 +1252,20 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_APA106_3: col = (static_cast<B_32_I1_APA106_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
#endif
|
||||
// case I_32_BB_APA106_3: col = (static_cast<B_32_BB_APA106_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_RN_FW6_5: { RgbwwColor c = (static_cast<B_32_RN_FW6_5*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_FW6_5: { RgbwwColor c = (static_cast<B_32_I0_FW6_5*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_FW6_5: { RgbwwColor c = (static_cast<B_32_I1_FW6_5*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W
|
||||
#endif
|
||||
case I_32_RN_2805_5: { RgbwwColor c = (static_cast<B_32_RN_2805_5*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_2805_5: { RgbwwColor c = (static_cast<B_32_I0_2805_5*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_2805_5: { RgbwwColor c = (static_cast<B_32_I1_2805_5*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W
|
||||
#endif
|
||||
#endif
|
||||
case I_HS_DOT_3: col = (static_cast<B_HS_DOT_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_SS_DOT_3: col = (static_cast<B_SS_DOT_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
@ -1171,6 +1335,14 @@ class PolyBus {
|
||||
case I_8266_U1_APA106_3: delete (static_cast<B_8266_U1_APA106_3*>(busPtr)); break;
|
||||
case I_8266_DM_APA106_3: delete (static_cast<B_8266_DM_APA106_3*>(busPtr)); break;
|
||||
case I_8266_BB_APA106_3: delete (static_cast<B_8266_BB_APA106_3*>(busPtr)); break;
|
||||
case I_8266_U0_FW6_5: delete (static_cast<B_8266_U0_FW6_5*>(busPtr)); break;
|
||||
case I_8266_U1_FW6_5: delete (static_cast<B_8266_U1_FW6_5*>(busPtr)); break;
|
||||
case I_8266_DM_FW6_5: delete (static_cast<B_8266_DM_FW6_5*>(busPtr)); break;
|
||||
case I_8266_BB_FW6_5: delete (static_cast<B_8266_BB_FW6_5*>(busPtr)); break;
|
||||
case I_8266_U0_2805_5: delete (static_cast<B_8266_U0_2805_5*>(busPtr)); break;
|
||||
case I_8266_U1_2805_5: delete (static_cast<B_8266_U1_2805_5*>(busPtr)); break;
|
||||
case I_8266_DM_2805_5: delete (static_cast<B_8266_DM_2805_5*>(busPtr)); break;
|
||||
case I_8266_BB_2805_5: delete (static_cast<B_8266_BB_2805_5*>(busPtr)); break;
|
||||
#endif
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
case I_32_RN_NEO_3: delete (static_cast<B_32_RN_NEO_3*>(busPtr)); break;
|
||||
@ -1180,7 +1352,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_NEO_3: delete (static_cast<B_32_I1_NEO_3*>(busPtr)); break;
|
||||
#endif
|
||||
// case I_32_BB_NEO_3: delete (static_cast<B_32_BB_NEO_3*>(busPtr)); break;
|
||||
case I_32_RN_NEO_4: delete (static_cast<B_32_RN_NEO_4*>(busPtr)); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_NEO_4: delete (static_cast<B_32_I0_NEO_4*>(busPtr)); break;
|
||||
@ -1188,7 +1359,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_NEO_4: delete (static_cast<B_32_I1_NEO_4*>(busPtr)); break;
|
||||
#endif
|
||||
// case I_32_BB_NEO_4: delete (static_cast<B_32_BB_NEO_4*>(busPtr)); break;
|
||||
case I_32_RN_400_3: delete (static_cast<B_32_RN_400_3*>(busPtr)); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_400_3: delete (static_cast<B_32_I0_400_3*>(busPtr)); break;
|
||||
@ -1196,7 +1366,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_400_3: delete (static_cast<B_32_I1_400_3*>(busPtr)); break;
|
||||
#endif
|
||||
// case I_32_BB_400_3: delete (static_cast<B_32_BB_400_3*>(busPtr)); break;
|
||||
case I_32_RN_TM1_4: delete (static_cast<B_32_RN_TM1_4*>(busPtr)); break;
|
||||
case I_32_RN_TM2_3: delete (static_cast<B_32_RN_TM2_3*>(busPtr)); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
@ -1214,7 +1383,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_UCS_3: delete (static_cast<B_32_I1_UCS_3*>(busPtr)); break;
|
||||
#endif
|
||||
// case I_32_BB_UCS_3: delete (static_cast<B_32_BB_UCS_3*>(busPtr)); break;
|
||||
case I_32_RN_UCS_4: delete (static_cast<B_32_RN_UCS_4*>(busPtr)); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_UCS_4: delete (static_cast<B_32_I0_UCS_4*>(busPtr)); break;
|
||||
@ -1222,7 +1390,6 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_UCS_4: delete (static_cast<B_32_I1_UCS_4*>(busPtr)); break;
|
||||
#endif
|
||||
// case I_32_BB_UCS_4: delete (static_cast<B_32_BB_UCS_4*>(busPtr)); break;
|
||||
case I_32_RN_APA106_3: delete (static_cast<B_32_RN_APA106_3*>(busPtr)); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_APA106_3: delete (static_cast<B_32_I0_APA106_3*>(busPtr)); break;
|
||||
@ -1230,7 +1397,20 @@ class PolyBus {
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_APA106_3: delete (static_cast<B_32_I1_APA106_3*>(busPtr)); break;
|
||||
#endif
|
||||
// case I_32_BB_APA106_3: delete (static_cast<B_32_BB_APA106_3*>(busPtr)); break;
|
||||
case I_32_RN_FW6_5: delete (static_cast<B_32_RN_FW6_5*>(busPtr)); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_FW6_5: delete (static_cast<B_32_I0_FW6_5*>(busPtr)); break;
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_FW6_5: delete (static_cast<B_32_I1_FW6_5*>(busPtr)); break;
|
||||
#endif
|
||||
case I_32_RN_2805_5: delete (static_cast<B_32_RN_2805_5*>(busPtr)); break;
|
||||
#ifndef WLED_NO_I2S0_PIXELBUS
|
||||
case I_32_I0_2805_5: delete (static_cast<B_32_I0_2805_5*>(busPtr)); break;
|
||||
#endif
|
||||
#ifndef WLED_NO_I2S1_PIXELBUS
|
||||
case I_32_I1_2805_5: delete (static_cast<B_32_I1_2805_5*>(busPtr)); break;
|
||||
#endif
|
||||
#endif
|
||||
case I_HS_DOT_3: delete (static_cast<B_HS_DOT_3*>(busPtr)); break;
|
||||
case I_SS_DOT_3: delete (static_cast<B_SS_DOT_3*>(busPtr)); break;
|
||||
@ -1292,13 +1472,17 @@ class PolyBus {
|
||||
return I_8266_U0_UCS_4 + offset;
|
||||
case TYPE_APA106:
|
||||
return I_8266_U0_APA106_3 + offset;
|
||||
case TYPE_FW1906:
|
||||
return I_8266_U0_FW6_5 + offset;
|
||||
case TYPE_WS2805:
|
||||
return I_8266_U0_2805_5 + offset;
|
||||
}
|
||||
#else //ESP32
|
||||
uint8_t offset = 0; //0 = RMT (num 0-7) 8 = I2S0 9 = I2S1
|
||||
uint8_t offset = 0; // 0 = RMT (num 1-8), 1 = I2S0 (used by Audioreactive), 2 = I2S1
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
// ESP32-S2 only has 4 RMT channels
|
||||
if (num > 4) return I_NONE;
|
||||
if (num > 3) offset = 1; // only one I2S
|
||||
if (num > 3) offset = 1; // only one I2S (use last to allow Audioreactive)
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
// On ESP32-C3 only the first 2 RMT channels are usable for transmitting
|
||||
if (num > 1) return I_NONE;
|
||||
@ -1310,7 +1494,8 @@ class PolyBus {
|
||||
#else
|
||||
// standard ESP32 has 8 RMT and 2 I2S channels
|
||||
if (num > 9) return I_NONE;
|
||||
if (num > 7) offset = num -7;
|
||||
if (num > 8) offset = 1;
|
||||
if (num == 0) offset = 2; // prefer I2S1 for 1st bus (less flickering but more RAM needed)
|
||||
#endif
|
||||
switch (busType) {
|
||||
case TYPE_WS2812_1CH_X3:
|
||||
@ -1332,11 +1517,14 @@ class PolyBus {
|
||||
return I_32_RN_UCS_4 + offset;
|
||||
case TYPE_APA106:
|
||||
return I_32_RN_APA106_3 + offset;
|
||||
case TYPE_FW1906:
|
||||
return I_32_RN_FW6_5 + offset;
|
||||
case TYPE_WS2805:
|
||||
return I_32_RN_2805_5 + offset;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return I_NONE;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
@ -21,7 +21,6 @@ void shortPressAction(uint8_t b)
|
||||
case 1: ++effectCurrent %= strip.getModeCount(); stateChanged = true; colorUpdated(CALL_MODE_BUTTON); break;
|
||||
}
|
||||
} else {
|
||||
unloadPlaylist(); // applying a preset unloads the playlist
|
||||
applyPreset(macroButton[b], CALL_MODE_BUTTON_PRESET);
|
||||
}
|
||||
|
||||
@ -43,7 +42,6 @@ void longPressAction(uint8_t b)
|
||||
case 1: bri += 8; stateUpdated(CALL_MODE_BUTTON); buttonPressedTime[b] = millis(); break; // repeatable action
|
||||
}
|
||||
} else {
|
||||
unloadPlaylist(); // applying a preset unloads the playlist
|
||||
applyPreset(macroLongPress[b], CALL_MODE_BUTTON_PRESET);
|
||||
}
|
||||
|
||||
@ -65,7 +63,6 @@ void doublePressAction(uint8_t b)
|
||||
case 1: ++effectPalette %= strip.getPaletteCount(); colorUpdated(CALL_MODE_BUTTON); break;
|
||||
}
|
||||
} else {
|
||||
unloadPlaylist(); // applying a preset unloads the playlist
|
||||
applyPreset(macroDoublePress[b], CALL_MODE_BUTTON_PRESET);
|
||||
}
|
||||
|
||||
|
@ -110,6 +110,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
Bus::setGlobalAWMode(hw_led[F("rgbwm")] | AW_GLOBAL_DISABLED);
|
||||
CJSON(correctWB, hw_led["cct"]);
|
||||
CJSON(cctFromRgb, hw_led[F("cr")]);
|
||||
CJSON(cctICused, hw_led[F("ic")]);
|
||||
CJSON(strip.cctBlending, hw_led[F("cb")]);
|
||||
Bus::setCCTBlend(strip.cctBlending);
|
||||
strip.setTargetFps(hw_led["fps"]); //NOP if 0, default 42 FPS
|
||||
@ -185,7 +186,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
uint8_t maPerLed = elm[F("ledma")] | 55;
|
||||
uint16_t maMax = elm[F("maxpwr")] | (ablMilliampsMax * length) / total; // rough (incorrect?) per strip ABL calculation when no config exists
|
||||
// To disable brightness limiter we either set output max current to 0 or single LED current to 0 (we choose output max current)
|
||||
if ((ledType > TYPE_TM1814 && ledType < TYPE_WS2801) || ledType >= TYPE_NET_DDP_RGB) { // analog and virtual
|
||||
if (IS_PWM(ledType) || IS_ONOFF(ledType) || IS_VIRTUAL(ledType)) { // analog and virtual
|
||||
maPerLed = 0;
|
||||
maMax = 0;
|
||||
}
|
||||
@ -632,12 +633,12 @@ static const char s_cfg_json[] PROGMEM = "/cfg.json";
|
||||
|
||||
void deserializeConfigFromFS() {
|
||||
bool success = deserializeConfigSec();
|
||||
#ifdef WLED_ADD_EEPROM_SUPPORT
|
||||
if (!success) { //if file does not exist, try reading from EEPROM
|
||||
#ifdef WLED_ADD_EEPROM_SUPPORT
|
||||
deEEPSettings();
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!requestJSONBufferLock(1)) return;
|
||||
|
||||
@ -767,6 +768,7 @@ void serializeConfig() {
|
||||
hw_led[F("ledma")] = 0; // no longer used
|
||||
hw_led["cct"] = correctWB;
|
||||
hw_led[F("cr")] = cctFromRgb;
|
||||
hw_led[F("ic")] = cctICused;
|
||||
hw_led[F("cb")] = strip.cctBlending;
|
||||
hw_led["fps"] = strip.getTargetFps();
|
||||
hw_led[F("rgbwm")] = Bus::getGlobalAWMode(); // global auto white mode override
|
||||
|
@ -53,24 +53,16 @@
|
||||
#define WLED_MAX_BUSSES 3 // will allow 2 digital & 1 analog (or the other way around)
|
||||
#define WLED_MIN_VIRTUAL_BUSSES 3
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2) // 4 RMT, 8 LEDC, only has 1 I2S bus, supported in NPB
|
||||
#if defined(USERMOD_AUDIOREACTIVE) // requested by @softhack007 https://github.com/blazoncek/WLED/issues/33
|
||||
#define WLED_MAX_BUSSES 6 // will allow 4 digital & 2 analog
|
||||
#define WLED_MIN_VIRTUAL_BUSSES 4
|
||||
#else
|
||||
#define WLED_MAX_BUSSES 7 // will allow 5 digital & 2 analog
|
||||
#define WLED_MIN_VIRTUAL_BUSSES 3
|
||||
#endif
|
||||
// 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
|
||||
#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
|
||||
#define WLED_MIN_VIRTUAL_BUSSES 4
|
||||
#else
|
||||
#if defined(USERMOD_AUDIOREACTIVE) // requested by @softhack007 https://github.com/blazoncek/WLED/issues/33
|
||||
#define WLED_MAX_BUSSES 8
|
||||
#define WLED_MIN_VIRTUAL_BUSSES 2
|
||||
#else
|
||||
#define WLED_MAX_BUSSES 10
|
||||
#define WLED_MIN_VIRTUAL_BUSSES 0
|
||||
#endif
|
||||
// the 10th digital bus (I2S0) will prevent Audioreactive usermod from functioning (it is last used though)
|
||||
#define WLED_MAX_BUSSES 10
|
||||
#define WLED_MIN_VIRTUAL_BUSSES 0
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
@ -180,7 +172,8 @@
|
||||
#define USERMOD_ID_STAIRWAY_WIPE 44 //Usermod "stairway-wipe-usermod-v2.h"
|
||||
#define USERMOD_ID_ANIMARTRIX 45 //Usermod "usermod_v2_animartrix.h"
|
||||
#define USERMOD_ID_HTTP_PULL_LIGHT_CONTROL 46 //usermod "usermod_v2_HttpPullLightControl.h"
|
||||
#define USERMOD_ID_MAX17048 47 //Usermod "usermod_max17048.h"
|
||||
#define USERMOD_ID_TETRISAI 47 //Usermod "usermod_v2_tetris.h"
|
||||
#define USERMOD_ID_MAX17048 48 //Usermod "usermod_max17048.h"
|
||||
|
||||
//Access point behavior
|
||||
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot
|
||||
@ -270,9 +263,11 @@
|
||||
#define TYPE_TM1829 25
|
||||
#define TYPE_UCS8903 26
|
||||
#define TYPE_APA106 27
|
||||
#define TYPE_FW1906 28 //RGB + CW + WW + unused channel (6 channels per IC)
|
||||
#define TYPE_UCS8904 29 //first RGBW digital type (hardcoded in busmanager.cpp, memUsage())
|
||||
#define TYPE_SK6812_RGBW 30
|
||||
#define TYPE_TM1814 31
|
||||
#define TYPE_WS2805 32 //RGB + WW + CW
|
||||
//"Analog" types (40-47)
|
||||
#define TYPE_ONOFF 40 //binary output (relays etc.; NOT PWM)
|
||||
#define TYPE_ANALOG_1CH 41 //single channel PWM. Uses value of brightest RGBW channel
|
||||
@ -297,6 +292,7 @@
|
||||
#define IS_DIGITAL(t) (((t) > 15 && (t) < 40) || ((t) > 47 && (t) < 64)) //digital are 16-39 and 48-63
|
||||
#define IS_2PIN(t) ((t) > 47 && (t) < 64)
|
||||
#define IS_16BIT(t) ((t) == TYPE_UCS8903 || (t) == TYPE_UCS8904)
|
||||
#define IS_ONOFF(t) ((t) == 40)
|
||||
#define IS_PWM(t) ((t) > 40 && (t) < 46) //does not include on/Off type
|
||||
#define NUM_PWM_PINS(t) ((t) - 40) //for analog PWM 41-45 only
|
||||
#define IS_VIRTUAL(t) ((t) >= 80 && (t) < 96) //this was a poor choice a better would be 96-111
|
||||
@ -374,6 +370,7 @@
|
||||
|
||||
//Playlist option byte
|
||||
#define PL_OPTION_SHUFFLE 0x01
|
||||
#define PL_OPTION_RESTORE 0x02
|
||||
|
||||
// Segment capability byte
|
||||
#define SEG_CAPABILITY_RGB 0x01
|
||||
@ -511,11 +508,11 @@
|
||||
|
||||
//this is merely a default now and can be changed at runtime
|
||||
#ifndef LEDPIN
|
||||
#if defined(ESP8266) || (defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(ARDUINO_ESP32_PICO)
|
||||
#define LEDPIN 2 // GPIO2 (D4) on Wemos D1 mini compatible boards, and on boards where GPIO16 is not available
|
||||
#else
|
||||
#define LEDPIN 16 // aligns with GPIO2 (D4) on Wemos D1 mini32 compatible boards
|
||||
#endif
|
||||
//#if defined(ESP8266) || (defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM)) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(ARDUINO_ESP32_PICO)
|
||||
#define LEDPIN 2 // GPIO2 (D4) on Wemos D1 mini compatible boards, safe to use on any board
|
||||
//#else
|
||||
// #define LEDPIN 16 // aligns with GPIO2 (D4) on Wemos D1 mini32 compatible boards
|
||||
//#endif
|
||||
#endif
|
||||
|
||||
#ifdef WLED_ENABLE_DMX
|
||||
|
@ -1290,6 +1290,7 @@ TD .checkmark, TD .radiomark {
|
||||
margin: 0 auto 12px;
|
||||
min-height: 40px;
|
||||
border: 1px solid var(--c-2);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Simplify segments */
|
||||
|
@ -309,7 +309,7 @@
|
||||
<button class="btn infobtn" 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>
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<div id="nodes" class="modal">
|
||||
|
@ -618,7 +618,7 @@ function populatePresets(fromls)
|
||||
|
||||
cn += `<div class="pres lstI" id="p${i}o">`;
|
||||
if (cfg.comp.pid) cn += `<div class="pid">${i}</div>`;
|
||||
cn += `<div class="pname lstIname" onclick="setPreset(${i})">${isPlaylist(i)?"<i class='icons btn-icon'></i>":""}${pName(i)}
|
||||
cn += `<div class="pname lstIname" onclick="setPreset(${i})">${i==lastinfo.leds.bootps?"<i class='icons btn-icon'></i>":""}${isPlaylist(i)?"<i class='icons btn-icon'></i>":""}${pName(i)}
|
||||
<i class="icons edit-icon flr" id="p${i}nedit" onclick="tglSegn(${i+100})"></i></div>
|
||||
<i class="icons e-icon flr" id="sege${i+100}" onclick="expand(${i+100})"></i>
|
||||
<div class="presin lstIcontent" id="seg${i+100}"></div>
|
||||
@ -1959,6 +1959,7 @@ function plR(p)
|
||||
function makeP(i,pl)
|
||||
{
|
||||
var content = "";
|
||||
const bps = lastinfo.leds.bootps;
|
||||
if (pl) {
|
||||
if (i===0) plJson[0] = {
|
||||
ps: [1],
|
||||
@ -1983,7 +1984,7 @@ function makeP(i,pl)
|
||||
<div class="sel">End preset:<br>
|
||||
<div class="sel-p"><select class="sel-ple" id="pl${i}selEnd" onchange="plR(${i})" data-val=${plJson[i].end?plJson[i].end:0}>
|
||||
<option value="0">None</option>
|
||||
<option value="255">Restore preset</option>
|
||||
<option value="255" ${plJson[i].end && plJson[i].end==255?"selected":""}>Restore preset</option>
|
||||
${makePlSel(plJson[i].end?plJson[i].end:0, true)}
|
||||
</select></div></div>
|
||||
</div>
|
||||
@ -2024,6 +2025,11 @@ ${makePlSel(plJson[i].end?plJson[i].end:0, true)}
|
||||
</div>
|
||||
<div class="po2" id="p${i}o2">API command<br><textarea class="apitxt" id="p${i}api"></textarea></div>
|
||||
<div class="po1" id="p${i}o1">${content}</div>
|
||||
<label class="check revchkl">
|
||||
<span class="lstIname">Apply at boot</span>
|
||||
<input type="checkbox" id="p${i}bps" ${i==bps?"checked":""}>
|
||||
<span class="checkmark"></span>
|
||||
</label>
|
||||
<div class="c m6">Save to ID <input id="p${i}id" type="number" oninput="checkUsed(${i})" max=250 min=1 value=${(i>0)?i:getLowestUnusedP()}></div>
|
||||
<div class="c">
|
||||
<button class="btn btn-p" onclick="saveP(${i},${pl})"><i class="icons btn-icon"></i>Save</button>
|
||||
@ -2445,8 +2451,9 @@ function saveP(i,pl)
|
||||
if (gId(`p${i}lmp`) && gId(`p${i}lmp`).value!=="") obj.ledmap = parseInt(gId(`p${i}lmp`).value);
|
||||
}
|
||||
}
|
||||
|
||||
obj.psave = pI; obj.n = pN;
|
||||
if (gId(`p${i}bps`).checked) obj.bootps = pI;
|
||||
obj.psave = pI;
|
||||
obj.n = pN;
|
||||
var pQN = gId(`p${i}ql`).value;
|
||||
if (pQN.length > 0) obj.ql = pQN;
|
||||
|
||||
|
@ -23,6 +23,8 @@
|
||||
function isD2P(t) { return t > 47 && t < 64; } // is digital 2 pin type
|
||||
function is16b(t) { return t == 26 || t == 29 } // is digital 16 bit type
|
||||
function isVir(t) { return t >= 80 && t < 96; } // is virtual type
|
||||
function hasW(t) { return (t >= 18 && t <= 21) || (t >= 28 && t <= 32) || (t >= 44 && t <= 45) || (t >= 88 && t <= 89); }
|
||||
function hasCCT(t) { return t == 20 || t == 21 || t == 42 || t == 45 || t == 28 || t == 32; }
|
||||
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
||||
function loadJS(FILE_URL, async = true) {
|
||||
let scE = d.createElement("script");
|
||||
@ -188,6 +190,7 @@
|
||||
if (isDig(t)) {
|
||||
if (is16b(t)) len *= 2; // 16 bit LEDs
|
||||
if (t > 28 && t < 40) ch = 4; //RGBW
|
||||
if (t == 28) ch = 5; //GRBCW
|
||||
if (maxM < 10000 && d.getElementsByName("L0"+n)[0].value == 3) { //8266 DMA uses 5x the mem
|
||||
mul = 5;
|
||||
}
|
||||
@ -202,7 +205,7 @@
|
||||
|
||||
function UI(change=false)
|
||||
{
|
||||
let isRGBW = false, gRGBW = false, memu = 0;
|
||||
let gRGBW = false, memu = 0;
|
||||
let busMA = 0;
|
||||
let sLC = 0, sPC = 0, sDI = 0, maxLC = 0;
|
||||
const ablEN = d.Sf.ABL.checked;
|
||||
@ -242,15 +245,15 @@
|
||||
d.Sf["MA"+n].min = (isVir(t) || isAna(t)) ? 0 : 250;
|
||||
}
|
||||
gId("rf"+n).onclick = (t == 31) ? (()=>{return false}) : (()=>{}); // prevent change for TM1814
|
||||
gRGBW |= isRGBW = ((t > 17 && t < 22) || (t > 28 && t < 32) || (t > 40 && t < 46 && t != 43) || t == 88); // RGBW checkbox, TYPE_xxxx values from const.h
|
||||
gRGBW |= hasW(t); // RGBW checkbox, TYPE_xxxx values from const.h
|
||||
gId("co"+n).style.display = (isVir(t) || isAna(t)) ? "none":"inline"; // hide color order for PWM
|
||||
gId("dig"+n+"w").style.display = (isDig(t) && isRGBW) ? "inline":"none"; // show swap channels dropdown
|
||||
if (!(isDig(t) && isRGBW)) d.Sf["WO"+n].value = 0; // reset swapping
|
||||
gId("dig"+n+"w").style.display = (isDig(t) && hasW(t)) ? "inline":"none"; // show swap channels dropdown
|
||||
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
|
||||
gId("dig"+n+"s").style.display = (isVir(t) || isAna(t)) ? "none":"inline"; // hide skip 1st for virtual & analog
|
||||
gId("dig"+n+"f").style.display = (isDig(t)) ? "inline":"none"; // hide refresh
|
||||
gId("dig"+n+"a").style.display = (isRGBW) ? "inline":"none"; // auto calculate white
|
||||
gId("dig"+n+"a").style.display = (hasW(t)) ? "inline":"none"; // auto calculate white
|
||||
gId("dig"+n+"l").style.display = (isD2P(t) || isPWM(t)) ? "inline":"none"; // bus clock speed / PWM speed (relative) (not On/Off)
|
||||
gId("rev"+n).innerHTML = isAna(t) ? "Inverted output":"Reversed (rotated 180°)"; // change reverse text for analog
|
||||
//gId("psd"+n).innerHTML = isAna(t) ? "Index:":"Start:"; // change analog start description
|
||||
@ -383,7 +386,9 @@ ${i+1}:
|
||||
<option value="25">TM1829</option>\
|
||||
<option value="26">UCS8903</option>\
|
||||
<option value="27">APA106/PL9823</option>\
|
||||
<option value="28">FW1906 GRBCW</option>\
|
||||
<option value="29">UCS8904 RGBW</option>\
|
||||
<option value="32">WS2805 RGBCW</option>\
|
||||
<option value="50">WS2801</option>\
|
||||
<option value="51">APA102</option>\
|
||||
<option value="52">LPD8806</option>\
|
||||
@ -861,6 +866,7 @@ Swap: <select id="xw${i}" name="XW${i}">
|
||||
</select>
|
||||
<br>
|
||||
Calculate CCT from RGB: <input type="checkbox" name="CR"><br>
|
||||
CCT IC used (Athom 15W): <input type="checkbox" name="IC"><br>
|
||||
CCT additive blending: <input type="number" class="s" min="0" max="100" name="CB" required> %
|
||||
</div>
|
||||
<h3>Advanced</h3>
|
||||
|
@ -133,11 +133,11 @@
|
||||
<div>Restore configuration<br><input type="file" name="data2" accept=".json"> <button type="button" onclick="uploadFile(d.Sf.data2,'/cfg.json');">Upload</button><br></div>
|
||||
<hr>
|
||||
<h3>About</h3>
|
||||
<a href="https://github.com/Aircoookie/WLED/" target="_blank">WLED</a> version ##VERSION##<!-- Autoreplaced from package.json --><br><br>
|
||||
<a href="https://github.com/Aircoookie/WLED/" target="_blank">WLED</a> version ##VERSION##<!-- Autoreplaced from package.json --><br><br>
|
||||
<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-2023 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>
|
||||
(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>
|
||||
<div id="toast"></div>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save</button>
|
||||
|
@ -84,7 +84,7 @@
|
||||
option.textContent = "Other network...";
|
||||
select.appendChild(option);
|
||||
|
||||
if (input.value === "" || found) input.replaceWith(select);
|
||||
if (input.value === "" || input.value === "Your_Network" || found) input.replaceWith(select);
|
||||
else select.remove();
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
//DDP protocol support, called by handleE131Packet
|
||||
//handles RGB data only
|
||||
void handleDDPPacket(e131_packet_t* p) {
|
||||
static bool ddpSeenPush = false; // have we seen a push yet?
|
||||
int lastPushSeq = e131LastSequenceNumber[0];
|
||||
|
||||
//reject late packets belonging to previous frame (assuming 4 packets max. before push)
|
||||
@ -34,6 +35,7 @@ void handleDDPPacket(e131_packet_t* p) {
|
||||
uint16_t c = 0;
|
||||
if (p->flags & DDP_TIMECODE_FLAG) c = 4; //packet has timecode flag, we do not support it, but data starts 4 bytes later
|
||||
|
||||
if (realtimeMode != REALTIME_MODE_DDP) ddpSeenPush = false; // just starting, no push yet
|
||||
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_DDP);
|
||||
|
||||
if (!realtimeOverride || (realtimeMode && useMainSegmentOnly)) {
|
||||
@ -44,7 +46,8 @@ void handleDDPPacket(e131_packet_t* p) {
|
||||
}
|
||||
|
||||
bool push = p->flags & DDP_PUSH_FLAG;
|
||||
if (push) {
|
||||
ddpSeenPush |= push;
|
||||
if (!ddpSeenPush || push) { // if we've never seen a push, or this is one, render display
|
||||
e131NewData = true;
|
||||
byte sn = p->sequenceNum & 0xF;
|
||||
if (sn) e131LastSequenceNumber[0] = sn;
|
||||
@ -184,7 +187,6 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
|
||||
// only apply preset if not in playlist, or playlist changed
|
||||
(currentPlaylist < 0 || dmxValPreset != currentPlaylist)) {
|
||||
presetCycCurr = dmxValPreset;
|
||||
unloadPlaylist(); // applying a preset unloads the playlist
|
||||
applyPreset(dmxValPreset, CALL_MODE_NOTIFICATION);
|
||||
}
|
||||
|
||||
|
@ -233,6 +233,7 @@ const char *getPresetsFileName(bool persistent = true);
|
||||
void initPresetsFile();
|
||||
void handlePresets();
|
||||
bool applyPreset(byte index, byte callMode = CALL_MODE_DIRECT_CHANGE);
|
||||
bool applyPresetFromPlaylist(byte index);
|
||||
void applyPresetWithFallback(uint8_t presetID, uint8_t callMode, uint8_t effectID = 0, uint8_t paletteID = 0);
|
||||
inline bool applyTemporaryPreset() {return applyPreset(255);};
|
||||
void savePreset(byte index, const char* pname = nullptr, JsonObject saveobj = JsonObject());
|
||||
@ -434,7 +435,6 @@ void handleSerial();
|
||||
void updateBaudRate(uint32_t rate);
|
||||
|
||||
//wled_server.cpp
|
||||
String getFileContentType(String &filename);
|
||||
void createEditHandler(bool enable);
|
||||
void initServer();
|
||||
void serveMessage(AsyncWebServerRequest* request, uint16_t code, const String& headl, const String& subl="", byte optionT=255);
|
||||
|
@ -375,20 +375,16 @@ void updateFSInfo() {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(BOARD_HAS_PSRAM) && defined(WLED_USE_PSRAM)
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
// caching presets in PSRAM may prevent occasional flashes seen when HomeAssitant polls WLED
|
||||
// original idea by @akaricchi (https://github.com/Akaricchi)
|
||||
// returns a pointer to the PSRAM buffer updates size parameter
|
||||
// returns a pointer to the PSRAM buffer, updates size parameter
|
||||
static const uint8_t *getPresetCache(size_t &size) {
|
||||
static unsigned long presetsCachedTime;
|
||||
static uint8_t *presetsCached;
|
||||
static size_t presetsCachedSize;
|
||||
|
||||
if (!psramFound()) {
|
||||
size = 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (presetsModifiedTime != presetsCachedTime) {
|
||||
if (presetsCached) {
|
||||
free(presetsCached);
|
||||
@ -420,26 +416,19 @@ bool handleFileRead(AsyncWebServerRequest* request, String path){
|
||||
DEBUG_PRINT(F("WS FileRead: ")); DEBUG_PRINTLN(path);
|
||||
if(path.endsWith("/")) path += "index.htm";
|
||||
if(path.indexOf(F("sec")) > -1) return false;
|
||||
String contentType = getFileContentType(path);
|
||||
if(request->hasArg(F("download"))) contentType = F("application/octet-stream");
|
||||
/*String pathWithGz = path + ".gz";
|
||||
if(WLED_FS.exists(pathWithGz)){
|
||||
request->send(WLED_FS, pathWithGz, contentType);
|
||||
return true;
|
||||
}*/
|
||||
#if defined(BOARD_HAS_PSRAM) && defined(WLED_USE_PSRAM)
|
||||
if (path.endsWith(FPSTR(getPresetsFileName()))) {
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
if (psramSafe && psramFound() && path.endsWith(FPSTR(getPresetsFileName()))) {
|
||||
size_t psize;
|
||||
const uint8_t *presets = getPresetCache(psize);
|
||||
if (presets) {
|
||||
AsyncWebServerResponse *response = request->beginResponse_P(200, contentType, presets, psize);
|
||||
AsyncWebServerResponse *response = request->beginResponse_P(200, FPSTR(CONTENT_TYPE_JSON), presets, psize);
|
||||
request->send(response);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if(WLED_FS.exists(path)) {
|
||||
request->send(WLED_FS, path, contentType);
|
||||
if(WLED_FS.exists(path) || WLED_FS.exists(path + ".gz")) {
|
||||
request->send(WLED_FS, path, String(), request->hasArg(F("download")));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -210,7 +210,7 @@ void sendImprovInfoResponse() {
|
||||
//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-b1/%i"), VERSION);
|
||||
sprintf_P(vString, PSTR("0.15.0-b2/%i"), VERSION);
|
||||
const char *str[4] = {"WLED", vString, bString, useMdnsName ? cmDNS : serverDescription};
|
||||
|
||||
sendImprovRPCResult(ImprovRPCType::Request_Info, 4, str);
|
||||
|
@ -142,28 +142,42 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
{
|
||||
if (seg.getLightCapabilities() & 3) {
|
||||
// segment has RGB or White
|
||||
for (size_t i = 0; i < 3; i++)
|
||||
{
|
||||
for (size_t i = 0; i < NUM_COLORS; i++) {
|
||||
// JSON "col" array can contain the following values for each of segment's colors (primary, background, custom):
|
||||
// "col":[int|string|object|array, int|string|object|array, int|string|object|array]
|
||||
// int = Kelvin temperature or 0 for black
|
||||
// string = hex representation of [WW]RRGGBB
|
||||
// object = individual channel control {"r":0,"g":127,"b":255,"w":255}, each being optional (valid to send {})
|
||||
// array = direct channel values [r,g,b,w] (w element being optional)
|
||||
int rgbw[] = {0,0,0,0};
|
||||
bool colValid = false;
|
||||
JsonArray colX = colarr[i];
|
||||
if (colX.isNull()) {
|
||||
byte brgbw[] = {0,0,0,0};
|
||||
const char* hexCol = colarr[i];
|
||||
if (hexCol == nullptr) { //Kelvin color temperature (or invalid), e.g 2400
|
||||
int kelvin = colarr[i] | -1;
|
||||
if (kelvin < 0) continue;
|
||||
if (kelvin == 0) seg.setColor(i, 0);
|
||||
if (kelvin > 0) colorKtoRGB(kelvin, brgbw);
|
||||
JsonObject oCol = colarr[i];
|
||||
if (!oCol.isNull()) {
|
||||
// we have a JSON object for color {"w":123,"r":123,...}; allows individual channel control
|
||||
rgbw[0] = oCol["r"] | R(seg.colors[i]);
|
||||
rgbw[1] = oCol["g"] | G(seg.colors[i]);
|
||||
rgbw[2] = oCol["b"] | B(seg.colors[i]);
|
||||
rgbw[3] = oCol["w"] | W(seg.colors[i]);
|
||||
colValid = true;
|
||||
} else { //HEX string, e.g. "FFAA00"
|
||||
colValid = colorFromHexString(brgbw, hexCol);
|
||||
} else {
|
||||
byte brgbw[] = {0,0,0,0};
|
||||
const char* hexCol = colarr[i];
|
||||
if (hexCol == nullptr) { //Kelvin color temperature (or invalid), e.g 2400
|
||||
int kelvin = colarr[i] | -1;
|
||||
if (kelvin < 0) continue;
|
||||
if (kelvin == 0) seg.setColor(i, 0);
|
||||
if (kelvin > 0) colorKtoRGB(kelvin, brgbw);
|
||||
colValid = true;
|
||||
} else { //HEX string, e.g. "FFAA00"
|
||||
colValid = colorFromHexString(brgbw, hexCol);
|
||||
}
|
||||
for (size_t c = 0; c < 4; c++) rgbw[c] = brgbw[c];
|
||||
}
|
||||
for (size_t c = 0; c < 4; c++) rgbw[c] = brgbw[c];
|
||||
} else { //Array of ints (RGB or RGBW color), e.g. [255,160,0]
|
||||
byte sz = colX.size();
|
||||
if (sz == 0) continue; //do nothing on empty array
|
||||
|
||||
copyArray(colX, rgbw, 4);
|
||||
colValid = true;
|
||||
}
|
||||
@ -226,14 +240,19 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
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)) seg.setPalette(pal);
|
||||
if (getVal(elem["pal"], &pal, 0, last)) seg.setPalette(pal);
|
||||
}
|
||||
|
||||
getVal(elem["c1"], &seg.custom1);
|
||||
getVal(elem["c2"], &seg.custom2);
|
||||
uint8_t cust3 = seg.custom3;
|
||||
getVal(elem["c3"], &cust3); // we can't pass reference to bitfield
|
||||
getVal(elem["c3"], &cust3, 0, 31); // we can't pass reference to bitfield
|
||||
seg.custom3 = constrain(cust3, 0, 31);
|
||||
|
||||
seg.check1 = getBoolVal(elem["o1"], seg.check1);
|
||||
@ -298,7 +317,7 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
return true;
|
||||
}
|
||||
|
||||
// deserializes WLED state (fileDoc points to doc object if called from web server)
|
||||
// deserializes WLED state
|
||||
// presetId is non-0 if called from handlePreset()
|
||||
bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
{
|
||||
@ -442,13 +461,11 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
currentPreset = root[F("pd")] | currentPreset;
|
||||
if (root["win"].isNull()) presetCycCurr = currentPreset; // otherwise it was set in handleSet() [set.cpp]
|
||||
presetToRestore = currentPreset; // stateUpdated() will clear the preset, so we need to restore it after
|
||||
//unloadPlaylist(); // applying a preset unloads the playlist, may be needed here too?
|
||||
} else if (!root["ps"].isNull()) {
|
||||
ps = presetCycCurr;
|
||||
if (root["win"].isNull() && getVal(root["ps"], &ps, 0, 0) && ps > 0 && ps < 251 && ps != currentPreset) {
|
||||
// b) preset ID only or preset that does not change state (use embedded cycling limits if they exist in getVal())
|
||||
presetCycCurr = ps;
|
||||
unloadPlaylist(); // applying a preset unloads the playlist
|
||||
applyPreset(ps, callMode); // async load from file system (only preset ID was specified)
|
||||
return stateResponse;
|
||||
}
|
||||
@ -628,6 +645,7 @@ void serializeInfo(JsonObject root)
|
||||
leds[F("maxseg")] = strip.getMaxSegments();
|
||||
//leds[F("actseg")] = strip.getActiveSegmentsNum();
|
||||
//leds[F("seglock")] = false; //might be used in the future to prevent modifications to segment config
|
||||
leds[F("bootps")] = bootPreset;
|
||||
|
||||
#ifndef WLED_DISABLE_2D
|
||||
if (strip.isMatrix) {
|
||||
@ -748,8 +766,8 @@ void serializeInfo(JsonObject root)
|
||||
#endif
|
||||
|
||||
root[F("freeheap")] = ESP.getFreeHeap();
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM)
|
||||
if (psramFound()) root[F("psram")] = ESP.getFreePsram();
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
if (psramSafe && psramFound()) root[F("psram")] = ESP.getFreePsram();
|
||||
#endif
|
||||
root[F("uptime")] = millis()/1000 + rolloverMillis*4294967;
|
||||
|
||||
@ -851,8 +869,8 @@ void serializePalettes(JsonObject root, int page)
|
||||
int itemPerPage = 8;
|
||||
#endif
|
||||
|
||||
int palettesCount = strip.getPaletteCount();
|
||||
int customPalettes = strip.customPalettes.size();
|
||||
int palettesCount = strip.getPaletteCount() - customPalettes;
|
||||
|
||||
int maxPage = (palettesCount + customPalettes -1) / itemPerPage;
|
||||
if (page > maxPage) page = maxPage;
|
||||
@ -1064,7 +1082,7 @@ void serveJson(AsyncWebServerRequest* request)
|
||||
}
|
||||
#endif
|
||||
else if (url.indexOf("pal") > 0) {
|
||||
request->send_P(200, "application/json", JSON_palette_names); // contentType defined in AsyncJson-v6.h
|
||||
request->send_P(200, FPSTR(CONTENT_TYPE_JSON), JSON_palette_names);
|
||||
return;
|
||||
}
|
||||
else if (url.indexOf(F("cfg")) > 0 && handleFileRead(request, F("/cfg.json"))) {
|
||||
@ -1151,10 +1169,10 @@ bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient)
|
||||
}
|
||||
#endif
|
||||
|
||||
char buffer[2048]; // shoud be enough for 256 LEDs [RRGGBB] + all other text (9+25)
|
||||
strcpy_P(buffer, PSTR("{\"leds\":["));
|
||||
obuf = buffer; // assign buffer for oappnd() functions
|
||||
olen = 9;
|
||||
DynamicBuffer buffer(9 + (9*(1+(used/n))) + 7 + 5 + 6 + 5 + 6 + 5 + 2);
|
||||
char* buf = buffer.data(); // assign buffer for oappnd() functions
|
||||
strncpy_P(buffer.data(), PSTR("{\"leds\":["), buffer.size());
|
||||
buf += 9; // sizeof(PSTR()) from last line
|
||||
|
||||
for (size_t i = 0; i < used; i += n)
|
||||
{
|
||||
@ -1169,29 +1187,27 @@ bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient)
|
||||
r = scale8(qadd8(w, r), strip.getBrightness()); //R, add white channel to RGB channels as a simple RGBW -> RGB map
|
||||
g = scale8(qadd8(w, g), strip.getBrightness()); //G
|
||||
b = scale8(qadd8(w, b), strip.getBrightness()); //B
|
||||
olen += sprintf_P(obuf + olen, PSTR("\"%06X\","), RGBW32(r,g,b,0));
|
||||
buf += sprintf_P(buf, PSTR("\"%06X\","), RGBW32(r,g,b,0));
|
||||
}
|
||||
olen -= 1;
|
||||
oappend((const char*)F("],\"n\":"));
|
||||
oappendi(n);
|
||||
buf--; // remove last comma
|
||||
buf += sprintf_P(buf, PSTR("],\"n\":%d"), n);
|
||||
#ifndef WLED_DISABLE_2D
|
||||
if (strip.isMatrix) {
|
||||
oappend((const char*)F(",\"w\":"));
|
||||
oappendi(Segment::maxWidth/n);
|
||||
oappend((const char*)F(",\"h\":"));
|
||||
oappendi(Segment::maxHeight/n);
|
||||
buf += sprintf_P(buf, PSTR(",\"w\":%d"), Segment::maxWidth/n);
|
||||
buf += sprintf_P(buf, PSTR(",\"h\":%d"), Segment::maxHeight/n);
|
||||
}
|
||||
#endif
|
||||
oappend("}");
|
||||
(*buf++) = '}';
|
||||
(*buf++) = 0;
|
||||
|
||||
if (request) {
|
||||
request->send(200, "application/json", buffer); // contentType defined in AsyncJson-v6.h
|
||||
request->send(200, FPSTR(CONTENT_TYPE_JSON), toString(std::move(buffer)));
|
||||
}
|
||||
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||
else {
|
||||
wsc->text(obuf, olen);
|
||||
wsc->text(toString(std::move(buffer)));
|
||||
}
|
||||
#endif
|
||||
obuf = nullptr;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
@ -172,7 +172,9 @@ void updateInterfaces(uint8_t callMode)
|
||||
espalexaDevice->setColor(col[0], col[1], col[2]);
|
||||
}
|
||||
#endif
|
||||
doPublishMqtt = true;
|
||||
#ifndef WLED_DISABLE_MQTT
|
||||
publishMqtt();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -180,9 +182,6 @@ void handleTransitions()
|
||||
{
|
||||
//handle still pending interface update
|
||||
updateInterfaces(interfaceUpdateCallMode);
|
||||
#ifndef WLED_DISABLE_MQTT
|
||||
if (doPublishMqtt) publishMqtt();
|
||||
#endif
|
||||
|
||||
if (transitionActive && strip.getTransition() > 0) {
|
||||
float tper = (millis() - transitionStartTime)/(float)strip.getTransition();
|
||||
|
395
wled00/mqtt.cpp
395
wled00/mqtt.cpp
@ -1,198 +1,197 @@
|
||||
#include "wled.h"
|
||||
|
||||
/*
|
||||
* MQTT communication protocol for home automation
|
||||
*/
|
||||
|
||||
#ifdef WLED_ENABLE_MQTT
|
||||
#define MQTT_KEEP_ALIVE_TIME 60 // contact the MQTT broker every 60 seconds
|
||||
|
||||
void parseMQTTBriPayload(char* payload)
|
||||
{
|
||||
if (strstr(payload, "ON") || strstr(payload, "on") || strstr(payload, "true")) {bri = briLast; stateUpdated(CALL_MODE_DIRECT_CHANGE);}
|
||||
else if (strstr(payload, "T" ) || strstr(payload, "t" )) {toggleOnOff(); stateUpdated(CALL_MODE_DIRECT_CHANGE);}
|
||||
else {
|
||||
uint8_t in = strtoul(payload, NULL, 10);
|
||||
if (in == 0 && bri > 0) briLast = bri;
|
||||
bri = in;
|
||||
stateUpdated(CALL_MODE_DIRECT_CHANGE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void onMqttConnect(bool sessionPresent)
|
||||
{
|
||||
//(re)subscribe to required topics
|
||||
char subuf[38];
|
||||
|
||||
if (mqttDeviceTopic[0] != 0) {
|
||||
strlcpy(subuf, mqttDeviceTopic, 33);
|
||||
mqtt->subscribe(subuf, 0);
|
||||
strcat_P(subuf, PSTR("/col"));
|
||||
mqtt->subscribe(subuf, 0);
|
||||
strlcpy(subuf, mqttDeviceTopic, 33);
|
||||
strcat_P(subuf, PSTR("/api"));
|
||||
mqtt->subscribe(subuf, 0);
|
||||
}
|
||||
|
||||
if (mqttGroupTopic[0] != 0) {
|
||||
strlcpy(subuf, mqttGroupTopic, 33);
|
||||
mqtt->subscribe(subuf, 0);
|
||||
strcat_P(subuf, PSTR("/col"));
|
||||
mqtt->subscribe(subuf, 0);
|
||||
strlcpy(subuf, mqttGroupTopic, 33);
|
||||
strcat_P(subuf, PSTR("/api"));
|
||||
mqtt->subscribe(subuf, 0);
|
||||
}
|
||||
|
||||
usermods.onMqttConnect(sessionPresent);
|
||||
|
||||
doPublishMqtt = true;
|
||||
DEBUG_PRINTLN(F("MQTT ready"));
|
||||
}
|
||||
|
||||
|
||||
void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
|
||||
static char *payloadStr;
|
||||
|
||||
DEBUG_PRINT(F("MQTT msg: "));
|
||||
DEBUG_PRINTLN(topic);
|
||||
|
||||
// paranoia check to avoid npe if no payload
|
||||
if (payload==nullptr) {
|
||||
DEBUG_PRINTLN(F("no payload -> leave"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (index == 0) { // start (1st partial packet or the only packet)
|
||||
if (payloadStr) delete[] payloadStr; // fail-safe: release buffer
|
||||
payloadStr = new char[total+1]; // allocate new buffer
|
||||
}
|
||||
if (payloadStr == nullptr) return; // buffer not allocated
|
||||
|
||||
// copy (partial) packet to buffer and 0-terminate it if it is last packet
|
||||
char* buff = payloadStr + index;
|
||||
memcpy(buff, payload, len);
|
||||
if (index + len >= total) { // at end
|
||||
payloadStr[total] = '\0'; // terminate c style string
|
||||
} else {
|
||||
DEBUG_PRINTLN(F("Partial packet received."));
|
||||
return; // process next packet
|
||||
}
|
||||
DEBUG_PRINTLN(payloadStr);
|
||||
|
||||
size_t topicPrefixLen = strlen(mqttDeviceTopic);
|
||||
if (strncmp(topic, mqttDeviceTopic, topicPrefixLen) == 0) {
|
||||
topic += topicPrefixLen;
|
||||
} else {
|
||||
topicPrefixLen = strlen(mqttGroupTopic);
|
||||
if (strncmp(topic, mqttGroupTopic, topicPrefixLen) == 0) {
|
||||
topic += topicPrefixLen;
|
||||
} else {
|
||||
// Non-Wled Topic used here. Probably a usermod subscribed to this topic.
|
||||
usermods.onMqttMessage(topic, payloadStr);
|
||||
delete[] payloadStr;
|
||||
payloadStr = nullptr;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//Prefix is stripped from the topic at this point
|
||||
|
||||
if (strcmp_P(topic, PSTR("/col")) == 0) {
|
||||
colorFromDecOrHexString(col, payloadStr);
|
||||
colorUpdated(CALL_MODE_DIRECT_CHANGE);
|
||||
} else if (strcmp_P(topic, PSTR("/api")) == 0) {
|
||||
if (!requestJSONBufferLock(15)) {
|
||||
delete[] payloadStr;
|
||||
payloadStr = nullptr;
|
||||
return;
|
||||
}
|
||||
if (payloadStr[0] == '{') { //JSON API
|
||||
deserializeJson(*pDoc, payloadStr);
|
||||
deserializeState(pDoc->as<JsonObject>());
|
||||
} else { //HTTP API
|
||||
String apireq = "win"; apireq += '&'; // reduce flash string usage
|
||||
apireq += payloadStr;
|
||||
handleSet(nullptr, apireq);
|
||||
}
|
||||
releaseJSONBufferLock();
|
||||
} else if (strlen(topic) != 0) {
|
||||
// non standard topic, check with usermods
|
||||
usermods.onMqttMessage(topic, payloadStr);
|
||||
} else {
|
||||
// topmost topic (just wled/MAC)
|
||||
parseMQTTBriPayload(payloadStr);
|
||||
}
|
||||
delete[] payloadStr;
|
||||
payloadStr = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void publishMqtt()
|
||||
{
|
||||
doPublishMqtt = false;
|
||||
if (!WLED_MQTT_CONNECTED) return;
|
||||
DEBUG_PRINTLN(F("Publish MQTT"));
|
||||
|
||||
#ifndef USERMOD_SMARTNEST
|
||||
char s[10];
|
||||
char subuf[38];
|
||||
|
||||
sprintf_P(s, PSTR("%u"), bri);
|
||||
strlcpy(subuf, mqttDeviceTopic, 33);
|
||||
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]));
|
||||
strlcpy(subuf, mqttDeviceTopic, 33);
|
||||
strcat_P(subuf, PSTR("/c"));
|
||||
mqtt->publish(subuf, 0, retainMqttMsg, s); // optionally retain message (#2263)
|
||||
|
||||
strlcpy(subuf, mqttDeviceTopic, 33);
|
||||
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);
|
||||
strlcpy(subuf, mqttDeviceTopic, 33);
|
||||
strcat_P(subuf, PSTR("/v"));
|
||||
mqtt->publish(subuf, 0, retainMqttMsg, apires); // optionally retain message (#2263)
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//HA autodiscovery was removed in favor of the native integration in HA v0.102.0
|
||||
|
||||
bool initMqtt()
|
||||
{
|
||||
if (!mqttEnabled || mqttServer[0] == 0 || !WLED_CONNECTED) return false;
|
||||
|
||||
if (mqtt == nullptr) {
|
||||
mqtt = new AsyncMqttClient();
|
||||
mqtt->onMessage(onMqttMessage);
|
||||
mqtt->onConnect(onMqttConnect);
|
||||
}
|
||||
if (mqtt->connected()) return true;
|
||||
|
||||
DEBUG_PRINTLN(F("Reconnecting MQTT"));
|
||||
IPAddress mqttIP;
|
||||
if (mqttIP.fromString(mqttServer)) //see if server is IP or domain
|
||||
{
|
||||
mqtt->setServer(mqttIP, mqttPort);
|
||||
} else {
|
||||
mqtt->setServer(mqttServer, mqttPort);
|
||||
}
|
||||
mqtt->setClientId(mqttClientID);
|
||||
if (mqttUser[0] && mqttPass[0]) mqtt->setCredentials(mqttUser, mqttPass);
|
||||
|
||||
#ifndef USERMOD_SMARTNEST
|
||||
strlcpy(mqttStatusTopic, mqttDeviceTopic, 33);
|
||||
strcat_P(mqttStatusTopic, PSTR("/status"));
|
||||
mqtt->setWill(mqttStatusTopic, 0, true, "offline"); // LWT message
|
||||
#endif
|
||||
mqtt->setKeepAlive(MQTT_KEEP_ALIVE_TIME);
|
||||
mqtt->connect();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#include "wled.h"
|
||||
|
||||
/*
|
||||
* MQTT communication protocol for home automation
|
||||
*/
|
||||
|
||||
#ifdef WLED_ENABLE_MQTT
|
||||
#define MQTT_KEEP_ALIVE_TIME 60 // contact the MQTT broker every 60 seconds
|
||||
|
||||
void parseMQTTBriPayload(char* payload)
|
||||
{
|
||||
if (strstr(payload, "ON") || strstr(payload, "on") || strstr(payload, "true")) {bri = briLast; stateUpdated(CALL_MODE_DIRECT_CHANGE);}
|
||||
else if (strstr(payload, "T" ) || strstr(payload, "t" )) {toggleOnOff(); stateUpdated(CALL_MODE_DIRECT_CHANGE);}
|
||||
else {
|
||||
uint8_t in = strtoul(payload, NULL, 10);
|
||||
if (in == 0 && bri > 0) briLast = bri;
|
||||
bri = in;
|
||||
stateUpdated(CALL_MODE_DIRECT_CHANGE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void onMqttConnect(bool sessionPresent)
|
||||
{
|
||||
//(re)subscribe to required topics
|
||||
char subuf[38];
|
||||
|
||||
if (mqttDeviceTopic[0] != 0) {
|
||||
strlcpy(subuf, mqttDeviceTopic, 33);
|
||||
mqtt->subscribe(subuf, 0);
|
||||
strcat_P(subuf, PSTR("/col"));
|
||||
mqtt->subscribe(subuf, 0);
|
||||
strlcpy(subuf, mqttDeviceTopic, 33);
|
||||
strcat_P(subuf, PSTR("/api"));
|
||||
mqtt->subscribe(subuf, 0);
|
||||
}
|
||||
|
||||
if (mqttGroupTopic[0] != 0) {
|
||||
strlcpy(subuf, mqttGroupTopic, 33);
|
||||
mqtt->subscribe(subuf, 0);
|
||||
strcat_P(subuf, PSTR("/col"));
|
||||
mqtt->subscribe(subuf, 0);
|
||||
strlcpy(subuf, mqttGroupTopic, 33);
|
||||
strcat_P(subuf, PSTR("/api"));
|
||||
mqtt->subscribe(subuf, 0);
|
||||
}
|
||||
|
||||
usermods.onMqttConnect(sessionPresent);
|
||||
|
||||
DEBUG_PRINTLN(F("MQTT ready"));
|
||||
publishMqtt();
|
||||
}
|
||||
|
||||
|
||||
void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
|
||||
static char *payloadStr;
|
||||
|
||||
DEBUG_PRINT(F("MQTT msg: "));
|
||||
DEBUG_PRINTLN(topic);
|
||||
|
||||
// paranoia check to avoid npe if no payload
|
||||
if (payload==nullptr) {
|
||||
DEBUG_PRINTLN(F("no payload -> leave"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (index == 0) { // start (1st partial packet or the only packet)
|
||||
if (payloadStr) delete[] payloadStr; // fail-safe: release buffer
|
||||
payloadStr = new char[total+1]; // allocate new buffer
|
||||
}
|
||||
if (payloadStr == nullptr) return; // buffer not allocated
|
||||
|
||||
// copy (partial) packet to buffer and 0-terminate it if it is last packet
|
||||
char* buff = payloadStr + index;
|
||||
memcpy(buff, payload, len);
|
||||
if (index + len >= total) { // at end
|
||||
payloadStr[total] = '\0'; // terminate c style string
|
||||
} else {
|
||||
DEBUG_PRINTLN(F("MQTT partial packet received."));
|
||||
return; // process next packet
|
||||
}
|
||||
DEBUG_PRINTLN(payloadStr);
|
||||
|
||||
size_t topicPrefixLen = strlen(mqttDeviceTopic);
|
||||
if (strncmp(topic, mqttDeviceTopic, topicPrefixLen) == 0) {
|
||||
topic += topicPrefixLen;
|
||||
} else {
|
||||
topicPrefixLen = strlen(mqttGroupTopic);
|
||||
if (strncmp(topic, mqttGroupTopic, topicPrefixLen) == 0) {
|
||||
topic += topicPrefixLen;
|
||||
} else {
|
||||
// Non-Wled Topic used here. Probably a usermod subscribed to this topic.
|
||||
usermods.onMqttMessage(topic, payloadStr);
|
||||
delete[] payloadStr;
|
||||
payloadStr = nullptr;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//Prefix is stripped from the topic at this point
|
||||
|
||||
if (strcmp_P(topic, PSTR("/col")) == 0) {
|
||||
colorFromDecOrHexString(col, payloadStr);
|
||||
colorUpdated(CALL_MODE_DIRECT_CHANGE);
|
||||
} else if (strcmp_P(topic, PSTR("/api")) == 0) {
|
||||
if (!requestJSONBufferLock(15)) {
|
||||
delete[] payloadStr;
|
||||
payloadStr = nullptr;
|
||||
return;
|
||||
}
|
||||
if (payloadStr[0] == '{') { //JSON API
|
||||
deserializeJson(*pDoc, payloadStr);
|
||||
deserializeState(pDoc->as<JsonObject>());
|
||||
} else { //HTTP API
|
||||
String apireq = "win"; apireq += '&'; // reduce flash string usage
|
||||
apireq += payloadStr;
|
||||
handleSet(nullptr, apireq);
|
||||
}
|
||||
releaseJSONBufferLock();
|
||||
} else if (strlen(topic) != 0) {
|
||||
// non standard topic, check with usermods
|
||||
usermods.onMqttMessage(topic, payloadStr);
|
||||
} else {
|
||||
// topmost topic (just wled/MAC)
|
||||
parseMQTTBriPayload(payloadStr);
|
||||
}
|
||||
delete[] payloadStr;
|
||||
payloadStr = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void publishMqtt()
|
||||
{
|
||||
if (!WLED_MQTT_CONNECTED) return;
|
||||
DEBUG_PRINTLN(F("Publish MQTT"));
|
||||
|
||||
#ifndef USERMOD_SMARTNEST
|
||||
char s[10];
|
||||
char subuf[48];
|
||||
|
||||
sprintf_P(s, PSTR("%u"), bri);
|
||||
strlcpy(subuf, mqttDeviceTopic, 33);
|
||||
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]));
|
||||
strlcpy(subuf, mqttDeviceTopic, 33);
|
||||
strcat_P(subuf, PSTR("/c"));
|
||||
mqtt->publish(subuf, 0, retainMqttMsg, s); // optionally retain message (#2263)
|
||||
|
||||
strlcpy(subuf, mqttDeviceTopic, 33);
|
||||
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);
|
||||
strlcpy(subuf, mqttDeviceTopic, 33);
|
||||
strcat_P(subuf, PSTR("/v"));
|
||||
mqtt->publish(subuf, 0, retainMqttMsg, apires); // optionally retain message (#2263)
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//HA autodiscovery was removed in favor of the native integration in HA v0.102.0
|
||||
|
||||
bool initMqtt()
|
||||
{
|
||||
if (!mqttEnabled || mqttServer[0] == 0 || !WLED_CONNECTED) return false;
|
||||
|
||||
if (mqtt == nullptr) {
|
||||
mqtt = new AsyncMqttClient();
|
||||
mqtt->onMessage(onMqttMessage);
|
||||
mqtt->onConnect(onMqttConnect);
|
||||
}
|
||||
if (mqtt->connected()) return true;
|
||||
|
||||
DEBUG_PRINTLN(F("Reconnecting MQTT"));
|
||||
IPAddress mqttIP;
|
||||
if (mqttIP.fromString(mqttServer)) //see if server is IP or domain
|
||||
{
|
||||
mqtt->setServer(mqttIP, mqttPort);
|
||||
} else {
|
||||
mqtt->setServer(mqttServer, mqttPort);
|
||||
}
|
||||
mqtt->setClientId(mqttClientID);
|
||||
if (mqttUser[0] && mqttPass[0]) mqtt->setCredentials(mqttUser, mqttPass);
|
||||
|
||||
#ifndef USERMOD_SMARTNEST
|
||||
strlcpy(mqttStatusTopic, mqttDeviceTopic, 33);
|
||||
strcat_P(mqttStatusTopic, PSTR("/status"));
|
||||
mqtt->setWill(mqttStatusTopic, 0, true, "offline"); // LWT message
|
||||
#endif
|
||||
mqtt->setKeepAlive(MQTT_KEEP_ALIVE_TIME);
|
||||
mqtt->connect();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
@ -399,7 +399,6 @@ void checkTimers()
|
||||
&& isTodayInDateRange(((timerMonth[i] >> 4) & 0x0F), timerDay[i], timerMonth[i] & 0x0F, timerDayEnd[i])
|
||||
)
|
||||
{
|
||||
unloadPlaylist();
|
||||
applyPreset(timerMacro[i]);
|
||||
}
|
||||
}
|
||||
@ -413,7 +412,6 @@ void checkTimers()
|
||||
&& (timerWeekday[8] & 0x01) //timer is enabled
|
||||
&& ((timerWeekday[8] >> weekdayMondayFirst()) & 0x01)) //timer should activate at current day of week
|
||||
{
|
||||
unloadPlaylist();
|
||||
applyPreset(timerMacro[8]);
|
||||
DEBUG_PRINTF_P(PSTR("Sunrise macro %d triggered."),timerMacro[8]);
|
||||
}
|
||||
@ -428,7 +426,6 @@ void checkTimers()
|
||||
&& (timerWeekday[9] & 0x01) //timer is enabled
|
||||
&& ((timerWeekday[9] >> weekdayMondayFirst()) & 0x01)) //timer should activate at current day of week
|
||||
{
|
||||
unloadPlaylist();
|
||||
applyPreset(timerMacro[9]);
|
||||
DEBUG_PRINTF_P(PSTR("Sunset macro %d triggered."),timerMacro[9]);
|
||||
}
|
||||
|
@ -209,11 +209,10 @@ bool PinManagerClass::allocatePin(byte gpio, bool output, PinOwner tag)
|
||||
|
||||
// if tag is set to PinOwner::None, checks for ANY owner of the pin.
|
||||
// if tag is set to any other value, checks if that tag is the current owner of the pin.
|
||||
bool PinManagerClass::isPinAllocated(byte gpio, PinOwner tag)
|
||||
bool PinManagerClass::isPinAllocated(byte gpio, PinOwner tag) const
|
||||
{
|
||||
if (!isPinOk(gpio, false)) return true;
|
||||
if ((tag != PinOwner::None) && (ownerTag[gpio] != tag)) return false;
|
||||
if (gpio >= WLED_NUM_PINS) return false; // catch error case, to avoid array out-of-bounds access
|
||||
byte by = gpio >> 3;
|
||||
byte bi = gpio - (by<<3);
|
||||
return bitRead(pinAlloc[by], bi);
|
||||
@ -236,8 +235,9 @@ bool PinManagerClass::isPinAllocated(byte gpio, PinOwner tag)
|
||||
*/
|
||||
|
||||
// Check if supplied GPIO is ok to use
|
||||
bool PinManagerClass::isPinOk(byte gpio, bool output)
|
||||
bool PinManagerClass::isPinOk(byte gpio, bool output) const
|
||||
{
|
||||
if (gpio >= WLED_NUM_PINS) return false; // catch error case, to avoid array out-of-bounds access
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
if (digitalPinIsValid(gpio)) {
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
@ -257,9 +257,7 @@ bool PinManagerClass::isPinOk(byte gpio, bool output)
|
||||
// GPIO46 is input only and pulled down
|
||||
#else
|
||||
if (gpio > 5 && gpio < 12) return false; //SPI flash pins
|
||||
#ifdef BOARD_HAS_PSRAM
|
||||
if (gpio == 16 || gpio == 17) return false; //PSRAM pins
|
||||
#endif
|
||||
if (gpio == 16 || gpio == 17) return !psramFound(); //PSRAM pins on ESP32 (these are IO)
|
||||
#endif
|
||||
if (output) return digitalPinCanOutput(gpio);
|
||||
else return true;
|
||||
@ -272,8 +270,8 @@ bool PinManagerClass::isPinOk(byte gpio, bool output)
|
||||
return false;
|
||||
}
|
||||
|
||||
PinOwner PinManagerClass::getPinOwner(byte gpio) {
|
||||
if (gpio >= WLED_NUM_PINS) return PinOwner::None; // catch error case, to avoid array out-of-bounds access
|
||||
PinOwner PinManagerClass::getPinOwner(byte gpio) const
|
||||
{
|
||||
if (!isPinOk(gpio, false)) return PinOwner::None;
|
||||
return ownerTag[gpio];
|
||||
}
|
||||
|
@ -109,11 +109,11 @@ class PinManagerClass {
|
||||
inline void deallocatePin(byte gpio) { deallocatePin(gpio, PinOwner::None); }
|
||||
|
||||
// will return true for reserved pins
|
||||
bool isPinAllocated(byte gpio, PinOwner tag = PinOwner::None);
|
||||
bool isPinAllocated(byte gpio, PinOwner tag = PinOwner::None) const;
|
||||
// will return false for reserved pins
|
||||
bool isPinOk(byte gpio, bool output = true);
|
||||
bool isPinOk(byte gpio, bool output = true) const;
|
||||
|
||||
PinOwner getPinOwner(byte gpio);
|
||||
PinOwner getPinOwner(byte gpio) const;
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
byte allocateLedc(byte channels);
|
||||
|
@ -109,7 +109,10 @@ int16_t loadPlaylist(JsonObject playlistObj, byte presetId) {
|
||||
if (playlistRepeat > 0) playlistRepeat++; //add one extra repetition immediately since it will be deducted on first start
|
||||
playlistEndPreset = playlistObj["end"] | 0;
|
||||
// if end preset is 255 restore original preset (if any running) upon playlist end
|
||||
if (playlistEndPreset == 255 && currentPreset > 0) playlistEndPreset = currentPreset;
|
||||
if (playlistEndPreset == 255 && currentPreset > 0) {
|
||||
playlistEndPreset = currentPreset;
|
||||
playlistOptions |= PL_OPTION_RESTORE; // for async save operation
|
||||
}
|
||||
if (playlistEndPreset > 250) playlistEndPreset = 0;
|
||||
shuffle = shuffle || playlistObj["r"];
|
||||
if (shuffle) playlistOptions |= PL_OPTION_SHUFFLE;
|
||||
@ -122,8 +125,7 @@ int16_t loadPlaylist(JsonObject playlistObj, byte presetId) {
|
||||
|
||||
void handlePlaylist() {
|
||||
static unsigned long presetCycledTime = 0;
|
||||
// if fileDoc is not null JSON buffer is in use so just quit
|
||||
if (currentPlaylist < 0 || playlistEntries == nullptr || fileDoc != nullptr) return;
|
||||
if (currentPlaylist < 0 || playlistEntries == nullptr) return;
|
||||
|
||||
if (millis() - presetCycledTime > (100*playlistEntryDur)) {
|
||||
presetCycledTime = millis();
|
||||
@ -135,7 +137,7 @@ void handlePlaylist() {
|
||||
if (!playlistIndex) {
|
||||
if (playlistRepeat == 1) { //stop if all repetitions are done
|
||||
unloadPlaylist();
|
||||
if (playlistEndPreset) applyPreset(playlistEndPreset);
|
||||
if (playlistEndPreset) applyPresetFromPlaylist(playlistEndPreset);
|
||||
return;
|
||||
}
|
||||
if (playlistRepeat > 1) playlistRepeat--; // decrease repeat count on each index reset if not an endless playlist
|
||||
@ -146,7 +148,7 @@ void handlePlaylist() {
|
||||
jsonTransitionOnce = true;
|
||||
strip.setTransition(fadeTransition ? playlistEntries[playlistIndex].tr * 100 : 0);
|
||||
playlistEntryDur = playlistEntries[playlistIndex].dur;
|
||||
applyPreset(playlistEntries[playlistIndex].preset);
|
||||
applyPresetFromPlaylist(playlistEntries[playlistIndex].preset);
|
||||
}
|
||||
}
|
||||
|
||||
@ -157,7 +159,7 @@ void serializePlaylist(JsonObject sObj) {
|
||||
JsonArray dur = playlist.createNestedArray("dur");
|
||||
JsonArray transition = playlist.createNestedArray(F("transition"));
|
||||
playlist[F("repeat")] = (playlistIndex < 0 && playlistRepeat > 0) ? playlistRepeat - 1 : playlistRepeat; // remove added repetition count (if not yet running)
|
||||
playlist["end"] = playlistEndPreset;
|
||||
playlist["end"] = playlistOptions & PL_OPTION_RESTORE ? 255 : playlistEndPreset;
|
||||
playlist["r"] = playlistOptions & PL_OPTION_SHUFFLE;
|
||||
for (int i=0; i<playlistLen; i++) {
|
||||
ps.add(playlistEntries[i].preset);
|
||||
|
@ -27,7 +27,7 @@ static void doSaveState() {
|
||||
|
||||
unsigned long start = millis();
|
||||
while (strip.isUpdating() && millis()-start < (2*FRAMETIME_FIXED)+1) yield(); // wait 2 frames
|
||||
if (!requestJSONBufferLock(10)) return; // will set fileDoc
|
||||
if (!requestJSONBufferLock(10)) return;
|
||||
|
||||
initPresetsFile(); // just in case if someone deleted presets.json using /edit
|
||||
JsonObject sObj = pDoc->to<JsonObject>();
|
||||
@ -53,23 +53,21 @@ static void doSaveState() {
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
if (!persist) {
|
||||
if (tmpRAMbuffer!=nullptr) free(tmpRAMbuffer);
|
||||
size_t len = measureJson(*fileDoc) + 1;
|
||||
size_t len = measureJson(*pDoc) + 1;
|
||||
DEBUG_PRINTLN(len);
|
||||
// if possible use SPI RAM on ESP32
|
||||
#if defined(BOARD_HAS_PSRAM) && defined(WLED_USE_PSRAM)
|
||||
if (psramFound())
|
||||
if (psramSafe && psramFound())
|
||||
tmpRAMbuffer = (char*) ps_malloc(len);
|
||||
else
|
||||
#endif
|
||||
tmpRAMbuffer = (char*) malloc(len);
|
||||
if (tmpRAMbuffer!=nullptr) {
|
||||
serializeJson(*fileDoc, tmpRAMbuffer, len);
|
||||
serializeJson(*pDoc, tmpRAMbuffer, len);
|
||||
} else {
|
||||
writeObjectToFileUsingId(getPresetsFileName(persist), presetToSave, fileDoc);
|
||||
writeObjectToFileUsingId(getPresetsFileName(persist), presetToSave, pDoc);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
writeObjectToFileUsingId(getPresetsFileName(persist), presetToSave, fileDoc);
|
||||
writeObjectToFileUsingId(getPresetsFileName(persist), presetToSave, pDoc);
|
||||
|
||||
if (persist) presetsModifiedTime = toki.second(); //unix time
|
||||
releaseJSONBufferLock();
|
||||
@ -117,8 +115,18 @@ void initPresetsFile()
|
||||
f.close();
|
||||
}
|
||||
|
||||
bool applyPresetFromPlaylist(byte index)
|
||||
{
|
||||
DEBUG_PRINT(F("Request to apply preset: "));
|
||||
DEBUG_PRINTLN(index);
|
||||
presetToApply = index;
|
||||
callModeToApply = CALL_MODE_DIRECT_CHANGE;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool applyPreset(byte index, byte callMode)
|
||||
{
|
||||
unloadPlaylist(); // applying a preset unloads the playlist (#3827)
|
||||
DEBUG_PRINT(F("Request to apply preset: "));
|
||||
DEBUG_PRINTLN(index);
|
||||
presetToApply = index;
|
||||
@ -144,7 +152,7 @@ void handlePresets()
|
||||
return;
|
||||
}
|
||||
|
||||
if (presetToApply == 0 || fileDoc) return; // no preset waiting to apply, or JSON buffer is already allocated, return to loop until free
|
||||
if (presetToApply == 0 || !requestJSONBufferLock(9)) return; // no preset waiting to apply, or JSON buffer is already allocated, return to loop until free
|
||||
|
||||
bool changePreset = false;
|
||||
uint8_t tmpPreset = presetToApply; // store temporary since deserializeState() may call applyPreset()
|
||||
@ -152,9 +160,6 @@ void handlePresets()
|
||||
|
||||
JsonObject fdo;
|
||||
|
||||
// allocate buffer
|
||||
if (!requestJSONBufferLock(9)) return; // will also assign fileDoc
|
||||
|
||||
presetToApply = 0; //clear request for preset
|
||||
callModeToApply = 0;
|
||||
|
||||
@ -163,14 +168,14 @@ void handlePresets()
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
if (tmpPreset==255 && tmpRAMbuffer!=nullptr) {
|
||||
deserializeJson(*fileDoc,tmpRAMbuffer);
|
||||
deserializeJson(*pDoc,tmpRAMbuffer);
|
||||
errorFlag = ERR_NONE;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
errorFlag = readObjectFromFileUsingId(getPresetsFileName(tmpPreset < 255), tmpPreset, fileDoc) ? ERR_NONE : ERR_FS_PLOAD;
|
||||
errorFlag = readObjectFromFileUsingId(getPresetsFileName(tmpPreset < 255), tmpPreset, pDoc) ? ERR_NONE : ERR_FS_PLOAD;
|
||||
}
|
||||
fdo = fileDoc->as<JsonObject>();
|
||||
fdo = pDoc->as<JsonObject>();
|
||||
|
||||
//HTTP API commands
|
||||
const char* httpwin = fdo["win"];
|
||||
@ -197,13 +202,13 @@ void handlePresets()
|
||||
}
|
||||
#endif
|
||||
|
||||
releaseJSONBufferLock(); // will also clear fileDoc
|
||||
releaseJSONBufferLock();
|
||||
if (changePreset) notify(tmpMode); // force UDP notification
|
||||
stateUpdated(tmpMode); // was colorUpdated() if anything breaks
|
||||
updateInterfaces(tmpMode);
|
||||
}
|
||||
|
||||
//called from handleSet(PS=) [network callback (fileDoc==nullptr), IR (irrational), deserializeState, UDP] and deserializeState() [network callback (filedoc!=nullptr)]
|
||||
//called from handleSet(PS=) [network callback (sObj is empty), IR (irrational), deserializeState, UDP] and deserializeState() [network callback (filedoc!=nullptr)]
|
||||
void savePreset(byte index, const char* pname, JsonObject sObj)
|
||||
{
|
||||
if (!saveName) saveName = new char[33];
|
||||
@ -224,6 +229,13 @@ void savePreset(byte index, const char* pname, JsonObject sObj)
|
||||
if (sObj[F("ql")].is<const char*>()) strlcpy(quickLoad, sObj[F("ql")].as<const char*>(), 9); // client limits QL to 2 chars, buffer for 8 bytes to allow unicode
|
||||
else quickLoad[0] = 0;
|
||||
|
||||
const char *bootPS = PSTR("bootps");
|
||||
if (!sObj[FPSTR(bootPS)].isNull()) {
|
||||
bootPreset = sObj[FPSTR(bootPS)] | bootPreset;
|
||||
sObj.remove(FPSTR(bootPS));
|
||||
doSerializeConfig = true;
|
||||
}
|
||||
|
||||
if (sObj.size()==0 || sObj["o"].isNull()) { // no "o" means not a playlist or custom API call, saving of state is async (not immediately)
|
||||
includeBri = sObj["ib"].as<bool>() || sObj.size()==0 || index==255; // temporary preset needs brightness
|
||||
segBounds = sObj["sb"].as<bool>() || sObj.size()==0 || index==255; // temporary preset needs bounds
|
||||
@ -234,7 +246,7 @@ void savePreset(byte index, const char* pname, JsonObject sObj)
|
||||
if (sObj[F("playlist")].isNull()) {
|
||||
// we will save API call immediately (often causes presets.json corruption)
|
||||
presetToSave = 0;
|
||||
if (index <= 250 && fileDoc) { // cannot save API calls to temporary preset (255)
|
||||
if (index <= 250) { // cannot save API calls to temporary preset (255)
|
||||
sObj.remove("o");
|
||||
sObj.remove("v");
|
||||
sObj.remove("time");
|
||||
@ -242,7 +254,7 @@ void savePreset(byte index, const char* pname, JsonObject sObj)
|
||||
sObj.remove(F("psave"));
|
||||
if (sObj["n"].isNull()) sObj["n"] = saveName;
|
||||
initPresetsFile(); // just in case if someone deleted presets.json using /edit
|
||||
writeObjectToFileUsingId(getPresetsFileName(), index, fileDoc);
|
||||
writeObjectToFileUsingId(getPresetsFileName(), index, pDoc);
|
||||
presetsModifiedTime = toki.second(); //unix time
|
||||
updateFSInfo();
|
||||
}
|
||||
|
@ -108,7 +108,6 @@ static void setOff() {
|
||||
|
||||
void presetWithFallback(uint8_t presetID, uint8_t effectID, uint8_t paletteID) {
|
||||
resetNightMode();
|
||||
unloadPlaylist();
|
||||
applyPresetWithFallback(presetID, CALL_MODE_BUTTON_PRESET, effectID, paletteID);
|
||||
}
|
||||
|
||||
|
2
wled00/set.cpp
Executable file → Normal file
2
wled00/set.cpp
Executable file → Normal file
@ -123,6 +123,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
autoSegments = request->hasArg(F("MS"));
|
||||
correctWB = request->hasArg(F("CCT"));
|
||||
cctFromRgb = request->hasArg(F("CR"));
|
||||
cctICused = request->hasArg(F("IC"));
|
||||
strip.cctBlending = request->arg(F("CB")).toInt();
|
||||
Bus::setCCTBlend(strip.cctBlending);
|
||||
Bus::setGlobalAWMode(request->arg(F("AW")).toInt());
|
||||
@ -883,7 +884,6 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
|
||||
//apply preset
|
||||
if (updateVal(req.c_str(), "PL=", &presetCycCurr, presetCycMin, presetCycMax)) {
|
||||
unloadPlaylist();
|
||||
applyPreset(presetCycCurr);
|
||||
}
|
||||
|
||||
|
@ -21,8 +21,6 @@
|
||||
#define DYNAMIC_JSON_DOCUMENT_SIZE 16384
|
||||
#endif
|
||||
|
||||
constexpr const char* JSON_MIMETYPE = "application/json";
|
||||
|
||||
/*
|
||||
* Json Response
|
||||
* */
|
||||
@ -66,7 +64,7 @@ class AsyncJsonResponse: public AsyncAbstractResponse {
|
||||
|
||||
AsyncJsonResponse(JsonDocument *ref, bool isArray=false) : _jsonBuffer(1), _isValid{false} {
|
||||
_code = 200;
|
||||
_contentType = JSON_MIMETYPE;
|
||||
_contentType = FPSTR(CONTENT_TYPE_JSON);
|
||||
if(isArray)
|
||||
_root = ref->to<JsonArray>();
|
||||
else
|
||||
@ -75,7 +73,7 @@ class AsyncJsonResponse: public AsyncAbstractResponse {
|
||||
|
||||
AsyncJsonResponse(size_t maxJsonBufferSize = DYNAMIC_JSON_DOCUMENT_SIZE, bool isArray=false) : _jsonBuffer(maxJsonBufferSize), _isValid{false} {
|
||||
_code = 200;
|
||||
_contentType = JSON_MIMETYPE;
|
||||
_contentType = FPSTR(CONTENT_TYPE_JSON);
|
||||
if(isArray)
|
||||
_root = _jsonBuffer.createNestedArray();
|
||||
else
|
||||
|
@ -213,6 +213,10 @@
|
||||
#include "../usermods/MAX17048_v2/usermod_max17048.h"
|
||||
#endif
|
||||
|
||||
#ifdef USERMOD_TETRISAI
|
||||
#include "../usermods/TetrisAI_v2/usermod_v2_tetrisai.h"
|
||||
#endif
|
||||
|
||||
void registerUsermods()
|
||||
{
|
||||
/*
|
||||
@ -413,4 +417,8 @@ void registerUsermods()
|
||||
#ifdef USERMOD_MAX17048
|
||||
usermods.add(new Usermod_MAX17048());
|
||||
#endif
|
||||
|
||||
#ifdef USERMOD_TETRISAI
|
||||
usermods.add(new TetrisAIUsermod());
|
||||
#endif
|
||||
}
|
||||
|
@ -228,7 +228,6 @@ bool requestJSONBufferLock(uint8_t module)
|
||||
DEBUG_PRINT(F("JSON buffer locked. ("));
|
||||
DEBUG_PRINT(jsonBufferLock);
|
||||
DEBUG_PRINTLN(")");
|
||||
fileDoc = pDoc; // used for applying presets (presets.cpp)
|
||||
pDoc->clear();
|
||||
return true;
|
||||
}
|
||||
@ -239,7 +238,6 @@ void releaseJSONBufferLock()
|
||||
DEBUG_PRINT(F("JSON buffer released. ("));
|
||||
DEBUG_PRINT(jsonBufferLock);
|
||||
DEBUG_PRINTLN(")");
|
||||
fileDoc = nullptr;
|
||||
jsonBufferLock = 0;
|
||||
}
|
||||
|
||||
@ -265,8 +263,8 @@ uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLe
|
||||
} else return 0;
|
||||
}
|
||||
|
||||
if (src == JSON_palette_names && mode > GRADIENT_PALETTE_COUNT) {
|
||||
snprintf_P(dest, maxLen, PSTR("~ Custom %d~"), 255-mode);
|
||||
if (src == JSON_palette_names && mode > (GRADIENT_PALETTE_COUNT + 13)) {
|
||||
snprintf_P(dest, maxLen, PSTR("~ Custom %d ~"), 255-mode);
|
||||
dest[maxLen-1] = '\0';
|
||||
return strlen(dest);
|
||||
}
|
||||
|
@ -240,10 +240,11 @@ void WLED::loop()
|
||||
DEBUG_PRINT(F("Runtime: ")); DEBUG_PRINTLN(millis());
|
||||
DEBUG_PRINT(F("Unix time: ")); toki.printTime(toki.getTime());
|
||||
DEBUG_PRINT(F("Free heap: ")); DEBUG_PRINTLN(ESP.getFreeHeap());
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM)
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
if (psramFound()) {
|
||||
DEBUG_PRINT(F("Total PSRAM: ")); DEBUG_PRINT(ESP.getPsramSize()/1024); DEBUG_PRINTLN("kB");
|
||||
DEBUG_PRINT(F("Free PSRAM: ")); DEBUG_PRINT(ESP.getFreePsram()/1024); DEBUG_PRINTLN("kB");
|
||||
if (!psramSafe) DEBUG_PRINTLN(F("Not using PSRAM."));
|
||||
}
|
||||
#endif
|
||||
DEBUG_PRINT(F("Wifi state: ")); DEBUG_PRINTLN(WiFi.status());
|
||||
@ -269,6 +270,7 @@ void WLED::loop()
|
||||
maxLoopMillis = 0;
|
||||
maxUsermodMillis = 0;
|
||||
maxStripMillis = 0;
|
||||
avgLoopMillis = 0;
|
||||
avgUsermodMillis = 0;
|
||||
avgStripMillis = 0;
|
||||
debugTime = millis();
|
||||
@ -365,42 +367,18 @@ void WLED::setup()
|
||||
#endif
|
||||
DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap());
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM)
|
||||
/*
|
||||
* The following code is obsolete as PinManager::isPinOK() will return false for reserved GPIO.
|
||||
* Additionally xml.cpp will inform UI about reserved GPIO.
|
||||
*
|
||||
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
// S3: reserve GPIO 33-37 for "octal" PSRAM
|
||||
managed_pin_type pins[] = { {33, true}, {34, true}, {35, true}, {36, true}, {37, true} };
|
||||
pinManager.allocateMultiplePins(pins, sizeof(pins)/sizeof(managed_pin_type), PinOwner::SPI_RAM);
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
// S2: reserve GPIO 26-32 for PSRAM (may fail due to isPinOk() but that will also prevent other allocation)
|
||||
managed_pin_type pins[] = { {26, true}, {27, true}, {28, true}, {29, true}, {30, true}, {31, true}, {32, true} };
|
||||
pinManager.allocateMultiplePins(pins, sizeof(pins)/sizeof(managed_pin_type), PinOwner::SPI_RAM);
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
// C3: reserve GPIO 12-17 for PSRAM (may fail due to isPinOk() but that will also prevent other allocation)
|
||||
managed_pin_type pins[] = { {12, true}, {13, true}, {14, true}, {15, true}, {16, true}, {17, true} };
|
||||
pinManager.allocateMultiplePins(pins, sizeof(pins)/sizeof(managed_pin_type), PinOwner::SPI_RAM);
|
||||
#else
|
||||
// GPIO16/GPIO17 reserved for SPI RAM
|
||||
managed_pin_type pins[] = { {16, true}, {17, true} };
|
||||
pinManager.allocateMultiplePins(pins, sizeof(pins)/sizeof(managed_pin_type), PinOwner::SPI_RAM);
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
#ifndef BOARD_HAS_PSRAM
|
||||
if (psramFound() && ESP.getChipRevision() < 3) psramSafe = false;
|
||||
if (!psramSafe) DEBUG_PRINTLN(F("Not using PSRAM."));
|
||||
#endif
|
||||
*/
|
||||
#if defined(BOARD_HAS_PSRAM) && defined(WLED_USE_PSRAM)
|
||||
pDoc = new PSRAMDynamicJsonDocument(2*JSON_BUFFER_SIZE);
|
||||
if (!pDoc) pDoc = new PSRAMDynamicJsonDocument(JSON_BUFFER_SIZE); // falback if double sized buffer could not be allocated
|
||||
// if the above still fails requestJsonBufferLock() will always return false preventing crashes
|
||||
pDoc = new PSRAMDynamicJsonDocument((psramSafe && psramFound() ? 2 : 1)*JSON_BUFFER_SIZE);
|
||||
DEBUG_PRINT(F("JSON buffer allocated: ")); DEBUG_PRINTLN((psramSafe && psramFound() ? 2 : 1)*JSON_BUFFER_SIZE);
|
||||
// if the above fails requestJsonBufferLock() will always return false preventing crashes
|
||||
if (psramFound()) {
|
||||
DEBUG_PRINT(F("Total PSRAM: ")); DEBUG_PRINT(ESP.getPsramSize()/1024); DEBUG_PRINTLN("kB");
|
||||
DEBUG_PRINT(F("Free PSRAM : ")); DEBUG_PRINT(ESP.getFreePsram()/1024); DEBUG_PRINTLN("kB");
|
||||
}
|
||||
#else
|
||||
if (!pDoc) pDoc = &gDoc; // just in case ... (it should be globally assigned)
|
||||
DEBUG_PRINTLN(F("PSRAM not used."));
|
||||
#endif
|
||||
#endif
|
||||
#if defined(ARDUINO_ESP32_PICO)
|
||||
// special handling for PICO-D4: gpio16+17 are in use for onboard SPI FLASH (not PSRAM)
|
||||
@ -408,9 +386,6 @@ void WLED::setup()
|
||||
pinManager.allocateMultiplePins(pins, sizeof(pins)/sizeof(managed_pin_type), PinOwner::SPI_RAM);
|
||||
#endif
|
||||
|
||||
//DEBUG_PRINT(F("LEDs inited. heap usage ~"));
|
||||
//DEBUG_PRINTLN(heapPreAlloc - ESP.getFreeHeap());
|
||||
|
||||
#if defined(WLED_DEBUG) && !defined(WLED_DEBUG_HOST)
|
||||
pinManager.allocatePin(hardwareTX, true, PinOwner::DebugOut); // TX (GPIO1 on ESP32) reserved for debug output
|
||||
#endif
|
||||
@ -451,6 +426,7 @@ void WLED::setup()
|
||||
|
||||
DEBUG_PRINTLN(F("Reading config"));
|
||||
deserializeConfigFromFS();
|
||||
DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap());
|
||||
|
||||
#if defined(STATUSLED) && STATUSLED>=0
|
||||
if (!pinManager.isPinAllocated(STATUSLED)) {
|
||||
@ -554,7 +530,7 @@ void WLED::setup()
|
||||
void WLED::beginStrip()
|
||||
{
|
||||
// Initialize NeoPixel Strip and button
|
||||
strip.finalizeInit(); // busses created during deserializeConfig()
|
||||
strip.finalizeInit(); // busses created during deserializeConfig() if config existed
|
||||
strip.makeAutoSegments();
|
||||
strip.setBrightness(0);
|
||||
strip.setShowCallback(handleOverlayDraw);
|
||||
|
26
wled00/wled.h
Executable file → Normal file
26
wled00/wled.h
Executable file → Normal file
@ -3,12 +3,12 @@
|
||||
/*
|
||||
Main sketch, global variable declarations
|
||||
@title WLED project sketch
|
||||
@version 0.15.0-b1
|
||||
@version 0.15.0-b2
|
||||
@author Christian Schwinne
|
||||
*/
|
||||
|
||||
// version code in format yymmddb (b = daily build)
|
||||
#define VERSION 2403070
|
||||
#define VERSION 2403280
|
||||
|
||||
//uncomment this if you have a "my_config.h" file you'd like to use
|
||||
//#define WLED_USE_MY_CONFIG
|
||||
@ -158,15 +158,16 @@
|
||||
// The following is a construct to enable code to compile without it.
|
||||
// There is a code that will still not use PSRAM though:
|
||||
// AsyncJsonResponse is a derived class that implements DynamicJsonDocument (AsyncJson-v6.h)
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM) && defined(WLED_USE_PSRAM)
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
extern bool psramSafe;
|
||||
struct PSRAM_Allocator {
|
||||
void* allocate(size_t size) {
|
||||
if (psramFound()) return ps_malloc(size); // use PSRAM if it exists
|
||||
else return malloc(size); // fallback
|
||||
if (psramSafe && psramFound()) return ps_malloc(size); // use PSRAM if it exists
|
||||
else return malloc(size); // fallback
|
||||
}
|
||||
void* reallocate(void* ptr, size_t new_size) {
|
||||
if (psramFound()) return ps_realloc(ptr, new_size); // use PSRAM if it exists
|
||||
else return realloc(ptr, new_size); // fallback
|
||||
if (psramSafe && psramFound()) return ps_realloc(ptr, new_size); // use PSRAM if it exists
|
||||
else return realloc(ptr, new_size); // fallback
|
||||
}
|
||||
void deallocate(void* pointer) {
|
||||
free(pointer);
|
||||
@ -348,6 +349,11 @@ WLED_GLOBAL bool useGlobalLedBuffer _INIT(true); // double buffering enabled on
|
||||
#endif
|
||||
WLED_GLOBAL bool correctWB _INIT(false); // CCT color correction of RGB color
|
||||
WLED_GLOBAL bool cctFromRgb _INIT(false); // CCT is calculated from RGB instead of using seg.cct
|
||||
#ifdef WLED_USE_IC_CCT
|
||||
WLED_GLOBAL bool cctICused _INIT(true); // CCT IC used (Athom 15W bulbs)
|
||||
#else
|
||||
WLED_GLOBAL bool cctICused _INIT(false); // CCT IC used (Athom 15W bulbs)
|
||||
#endif
|
||||
WLED_GLOBAL bool gammaCorrectCol _INIT(true); // use gamma correction on colors
|
||||
WLED_GLOBAL bool gammaCorrectBri _INIT(false); // use gamma correction on brightness
|
||||
WLED_GLOBAL float gammaCorrectVal _INIT(2.8f); // gamma correction value
|
||||
@ -692,7 +698,6 @@ WLED_GLOBAL uint16_t olen _INIT(0);
|
||||
WLED_GLOBAL size_t fsBytesUsed _INIT(0);
|
||||
WLED_GLOBAL size_t fsBytesTotal _INIT(0);
|
||||
WLED_GLOBAL unsigned long presetsModifiedTime _INIT(0L);
|
||||
WLED_GLOBAL JsonDocument* fileDoc;
|
||||
WLED_GLOBAL bool doCloseFile _INIT(false);
|
||||
|
||||
// presets
|
||||
@ -705,7 +710,8 @@ WLED_GLOBAL byte optionType;
|
||||
|
||||
WLED_GLOBAL bool doSerializeConfig _INIT(false); // flag to initiate saving of config
|
||||
WLED_GLOBAL bool doReboot _INIT(false); // flag to initiate reboot from async handlers
|
||||
WLED_GLOBAL bool doPublishMqtt _INIT(false);
|
||||
|
||||
WLED_GLOBAL bool psramSafe _INIT(true); // is it safe to use PSRAM (on ESP32 rev.1; compiler fix used "-mfix-esp32-psram-cache-issue")
|
||||
|
||||
// status led
|
||||
#if defined(STATUSLED)
|
||||
@ -782,7 +788,7 @@ WLED_GLOBAL int8_t spi_sclk _INIT(SPISCLKPIN);
|
||||
#endif
|
||||
|
||||
// global ArduinoJson buffer
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM) && defined(WLED_USE_PSRAM)
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
WLED_GLOBAL JsonDocument *pDoc _INIT(nullptr);
|
||||
#else
|
||||
WLED_GLOBAL StaticJsonDocument<JSON_BUFFER_SIZE> gDoc;
|
||||
|
@ -18,36 +18,6 @@ static const char s_unlock_ota [] PROGMEM = "Please unlock OTA in security setti
|
||||
static const char s_unlock_cfg [] PROGMEM = "Please unlock settings using PIN code!";
|
||||
static const char s_notimplemented[] PROGMEM = "Not implemented";
|
||||
static const char s_accessdenied[] PROGMEM = "Access Denied";
|
||||
static const char s_javascript[] PROGMEM = "application/javascript";
|
||||
static const char s_json[] = "application/json"; // AsyncJson-v6.h
|
||||
static const char s_html[] PROGMEM = "text/html";
|
||||
static const char s_plain[] = "text/plain"; // Espalexa.h
|
||||
static const char s_css[] PROGMEM = "text/css";
|
||||
static const char s_png[] PROGMEM = "image/png";
|
||||
static const char s_gif[] PROGMEM = "image/gif";
|
||||
static const char s_jpg[] PROGMEM = "image/jpeg";
|
||||
static const char s_ico[] PROGMEM = "image/x-icon";
|
||||
//static const char s_xml[] PROGMEM = "text/xml";
|
||||
//static const char s_pdf[] PROGMEM = "application/x-pdf";
|
||||
//static const char s_zip[] PROGMEM = "application/x-zip";
|
||||
//static const char s_gz[] PROGMEM = "application/x-gzip";
|
||||
|
||||
String getFileContentType(String &filename) {
|
||||
if (filename.endsWith(F(".htm"))) return FPSTR(s_html);
|
||||
else if (filename.endsWith(F(".html"))) return FPSTR(s_html);
|
||||
else if (filename.endsWith(F(".css"))) return FPSTR(s_css);
|
||||
else if (filename.endsWith(F(".js"))) return FPSTR(s_javascript);
|
||||
else if (filename.endsWith(F(".json"))) return s_json;
|
||||
else if (filename.endsWith(F(".png"))) return FPSTR(s_png);
|
||||
else if (filename.endsWith(F(".gif"))) return FPSTR(s_gif);
|
||||
else if (filename.endsWith(F(".jpg"))) return FPSTR(s_jpg);
|
||||
else if (filename.endsWith(F(".ico"))) return FPSTR(s_ico);
|
||||
// else if (filename.endsWith(F(".xml"))) return FPSTR(s_xml);
|
||||
// else if (filename.endsWith(F(".pdf"))) return FPSTR(s_pdf);
|
||||
// else if (filename.endsWith(F(".zip"))) return FPSTR(s_zip);
|
||||
// else if (filename.endsWith(F(".gz"))) return FPSTR(s_gz);
|
||||
return s_plain;
|
||||
}
|
||||
|
||||
//Is this an IP?
|
||||
static bool isIp(String str) {
|
||||
@ -183,7 +153,7 @@ static String msgProcessor(const String& var)
|
||||
|
||||
static void handleUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) {
|
||||
if (!correctPIN) {
|
||||
if (final) request->send(401, FPSTR(s_plain), FPSTR(s_unlock_cfg));
|
||||
if (final) request->send(401, FPSTR(CONTENT_TYPE_PLAIN), FPSTR(s_unlock_cfg));
|
||||
return;
|
||||
}
|
||||
if (!index) {
|
||||
@ -204,10 +174,10 @@ static void handleUpload(AsyncWebServerRequest *request, const String& filename,
|
||||
request->_tempFile.close();
|
||||
if (filename.indexOf(F("cfg.json")) >= 0) { // check for filename with or without slash
|
||||
doReboot = true;
|
||||
request->send(200, FPSTR(s_plain), F("Configuration restore successful.\nRebooting..."));
|
||||
request->send(200, FPSTR(CONTENT_TYPE_PLAIN), F("Configuration restore successful.\nRebooting..."));
|
||||
} else {
|
||||
if (filename.indexOf(F("palette")) >= 0 && filename.indexOf(F(".json")) >= 0) strip.loadCustomPalettes();
|
||||
request->send(200, FPSTR(s_plain), F("File Uploaded!"));
|
||||
request->send(200, FPSTR(CONTENT_TYPE_PLAIN), F("File Uploaded!"));
|
||||
}
|
||||
cacheInvalidate++;
|
||||
}
|
||||
@ -259,24 +229,24 @@ void initServer()
|
||||
|
||||
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||
#ifndef WLED_DISABLE_2D
|
||||
server.on(SET_F("/liveview2D"), HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||
handleStaticContent(request, "", 200, FPSTR(s_html), PAGE_liveviewws2D, PAGE_liveviewws2D_length);
|
||||
server.on(F("/liveview2D"), HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||
handleStaticContent(request, "", 200, FPSTR(CONTENT_TYPE_HTML), PAGE_liveviewws2D, PAGE_liveviewws2D_length);
|
||||
});
|
||||
#endif
|
||||
#endif
|
||||
server.on(SET_F("/liveview"), HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||
handleStaticContent(request, "", 200, FPSTR(s_html), PAGE_liveview, PAGE_liveview_length);
|
||||
server.on(F("/liveview"), HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||
handleStaticContent(request, "", 200, FPSTR(CONTENT_TYPE_HTML), PAGE_liveview, PAGE_liveview_length);
|
||||
});
|
||||
|
||||
//settings page
|
||||
server.on(SET_F("/settings"), HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
server.on(F("/settings"), HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
serveSettings(request);
|
||||
});
|
||||
|
||||
// "/settings/settings.js&p=x" request also handled by serveSettings()
|
||||
static const char _style_css[] PROGMEM = "/style.css";
|
||||
server.on(_style_css, HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||
handleStaticContent(request, FPSTR(_style_css), 200, FPSTR(s_css), PAGE_settingsCss, PAGE_settingsCss_length);
|
||||
handleStaticContent(request, FPSTR(_style_css), 200, FPSTR(CONTENT_TYPE_CSS), PAGE_settingsCss, PAGE_settingsCss_length);
|
||||
});
|
||||
|
||||
static const char _favicon_ico[] PROGMEM = "/favicon.ico";
|
||||
@ -287,28 +257,29 @@ void initServer()
|
||||
static const char _skin_css[] PROGMEM = "/skin.css";
|
||||
server.on(_skin_css, HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||
if (handleFileRead(request, FPSTR(_skin_css))) return;
|
||||
AsyncWebServerResponse *response = request->beginResponse(200, FPSTR(s_css));
|
||||
AsyncWebServerResponse *response = request->beginResponse(200, FPSTR(CONTENT_TYPE_CSS));
|
||||
request->send(response);
|
||||
});
|
||||
|
||||
server.on(SET_F("/welcome"), HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
server.on(F("/welcome"), HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
serveSettings(request);
|
||||
});
|
||||
|
||||
server.on(SET_F("/reset"), HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
server.on(F("/reset"), HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
serveMessage(request, 200,F("Rebooting now..."),F("Please wait ~10 seconds..."),129);
|
||||
doReboot = true;
|
||||
});
|
||||
|
||||
server.on(SET_F("/settings"), HTTP_POST, [](AsyncWebServerRequest *request){
|
||||
server.on(F("/settings"), HTTP_POST, [](AsyncWebServerRequest *request){
|
||||
serveSettings(request, true);
|
||||
});
|
||||
|
||||
server.on(SET_F("/json"), HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
const static char _json[] PROGMEM = "/json";
|
||||
server.on(FPSTR(_json), HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
serveJson(request);
|
||||
});
|
||||
|
||||
AsyncCallbackJsonWebHandler* handler = new AsyncCallbackJsonWebHandler(F("/json"), [](AsyncWebServerRequest *request) {
|
||||
AsyncCallbackJsonWebHandler* handler = new AsyncCallbackJsonWebHandler(FPSTR(_json), [](AsyncWebServerRequest *request) {
|
||||
bool verboseResponse = false;
|
||||
bool isConfig = false;
|
||||
|
||||
@ -356,33 +327,33 @@ void initServer()
|
||||
doSerializeConfig = true; //serializeConfig(); //Save new settings to FS
|
||||
}
|
||||
}
|
||||
request->send(200, s_json, F("{\"success\":true}"));
|
||||
request->send(200, CONTENT_TYPE_JSON, F("{\"success\":true}"));
|
||||
}, JSON_BUFFER_SIZE);
|
||||
server.addHandler(handler);
|
||||
|
||||
server.on(SET_F("/version"), HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
request->send(200, FPSTR(s_plain), (String)VERSION);
|
||||
server.on(F("/version"), HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
request->send(200, FPSTR(CONTENT_TYPE_PLAIN), (String)VERSION);
|
||||
});
|
||||
|
||||
server.on(SET_F("/uptime"), HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
request->send(200, FPSTR(s_plain), (String)millis());
|
||||
server.on(F("/uptime"), HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
request->send(200, FPSTR(CONTENT_TYPE_PLAIN), (String)millis());
|
||||
});
|
||||
|
||||
server.on(SET_F("/freeheap"), HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
request->send(200, FPSTR(s_plain), (String)ESP.getFreeHeap());
|
||||
server.on(F("/freeheap"), HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
request->send(200, FPSTR(CONTENT_TYPE_PLAIN), (String)ESP.getFreeHeap());
|
||||
});
|
||||
|
||||
#ifdef WLED_ENABLE_USERMOD_PAGE
|
||||
server.on("/u", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||
handleStaticContent(request, "", 200, FPSTR(s_html), PAGE_usermod, PAGE_usermod_length);
|
||||
handleStaticContent(request, "", 200, FPSTR(CONTENT_TYPE_HTML), PAGE_usermod, PAGE_usermod_length);
|
||||
});
|
||||
#endif
|
||||
|
||||
server.on(SET_F("/teapot"), HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
server.on(F("/teapot"), HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
serveMessage(request, 418, F("418. I'm a teapot."), F("(Tangible Embedded Advanced Project Of Twinkling)"), 254);
|
||||
});
|
||||
|
||||
server.on(SET_F("/upload"), HTTP_POST, [](AsyncWebServerRequest *request) {},
|
||||
server.on(F("/upload"), HTTP_POST, [](AsyncWebServerRequest *request) {},
|
||||
[](AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data,
|
||||
size_t len, bool final) {handleUpload(request, filename, index, data, len, final);}
|
||||
);
|
||||
@ -453,7 +424,7 @@ void initServer()
|
||||
|
||||
#ifdef WLED_ENABLE_DMX
|
||||
server.on(SET_F("/dmxmap"), HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
request->send_P(200, FPSTR(s_html), PAGE_dmxmap , dmxProcessor);
|
||||
request->send_P(200, FPSTR(CONTENT_TYPE_HTML), PAGE_dmxmap , dmxProcessor);
|
||||
});
|
||||
#else
|
||||
server.on(SET_F("/dmxmap"), HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
@ -464,7 +435,7 @@ void initServer()
|
||||
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||
if (captivePortal(request)) return;
|
||||
if (!showWelcomePage || request->hasArg(F("sliders"))) {
|
||||
handleStaticContent(request, F("/index.htm"), 200, FPSTR(s_html), PAGE_index, PAGE_index_L);
|
||||
handleStaticContent(request, F("/index.htm"), 200, FPSTR(CONTENT_TYPE_HTML), PAGE_index, PAGE_index_L);
|
||||
} else {
|
||||
serveSettings(request);
|
||||
}
|
||||
@ -473,20 +444,20 @@ void initServer()
|
||||
#ifdef WLED_ENABLE_PIXART
|
||||
static const char _pixart_htm[] PROGMEM = "/pixart.htm";
|
||||
server.on(_pixart_htm, HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||
handleStaticContent(request, FPSTR(_pixart_htm), 200, FPSTR(s_html), PAGE_pixart, PAGE_pixart_L);
|
||||
handleStaticContent(request, FPSTR(_pixart_htm), 200, FPSTR(CONTENT_TYPE_HTML), PAGE_pixart, PAGE_pixart_L);
|
||||
});
|
||||
#endif
|
||||
|
||||
#ifndef WLED_DISABLE_PXMAGIC
|
||||
static const char _pxmagic_htm[] PROGMEM = "/pxmagic.htm";
|
||||
server.on(_pxmagic_htm, HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||
handleStaticContent(request, FPSTR(_pxmagic_htm), 200, FPSTR(s_html), PAGE_pxmagic, PAGE_pxmagic_L);
|
||||
handleStaticContent(request, FPSTR(_pxmagic_htm), 200, FPSTR(CONTENT_TYPE_HTML), PAGE_pxmagic, PAGE_pxmagic_L);
|
||||
});
|
||||
#endif
|
||||
|
||||
static const char _cpal_htm[] PROGMEM = "/cpal.htm";
|
||||
server.on(_cpal_htm, HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||
handleStaticContent(request, FPSTR(_cpal_htm), 200, FPSTR(s_html), PAGE_cpal, PAGE_cpal_L);
|
||||
handleStaticContent(request, FPSTR(_cpal_htm), 200, FPSTR(CONTENT_TYPE_HTML), PAGE_cpal, PAGE_cpal_L);
|
||||
});
|
||||
|
||||
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||
@ -511,7 +482,7 @@ void initServer()
|
||||
#ifndef WLED_DISABLE_ALEXA
|
||||
if(espalexa.handleAlexaApiCall(request)) return;
|
||||
#endif
|
||||
handleStaticContent(request, request->url(), 404, FPSTR(s_html), PAGE_404, PAGE_404_length);
|
||||
handleStaticContent(request, request->url(), 404, FPSTR(CONTENT_TYPE_HTML), PAGE_404, PAGE_404_length);
|
||||
});
|
||||
}
|
||||
|
||||
@ -522,7 +493,7 @@ void serveMessage(AsyncWebServerRequest* request, uint16_t code, const String& h
|
||||
messageSub = subl;
|
||||
optionType = optionT;
|
||||
|
||||
request->send_P(code, FPSTR(s_html), PAGE_msg, msgProcessor);
|
||||
request->send_P(code, FPSTR(CONTENT_TYPE_HTML), PAGE_msg, msgProcessor);
|
||||
}
|
||||
|
||||
|
||||
@ -530,7 +501,7 @@ void serveJsonError(AsyncWebServerRequest* request, uint16_t code, uint16_t erro
|
||||
{
|
||||
AsyncJsonResponse *response = new AsyncJsonResponse(64);
|
||||
if (error < ERR_NOT_IMPL) response->addHeader(F("Retry-After"), F("1"));
|
||||
response->setContentType(s_json);
|
||||
response->setContentType(CONTENT_TYPE_JSON);
|
||||
response->setCode(code);
|
||||
JsonObject obj = response->getRoot();
|
||||
obj[F("error")] = error;
|
||||
@ -546,12 +517,12 @@ void serveSettingsJS(AsyncWebServerRequest* request)
|
||||
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(s_javascript), buf);
|
||||
request->send(501, FPSTR(CONTENT_TYPE_JAVASCRIPT), buf);
|
||||
return;
|
||||
}
|
||||
if (subPage > 0 && !correctPIN && strlen(settingsPIN)>0) {
|
||||
strcpy_P(buf, PSTR("alert('PIN incorrect.');"));
|
||||
request->send(401, FPSTR(s_javascript), buf);
|
||||
request->send(401, FPSTR(CONTENT_TYPE_JAVASCRIPT), buf);
|
||||
return;
|
||||
}
|
||||
strcat_P(buf,PSTR("function GetV(){var d=document;"));
|
||||
@ -559,7 +530,7 @@ void serveSettingsJS(AsyncWebServerRequest* request)
|
||||
strcat_P(buf,PSTR("}"));
|
||||
|
||||
AsyncWebServerResponse *response;
|
||||
response = request->beginResponse(200, FPSTR(s_javascript), buf);
|
||||
response = request->beginResponse(200, FPSTR(CONTENT_TYPE_JAVASCRIPT), buf);
|
||||
response->addHeader(F("Cache-Control"), F("no-store"));
|
||||
response->addHeader(F("Expires"), F("0"));
|
||||
request->send(response);
|
||||
@ -640,7 +611,7 @@ void serveSettings(AsyncWebServerRequest* request, bool post) {
|
||||
}
|
||||
|
||||
int code = 200;
|
||||
String contentType = FPSTR(s_html);
|
||||
String contentType = FPSTR(CONTENT_TYPE_HTML);
|
||||
const uint8_t* content;
|
||||
size_t len;
|
||||
|
||||
@ -666,7 +637,7 @@ void serveSettings(AsyncWebServerRequest* request, bool post) {
|
||||
return;
|
||||
}
|
||||
case SUBPAGE_PINREQ : content = PAGE_settings_pin; len = PAGE_settings_pin_length; code = 401; break;
|
||||
case SUBPAGE_CSS : content = PAGE_settingsCss; len = PAGE_settingsCss_length; contentType = FPSTR(s_css); break;
|
||||
case SUBPAGE_CSS : content = PAGE_settingsCss; len = PAGE_settingsCss_length; contentType = FPSTR(CONTENT_TYPE_CSS); break;
|
||||
case SUBPAGE_JS : serveSettingsJS(request); return;
|
||||
case SUBPAGE_WELCOME : content = PAGE_welcome; len = PAGE_welcome_length; break;
|
||||
default: content = PAGE_settings; len = PAGE_settings_length; break;
|
||||
|
@ -55,7 +55,7 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
|
||||
} else {
|
||||
verboseResponse = deserializeState(root);
|
||||
}
|
||||
releaseJSONBufferLock(); // will clean fileDoc
|
||||
releaseJSONBufferLock();
|
||||
|
||||
if (!interfaceUpdateCallMode) { // individual client response only needed if no WS broadcast soon
|
||||
if (verboseResponse) {
|
||||
@ -102,7 +102,6 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
|
||||
void sendDataWs(AsyncWebSocketClient * client)
|
||||
{
|
||||
if (!ws.count()) return;
|
||||
AsyncWebSocketMessageBuffer * buffer;
|
||||
|
||||
if (!requestJSONBufferLock(12)) {
|
||||
if (client) {
|
||||
@ -129,7 +128,7 @@ void sendDataWs(AsyncWebSocketClient * client)
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
buffer = ws.makeBuffer(len); // will not allocate correct memory sometimes on ESP8266
|
||||
AsyncWebSocketBuffer buffer(len);
|
||||
#ifdef ESP8266
|
||||
size_t heap2 = ESP.getFreeHeap();
|
||||
DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap());
|
||||
@ -141,23 +140,18 @@ void sendDataWs(AsyncWebSocketClient * client)
|
||||
DEBUG_PRINTLN(F("WS buffer allocation failed."));
|
||||
ws.closeAll(1013); //code 1013 = temporary overload, try again later
|
||||
ws.cleanupClients(0); //disconnect all clients to release memory
|
||||
ws._cleanBuffers();
|
||||
return; //out of memory
|
||||
}
|
||||
|
||||
buffer->lock();
|
||||
serializeJson(*pDoc, (char *)buffer->get(), len);
|
||||
serializeJson(*pDoc, (char *)buffer.data(), len);
|
||||
|
||||
DEBUG_PRINT(F("Sending WS data "));
|
||||
if (client) {
|
||||
client->text(buffer);
|
||||
client->text(std::move(buffer));
|
||||
DEBUG_PRINTLN(F("to a single client."));
|
||||
} else {
|
||||
ws.textAll(buffer);
|
||||
ws.textAll(std::move(buffer));
|
||||
DEBUG_PRINTLN(F("to multiple clients."));
|
||||
}
|
||||
buffer->unlock();
|
||||
ws._cleanBuffers();
|
||||
|
||||
releaseJSONBufferLock();
|
||||
}
|
||||
@ -187,11 +181,10 @@ bool sendLiveLedsWs(uint32_t wsClient)
|
||||
#endif
|
||||
size_t bufSize = pos + (used/n)*3;
|
||||
|
||||
AsyncWebSocketMessageBuffer * wsBuf = ws.makeBuffer(bufSize);
|
||||
AsyncWebSocketBuffer wsBuf(bufSize);
|
||||
if (!wsBuf) return false; //out of memory
|
||||
uint8_t* buffer = wsBuf->get();
|
||||
uint8_t* buffer = reinterpret_cast<uint8_t*>(wsBuf.data());
|
||||
if (!buffer) return false; //out of memory
|
||||
wsBuf->lock(); // protect buffer from being cleaned by another WS instance
|
||||
buffer[0] = 'L';
|
||||
buffer[1] = 1; //version
|
||||
|
||||
@ -218,9 +211,7 @@ bool sendLiveLedsWs(uint32_t wsClient)
|
||||
buffer[pos++] = scale8(qadd8(w, b), strip.getBrightness()); //B
|
||||
}
|
||||
|
||||
wsc->binary(wsBuf);
|
||||
wsBuf->unlock(); // un-protect buffer
|
||||
ws._cleanBuffers();
|
||||
wsc->binary(std::move(wsBuf));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
5
wled00/xml.cpp
Executable file → Normal file
5
wled00/xml.cpp
Executable file → Normal file
@ -163,7 +163,7 @@ void appendGPIOinfo() {
|
||||
|
||||
//Note: Using pin 3 (RX) disables Adalight / Serial JSON
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM)
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
if (psramFound()) oappend(SET_F(",16,17")); // GPIO16 & GPIO17 reserved for SPI RAM on ESP32 (not on S2, S3 or C3)
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
@ -360,6 +360,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
|
||||
sappend('c',SET_F("MS"),autoSegments);
|
||||
sappend('c',SET_F("CCT"),correctWB);
|
||||
sappend('c',SET_F("IC"),cctICused);
|
||||
sappend('c',SET_F("CR"),cctFromRgb);
|
||||
sappend('v',SET_F("CB"),strip.cctBlending);
|
||||
sappend('v',SET_F("FR"),strip.getTargetFps());
|
||||
@ -471,8 +472,10 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
}
|
||||
sappend('c',SET_F("IP"),disablePullUp);
|
||||
sappend('v',SET_F("TT"),touchThreshold);
|
||||
#ifndef WLED_DISABLE_INFRARED
|
||||
sappend('v',SET_F("IR"),irPin);
|
||||
sappend('v',SET_F("IT"),irEnabled);
|
||||
#endif
|
||||
sappend('c',SET_F("MSO"),!irApplyToAllSelected);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user