Compare commits
359 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
46d66dded8 | ||
|
|
de6f32e486 | ||
|
|
fbe866198d | ||
|
|
d603a8a9be | ||
|
|
8f92077454 | ||
|
|
8755a9bcda | ||
|
|
4a1ecc7b72 | ||
|
|
e46078286d | ||
|
|
806221bc3f | ||
|
|
4264c2a173 | ||
|
|
1f4a15ee6b | ||
|
|
bab4f9963f | ||
|
|
1dbcac4f53 | ||
|
|
8d20a13776 | ||
|
|
213bc75ae1 | ||
|
|
8a2256e0d8 | ||
|
|
eee2450c9e | ||
|
|
e2242f5d99 | ||
|
|
30df67721d | ||
|
|
4a20f43fbf | ||
|
|
e06d269b82 | ||
|
|
ba4c3e3852 | ||
|
|
b8de36b340 | ||
|
|
bbe3e8093c | ||
|
|
26096bc136 | ||
|
|
3460f9d9cc | ||
|
|
6eacf8ed7e | ||
|
|
20bebe98b1 | ||
|
|
91d885eae4 | ||
|
|
ea3358ecb2 | ||
|
|
9b3e6270d5 | ||
|
|
71edc3a084 | ||
|
|
05521bfd3a | ||
|
|
6c997f573a | ||
|
|
c0dd98b6d7 | ||
|
|
56cf1c818b | ||
|
|
5553964d52 | ||
|
|
90808ac67e | ||
|
|
7aab7678e9 | ||
|
|
195af002cf | ||
|
|
38db8d2bfd | ||
|
|
44a9fed8a9 | ||
|
|
cfc346abad | ||
|
|
befeb55349 | ||
|
|
b460d0f533 | ||
|
|
746a8badac | ||
|
|
d7790a04c5 | ||
|
|
2c0b07387b | ||
|
|
06f2f9adbb | ||
|
|
37d5b9109f | ||
|
|
76e269ee21 | ||
|
|
3103939197 | ||
|
|
3f01c87223 | ||
|
|
e4cda4bb99 | ||
|
|
f333f867c5 | ||
|
|
75c46f7a0e | ||
|
|
5c6cb41124 | ||
|
|
94f7c03871 | ||
|
|
96d5c03a6d | ||
|
|
3a03bc41a7 | ||
|
|
331844ff73 | ||
|
|
2bc38e3784 | ||
|
|
d580dedfc8 | ||
|
|
aa0f4c9985 | ||
|
|
aa242d897d | ||
|
|
d56ab6c971 | ||
|
|
2f7be3475d | ||
|
|
2544d2e068 | ||
|
|
a09f64aee5 | ||
|
|
f7114fc2aa | ||
|
|
7092f337ef | ||
|
|
8e71c3ae17 | ||
|
|
a9c211d66c | ||
|
|
a1c2c04510 | ||
|
|
0902b628f8 | ||
|
|
517a85f9e9 | ||
|
|
94941a7732 | ||
|
|
f3aa8d368e | ||
|
|
9518c5f2e4 | ||
|
|
e44173ff09 | ||
|
|
fa1106d3cf | ||
|
|
c24d574f90 | ||
|
|
8ed35652bc | ||
|
|
9bdcfc8a45 | ||
|
|
89b76b514c | ||
|
|
dd433d8af0 | ||
|
|
c105f3b970 | ||
|
|
94471c0d1c | ||
|
|
849e04ab83 | ||
|
|
67833c5513 | ||
|
|
b0306867b4 | ||
|
|
d5025fdbcc | ||
|
|
e6cf1dc98d | ||
|
|
0266370218 | ||
|
|
aeb3f2b018 | ||
|
|
bb8d5ac13f | ||
|
|
d02bf37167 | ||
|
|
99dbd9e649 | ||
|
|
0d63dad8c2 | ||
|
|
6ce465664f | ||
|
|
b934634159 | ||
|
|
ef904e01ec | ||
|
|
25b77db4cd | ||
|
|
88c0a9e30a | ||
|
|
75c219d6c6 | ||
|
|
82e7328903 | ||
|
|
d6b366c77f | ||
|
|
42a7c84a33 | ||
|
|
1f4c1f2af5 | ||
|
|
e665e4dc57 | ||
|
|
9551519a35 | ||
|
|
df51b80e07 | ||
|
|
0df6826c91 | ||
|
|
af61962314 | ||
|
|
f5ed710c0b | ||
|
|
e5ae07b3e8 | ||
|
|
f1535e1f71 | ||
|
|
a6316b40d1 | ||
|
|
c2746a55e3 | ||
|
|
e9c782bf9e | ||
|
|
ad6c154eb6 | ||
|
|
b747b10642 | ||
|
|
2005a2abd4 | ||
|
|
c5818ff5e4 | ||
|
|
b5e02e6ff9 | ||
|
|
205f62e732 | ||
|
|
fdc8b5eb54 | ||
|
|
36abe8e808 | ||
|
|
fcf0e08e01 | ||
|
|
0edcf97e3f | ||
|
|
0707b26303 | ||
|
|
09662a4bcd | ||
|
|
cb06961b82 | ||
|
|
824fb4adae | ||
|
|
a91d993c6d | ||
|
|
e16bab8dd9 | ||
|
|
068c5851ef | ||
|
|
af48dcd884 | ||
|
|
058806c241 | ||
|
|
48f6e33bf2 | ||
|
|
6a3ef42d37 | ||
|
|
f10a9d7f61 | ||
|
|
c315c04b9a | ||
|
|
f7893d4e4b | ||
|
|
2e2f7fa6c3 | ||
|
|
7aff64f877 | ||
|
|
0d05bc2676 | ||
|
|
131b350ee7 | ||
|
|
06651dbc4c | ||
|
|
0296247d82 | ||
|
|
79e767ba79 | ||
|
|
f771dee852 | ||
|
|
c4d8ef5954 | ||
|
|
5d6b97a63e | ||
|
|
c277ebb43e | ||
|
|
c9cd7b087a | ||
|
|
da7ff52a2f | ||
|
|
84e4a4bb52 | ||
|
|
34c9c5a9b1 | ||
|
|
e348e66f14 | ||
|
|
1e83614f8b | ||
|
|
c53647cd18 | ||
|
|
faa4e7753c | ||
|
|
220757be06 | ||
|
|
7f1013123a | ||
|
|
b1a7fe0f80 | ||
|
|
153e6b56ba | ||
|
|
35998df05c | ||
|
|
5176a8cb9e | ||
|
|
4892b648ae | ||
|
|
b4506c2b9b | ||
|
|
4373163869 | ||
|
|
4b8cde7b3b | ||
|
|
b7543c8a45 | ||
|
|
b5232886d9 | ||
|
|
aefd81228e | ||
|
|
03516e11f7 | ||
|
|
455a17cdb2 | ||
|
|
564ad09b98 | ||
|
|
135f6b0050 | ||
|
|
d5e79ff36c | ||
|
|
7a7f34746e | ||
|
|
6b4bbe625b | ||
|
|
28c0b2737b | ||
|
|
7684fb83d6 | ||
|
|
4d22608724 | ||
|
|
b7a42d61c4 | ||
|
|
bdaef7e541 | ||
|
|
854501385e | ||
|
|
7b875ed378 | ||
|
|
c930d6ddc0 | ||
|
|
aab2e4555a | ||
|
|
938eefae9b | ||
|
|
eccc5e6d61 | ||
|
|
bc96ca48b6 | ||
|
|
e5dd88cdce | ||
|
|
51acd4952b | ||
|
|
88e0da765c | ||
|
|
3ba708b98d | ||
|
|
dfb6216271 | ||
|
|
70387e6976 | ||
|
|
55fd781c77 | ||
|
|
36a0a240f9 | ||
|
|
ed0b507fb5 | ||
|
|
3a3948e74f | ||
|
|
c01dd232c5 | ||
|
|
825cc096c0 | ||
|
|
bcd574036e | ||
|
|
634fe64dca | ||
|
|
e33a0bf940 | ||
|
|
fb91d9b2d4 | ||
|
|
3d89588eb1 | ||
|
|
ac010cd7b2 | ||
|
|
d0c94ba565 | ||
|
|
adbeb4ae54 | ||
|
|
c7e1b47c59 | ||
|
|
b25e22bca4 | ||
|
|
6cb6a8ee98 | ||
|
|
223bd969fd | ||
|
|
ae46eeabef | ||
|
|
79c83a96a0 | ||
|
|
db33eb5b1f | ||
|
|
bc45f8f1d8 | ||
|
|
7875a96137 | ||
|
|
4875f5e275 | ||
|
|
7f9da22626 | ||
|
|
78098e612d | ||
|
|
e19ab9a0d5 | ||
|
|
ace45516d9 | ||
|
|
fe57bfce1b | ||
|
|
453cc0cc05 | ||
|
|
39009c482d | ||
|
|
6b942be1cd | ||
|
|
77aa2b6ba9 | ||
|
|
074d53fa17 | ||
|
|
a839ec4832 | ||
|
|
5119799256 | ||
|
|
176e18e4c0 | ||
|
|
b697df35c6 | ||
|
|
5236625485 | ||
|
|
f36073f5cd | ||
|
|
595fd9377c | ||
|
|
76f4c49e22 | ||
|
|
8c0592cdb7 | ||
|
|
0c73ecf6a8 | ||
|
|
c365fd9d74 | ||
|
|
aa8c587ac8 | ||
|
|
e9d9760e16 | ||
|
|
560f72a320 | ||
|
|
3425f2bf34 | ||
|
|
e28dbb3b93 | ||
|
|
1b3ed80d37 | ||
|
|
89a2e15cfb | ||
|
|
99b1282e98 | ||
|
|
ed753b590c | ||
|
|
bda095b0ec | ||
|
|
9d7f1d230c | ||
|
|
bdf0458780 | ||
|
|
7f973ad131 | ||
|
|
1f42070104 | ||
|
|
98e4ac6b27 | ||
|
|
8d318e7206 | ||
|
|
362156c8ab | ||
|
|
3ff23ade8b | ||
|
|
d9050dd8b9 | ||
|
|
bcee2c37d7 | ||
|
|
b8fcab29ac | ||
|
|
8ddae6bba0 | ||
|
|
fc9255cdc4 | ||
|
|
f725506df0 | ||
|
|
aa27b85538 | ||
|
|
afe75f8a89 | ||
|
|
b725d66ee3 | ||
|
|
fe3fb622ee | ||
|
|
e8bd114c01 | ||
|
|
b694bcf62a | ||
|
|
b0f933c926 | ||
|
|
2d12bc01de | ||
|
|
17b4ff7a1f | ||
|
|
6aff9f91d5 | ||
|
|
cac8fd93e4 | ||
|
|
f046abefbc | ||
|
|
b34e060b17 | ||
|
|
907be77ef4 | ||
|
|
373d12be64 | ||
|
|
bf45d55b4a | ||
|
|
2525429070 | ||
|
|
2513bcf2c6 | ||
|
|
bbffb6d901 | ||
|
|
3b7f5a1397 | ||
|
|
600e949628 | ||
|
|
235c123ad0 | ||
|
|
dcea584a9a | ||
|
|
d583adb958 | ||
|
|
0d96a0fb7c | ||
|
|
fb6b2cbfa2 | ||
|
|
eb65eafbe0 | ||
|
|
13f18492ad | ||
|
|
3d04541ee3 | ||
|
|
6ded0cce12 | ||
|
|
1ecbaf2c7f | ||
|
|
b0828a6280 | ||
|
|
d2ffb3ca9d | ||
|
|
606cd18dc4 | ||
|
|
8a713b2bbb | ||
|
|
c68f31a11c | ||
|
|
3107943af8 | ||
|
|
bf9360f374 | ||
|
|
f66c28a1bc | ||
|
|
5d6e214e0e | ||
|
|
ee8596d175 | ||
|
|
3c900814be | ||
|
|
52df963be9 | ||
|
|
8c513c2aad | ||
|
|
1e3834dc3d | ||
|
|
386b10a004 | ||
|
|
f697f3d7ad | ||
|
|
8d3ff16037 | ||
|
|
b10ab358da | ||
|
|
2cc6edd868 | ||
|
|
cac974b8e1 | ||
|
|
2c02e27197 | ||
|
|
85c0002a78 | ||
|
|
bd65bf2175 | ||
|
|
d70332f2a2 | ||
|
|
35b54e2f88 | ||
|
|
a3e1af72ab | ||
|
|
1313a44ba3 | ||
|
|
edbe8131ab | ||
|
|
ff55a305cd | ||
|
|
10c22efbb5 | ||
|
|
118bbfbcf7 | ||
|
|
e7709d8463 | ||
|
|
d70e421db3 | ||
|
|
0028c3c640 | ||
|
|
2594cb23c4 | ||
|
|
d975f6e23a | ||
|
|
5e46975c63 | ||
|
|
16f41fc4b4 | ||
|
|
1263f5e046 | ||
|
|
96713ef383 | ||
|
|
26a8686a54 | ||
|
|
57421d2392 | ||
|
|
63d92381ee | ||
|
|
2716f4cbe9 | ||
|
|
6ef4582ebd | ||
|
|
649ebb8a4e | ||
|
|
b1acf6088f | ||
|
|
78f5d80c5b | ||
|
|
5896b1eb71 | ||
|
|
559891ac43 | ||
|
|
1fbe1d1855 | ||
|
|
71473fd5c4 | ||
|
|
c7beacf3b9 | ||
|
|
3dc55ff8b5 | ||
|
|
b6789e0011 | ||
|
|
2f2bebe506 | ||
|
|
8bb70fb1b0 | ||
|
|
dfc99faea8 |
22
.devcontainer/Dockerfile
Normal file
@@ -0,0 +1,22 @@
|
||||
# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.148.1/containers/python-3/.devcontainer/base.Dockerfile
|
||||
|
||||
# [Choice] Python version: 3, 3.9, 3.8, 3.7, 3.6
|
||||
ARG VARIANT="3"
|
||||
FROM mcr.microsoft.com/vscode/devcontainers/python:0-${VARIANT}
|
||||
|
||||
# [Option] Install Node.js
|
||||
ARG INSTALL_NODE="true"
|
||||
ARG NODE_VERSION="lts/*"
|
||||
RUN if [ "${INSTALL_NODE}" = "true" ]; then su vscode -c "source /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi
|
||||
|
||||
# [Optional] If your pip requirements rarely change, uncomment this section to add them to the image.
|
||||
# COPY requirements.txt /tmp/pip-tmp/
|
||||
# RUN pip3 --disable-pip-version-check --no-cache-dir install -r /tmp/pip-tmp/requirements.txt \
|
||||
# && rm -rf /tmp/pip-tmp
|
||||
|
||||
# [Optional] Uncomment this section to install additional OS packages.
|
||||
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
||||
# && apt-get -y install --no-install-recommends <your-package-list-here>
|
||||
|
||||
# [Optional] Uncomment this line to install global node packages.
|
||||
# RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g <your-package-here>" 2>&1
|
||||
47
.devcontainer/devcontainer.json
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"name": "Python 3",
|
||||
"build": {
|
||||
"dockerfile": "Dockerfile",
|
||||
"context": "..",
|
||||
"args": {
|
||||
// Update 'VARIANT' to pick a Python version: 3, 3.6, 3.7, 3.8, 3.9
|
||||
"VARIANT": "3",
|
||||
// Options
|
||||
"INSTALL_NODE": "true",
|
||||
"NODE_VERSION": "lts/*"
|
||||
}
|
||||
},
|
||||
|
||||
// Set *default* container specific settings.json values on container create.
|
||||
"settings": {
|
||||
"terminal.integrated.shell.linux": "/bin/bash",
|
||||
"python.pythonPath": "/usr/local/bin/python",
|
||||
"python.linting.enabled": true,
|
||||
"python.linting.pylintEnabled": true,
|
||||
"python.formatting.autopep8Path": "/usr/local/py-utils/bin/autopep8",
|
||||
"python.formatting.blackPath": "/usr/local/py-utils/bin/black",
|
||||
"python.formatting.yapfPath": "/usr/local/py-utils/bin/yapf",
|
||||
"python.linting.banditPath": "/usr/local/py-utils/bin/bandit",
|
||||
"python.linting.flake8Path": "/usr/local/py-utils/bin/flake8",
|
||||
"python.linting.mypyPath": "/usr/local/py-utils/bin/mypy",
|
||||
"python.linting.pycodestylePath": "/usr/local/py-utils/bin/pycodestyle",
|
||||
"python.linting.pydocstylePath": "/usr/local/py-utils/bin/pydocstyle",
|
||||
"python.linting.pylintPath": "/usr/local/py-utils/bin/pylint"
|
||||
},
|
||||
|
||||
// Add the IDs of extensions you want installed when the container is created.
|
||||
"extensions": [
|
||||
"ms-python.python",
|
||||
"platformio.platformio-ide"
|
||||
],
|
||||
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||
// "forwardPorts": [],
|
||||
|
||||
// Use 'postCreateCommand' to run commands after the container is created.
|
||||
"postCreateCommand": "npm install",
|
||||
|
||||
// Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
|
||||
"remoteUser": "vscode"
|
||||
}
|
||||
|
||||
31
.github/workflows/wled-ci.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
name: PlatformIO CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-
|
||||
- name: Cache PlatformIO
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.platformio
|
||||
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
- name: Install PlatformIO
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install --upgrade platformio
|
||||
- name: Run PlatformIO
|
||||
run: pio run
|
||||
4
.gitignore
vendored
@@ -1,4 +1,5 @@
|
||||
.pio
|
||||
.cache
|
||||
.pioenvs
|
||||
.piolibdeps
|
||||
.vscode
|
||||
@@ -6,7 +7,10 @@
|
||||
/wled00/Release
|
||||
/wled00/extLibs
|
||||
/platformio_override.ini
|
||||
/wled00/my_config.h
|
||||
/build_output
|
||||
.DS_Store
|
||||
.gitignore
|
||||
.clang-format
|
||||
node_modules
|
||||
.idea
|
||||
|
||||
5
.gitpod.Dockerfile
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
FROM gitpod/workspace-full
|
||||
|
||||
USER gitpod
|
||||
|
||||
RUN pip3 install -U platformio
|
||||
12
.gitpod.yml
Normal file
@@ -0,0 +1,12 @@
|
||||
tasks:
|
||||
- command: platformio run
|
||||
|
||||
image:
|
||||
file: .gitpod.Dockerfile
|
||||
|
||||
vscode:
|
||||
extensions:
|
||||
- ms-vscode.cpptools@0.26.3:u3GsZ5PK12Ddr79vh4TWgQ==
|
||||
- eamodio.gitlens@10.2.1:e0IYyp0efFqVsrZwsIe8CA==
|
||||
- Atishay-Jain.All-Autocomplete@0.0.23:fbZNfSpnd8XkAHGfAPS2rA==
|
||||
- 2gua.rainbow-brackets@0.0.6:Tbu8dTz0i+/bgcKQTQ5b8g==
|
||||
43
.travis.yml
@@ -1,43 +0,0 @@
|
||||
# Continuous Integration (CI) is the practice, in software
|
||||
# engineering, of merging all developer working copies with a shared mainline
|
||||
# several times a day < https://docs.platformio.org/page/ci/index.html >
|
||||
#
|
||||
# Documentation:
|
||||
#
|
||||
# * Travis CI Embedded Builds with PlatformIO
|
||||
# < https://docs.travis-ci.com/user/integration/platformio/ >
|
||||
#
|
||||
# * PlatformIO integration with Travis CI
|
||||
# < https://docs.platformio.org/page/ci/travis.html >
|
||||
#
|
||||
# * User Guide for `platformio ci` command
|
||||
# < https://docs.platformio.org/page/userguide/cmd_ci.html >
|
||||
#
|
||||
#
|
||||
# Please choose one of the following templates (proposed below) and uncomment
|
||||
# it (remove "# " before each line) or use own configuration according to the
|
||||
# Travis CI documentation (see above).
|
||||
#
|
||||
# * Test the Travis config here:
|
||||
# < https://config.travis-ci.com/explore >
|
||||
#
|
||||
|
||||
language: python
|
||||
python:
|
||||
# - "2.7"
|
||||
- "3.5"
|
||||
os: linux
|
||||
cache:
|
||||
bundler: true
|
||||
ccache: true
|
||||
directories:
|
||||
- "~/.platformio"
|
||||
- "~/.buildcache"
|
||||
env:
|
||||
- PLATFORMIO_CI_SRC=wled00
|
||||
install:
|
||||
- pip install -U platformio
|
||||
- platformio update
|
||||
script:
|
||||
# - platformio ci --project-conf=./platformio.ini
|
||||
- platformio run
|
||||
42
.vscode/tasks.json
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Build: HTML and binary",
|
||||
"dependsOn": [
|
||||
"Build: HTML only",
|
||||
"Build: binary only"
|
||||
],
|
||||
"dependsOrder": "sequence",
|
||||
"problemMatcher": [
|
||||
"$platformio",
|
||||
],
|
||||
},
|
||||
{
|
||||
"type": "PlatformIO",
|
||||
"label": "Build: binary only",
|
||||
"task": "Build",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true,
|
||||
},
|
||||
"problemMatcher": [
|
||||
"$platformio"
|
||||
],
|
||||
"presentation": {
|
||||
"panel": "shared"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "build",
|
||||
"group": "build",
|
||||
"problemMatcher": [],
|
||||
"label": "Build: HTML only",
|
||||
"detail": "npm run build",
|
||||
"presentation": {
|
||||
"panel": "shared"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
373
CHANGELOG.md
@@ -1,5 +1,378 @@
|
||||
## WLED changelog
|
||||
|
||||
### WLED release 0.12.0
|
||||
|
||||
#### Build 2104020
|
||||
|
||||
- Allow clearing button/IR/relay pin on platforms that don't support negative numbers
|
||||
- Removed AUX pin
|
||||
- Hid some easter eggs, only to be found at easter
|
||||
|
||||
### Development versions between 0.11.1 and 0.12.0 releases
|
||||
|
||||
#### Build 2103310
|
||||
|
||||
- Version bump to 0.12.0 "Hikari"
|
||||
- Fixed LED settings submission in iOS app
|
||||
|
||||
#### Build 2103300
|
||||
|
||||
- Version bump to 0.12.0-b5 "Hikari"
|
||||
- Update to core espressif32@3.2
|
||||
- Fixed IR pin not configurable
|
||||
|
||||
#### Build 2103290
|
||||
|
||||
- Version bump to 0.12.0-b4 "Hikari"
|
||||
- Experimental use of espressif32@3.1.1
|
||||
- Fixed RGBW mode disabled after LED settings saved
|
||||
- Fixed infrared support not compiled in if IRPIN is not defined
|
||||
|
||||
#### Build 2103230
|
||||
|
||||
- Fixed current estimation
|
||||
|
||||
#### Build 2103220
|
||||
|
||||
- Version bump to 0.12.0-b2 "Hikari"
|
||||
- Worked around an issue causing a critical decrease in framerate (wled.cpp l.240 block)
|
||||
- Bump to Espalexa v2.7.0, fixing discovery
|
||||
|
||||
#### Build 2103210
|
||||
|
||||
- Version bump to 0.12.0-b1 "Hikari"
|
||||
- More colors visible on Palette preview
|
||||
- Fixed chevron icon not included
|
||||
- Fixed color order override
|
||||
- Cleanup
|
||||
|
||||
#### Build 2103200
|
||||
|
||||
- Version bump to 0.12.0-b0 "Hikari"
|
||||
- Added palette preview and search (PR #1637)
|
||||
- Added Reverse checkbox for PWM busses - reverses logic level for on
|
||||
- Fixed various problems with the Playlist feature (PR #1724)
|
||||
- Replaced "Layer" icon with "i" icon for Info button
|
||||
- Chunchun effect more fitting for various segment lengths (PR #1804)
|
||||
- Removed global reverse (in favor of individual bus reverse)
|
||||
- Removed some unused icons from UI icon font
|
||||
|
||||
#### Build 2103130
|
||||
|
||||
- Added options for Auto Node discovery
|
||||
- Optimized strings (no string both F() and raw)
|
||||
|
||||
#### Build 2103090
|
||||
|
||||
- Added Auto Node discovery (PR #1683)
|
||||
- Added tooltips to quick color selectors for accessibility
|
||||
|
||||
#### Build 2103060
|
||||
|
||||
- Auto start field population in bus config
|
||||
|
||||
#### Build 2103050
|
||||
|
||||
- Fixed incorrect over-memory indication in LED settings on ESP32
|
||||
|
||||
#### Build 2103041
|
||||
|
||||
- Added destructor for BusPwm (fixes #1789)
|
||||
|
||||
#### Build 2103040
|
||||
|
||||
- Fixed relay mode inverted when upgrading from 0.11.0
|
||||
- Fixed no more than 2 pins per bus configurable in UI
|
||||
- Changed to non-linear IR brightness steps (PR #1742)
|
||||
- Fixed various warnings (PR #1744)
|
||||
- Added UDP DNRGBW Mode (PR #1704)
|
||||
- Added dynamic LED mapping with ledmap.json file (PR #1738)
|
||||
- Added support for QuinLED-ESP32-Ethernet board
|
||||
- Added support for WESP32 ethernet board (PR #1764)
|
||||
- Added Caching for main UI (PR #1704)
|
||||
- Added Tetrix mode (PR #1729)
|
||||
- Added memory check on Bus creation
|
||||
|
||||
#### Build 2102050
|
||||
|
||||
- Version bump to 0.12.0-a0 "Hikari"
|
||||
- Added FPS indication in info
|
||||
- Bumped max outputs from 7 to 10 busses for ESP32
|
||||
|
||||
#### Build 2101310
|
||||
|
||||
- First alpha configurable multipin
|
||||
|
||||
#### Build 2101130
|
||||
|
||||
- Added color transitions for all segments and slots and for segment brightness
|
||||
- Fixed bug that prevented setting a boot preset higher than 25
|
||||
|
||||
#### Build 2101040
|
||||
|
||||
- Replaced Red & Blue effect with Aurora effect (PR #1589)
|
||||
- Fixed HTTP changing segments uncommanded (#1618)
|
||||
- Updated copyright year and contributor page link
|
||||
|
||||
#### Build 2012311
|
||||
|
||||
- Fixed Countdown mode
|
||||
|
||||
#### Build 2012310
|
||||
|
||||
- (Hopefully actually) fixed display of usermod values in info screen
|
||||
|
||||
#### Build 2012240
|
||||
|
||||
- Fixed display of usermod values in info screen
|
||||
- 4 more effects now use FRAMETIME
|
||||
- Remove unsupported environments from platformio.ini
|
||||
|
||||
#### Build 2012210
|
||||
|
||||
- Split index.htm in separate CSS + JS files (PR #1542)
|
||||
- Minify UI HTML, saving >1.5kB flash
|
||||
- Fixed JShint warnings
|
||||
|
||||
#### Build 2012180
|
||||
|
||||
- Boot brightness 0 will now use the brightness from preset
|
||||
- Add iOS scrolling momentum (from PR #1528)
|
||||
|
||||
### WLED release 0.11.1
|
||||
|
||||
#### Build 2012180
|
||||
|
||||
- Release of WLED 0.11.1 "Mirai"
|
||||
- Fixed AP hide not saving (fixes #1520)
|
||||
- Fixed MQTT password re-transmitted to HTML
|
||||
- Hide Update buttons while uploading, accept .bin
|
||||
- Make sure AP password is at least 8 characters long
|
||||
|
||||
### Development versions after 0.11.0 release
|
||||
|
||||
#### Build 2012160
|
||||
|
||||
- Bump Espalexa to 2.5.0, fixing discovery (PR Espalexa/#152, originally PR #1497)
|
||||
|
||||
#### Build 2012150
|
||||
|
||||
- Added Blends FX (PR #1491)
|
||||
- Fixed an issue that made it impossible to deactivate timed presets
|
||||
|
||||
#### Build 2012140
|
||||
|
||||
- Added Preset ID quick display option (PR #1462)
|
||||
- Fixed LEDs not turning on when using gamma correct brightness and LEDPIN 2 (default)
|
||||
- Fixed notifier applying main segment to selected segments on notification with FX/Col disabled
|
||||
|
||||
#### Build 2012130
|
||||
|
||||
- Fixed RGBW mode not saved between reboots (fixes #1457)
|
||||
- Added brightness scaling in palette function for default (PR #1484)
|
||||
|
||||
#### Build 2012101
|
||||
|
||||
- Fixed preset cycle default duration rounded down to nearest 10sec interval (#1458)
|
||||
- Enabled E1.31/DDP/Art-Net in AP mode
|
||||
|
||||
#### Build 2012100
|
||||
|
||||
- Fixed multi-segment preset cycle
|
||||
- Fixed EEPROM (pre-0.11 settings) not cleared on factory reset
|
||||
- Fixed an issue with intermittent crashes on FX change (PR #1465)
|
||||
- Added function to know if strip is updating (PR #1466)
|
||||
- Fixed using colorwheel sliding the UI (PR #1459)
|
||||
- Fixed analog clock settings not saving (PR #1448)
|
||||
- Added Temperature palette (PR #1430)
|
||||
- Added Candy cane FX (PR #1445)
|
||||
|
||||
#### Build 2012020
|
||||
|
||||
- UDP `parsePacket()` with sync disabled (#1390)
|
||||
- Added Multi RGBW DMX mode (PR #1383)
|
||||
|
||||
#### Build 2012010
|
||||
|
||||
- Fixed compilation for analog (PWM) LEDs
|
||||
|
||||
### WLED version 0.11.0
|
||||
|
||||
#### Build 2011290
|
||||
|
||||
- Release of WLED 0.11.0 "Mirai"
|
||||
- Workaround for weird empty %f Espalexa issue
|
||||
- Fixed crash on saving preset with HTTP API `PS`
|
||||
- Improved performance for color changes in non-main segment
|
||||
|
||||
#### Build 2011270
|
||||
|
||||
- Added tooltips for speed and intensity sliders (PR #1378)
|
||||
- Moved color order to NpbWrapper.h
|
||||
- Added compile time define to override the color order for a specific range
|
||||
|
||||
#### Build 2011260
|
||||
|
||||
- Add `live` property to state, allowing toggling of realtime (not incl. in state resp.)
|
||||
- PIO environment changes
|
||||
|
||||
#### Build 2011230
|
||||
|
||||
- Version bump to 0.11.0 "Mirai"
|
||||
- Improved preset name sorting
|
||||
- Fixed Preset cycle not working beyond preset 16
|
||||
|
||||
### Development versions between 0.10.2 and 0.11.0 releases
|
||||
|
||||
#### Build 2011220
|
||||
|
||||
- Fixed invalid save when modifying preset before refresh (might be related to #1361)
|
||||
- Fixed brightness factor ignored on realtime timeout (fixes #1363)
|
||||
- Fixed Phase and Chase effects with LED counts >256 (PR #1366)
|
||||
|
||||
#### Build 2011210
|
||||
|
||||
- Fixed Brightness slider beneath color wheel not working (fixes #1360)
|
||||
- Fixed invalid UI state after saving modified preset
|
||||
|
||||
#### Build 2011200
|
||||
|
||||
- Added HEX color receiving to JSON API with `"col":["RRGGBBWW"]` format
|
||||
- Moved Kelvin color receiving in JSON API from `"col":[[val]]` to `"col":[val]` format
|
||||
_Notice:_ This is technically a breaking change. Since no release was made since the introduction and the Kelvin property was not previously documented in the wiki,
|
||||
impact should be minimal.
|
||||
- BTNPIN can now be disabled by setting to -1 (fixes #1237)
|
||||
|
||||
#### Build 2011180
|
||||
|
||||
- Platformio.ini updates and streamlining (PR #1266)
|
||||
- my_config.h custom compile settings system (not yet used for much, adapted from PR #1266)
|
||||
- Added Hawaii timezone (HST)
|
||||
- Linebreak after 5 quick select buttons
|
||||
|
||||
#### Build 2011154
|
||||
|
||||
- Fixed RGBW saved incorrectly
|
||||
- Fixed pmt caching requesting /presets.json too often
|
||||
- Fixed deEEP not copying the first segment of EEPROM preset 16
|
||||
|
||||
#### Build 2011153
|
||||
|
||||
- Fixed an ESP32 end-of-file issue
|
||||
- Fixed strip.isRgbw not read from cfg.json
|
||||
|
||||
#### Build 2011152
|
||||
|
||||
- Version bump to 0.11.0p "Mirai"
|
||||
- Increased max. num of segments to 12 (ESP8266) / 16 (ESP32)
|
||||
- Up to 250 presets stored in the `presets.json` file in filesystem
|
||||
- Complete overhaul of the Presets UI tab
|
||||
- Updated iro.js to v5 (fixes black color wheel)
|
||||
- Added white temperature slider to color wheel
|
||||
- Add JSON settings serialization/deserialization to cfg.json and wsec.json
|
||||
- Added deEEP to convert the EEPROM settings and presets to files
|
||||
- Playlist support - JSON only for now
|
||||
- New v2 usermod methods `addToConfig()` and `readFromConfig()` (see EXAMPLE_v2 for doc)
|
||||
- Added Ethernet support for ESP32 (PR #1316)
|
||||
- IP addresses are now handled by the `Network` class
|
||||
- New `esp32_poe` PIO environment
|
||||
- Use EspAsyncWebserver Aircoookie fork v.2.0.0 (hiding wsec.json)
|
||||
- Removed `WLED_DISABLE_FILESYSTEM` and `WLED_ENABLE_FS_SERVING` defines as they are now required
|
||||
- Added pin manager
|
||||
- UI performance improvements (no drop shadows)
|
||||
- More explanatory error messages in UI
|
||||
- Improved candle brightness
|
||||
- Return remaining nightlight time `nl.rem` in JSON API (PR #1302)
|
||||
- UI sends timestamp with every command, allowing for timed presets without using NTP
|
||||
- Added gamma calculation (yet unused)
|
||||
- Added LED type definitions to const.h (yet unused)
|
||||
- Added nicer 404 page
|
||||
- Removed `NP` and `MS=` macro HTTP API commands
|
||||
- Removed macros from Time settings
|
||||
|
||||
#### Build 2011120
|
||||
|
||||
- Added the ability for the /api MQTT topic to receive JSON API payloads
|
||||
|
||||
#### Build 2011040
|
||||
|
||||
- Inversed Rain direction (fixes #1147)
|
||||
|
||||
#### Build 2011010
|
||||
|
||||
- Re-added previous C9 palette
|
||||
- Renamed new C9 palette
|
||||
|
||||
#### Build 2010290
|
||||
|
||||
- Colorful effect now supports palettes
|
||||
- Added C9 2 palette (#1291)
|
||||
- Improved C9 palette brightness by 12%
|
||||
- Disable onboard LED if LEDs are off (PR #1245)
|
||||
- Added optional status LED (PR #1264)
|
||||
- Realtime max. brightness now honors brightness factor (fixes #1271)
|
||||
- Updated ArduinoJSON to 6.17.0
|
||||
|
||||
#### Build 2010020
|
||||
|
||||
- Fixed interaction of `T` and `NL` HTTP API commands (#1214)
|
||||
- Fixed an issue where Sunrise mode nightlight does not activate if toggled on simultaneously
|
||||
|
||||
#### Build 2009291
|
||||
|
||||
- Fixed MQTT bootloop (no F() macro, #1199)
|
||||
|
||||
#### Build 2009290
|
||||
|
||||
- Added basic DDP protocol support
|
||||
- Added Washing Machine effect (PR #1208)
|
||||
|
||||
#### Build 2009260
|
||||
|
||||
- Added Loxone parser (PR #1185)
|
||||
- Added support for kelvin input via `K=` HTTP and `"col":[[val]]` JSON API calls
|
||||
_Notice:_ `"col":[[val]]` removed in build 2011200, use `"col":[val]`
|
||||
- Added supplementary UDP socket (#1205)
|
||||
- TMP2.net receivable by default
|
||||
- UDP sockets accept HTTP and JSON API commands
|
||||
- Fixed missing timezones (#1201)
|
||||
|
||||
#### Build 2009202
|
||||
|
||||
- Fixed LPD8806 compilation
|
||||
|
||||
#### Build 2009201
|
||||
|
||||
- Added support for preset cycle toggling using CY=2
|
||||
- Added ESP32 touch pin support (#1190)
|
||||
- Fixed modem sleep on ESP8266 (#1184)
|
||||
|
||||
#### Build 2009200
|
||||
|
||||
- Increased available heap memory by 4kB
|
||||
- Use F() macro for the majority of strings
|
||||
- Restructure timezone code
|
||||
- Restructured settings saved code
|
||||
- Updated ArduinoJSON to 6.16.1
|
||||
|
||||
#### Build 2009170
|
||||
|
||||
- New WLED logo on Welcome screen (#1164)
|
||||
- Fixed 170th pixel dark in E1.31
|
||||
|
||||
#### Build 2009100
|
||||
|
||||
- Fixed sunrise mode not reinitializing
|
||||
- Fixed passwords not clearable
|
||||
|
||||
#### Build 2009070
|
||||
|
||||
- New Segments are now initialized with default speed and intensity
|
||||
|
||||
#### Build 2009030
|
||||
|
||||
- Fixed bootloop if mDNS is used on builds without OTA support
|
||||
|
||||
### WLED version 0.10.2
|
||||
|
||||
#### Build 2008310
|
||||
|
||||
5
images/Readme.md
Normal file
@@ -0,0 +1,5 @@
|
||||
### Additional Logos
|
||||
|
||||
Additional awesome logos for WLED can be found here [Aircoookie/Akemi](https://github.com/Aircoookie/Akemi).
|
||||
|
||||
<img src="https://github.com/Aircoookie/Akemi/blob/master/akemi/001_cheerful.png">
|
||||
|
Before Width: | Height: | Size: 490 KiB After Width: | Height: | Size: 489 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 602 B |
179
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wled",
|
||||
"version": "0.10.2",
|
||||
"version": "0.11.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -239,6 +239,11 @@
|
||||
"fill-range": "^7.0.1"
|
||||
}
|
||||
},
|
||||
"buffer-from": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
|
||||
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
|
||||
},
|
||||
"cacheable-request": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz",
|
||||
@@ -268,15 +273,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"camel-case": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz",
|
||||
"integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=",
|
||||
"requires": {
|
||||
"no-case": "^2.2.0",
|
||||
"upper-case": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"camelcase": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz",
|
||||
@@ -566,6 +562,34 @@
|
||||
"domelementtype": "1"
|
||||
}
|
||||
},
|
||||
"dot-case": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.3.tgz",
|
||||
"integrity": "sha512-7hwEmg6RiSQfm/GwPL4AAWXKy3YNNZA3oFv2Pdiey0mwkRCPZ9x6SZbkLcn8Ma5PYeVokzoD4Twv2n7LKp5WeA==",
|
||||
"requires": {
|
||||
"no-case": "^3.0.3",
|
||||
"tslib": "^1.10.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"lower-case": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.1.tgz",
|
||||
"integrity": "sha512-LiWgfDLLb1dwbFQZsSglpRj+1ctGnayXz3Uv0/WO8n558JycT5fg6zkNcnW0G68Nn0aEldTFeEfmjCfmqry/rQ==",
|
||||
"requires": {
|
||||
"tslib": "^1.10.0"
|
||||
}
|
||||
},
|
||||
"no-case": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.3.tgz",
|
||||
"integrity": "sha512-ehY/mVQCf9BL0gKfsJBvFJen+1V//U+0HQMPrWct40ixE4jnv0bfvxDbWtAHL9EcaPEOJHVVYKoQn1TlZUB8Tw==",
|
||||
"requires": {
|
||||
"lower-case": "^2.0.1",
|
||||
"tslib": "^1.10.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"dot-prop": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.2.0.tgz",
|
||||
@@ -818,26 +842,41 @@
|
||||
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
|
||||
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
|
||||
},
|
||||
"html-minifier": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-4.0.0.tgz",
|
||||
"integrity": "sha512-aoGxanpFPLg7MkIl/DDFYtb0iWz7jMFGqFhvEDZga6/4QTjneiD8I/NXL1x5aaoCp7FSIT6h/OhykDdPsbtMig==",
|
||||
"html-minifier-terser": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz",
|
||||
"integrity": "sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg==",
|
||||
"requires": {
|
||||
"camel-case": "^3.0.0",
|
||||
"clean-css": "^4.2.1",
|
||||
"commander": "^2.19.0",
|
||||
"camel-case": "^4.1.1",
|
||||
"clean-css": "^4.2.3",
|
||||
"commander": "^4.1.1",
|
||||
"he": "^1.2.0",
|
||||
"param-case": "^2.1.1",
|
||||
"param-case": "^3.0.3",
|
||||
"relateurl": "^0.2.7",
|
||||
"uglify-js": "^3.5.1"
|
||||
"terser": "^4.6.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"uglify-js": {
|
||||
"version": "3.9.3",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.9.3.tgz",
|
||||
"integrity": "sha512-r5ImcL6QyzQGVimQoov3aL2ZScywrOgBXGndbWrdehKoSvGe/RmiE5Jpw/v+GvxODt6l2tpBXwA7n+qZVlHBMA==",
|
||||
"camel-case": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.1.tgz",
|
||||
"integrity": "sha512-7fa2WcG4fYFkclIvEmxBbTvmibwF2/agfEBc6q3lOpVu0A13ltLsA+Hr/8Hp6kp5f+G7hKi6t8lys6XxP+1K6Q==",
|
||||
"requires": {
|
||||
"commander": "~2.20.3"
|
||||
"pascal-case": "^3.1.1",
|
||||
"tslib": "^1.10.0"
|
||||
}
|
||||
},
|
||||
"commander": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
|
||||
"integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="
|
||||
},
|
||||
"param-case": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.3.tgz",
|
||||
"integrity": "sha512-VWBVyimc1+QrzappRs7waeN2YmoZFCGXWASRYX1/rGHtXqEcrGEIDm+jqIwFa2fRXNgQEwrxaYuIrX0WcAguTA==",
|
||||
"requires": {
|
||||
"dot-case": "^3.0.3",
|
||||
"tslib": "^1.10.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -919,9 +958,9 @@
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
|
||||
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
|
||||
"version": "1.3.8",
|
||||
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
|
||||
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="
|
||||
},
|
||||
"inliner": {
|
||||
"version": "1.13.1",
|
||||
@@ -1248,11 +1287,6 @@
|
||||
"resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz",
|
||||
"integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc="
|
||||
},
|
||||
"lower-case": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz",
|
||||
"integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw="
|
||||
},
|
||||
"lowercase-keys": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
|
||||
@@ -1330,14 +1364,6 @@
|
||||
"inherits": "~2.0.1"
|
||||
}
|
||||
},
|
||||
"no-case": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz",
|
||||
"integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==",
|
||||
"requires": {
|
||||
"lower-case": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"nodemon": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.4.tgz",
|
||||
@@ -1609,12 +1635,32 @@
|
||||
"registry-url": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"param-case": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz",
|
||||
"integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=",
|
||||
"pascal-case": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.1.tgz",
|
||||
"integrity": "sha512-XIeHKqIrsquVTQL2crjq3NfJUxmdLasn3TYOU0VBM+UX2a6ztAWBlJQBePLGY7VHW8+2dRadeIPK5+KImwTxQA==",
|
||||
"requires": {
|
||||
"no-case": "^2.2.0"
|
||||
"no-case": "^3.0.3",
|
||||
"tslib": "^1.10.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"lower-case": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.1.tgz",
|
||||
"integrity": "sha512-LiWgfDLLb1dwbFQZsSglpRj+1ctGnayXz3Uv0/WO8n558JycT5fg6zkNcnW0G68Nn0aEldTFeEfmjCfmqry/rQ==",
|
||||
"requires": {
|
||||
"tslib": "^1.10.0"
|
||||
}
|
||||
},
|
||||
"no-case": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.3.tgz",
|
||||
"integrity": "sha512-ehY/mVQCf9BL0gKfsJBvFJen+1V//U+0HQMPrWct40ixE4jnv0bfvxDbWtAHL9EcaPEOJHVVYKoQn1TlZUB8Tw==",
|
||||
"requires": {
|
||||
"lower-case": "^2.0.1",
|
||||
"tslib": "^1.10.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"performance-now": {
|
||||
@@ -1893,6 +1939,22 @@
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
|
||||
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
|
||||
},
|
||||
"source-map-support": {
|
||||
"version": "0.5.19",
|
||||
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
|
||||
"integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
|
||||
"requires": {
|
||||
"buffer-from": "^1.0.0",
|
||||
"source-map": "^0.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"sprintf-js": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
||||
@@ -2004,6 +2066,23 @@
|
||||
"resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.0.tgz",
|
||||
"integrity": "sha512-a6sumDlzyHVJWb8+YofY4TW112G6p2FCPEAFk+59gIYHv3XHRhm9ltVQ9kli4hNWeQBwSpe8cRN25x0ROunMOw=="
|
||||
},
|
||||
"terser": {
|
||||
"version": "4.8.0",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz",
|
||||
"integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==",
|
||||
"requires": {
|
||||
"commander": "^2.20.0",
|
||||
"source-map": "~0.6.1",
|
||||
"source-map-support": "~0.5.12"
|
||||
},
|
||||
"dependencies": {
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"then-fs": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/then-fs/-/then-fs-2.0.0.tgz",
|
||||
@@ -2047,6 +2126,11 @@
|
||||
"punycode": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"tunnel-agent": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
|
||||
@@ -2119,11 +2203,6 @@
|
||||
"string-length": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"upper-case": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz",
|
||||
"integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg="
|
||||
},
|
||||
"uri-js": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wled",
|
||||
"version": "0.10.2",
|
||||
"version": "0.12.0",
|
||||
"description": "Tools for WLED project",
|
||||
"main": "tools/cdata.js",
|
||||
"directories": {
|
||||
@@ -23,7 +23,7 @@
|
||||
"homepage": "https://github.com/Aircoookie/WLED#readme",
|
||||
"dependencies": {
|
||||
"clean-css": "^4.2.3",
|
||||
"html-minifier": "^4.0.0",
|
||||
"html-minifier-terser": "^5.1.1",
|
||||
"inliner": "^1.13.1",
|
||||
"nodemon": "^2.0.4",
|
||||
"zlib": "^1.0.5"
|
||||
|
||||
23
pio-scripts/gzip-firmware.py
Normal file
@@ -0,0 +1,23 @@
|
||||
Import('env')
|
||||
import os
|
||||
import shutil
|
||||
import gzip
|
||||
|
||||
OUTPUT_DIR = "build_output{}".format(os.path.sep)
|
||||
|
||||
def bin_gzip(source, target, env):
|
||||
variant = str(target[0]).split(os.path.sep)[2]
|
||||
|
||||
# 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:
|
||||
shutil.copyfileobj(fp, f)
|
||||
|
||||
env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", [bin_gzip])
|
||||
34
pio-scripts/name-firmware.py
Normal file
@@ -0,0 +1,34 @@
|
||||
Import('env')
|
||||
import os
|
||||
import shutil
|
||||
|
||||
OUTPUT_DIR = "build_output{}".format(os.path.sep)
|
||||
|
||||
def bin_rename_copy(source, target, env):
|
||||
variant = str(target[0]).split(os.path.sep)[2]
|
||||
|
||||
# check if output directories exist and create if necessary
|
||||
if not os.path.isdir(OUTPUT_DIR):
|
||||
os.mkdir(OUTPUT_DIR)
|
||||
|
||||
for d in ['firmware', 'map']:
|
||||
if not os.path.isdir("{}{}".format(OUTPUT_DIR, d)):
|
||||
os.mkdir("{}{}".format(OUTPUT_DIR, d))
|
||||
|
||||
# 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)
|
||||
|
||||
# copy firmware.map to map/<variant>.map
|
||||
if os.path.isfile("firmware.map"):
|
||||
shutil.move("firmware.map", map_file)
|
||||
|
||||
env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", [bin_rename_copy])
|
||||
9
pio-scripts/obj-dump.py
Normal file
@@ -0,0 +1,9 @@
|
||||
# Little convenience script to get an object dump
|
||||
|
||||
Import('env')
|
||||
|
||||
def obj_dump_after_elf(source, target, env):
|
||||
print("Create firmware.asm")
|
||||
env.Execute("xtensa-lx106-elf-objdump "+ "-D " + str(target[0]) + " > "+ "${PROGNAME}.asm")
|
||||
|
||||
env.AddPostAction("$BUILD_DIR/${PROGNAME}.elf", [obj_dump_after_elf])
|
||||
15
pio-scripts/strip-floats.py
Normal file
@@ -0,0 +1,15 @@
|
||||
Import('env')
|
||||
|
||||
#
|
||||
# Dump build environment (for debug)
|
||||
#print env.Dump()
|
||||
#
|
||||
|
||||
flags = " ".join(env['LINKFLAGS'])
|
||||
flags = flags.replace("-u _printf_float", "")
|
||||
flags = flags.replace("-u _scanf_float", "")
|
||||
newflags = flags.split()
|
||||
|
||||
env.Replace(
|
||||
LINKFLAGS=newflags
|
||||
)
|
||||
9
pio-scripts/user_config_copy.py
Normal file
@@ -0,0 +1,9 @@
|
||||
Import('env')
|
||||
import os
|
||||
import shutil
|
||||
|
||||
# copy WLED00/my_config_sample.h to WLED00/my_config.h
|
||||
if os.path.isfile("wled00/my_config.h"):
|
||||
print ("*** use existing my_config.h ***")
|
||||
else:
|
||||
shutil.copy("wled00/my_config_sample.h", "wled00/my_config.h")
|
||||
346
platformio.ini
@@ -2,29 +2,20 @@
|
||||
; Please visit documentation: https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[platformio]
|
||||
src_dir = ./wled00
|
||||
data_dir = ./wled00/data
|
||||
lib_dir = ./wled00/src
|
||||
build_cache_dir = ~/.buildcache
|
||||
extra_configs =
|
||||
platformio_override.ini
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# ENVIRONMENTS
|
||||
#
|
||||
# Please uncomment one of the lines below to select your board(s)
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# Travis CI binaries
|
||||
default_envs = travis_esp8266, travis_esp32
|
||||
# Travis CI binaries (comment this out with a ';' when building for your own board)
|
||||
;default_envs = travis_esp8266, travis_esp32
|
||||
|
||||
# Release binaries
|
||||
; default_envs = nodemcuv2, esp01_1m_full, esp32dev, custom_WS2801, custom_APA102, custom_LEDPIN_16, custom_LEDPIN_4, custom_LEDPIN_3, custom32_LEDPIN_16
|
||||
default_envs = nodemcuv2, esp01_1m_full, esp32dev, esp32_eth
|
||||
|
||||
# Single binaries (uncomment your board)
|
||||
; default_envs = nodemcuv2
|
||||
; default_envs = esp01
|
||||
; default_envs = esp01_1m_ota
|
||||
; default_envs = esp01_1m_full
|
||||
; default_envs = esp07
|
||||
; default_envs = d1_mini
|
||||
@@ -39,37 +30,23 @@ default_envs = travis_esp8266, travis_esp32
|
||||
; default_envs = d1_mini_5CH_Shojo_PCB
|
||||
; default_envs = wemos_shield_esp32
|
||||
; default_envs = m5atom
|
||||
; default_envs = esp32_eth
|
||||
|
||||
src_dir = ./wled00
|
||||
data_dir = ./wled00/data
|
||||
build_cache_dir = ~/.buildcache
|
||||
extra_configs =
|
||||
platformio_override.ini
|
||||
|
||||
[common]
|
||||
# ------------------------------------------------------------------------------
|
||||
# PLATFORM:
|
||||
# !! DO NOT confuse platformio's ESP8266 development platform with Arduino core for ESP8266
|
||||
#
|
||||
# arduino core 2.3.0 = platformIO 1.5.0
|
||||
# arduino core 2.4.0 = platformIO 1.6.0
|
||||
# arduino core 2.4.1 = platformIO 1.7.3
|
||||
# arduino core 2.4.2 = platformIO 1.8.0
|
||||
# arduino core 2.5.0 = platformIO 2.0.4
|
||||
# arduino core 2.5.1 = platformIO 2.1.1
|
||||
# arduino core 2.5.2 = platformIO 2.2.3
|
||||
# arduino core 2.6.1 = platformIO 2.3.0
|
||||
# arduino core 2.6.2 = platformIO 2.3.1
|
||||
# arduino core 2.6.3 = platformIO 2.3.2
|
||||
# arduino core 2.7.0 = platformIO 2.5.0
|
||||
# ------------------------------------------------------------------------------
|
||||
arduino_core_2_3_0 = espressif8266@1.5.0
|
||||
arduino_core_2_4_0 = espressif8266@1.6.0
|
||||
arduino_core_2_4_1 = espressif8266@1.7.3
|
||||
arduino_core_2_4_2 = espressif8266@1.8.0
|
||||
arduino_core_2_5_0 = espressif8266@2.0.4
|
||||
arduino_core_2_5_1 = espressif8266@2.1.1
|
||||
arduino_core_2_5_2 = espressif8266@2.2.3
|
||||
arduino_core_2_6_1 = espressif8266@2.3.0
|
||||
arduino_core_2_6_2 = espressif8266@2.3.1
|
||||
arduino_core_2_6_3 = espressif8266@2.3.3
|
||||
arduino_core_2_7_1 = espressif8266@2.5.1
|
||||
arduino_core_2_7_2 = espressif8266@2.6.0
|
||||
arduino_core_2_7_3 = espressif8266@2.6.1
|
||||
arduino_core_2_7_4 = espressif8266@2.6.2
|
||||
|
||||
# Development platforms
|
||||
@@ -78,8 +55,11 @@ arduino_core_git = https://github.com/platformio/platform-espressif8266#feature/
|
||||
|
||||
# Platform to use for ESP8266
|
||||
platform_wled_default = ${common.arduino_core_2_7_4}
|
||||
# We use 2.7.0+ on analog boards because of PWM flicker fix
|
||||
platform_latest = ${common.arduino_core_2_7_4}
|
||||
# We use 2.7.4.7 for all, includes PWM flicker fix and Wstring optimization
|
||||
platform_packages = tasmota/framework-arduinoespressif8266 @ 3.20704.7
|
||||
platformio/toolchain-xtensa @ ~2.40802.200502
|
||||
platformio/tool-esptool @ ~1.413.0
|
||||
platformio/tool-esptoolpy @ ~1.30000.0
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# FLAGS: DEBUG
|
||||
@@ -87,10 +67,10 @@ platform_latest = ${common.arduino_core_2_7_4}
|
||||
# ------------------------------------------------------------------------------
|
||||
debug_flags = -D DEBUG=1 -D WLED_DEBUG -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_UPDATE -DDEBUG_ESP_HTTP_SERVER -DDEBUG_ESP_UPDATER -DDEBUG_ESP_OTA -DDEBUG_TLS_MEM
|
||||
#if needed (for memleaks etc) also add; -DDEBUG_ESP_OOM -include "umm_malloc/umm_malloc_cfg.h"
|
||||
#-DDEBUG_ESP_CORE is not working right now
|
||||
#-DDEBUG_ESP_CORE is not working right now
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# FLAGS: ldscript
|
||||
# FLAGS: ldscript (available ldscripts at https://github.com/esp8266/Arduino/tree/master/tools/sdk/ld)
|
||||
# ldscript_512k ( 512 KB) = 487 KB sketch, 4 KB eeprom, no spiffs, 16 KB reserved
|
||||
# ldscript_1m0m (1024 KB) = 999 KB sketch, 4 KB eeprom, no spiffs, 16 KB reserved
|
||||
# ldscript_2m1m (2048 KB) = 1019 KB sketch, 4 KB eeprom, 1004 KB spiffs, 16 KB reserved
|
||||
@@ -101,6 +81,7 @@ debug_flags = -D DEBUG=1 -D WLED_DEBUG -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_CLIENT
|
||||
# -DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH = v1.4 Higher Bandwidth (default)
|
||||
# -DPIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY = v2 Lower Memory
|
||||
# -DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH = v2 Higher Bandwidth
|
||||
# -DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH_LOW_FLASH
|
||||
#
|
||||
# BearSSL performance:
|
||||
# When building with -DSECURE_CLIENT=SECURE_CLIENT_BEARSSL, please add `board_build.f_cpu = 160000000` to the environment configuration
|
||||
@@ -113,18 +94,23 @@ debug_flags = -D DEBUG=1 -D WLED_DEBUG -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_CLIENT
|
||||
# TLS_RSA_WITH_AES_256_CBC_SHA / AES256-SHA
|
||||
# This reduces the OTA size with ~45KB, so it's especially useful on low memory boards (512k/1m).
|
||||
# ------------------------------------------------------------------------------
|
||||
build_flags = -g -w -DMQTT_MAX_PACKET_SIZE=1024 -DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH
|
||||
-DSECURE_CLIENT=SECURE_CLIENT_BEARSSL -DBEARSSL_SSL_BASIC
|
||||
build_flags =
|
||||
-DMQTT_MAX_PACKET_SIZE=1024
|
||||
-DSECURE_CLIENT=SECURE_CLIENT_BEARSSL
|
||||
-DBEARSSL_SSL_BASIC
|
||||
-D CORE_DEBUG_LEVEL=0
|
||||
-D NDEBUG
|
||||
#build_flags for the IRremoteESP8266 library (enabled decoders have to appear here)
|
||||
-D _IR_ENABLE_DEFAULT_=false
|
||||
-D DECODE_HASH=true
|
||||
-D _IR_ENABLE_DEFAULT_=false
|
||||
-D DECODE_HASH=true
|
||||
-D DECODE_NEC=true
|
||||
-D DECODE_SONY=true
|
||||
-D DECODE_SONY=true
|
||||
-D DECODE_SAMSUNG=true
|
||||
-D DECODE_LG=true
|
||||
|
||||
build_flags_esp8266 = ${common.build_flags} -DESP8266
|
||||
build_flags_esp32 = ${common.build_flags} -DARDUINO_ARCH_ESP32
|
||||
-DWLED_USE_MY_CONFIG
|
||||
; -D USERMOD_SENSORSTOMQTT
|
||||
|
||||
build_unflags =
|
||||
|
||||
# enables all features for travis CI
|
||||
build_flags_all_features =
|
||||
@@ -136,13 +122,39 @@ build_flags_all_features =
|
||||
-D WLED_ENABLE_MQTT
|
||||
-D WLED_ENABLE_WEBSOCKETS
|
||||
|
||||
ldscript_512k = eagle.flash.512k.ld ;for older versions change this to eagle.flash.512k0.ld
|
||||
ldscript_1m0m = eagle.flash.1m.ld ;for older versions change this to eagle.flash.1m0.ld
|
||||
build_flags_esp8266 = ${common.build_flags} ${esp8266.build_flags}
|
||||
build_flags_esp32 = ${common.build_flags} ${esp32.build_flags}
|
||||
|
||||
ldscript_1m128k = eagle.flash.1m128.ld
|
||||
ldscript_2m512k = eagle.flash.2m512.ld
|
||||
ldscript_2m1m = eagle.flash.2m1m.ld
|
||||
ldscript_4m1m = eagle.flash.4m1m.ld
|
||||
ldscript_4m3m = eagle.flash.4m3m.ld
|
||||
|
||||
shared_libdeps_dir = ./wled00/src
|
||||
[esp8266]
|
||||
build_flags =
|
||||
-DESP8266
|
||||
-DFP_IN_IROM
|
||||
; NONOSDK22x_190703 = 2.2.2-dev(38a443e)
|
||||
-DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_190703
|
||||
; lwIP 2 - Higher Bandwidth no Features
|
||||
; -DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH_LOW_FLASH
|
||||
; lwIP 1.4 - Higher Bandwidth (Aircoookie has)
|
||||
-DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH
|
||||
; VTABLES in Flash
|
||||
-DVTABLES_IN_FLASH
|
||||
; restrict to minimal mime-types
|
||||
-DMIMETYPE_MINIMAL
|
||||
|
||||
[esp32]
|
||||
build_flags = -g
|
||||
-DARDUINO_ARCH_ESP32
|
||||
-DCONFIG_LITTLEFS_FOR_IDF_3_2
|
||||
|
||||
[scripts_defaults]
|
||||
extra_scripts = pio-scripts/name-firmware.py
|
||||
pio-scripts/gzip-firmware.py
|
||||
pio-scripts/strip-floats.py
|
||||
pio-scripts/user_config_copy.py
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# COMMON SETTINGS:
|
||||
@@ -151,9 +163,10 @@ shared_libdeps_dir = ./wled00/src
|
||||
framework = arduino
|
||||
board_build.flash_mode = dout
|
||||
monitor_speed = 115200
|
||||
# slow upload speed (comment this out with a ';' when building for development use)
|
||||
upload_speed = 115200
|
||||
lib_extra_dirs =
|
||||
${common.shared_libdeps_dir}
|
||||
# fast upload speed (remove ';' when building for development use)
|
||||
; upload_speed = 921600
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# LIBRARIES: required dependencies
|
||||
@@ -164,24 +177,32 @@ lib_extra_dirs =
|
||||
# ------------------------------------------------------------------------------
|
||||
lib_compat_mode = strict
|
||||
lib_deps =
|
||||
FastLED@3.3.2
|
||||
NeoPixelBus@2.5.7
|
||||
ESPAsyncTCP@1.2.0
|
||||
fastled/FastLED @ 3.3.2
|
||||
NeoPixelBus @ 2.6.0
|
||||
ESPAsyncTCP @ 1.2.0
|
||||
ESPAsyncUDP
|
||||
AsyncTCP@1.0.3
|
||||
https://github.com/Aircoookie/ESPAsyncWebServer
|
||||
IRremoteESP8266@2.7.3
|
||||
#For use of the TTGO T-Display ESP32 Module with integrated TFT display uncomment the following line
|
||||
AsyncTCP @ 1.0.3
|
||||
IRremoteESP8266 @ 2.7.3
|
||||
https://github.com/lorol/LITTLEFS.git
|
||||
https://github.com/Aircoookie/ESPAsyncWebServer.git @ ~2.0.2
|
||||
#For use of the TTGO T-Display ESP32 Module with integrated TFT display uncomment the following line
|
||||
#TFT_eSPI
|
||||
#For use SSD1306 OLED display uncomment following
|
||||
#U8g2@~2.27.2
|
||||
#For Dallas sensor uncomment following 2 lines
|
||||
#OneWire@~2.3.5
|
||||
#milesburton/DallasTemperature@^3.9.0
|
||||
#For BME280 sensor uncomment following
|
||||
#BME280@~3.0.0
|
||||
; adafruit/Adafruit BMP280 Library @ 2.1.0
|
||||
; adafruit/Adafruit CCS811 Library @ 1.0.4
|
||||
; adafruit/Adafruit Si7021 Library @ 1.4.0
|
||||
|
||||
lib_ignore =
|
||||
AsyncTCP
|
||||
|
||||
extra_scripts = ${scripts_defaults.extra_scripts}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# WLED BUILDS
|
||||
# ------------------------------------------------------------------------------
|
||||
@@ -189,87 +210,103 @@ lib_ignore =
|
||||
[env:nodemcuv2]
|
||||
board = nodemcuv2
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp8266}
|
||||
|
||||
# Unsupported environment due to insufficient flash
|
||||
[env:esp01]
|
||||
board = esp01
|
||||
platform = ${common.platform_wled_default}
|
||||
board_build.ldscript = ${common.ldscript_512k}
|
||||
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_OTA -D WLED_DISABLE_ALEXA -D WLED_DISABLE_BLYNK
|
||||
-D WLED_DISABLE_CRONIXIE -D WLED_DISABLE_HUESYNC -D WLED_DISABLE_INFRARED -D WLED_DISABLE_MQTT -D WLED_DISABLE_WEBSOCKETS
|
||||
|
||||
# Unsupported environment due to insufficient flash
|
||||
[env:esp01_1m_ota]
|
||||
board = esp01_1m
|
||||
platform = ${common.platform_wled_default}
|
||||
board_build.ldscript = ${common.ldscript_1m0m}
|
||||
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_ALEXA -D WLED_DISABLE_BLYNK -D WLED_DISABLE_CRONIXIE
|
||||
-D WLED_DISABLE_HUESYNC -D WLED_DISABLE_INFRARED -D WLED_DISABLE_MQTT -D WLED_DISABLE_WEBSOCKETS
|
||||
|
||||
[env:esp01_1m_full]
|
||||
board = esp01_1m
|
||||
platform = ${common.platform_wled_default}
|
||||
board_build.ldscript = ${common.ldscript_1m0m}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_1m128k}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_OTA
|
||||
|
||||
[env:esp07]
|
||||
board = esp07
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_flags = ${common.build_flags_esp8266}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp8266}
|
||||
|
||||
[env:d1_mini]
|
||||
board = d1_mini
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
upload_speed = 921600
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_flags = ${common.build_flags_esp8266}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp8266}
|
||||
monitor_filters = esp8266_exception_decoder
|
||||
|
||||
[env:heltec_wifi_kit_8]
|
||||
board = d1_mini
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp8266}
|
||||
|
||||
[env:h803wf]
|
||||
board = d1_mini
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp8266} -D LEDPIN=1 -D WLED_DISABLE_INFRARED
|
||||
|
||||
[env:esp32dev]
|
||||
board = esp32dev
|
||||
platform = espressif32@1.12.4
|
||||
build_flags = ${common.build_flags_esp32}
|
||||
platform = espressif32@3.2
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp32}
|
||||
lib_ignore =
|
||||
ESPAsyncTCP
|
||||
ESPAsyncUDP
|
||||
|
||||
[env:esp32_eth]
|
||||
board = esp32-poe
|
||||
platform = espressif32@3.2
|
||||
upload_speed = 921600
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp32} -D RLYPIN=-1 -D WLED_USE_ETHERNET -D BTNPIN=-1
|
||||
lib_ignore =
|
||||
ESPAsyncTCP
|
||||
ESPAsyncUDP
|
||||
|
||||
[env:esp8285_4CH_MagicHome]
|
||||
board = esp8285
|
||||
platform = ${common.platform_latest}
|
||||
board_build.ldscript = ${common.ldscript_1m0m}
|
||||
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_HUESYNC -D WLED_USE_ANALOG_LEDS
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_1m128k}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_OTA -D WLED_USE_ANALOG_LEDS
|
||||
|
||||
[env:esp8285_4CH_H801]
|
||||
board = esp8285
|
||||
platform = ${common.platform_latest}
|
||||
board_build.ldscript = ${common.ldscript_1m0m}
|
||||
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_HUESYNC -D WLED_USE_ANALOG_LEDS -D WLED_USE_H801
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_1m128k}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_OTA -D WLED_USE_ANALOG_LEDS -D WLED_USE_H801
|
||||
|
||||
[env:esp8285_5CH_H801]
|
||||
board = esp8285
|
||||
platform = ${common.platform_latest}
|
||||
board_build.ldscript = ${common.ldscript_1m0m}
|
||||
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_HUESYNC -D WLED_USE_ANALOG_LEDS -D WLED_USE_H801 -D WLED_ENABLE_5CH_LEDS
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_1m128k}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_OTA -D WLED_USE_ANALOG_LEDS -D WLED_USE_H801 -D WLED_ENABLE_5CH_LEDS
|
||||
|
||||
[env:d1_mini_5CH_Shojo_PCB]
|
||||
board = d1_mini
|
||||
platform = ${common.platform_latest}
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_flags = ${common.build_flags_esp8266} -D WLED_USE_ANALOG_LEDS -D WLED_USE_SHOJO_PCB -D WLED_ENABLE_5CH_LEDS
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp8266} -D WLED_USE_ANALOG_LEDS -D WLED_USE_SHOJO_PCB -D WLED_ENABLE_5CH_LEDS
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# DEVELOPMENT BOARDS
|
||||
@@ -279,7 +316,9 @@ build_flags = ${common.build_flags_esp8266} -D WLED_USE_ANALOG_LEDS -D WLED_USE_
|
||||
board = d1_mini
|
||||
build_type = debug
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp8266} ${common.debug_flags}
|
||||
|
||||
[env:d1_mini_ota]
|
||||
@@ -288,8 +327,18 @@ upload_protocol = espota
|
||||
# exchange for your WLED IP
|
||||
upload_port = "10.10.1.27"
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_flags = ${common.build_flags_esp8266}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp8266}
|
||||
|
||||
[env:anavi_miracle_controller]
|
||||
board = d1_mini
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp8266} -D LEDPIN=12 -D IRPIN=-1 -D RLYPIN=2
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# custom board configurations
|
||||
@@ -297,49 +346,79 @@ build_flags = ${common.build_flags_esp8266}
|
||||
|
||||
[env:custom_LEDPIN_4]
|
||||
board = d1_mini
|
||||
platform = ${common.platform_latest}
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp8266} -D LEDPIN=4 -D IRPIN=5
|
||||
|
||||
[env:custom_LEDPIN_16]
|
||||
board = d1_mini
|
||||
platform = ${common.platform_latest}
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_flags = ${common.build_flags_esp8266} -D LEDPIN=16
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp8266} -D LEDPIN=16
|
||||
|
||||
|
||||
[env:custom_LEDPIN_3]
|
||||
board = d1_mini
|
||||
platform = ${common.platform_latest}
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp8266} -D LEDPIN=3
|
||||
|
||||
[env:custom_APA102]
|
||||
board = d1_mini
|
||||
platform = ${common.platform_latest}
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp8266} -D USE_APA102
|
||||
|
||||
[env:custom_WS2801]
|
||||
board = d1_mini
|
||||
platform = ${common.platform_latest}
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp8266} -D USE_WS2801
|
||||
|
||||
[env:custom32_LEDPIN_16]
|
||||
board = esp32dev
|
||||
platform = espressif32@1.12.4
|
||||
build_flags = ${common.build_flags_esp32} -D LEDPIN=16
|
||||
platform = espressif32@3.2
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp32} -D LEDPIN=16 -D RLYPIN=19
|
||||
lib_ignore =
|
||||
ESPAsyncTCP
|
||||
ESPAsyncUDP
|
||||
|
||||
[env:custom32_APA102]
|
||||
board = esp32dev
|
||||
platform = espressif32@3.2
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp32} -D USE_APA102
|
||||
lib_ignore =
|
||||
ESPAsyncTCP
|
||||
ESPAsyncUDP
|
||||
|
||||
[env:custom32_TOUCHPIN_T0]
|
||||
board = esp32dev
|
||||
platform = espressif32@3.2
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp32} -D TOUCHPIN=T0
|
||||
lib_ignore =
|
||||
ESPAsyncTCP
|
||||
ESPAsyncUDP
|
||||
|
||||
[env:wemos_shield_esp32]
|
||||
board = esp32dev
|
||||
platform = espressif32@1.12.4
|
||||
platform = espressif32@3.2
|
||||
upload_port = /dev/cu.SLAB_USBtoUART
|
||||
monitor_port = /dev/cu.SLAB_USBtoUART
|
||||
upload_speed = 460800
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp32} -D LEDPIN=16 -D RLYPIN=19 -D BTNPIN=17
|
||||
lib_ignore =
|
||||
ESPAsyncTCP
|
||||
@@ -347,11 +426,18 @@ lib_ignore =
|
||||
|
||||
[env:m5atom]
|
||||
board = esp32dev
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp32} -D LEDPIN=27 -D BTNPIN=39
|
||||
lib_ignore =
|
||||
lib_ignore =
|
||||
ESPAsyncTCP
|
||||
ESPAsyncUDP
|
||||
platform = espressif32@1.12.4
|
||||
platform = espressif32@3.2
|
||||
|
||||
[env:sp501e]
|
||||
board = esp_wroom_02
|
||||
platform = ${common.platform_wled_default}
|
||||
board_build.ldscript = ${common.ldscript_2m512k}
|
||||
build_flags = ${common.build_flags_esp8266} -D LEDPIN=3 -D BTNPIN=1
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# travis test board configurations
|
||||
@@ -360,9 +446,63 @@ platform = espressif32@1.12.4
|
||||
[env:travis_esp8266]
|
||||
extends = env:d1_mini
|
||||
build_type = debug
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp8266} ${common.debug_flags} ${common.build_flags_all_features}
|
||||
|
||||
[env:travis_esp32]
|
||||
extends = env:esp32dev
|
||||
build_type = debug
|
||||
; build_type = debug
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp32} ${common.debug_flags} ${common.build_flags_all_features}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# codm pixel controller board configurations
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
[env:codm-controller-0.4]
|
||||
board = esp_wroom_02
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_2m512k}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp8266} -D LEDPIN=3
|
||||
|
||||
[env:codm-controller-0.4-WS2801]
|
||||
board = esp_wroom_02
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_2m512k}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp8266} -D USE_WS2801 -D CLKPIN=13 -D DATAPIN=3
|
||||
|
||||
[env:codm-controller-0.4-APA102]
|
||||
board = esp_wroom_02
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_2m512k}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp8266} -D USE_APA102 -D CLKPIN=13 -D DATAPIN=3
|
||||
|
||||
[env:codm-controller-0.5]
|
||||
board = esp_wroom_02
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_2m512k}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp8266}
|
||||
|
||||
[env:codm-controller-0.5-WS2801]
|
||||
board = esp_wroom_02
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_2m512k}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp8266} -D USE_WS2801 #-D CLKPIN=0 -D DATAPIN=2
|
||||
|
||||
[env:codm-controller-0.5-APA102]
|
||||
board = esp_wroom_02
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_2m512k}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp8266} -D USE_APA102 #-D CLKPIN=0 -D DATAPIN=2
|
||||
|
||||
@@ -5,23 +5,31 @@
|
||||
# Please visit documentation: https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[platformio]
|
||||
default_envs = esp8266_1m_custom
|
||||
default_envs = WLED_tasmota_1M
|
||||
|
||||
[env:esp8266_1m_custom]
|
||||
[env:WLED_tasmota_1M]
|
||||
board = esp01_1m
|
||||
platform = ${common.arduino_core_2_4_2}
|
||||
board_build.ldscript = ${common.ldscript_1m0m}
|
||||
build_flags = ${common.build_flags_esp8266}
|
||||
-D WLED_DISABLE_OTA
|
||||
-D WLED_DISABLE_ALEXA
|
||||
-D WLED_DISABLE_BLYNK
|
||||
-D WLED_DISABLE_CRONIXIE
|
||||
-D WLED_DISABLE_HUESYNC
|
||||
-D WLED_DISABLE_INFRARED
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_1m128k}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp8266}
|
||||
; *********************************************************************
|
||||
; *** Use custom settings from file my_config.h
|
||||
-DWLED_USE_MY_CONFIG
|
||||
; *********************************************************************
|
||||
; -D WLED_DISABLE_OTA
|
||||
; -D WLED_DISABLE_ALEXA
|
||||
; -D WLED_DISABLE_BLYNK
|
||||
; -D WLED_DISABLE_CRONIXIE
|
||||
; -D WLED_DISABLE_HUESYNC
|
||||
; -D WLED_DISABLE_INFRARED
|
||||
; -D WLED_DISABLE_WEBSOCKETS
|
||||
; PIN defines - uncomment and change, if needed:
|
||||
; -D LEDPIN=2
|
||||
; -D BTNPIN=0
|
||||
; -D IR_PIN=4
|
||||
; -D TOUCHPIN=T0
|
||||
; -D IRPIN=4
|
||||
; -D RLYPIN=12
|
||||
; -D RLYMDE=1
|
||||
; digital LED strip types - uncomment only one ! - this will disable WS281x / SK681x support
|
||||
@@ -29,11 +37,11 @@ build_flags = ${common.build_flags_esp8266}
|
||||
; -D USE_WS2801
|
||||
; -D USE_LPD8806
|
||||
; PIN defines for 2 wire LEDs
|
||||
; -D CLKPIN=0
|
||||
; -D DATAPIN=2
|
||||
-D CLKPIN=0
|
||||
-D DATAPIN=2
|
||||
; to drive analog LED strips (aka 5050), uncomment the following
|
||||
; PWM pins 5,12,13,15 are used with Magic Home LED Controller (default)
|
||||
; -D WLED_USE_ANALOG_LEDS
|
||||
-D WLED_USE_ANALOG_LEDS
|
||||
; for the H801 controller (PINs 15,13,12,14 (W2 = 04)) uncomment this
|
||||
; -D WLED_USE_H801
|
||||
; for the BW-LT11 controller (PINs 12,4,14,5 ) uncomment this
|
||||
30
readme.md
@@ -1,15 +1,18 @@
|
||||
<p align="center">
|
||||
<img src="/images/wled_logo_akemi.png">
|
||||
<a href="https://github.com/Aircoookie/WLED/releases"><img src="https://img.shields.io/github/release/Aircoookie/WLED.svg?style=flat-square"></a>
|
||||
<a href="https://raw.githubusercontent.com/Aircoookie/WLED/master/LICENSE"><img src="https://img.shields.io/github/license/Aircoookie/wled?color=blue&style=flat-square"></a>
|
||||
<a href="https://wled.discourse.group"><img src="https://img.shields.io/discourse/topics?colorB=blue&label=forum&server=https%3A%2F%2Fwled.discourse.group%2F&style=flat-square"></a>
|
||||
<a href="https://discord.gg/KuqP7NE"><img src="https://img.shields.io/discord/473448917040758787.svg?colorB=blue&label=discord&style=flat-square"></a>
|
||||
<a href="https://github.com/Aircoookie/WLED/wiki"><img src="https://img.shields.io/badge/quick_start-wiki-blue.svg?style=flat-square"></a>
|
||||
<a href="https://github.com/Aircoookie/WLED-App"><img src="https://img.shields.io/badge/app-wled-blue.svg?style=flat-square"></a>
|
||||
<a href="https://gitpod.io/#https://github.com/Aircoookie/WLED"><img src="https://img.shields.io/badge/Gitpod-ready--to--code-blue?style=flat-square&logo=gitpod"></a>
|
||||
|
||||
</p>
|
||||
|
||||
# Welcome to my project WLED! ✨
|
||||
|
||||
A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control NeoPixel (WS2812B, WS2811, SK6812, APA102) LEDs or also SPI based chipsets like the WS2801!
|
||||
A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control NeoPixel (WS2812B, WS2811, SK6812) LEDs or also SPI based chipsets like the WS2801 and APA102!
|
||||
|
||||
## ⚙️ Features
|
||||
- WS2812FX library integrated for over 100 special effects
|
||||
@@ -18,20 +21,22 @@ A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control
|
||||
- Segments to set different effects and colors to parts of the LEDs
|
||||
- Settings page - configuration over network
|
||||
- Access Point and station mode - automatic failsafe AP
|
||||
- Up to 10 LED outputs per instance
|
||||
- Support for RGBW strips
|
||||
- 16 user presets to save and load colors/effects easily, supports cycling through them.
|
||||
- Macro functions to automatically execute API calls
|
||||
- Up to 250 user presets to save and load colors/effects easily, supports cycling through them.
|
||||
- Presets can be used to automatically execute API calls
|
||||
- Nightlight function (gradually dims down)
|
||||
- Full OTA software updatability (HTTP + ArduinoOTA), password protectable
|
||||
- Configurable analog clock + support for the Cronixie kit by Diamex
|
||||
- Configurable Auto Brightness limit for safer operation
|
||||
- Filesystem-based config for easier backup of presets and settings
|
||||
|
||||
## 💡 Supported light control interfaces
|
||||
- WLED app for [Android](https://play.google.com/store/apps/details?id=com.aircoookie.WLED) and [iOS](https://apps.apple.com/us/app/wled/id1475695033)
|
||||
- JSON and HTTP request APIs
|
||||
- MQTT
|
||||
- Blynk IoT
|
||||
- E1.31, Art-Net and TPM2.net
|
||||
- E1.31, Art-Net, DDP and TPM2.net
|
||||
- [Hyperion](https://github.com/hyperion-project/hyperion.ng)
|
||||
- UDP realtime
|
||||
- Alexa voice control (including dimming and color)
|
||||
@@ -45,15 +50,7 @@ A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control
|
||||
|
||||
See the [wiki](https://github.com/Aircoookie/WLED/wiki)!
|
||||
|
||||
DrZzs has made some excellent video guides:
|
||||
[Introduction, hardware and installation](https://www.youtube.com/watch?v=tXvtxwK3jRk)
|
||||
[Settings, tips and tricks](https://www.youtube.com/watch?v=6eCE2BpLaUQ)
|
||||
|
||||
If you'd rather read, here is a very [detailed step-by-step beginner tutorial](https://tynick.com/blog/11-03-2019/getting-started-with-wled-on-esp8266/) by tynick!
|
||||
|
||||
Russian speakers, check out the videos by Room31:
|
||||
[WLED Firmware Overview: Interface and Settings](https://youtu.be/h7lKsczEI7E)
|
||||
[ESP8266 based LED controller for WS2812b strip. WLED Firmware + OpenHAB](https://youtu.be/K4ioTt3XvGc)
|
||||
[On this page](https://github.com/Aircoookie/WLED/wiki/Learning-the-ropes) you can find excellent tutorials made by the community and helpful tools to help you get your new lamp up and running!
|
||||
|
||||
## 🖼️ Images
|
||||
<img src="/images/macbook-pro-space-gray-on-the-wooden-table.jpg" width="50%"><img src="/images/walking-with-iphone-x.jpg" width="50%">
|
||||
@@ -71,8 +68,9 @@ TM1814 | 12v | RGBW
|
||||
WS2811 | 12v | 3-LED segments
|
||||
WS2815 | 12v |
|
||||
GS8208 | 12v |
|
||||
Analog/non-addressable | any | Requires additional circuitry
|
||||
|
||||
## 🧊 Compatibe PC RGB Fans and ARGB accessories
|
||||
## 🧊 Compatible PC RGB Fans and ARGB accessories
|
||||
Brand | Model | Comments
|
||||
|---|---|---|
|
||||
Corsair | HD120 Fan | Uses WS2812B, data-in only
|
||||
@@ -97,7 +95,7 @@ If WLED really brightens up your every day, you can [ {
|
||||
console.info("Reading " + sourceFile);
|
||||
new inliner(sourceFile, function (error, html) {
|
||||
console.info("Inlined " + html.length + " characters");
|
||||
html = filter(html, "html-minify-ui");
|
||||
console.info("Minified to " + html.length + " characters");
|
||||
|
||||
if (error) {
|
||||
console.warn(error);
|
||||
@@ -105,7 +107,7 @@ ${array}
|
||||
}
|
||||
|
||||
const CleanCSS = require("clean-css");
|
||||
const MinifyHTML = require("html-minifier").minify;
|
||||
const MinifyHTML = require("html-minifier-terser").minify;
|
||||
|
||||
function filter(str, type) {
|
||||
str = adoptVersionAndRepo(str);
|
||||
@@ -119,7 +121,17 @@ function filter(str, type) {
|
||||
collapseWhitespace: true,
|
||||
maxLineLength: 80,
|
||||
minifyCSS: true,
|
||||
minifyJS: true,
|
||||
minifyJS: true,
|
||||
continueOnParseError: false,
|
||||
removeComments: true,
|
||||
});
|
||||
} else if (type == "html-minify-ui") {
|
||||
return MinifyHTML(str, {
|
||||
collapseWhitespace: true,
|
||||
conservativeCollapse: true,
|
||||
maxLineLength: 80,
|
||||
minifyCSS: true,
|
||||
minifyJS: true,
|
||||
continueOnParseError: false,
|
||||
removeComments: true,
|
||||
});
|
||||
@@ -132,7 +144,7 @@ function filter(str, type) {
|
||||
function specToChunk(srcDir, s) {
|
||||
if (s.method == "plaintext") {
|
||||
const buf = fs.readFileSync(srcDir + "/" + s.file);
|
||||
const str = buf.toString("ascii");
|
||||
const str = buf.toString("utf-8");
|
||||
const chunk = `
|
||||
// Autogenerated from ${srcDir}/${s.file}, do not edit!!
|
||||
const char ${s.name}[] PROGMEM = R"${s.prepend || ""}${filter(str, s.filter)}${
|
||||
@@ -386,6 +398,22 @@ const char PAGE_dmxmap[] PROGMEM = R"=====()=====";
|
||||
method: "plaintext",
|
||||
filter: "html-minify",
|
||||
},
|
||||
{
|
||||
file: "liveviewws.htm",
|
||||
name: "PAGE_liveviewws",
|
||||
prepend: "=====(",
|
||||
append: ")=====",
|
||||
method: "plaintext",
|
||||
filter: "html-minify",
|
||||
},
|
||||
{
|
||||
file: "404.htm",
|
||||
name: "PAGE_404",
|
||||
prepend: "=====(",
|
||||
append: ")=====",
|
||||
method: "plaintext",
|
||||
filter: "html-minify",
|
||||
},
|
||||
{
|
||||
file: "favicon.ico",
|
||||
name: "favicon",
|
||||
|
||||
427
usermods/Animated_Staircase/Animated_Staircase.h
Normal file
@@ -0,0 +1,427 @@
|
||||
/*
|
||||
* Usermod for detecting people entering/leaving a staircase and switching the
|
||||
* staircase on/off.
|
||||
*
|
||||
* Edit the Animated_Staircase_config.h file to compile this usermod for your
|
||||
* specific configuration.
|
||||
*
|
||||
* See the accompanying README.md file for more info.
|
||||
*/
|
||||
#pragma once
|
||||
#include "wled.h"
|
||||
#include "Animated_Staircase_config.h"
|
||||
#define USERMOD_ID_ANIMATED_STAIRCASE 1011
|
||||
|
||||
/* Initial configuration (available in API and stored in flash) */
|
||||
bool enabled = true; // Enable this usermod
|
||||
unsigned long segment_delay_ms = 150; // Time between switching each segment
|
||||
unsigned long on_time_ms = 5 * 1000; // The time for the light to stay on
|
||||
#ifndef TOP_PIR_PIN
|
||||
unsigned int topMaxTimeUs = 1749; // default echo timout, top
|
||||
#endif
|
||||
#ifndef BOTTOM_PIR_PIN
|
||||
unsigned int bottomMaxTimeUs = 1749; // default echo timout, bottom
|
||||
#endif
|
||||
|
||||
// Time between checking of the sensors
|
||||
const int scanDelay = 50;
|
||||
|
||||
class Animated_Staircase : public Usermod {
|
||||
private:
|
||||
// Lights on or off.
|
||||
// Flipping this will start a transition.
|
||||
bool on = false;
|
||||
|
||||
// Swipe direction for current transition
|
||||
#define SWIPE_UP true
|
||||
#define SWIPE_DOWN false
|
||||
bool swipe = SWIPE_UP;
|
||||
|
||||
// Indicates which Sensor was seen last (to determine
|
||||
// the direction when swiping off)
|
||||
#define LOWER false
|
||||
#define UPPER true
|
||||
bool lastSensor = LOWER;
|
||||
|
||||
// Time of the last transition action
|
||||
unsigned long lastTime = 0;
|
||||
|
||||
// Time of the last sensor check
|
||||
unsigned long lastScanTime = 0;
|
||||
|
||||
// Last time the lights were switched on or off
|
||||
unsigned long lastSwitchTime = 0;
|
||||
|
||||
// segment id between onIndex and offIndex are on.
|
||||
// controll the swipe by setting/moving these indices around.
|
||||
// onIndex must be less than or equal to offIndex
|
||||
byte onIndex = 0;
|
||||
byte offIndex = 0;
|
||||
|
||||
// The maximum number of configured segments.
|
||||
// Dynamically updated based on user configuration.
|
||||
byte maxSegmentId = 1;
|
||||
byte mainSegmentId = 0;
|
||||
|
||||
bool saveState = false;
|
||||
|
||||
// These values are used by the API to read the
|
||||
// last sensor state, or trigger a sensor
|
||||
// through the API
|
||||
bool topSensorRead = false;
|
||||
bool topSensorWrite = false;
|
||||
bool bottomSensorRead = false;
|
||||
bool bottomSensorWrite = false;
|
||||
|
||||
void updateSegments() {
|
||||
mainSegmentId = strip.getMainSegmentId();
|
||||
WS2812FX::Segment mainsegment = strip.getSegment(mainSegmentId);
|
||||
WS2812FX::Segment* segments = strip.getSegments();
|
||||
for (int i = 0; i < MAX_NUM_SEGMENTS; i++, segments++) {
|
||||
if (!segments->isActive()) {
|
||||
maxSegmentId = i - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= onIndex && i < offIndex) {
|
||||
segments->setOption(SEG_OPTION_ON, 1, 1);
|
||||
|
||||
// We may need to copy mode and colors from segment 0 to make sure
|
||||
// changes are propagated even when the config is changed during a wipe
|
||||
// segments->mode = mainsegment.mode;
|
||||
// segments->colors[0] = mainsegment.colors[0];
|
||||
} else {
|
||||
segments->setOption(SEG_OPTION_ON, 0, 1);
|
||||
}
|
||||
// Always mark segments as "transitional", we are animating the staircase
|
||||
segments->setOption(SEG_OPTION_TRANSITIONAL, 1, 1);
|
||||
}
|
||||
colorUpdated(NOTIFIER_CALL_MODE_DIRECT_CHANGE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Detects if an object is within ultrasound range.
|
||||
* signalPin: The pin where the pulse is sent
|
||||
* echoPin: The pin where the echo is received
|
||||
* maxTimeUs: Detection timeout in microseconds. If an echo is
|
||||
* received within this time, an object is detected
|
||||
* and the function will return true.
|
||||
*
|
||||
* The speed of sound is 343 meters per second at 20 degress Celcius.
|
||||
* Since the sound has to travel back and forth, the detection
|
||||
* distance for the sensor in cm is (0.0343 * maxTimeUs) / 2.
|
||||
*
|
||||
* For practical reasons, here are some useful distances:
|
||||
*
|
||||
* Distance = maxtime
|
||||
* 5 cm = 292 uS
|
||||
* 10 cm = 583 uS
|
||||
* 20 cm = 1166 uS
|
||||
* 30 cm = 1749 uS
|
||||
* 50 cm = 2915 uS
|
||||
* 100 cm = 5831 uS
|
||||
*/
|
||||
bool ultrasoundRead(uint8_t signalPin,
|
||||
uint8_t echoPin,
|
||||
unsigned int maxTimeUs) {
|
||||
digitalWrite(signalPin, HIGH);
|
||||
delayMicroseconds(10);
|
||||
digitalWrite(signalPin, LOW);
|
||||
return pulseIn(echoPin, HIGH, maxTimeUs) > 0;
|
||||
}
|
||||
|
||||
void checkSensors() {
|
||||
if ((millis() - lastScanTime) > scanDelay) {
|
||||
lastScanTime = millis();
|
||||
|
||||
#ifdef BOTTOM_PIR_PIN
|
||||
bottomSensorRead = bottomSensorWrite || (digitalRead(BOTTOM_PIR_PIN) == HIGH);
|
||||
#else
|
||||
bottomSensorRead = bottomSensorWrite || ultrasoundRead(BOTTOM_TRIGGER_PIN, BOTTOM_ECHO_PIN, bottomMaxTimeUs);
|
||||
#endif
|
||||
|
||||
#ifdef TOP_PIR_PIN
|
||||
topSensorRead = topSensorWrite || (digitalRead(TOP_PIR_PIN) == HIGH);
|
||||
#else
|
||||
topSensorRead = topSensorWrite || ultrasoundRead(TOP_TRIGGER_PIN, TOP_ECHO_PIN, topMaxTimeUs);
|
||||
#endif
|
||||
|
||||
// Values read, reset the flags for next API call
|
||||
topSensorWrite = false;
|
||||
bottomSensorWrite = false;
|
||||
|
||||
if (topSensorRead != bottomSensorRead) {
|
||||
lastSwitchTime = millis();
|
||||
|
||||
if (on) {
|
||||
lastSensor = topSensorRead;
|
||||
} else {
|
||||
// If the bottom sensor triggered, we need to swipe up, ON
|
||||
swipe = bottomSensorRead;
|
||||
|
||||
if (swipe) {
|
||||
Serial.println("ON -> Swipe up.");
|
||||
} else {
|
||||
Serial.println("ON -> Swipe down.");
|
||||
}
|
||||
|
||||
if (onIndex == offIndex) {
|
||||
// Position the indices for a correct on-swipe
|
||||
if (swipe == SWIPE_UP) {
|
||||
onIndex = mainSegmentId;
|
||||
} else {
|
||||
onIndex = maxSegmentId+1;
|
||||
}
|
||||
offIndex = onIndex;
|
||||
}
|
||||
on = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void autoPowerOff() {
|
||||
if (on && ((millis() - lastSwitchTime) > on_time_ms)) {
|
||||
// Swipe OFF in the direction of the last sensor detection
|
||||
swipe = lastSensor;
|
||||
on = false;
|
||||
|
||||
if (swipe) {
|
||||
Serial.println("OFF -> Swipe up.");
|
||||
} else {
|
||||
Serial.println("OFF -> Swipe down.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void updateSwipe() {
|
||||
if ((millis() - lastTime) > segment_delay_ms) {
|
||||
lastTime = millis();
|
||||
|
||||
byte oldOnIndex = onIndex;
|
||||
byte oldOffIndex = offIndex;
|
||||
|
||||
if (on) {
|
||||
// Turn on all segments
|
||||
onIndex = MAX(mainSegmentId, onIndex - 1);
|
||||
offIndex = MIN(maxSegmentId + 1, offIndex + 1);
|
||||
} else {
|
||||
if (swipe == SWIPE_UP) {
|
||||
onIndex = MIN(offIndex, onIndex + 1);
|
||||
} else {
|
||||
offIndex = MAX(onIndex, offIndex - 1);
|
||||
}
|
||||
}
|
||||
|
||||
updateSegments();
|
||||
}
|
||||
}
|
||||
|
||||
void writeSettingsToJson(JsonObject& root) {
|
||||
JsonObject staircase = root["staircase"];
|
||||
if (staircase.isNull()) {
|
||||
staircase = root.createNestedObject("staircase");
|
||||
}
|
||||
staircase["enabled"] = enabled;
|
||||
staircase["segment-delay-ms"] = segment_delay_ms;
|
||||
staircase["on-time-s"] = on_time_ms / 1000;
|
||||
|
||||
#ifdef TOP_TRIGGER_PIN
|
||||
staircase["top-echo-us"] = topMaxTimeUs;
|
||||
#endif
|
||||
#ifdef BOTTOM_TRIGGER_PIN
|
||||
staircase["bottom-echo-us"] = bottomMaxTimeUs;
|
||||
#endif
|
||||
}
|
||||
|
||||
void writeSensorsToJson(JsonObject& root) {
|
||||
JsonObject staircase = root["staircase"];
|
||||
if (staircase.isNull()) {
|
||||
staircase = root.createNestedObject("staircase");
|
||||
}
|
||||
staircase["top-sensor"] = topSensorRead;
|
||||
staircase["bottom-sensor"] = bottomSensorRead;
|
||||
}
|
||||
|
||||
bool readSettingsFromJson(JsonObject& root) {
|
||||
JsonObject staircase = root["staircase"];
|
||||
bool changed = false;
|
||||
|
||||
bool shouldEnable = staircase["enabled"] | enabled;
|
||||
if (shouldEnable != enabled) {
|
||||
enable(shouldEnable);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
unsigned long c_segment_delay_ms = staircase["segment-delay-ms"] | segment_delay_ms;
|
||||
if (c_segment_delay_ms != segment_delay_ms) {
|
||||
segment_delay_ms = c_segment_delay_ms;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
unsigned long c_on_time_ms = (staircase["on-time-s"] | (on_time_ms / 1000)) * 1000;
|
||||
if (c_on_time_ms != on_time_ms) {
|
||||
on_time_ms = c_on_time_ms;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
#ifdef TOP_TRIGGER_PIN
|
||||
unsigned int c_topMaxTimeUs = staircase["top-echo-us"] | topMaxTimeUs;
|
||||
if (c_topMaxTimeUs != topMaxTimeUs) {
|
||||
topMaxTimeUs = c_topMaxTimeUs;
|
||||
changed = true;
|
||||
}
|
||||
#endif
|
||||
#ifdef BOTTOM_TRIGGER_PIN
|
||||
unsigned int c_bottomMaxTimeUs = staircase["bottom-echo-us"] | bottomMaxTimeUs;
|
||||
if (c_bottomMaxTimeUs != bottomMaxTimeUs) {
|
||||
bottomMaxTimeUs = c_bottomMaxTimeUs;
|
||||
changed = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
void readSensorsFromJson(JsonObject& root) {
|
||||
JsonObject staircase = root["staircase"];
|
||||
bottomSensorWrite = bottomSensorRead || (staircase["bottom-sensor"].as<bool>());
|
||||
topSensorWrite = topSensorRead || (staircase["top-sensor"].as<bool>());
|
||||
}
|
||||
|
||||
void enable(bool enable) {
|
||||
if (enable) {
|
||||
Serial.println("Animated Staircase enabled.");
|
||||
Serial.print("Delay between steps: ");
|
||||
Serial.print(segment_delay_ms, DEC);
|
||||
Serial.print(" milliseconds.\nStairs switch off after: ");
|
||||
Serial.print(on_time_ms / 1000, DEC);
|
||||
Serial.println(" seconds.");
|
||||
|
||||
#ifdef BOTTOM_PIR_PIN
|
||||
pinMode(BOTTOM_PIR_PIN, INPUT);
|
||||
#else
|
||||
pinMode(BOTTOM_TRIGGER_PIN, OUTPUT);
|
||||
pinMode(BOTTOM_ECHO_PIN, INPUT);
|
||||
#endif
|
||||
|
||||
#ifdef TOP_PIR_PIN
|
||||
pinMode(TOP_PIR_PIN, INPUT);
|
||||
#else
|
||||
pinMode(TOP_TRIGGER_PIN, OUTPUT);
|
||||
pinMode(TOP_ECHO_PIN, INPUT);
|
||||
#endif
|
||||
} else {
|
||||
// Restore segment options
|
||||
WS2812FX::Segment mainsegment = strip.getSegment(mainSegmentId);
|
||||
WS2812FX::Segment* segments = strip.getSegments();
|
||||
for (int i = 0; i < MAX_NUM_SEGMENTS; i++, segments++) {
|
||||
if (!segments->isActive()) {
|
||||
maxSegmentId = i - 1;
|
||||
break;
|
||||
}
|
||||
segments->setOption(SEG_OPTION_ON, 1, 1);
|
||||
}
|
||||
colorUpdated(NOTIFIER_CALL_MODE_DIRECT_CHANGE);
|
||||
Serial.println("Animated Staircase disabled.");
|
||||
}
|
||||
enabled = enable;
|
||||
}
|
||||
|
||||
public:
|
||||
void setup() { enable(enabled); }
|
||||
|
||||
void loop() {
|
||||
// Write changed settings from to flash (see readFromJsonState())
|
||||
if (saveState) {
|
||||
serializeConfig();
|
||||
saveState = false;
|
||||
}
|
||||
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
checkSensors();
|
||||
autoPowerOff();
|
||||
updateSwipe();
|
||||
|
||||
}
|
||||
|
||||
uint16_t getId() { return USERMOD_ID_ANIMATED_STAIRCASE; }
|
||||
|
||||
/*
|
||||
* Shows configuration settings to the json API. This object looks like:
|
||||
*
|
||||
* "staircase" : {
|
||||
* "enabled" : true
|
||||
* "segment-delay-ms" : 150,
|
||||
* "on-time-s" : 5
|
||||
* }
|
||||
*
|
||||
*/
|
||||
void addToJsonState(JsonObject& root) {
|
||||
writeSettingsToJson(root);
|
||||
writeSensorsToJson(root);
|
||||
Serial.println("Staircase config exposed in API.");
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads configuration settings from the json API.
|
||||
* See void addToJsonState(JsonObject& root)
|
||||
*/
|
||||
void readFromJsonState(JsonObject& root) {
|
||||
// The call to serializeConfig() must be done in the main loop,
|
||||
// so we set a flag to signal the main loop to save state.
|
||||
saveState = readSettingsFromJson(root);
|
||||
readSensorsFromJson(root);
|
||||
Serial.println("Staircase config read from API.");
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes the configuration to internal flash memory.
|
||||
*/
|
||||
void addToConfig(JsonObject& root) {
|
||||
writeSettingsToJson(root);
|
||||
Serial.println("Staircase config saved.");
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads the configuration to internal flash memory before setup() is called.
|
||||
*/
|
||||
void readFromConfig(JsonObject& root) {
|
||||
readSettingsFromJson(root);
|
||||
Serial.println("Staircase config loaded.");
|
||||
}
|
||||
|
||||
/*
|
||||
* Shows the delay between steps and power-off time in the "info"
|
||||
* tab of the web-UI.
|
||||
*/
|
||||
void addToJsonInfo(JsonObject& root) {
|
||||
JsonObject staircase = root["u"];
|
||||
if (staircase.isNull()) {
|
||||
staircase = root.createNestedObject("u");
|
||||
}
|
||||
|
||||
if (enabled) {
|
||||
JsonArray usermodEnabled =
|
||||
staircase.createNestedArray("Staircase enabled"); // name
|
||||
usermodEnabled.add("yes"); // value
|
||||
|
||||
JsonArray segmentDelay =
|
||||
staircase.createNestedArray("Delay between stairs"); // name
|
||||
segmentDelay.add(segment_delay_ms); // value
|
||||
segmentDelay.add(" milliseconds"); // unit
|
||||
|
||||
JsonArray onTime =
|
||||
staircase.createNestedArray("Power-off stairs after"); // name
|
||||
onTime.add(on_time_ms / 1000); // value
|
||||
onTime.add(" seconds"); // unit
|
||||
} else {
|
||||
JsonArray usermodEnabled =
|
||||
staircase.createNestedArray("Staircase enabled"); // name
|
||||
usermodEnabled.add("no"); // value
|
||||
}
|
||||
}
|
||||
};
|
||||
21
usermods/Animated_Staircase/Animated_Staircase_config.h
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Animated_Staircase compiletime confguration.
|
||||
*
|
||||
* Please see README.md on how to change this file.
|
||||
*/
|
||||
|
||||
// Please change the pin numbering below to match your board.
|
||||
#define TOP_PIR_PIN D5
|
||||
#define BOTTOM_PIR_PIN D6
|
||||
|
||||
// Or uncumment and a pir and use an ultrasound HC-SR04 sensor,
|
||||
// see README.md for details
|
||||
#ifndef TOP_PIR_PIN
|
||||
#define TOP_TRIGGER_PIN D2
|
||||
#define TOP_ECHO_PIN D3
|
||||
#endif
|
||||
|
||||
#ifndef BOTTOM_PIR_PIN
|
||||
#define BOTTOM_TRIGGER_PIN D4
|
||||
#define BOTTOM_ECHO_PIN D5
|
||||
#endif
|
||||
203
usermods/Animated_Staircase/README.md
Normal file
@@ -0,0 +1,203 @@
|
||||
# Usermod Animated Staircase
|
||||
This usermod makes your staircase look cool by switching it on with an animation. It uses
|
||||
PIR or ultrasonic sensors at the top and bottom of your stairs to:
|
||||
|
||||
- Light up the steps in your walking direction, leading the way.
|
||||
- Switch off the steps after you, in the direction of the last detected movement.
|
||||
- Always switch on when one of the sensors detects movement, even if an effect
|
||||
is still running. It can therewith handle multiple people on the stairs gracefully.
|
||||
|
||||
The Animated Staircase can be controlled by the WLED API. Change settings such as
|
||||
speed, on/off time and distance settings by sending an HTTP request, see below.
|
||||
|
||||
## WLED integration
|
||||
To include this usermod in your WLED setup, you have to be able to [compile WLED from source](https://github.com/Aircoookie/WLED/wiki/Compiling-WLED).
|
||||
|
||||
Before compiling, you have to make the following modifications:
|
||||
|
||||
Edit `usermods_list.cpp`:
|
||||
1. Open `wled00/usermods_list.cpp`
|
||||
2. add `#include "../usermods/Animated_Staircase/Animated_Staircase.h"` to the top of the file
|
||||
3. add `usermods.add(new Animated_Staircase());` to the end of the `void registerUsermods()` function.
|
||||
|
||||
Edit `Animated_Staircase_config.h`:
|
||||
1. Open `usermods/Animated_Staircase/Animated_Staircase_config.h`
|
||||
2. To use PIR sensors, change these lines to match your setup:
|
||||
Using D7 and D6 pin notation as used on several boards:
|
||||
|
||||
```cpp
|
||||
#define TOP_PIR_PIN D7
|
||||
#define BOTTOM_PIR_PIN D6
|
||||
```
|
||||
|
||||
Or using GPIO numbering for pins 25 and 26:
|
||||
```cpp
|
||||
#define TOP_PIR_PIN 26
|
||||
#define BOTTOM_PIR_PIN 25
|
||||
```
|
||||
|
||||
To use Ultrasonic HC-SR04 sensors instead of (one of the) PIR sensors,
|
||||
uncomment one of the PIR sensor lines and adjust the pin numbers for the
|
||||
connected Ultrasonic sensor. In the example below we use an Ultrasonic
|
||||
sensor at the bottom of the stairs:
|
||||
|
||||
```cpp
|
||||
#define TOP_PIR_PIN 32
|
||||
//#define BOTTOM_PIR_PIN D6 /* This PIR sensor is disabled */
|
||||
|
||||
#ifndef TOP_PIR_PIN
|
||||
#define TOP_SIGNAL_PIN D2
|
||||
#define TOP_ECHO_PIN D3
|
||||
#endif
|
||||
|
||||
#ifndef BOTTOM_PIR_PIN /* If the bottom PIR is disabled, */
|
||||
#define BOTTOM_SIGNAL_PIN 25 /* This Ultrasonic sensor is used */
|
||||
#define BOTTOM_ECHO_PIN 26
|
||||
#endif
|
||||
```
|
||||
|
||||
After these modifications, compile and upload your WLED binary to your board
|
||||
and check the WLED info page to see if this usermod is enabled.
|
||||
|
||||
## Hardware installation
|
||||
1. Stick the LED strip under each step of the stairs.
|
||||
2. Connect the ESP8266 pin D4 or ESP32 pin D2 to the first LED data pin at the bottom step
|
||||
of your stairs.
|
||||
3. Connect the data-out pin at the end of each strip per step to the data-in pin on the
|
||||
other end of the next step, creating one large virtual LED strip.
|
||||
4. Mount sensors of choice at the bottom and top of the stairs and connect them to the ESP.
|
||||
5. To make sure all LEDs get enough power and have your staircase lighted evenly, power each
|
||||
step from one side, using at least AWG14 or 2.5mm^2 cable. Don't connect them serial as you
|
||||
do for the datacable!
|
||||
|
||||
You _may_ need to use 10k pull-down resistors on the selected PIR pins, depending on the sensor.
|
||||
|
||||
## WLED configuration
|
||||
1. In the WLED UI, confgure a segment for each step. The lowest step of the stairs is the
|
||||
lowest segment id.
|
||||
2. Save your segments into a preset.
|
||||
3. Ideally, add the preset in the config > LED setup menu to the "apply
|
||||
preset **n** at boot" setting.
|
||||
|
||||
## Changing behavior through API
|
||||
The Staircase settings can be changed through the WLED JSON api.
|
||||
|
||||
**NOTE:** We are using [curl](https://curl.se/) to send HTTP POSTs to the WLED API.
|
||||
If you're using Windows and want to use the curl commands, replace the `\` with a `^`
|
||||
or remove them and put everything on one line.
|
||||
|
||||
|
||||
| Setting | Description | Default |
|
||||
|------------------|---------------------------------------------------------------|---------|
|
||||
| enabled | Enable or disable the usermod | true |
|
||||
| segment-delay-ms | Delay (milliseconds) between switching on/off each step | 150 |
|
||||
| on-time-s | Time (seconds) the stairs stay lit after last detection | 5 |
|
||||
| bottom-echo-us | Detection range of ultrasonic sensor | 1749 |
|
||||
| bottomsensor | Manually trigger a down to up animation via API | false |
|
||||
| topsensor | Manually trigger an up to down animation via API | false |
|
||||
|
||||
|
||||
To read the current settings, open a browser to `http://xxx.xxx.xxx.xxx/json/state` (use your WLED
|
||||
device IP address). The device will respond with a json object containing all WLED settings.
|
||||
The staircase settings and sensor states are inside the WLED status element:
|
||||
|
||||
```json
|
||||
{
|
||||
"state": {
|
||||
"staircase": {
|
||||
"enabled": true,
|
||||
"segment-delay-ms": 150,
|
||||
"on-time-s": 5,
|
||||
"bottomsensor": false,
|
||||
"topsensor": false
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### Enable/disable the usermod
|
||||
By disabling the usermod you will be able to keep the LED's on, independent from the sensor
|
||||
activity. This enables to play with the lights without the usermod switching them on or off.
|
||||
|
||||
To disable the usermod:
|
||||
|
||||
```bash
|
||||
curl -X POST -H "Content-Type: application/json" \
|
||||
-d {"staircase":{"enabled":false}} \
|
||||
xxx.xxx.xxx.xxx/json/state
|
||||
```
|
||||
|
||||
To enable the usermod again, use `"enabled":true`.
|
||||
|
||||
### Changing animation parameters
|
||||
To change the delay between the steps to (for example) 100 milliseconds and the on-time to
|
||||
10 seconds:
|
||||
|
||||
```bash
|
||||
curl -X POST -H "Content-Type: application/json" \
|
||||
-d '{"staircase":{"segment-delay-ms":100,"on-time-s":10}}' \
|
||||
xxx.xxx.xxx.xxx/json/state
|
||||
```
|
||||
|
||||
### Changing detection range of the ultrasonic HC-SR04 sensor
|
||||
When an ultrasonic sensor is enabled in `Animated_Staircase_config.h`, you'll see a
|
||||
`bottom-echo-us` setting appear in the json api:
|
||||
|
||||
```json
|
||||
{
|
||||
"state": {
|
||||
"staircase": {
|
||||
"enabled": true,
|
||||
"segment-delay-ms": 150,
|
||||
"on-time-s": 5,
|
||||
"bottom-echo-us": 1749
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
If the HC-SR04 sensor detects an echo within 1749 microseconds (corresponding to ~30 cm
|
||||
detection range from the sensor), it will trigger switching on the staircase. This setting
|
||||
can be changed through the API with an HTTP POST:
|
||||
|
||||
```bash
|
||||
curl -X POST -H "Content-Type: application/json" \
|
||||
-d '{"staircase":{"bottom-echo-us":1166}}' \
|
||||
xxx.xxx.xxx.xxx/json/state
|
||||
```
|
||||
|
||||
Calculating the detection range can be performed as follows: The speed of sound is 343m/s at 20
|
||||
degrees Centigrade. Since the sound has to travel back and forth, the detection range for the
|
||||
sensor in cm is (0.0343 * maxTimeUs) / 2. To get you started, please find delays and distances below:
|
||||
|
||||
| Distance | Detection time |
|
||||
|---------:|----------------:|
|
||||
| 5 cm | 292 uS |
|
||||
| 10 cm | 583 uS |
|
||||
| 20 cm | 1166 uS |
|
||||
| 30 cm | 1749 uS |
|
||||
| 50 cm | 2915 uS |
|
||||
| 100 cm | 5831 uS |
|
||||
|
||||
**Please note:** that using an HC-SR04 sensor, particularly when detecting echos at longer
|
||||
distances creates delays in the WLED software, and _might_ introduce timing hickups in your animations or
|
||||
a less responsive web interface. It is therefore advised to keep the detection time as short as possible.
|
||||
|
||||
### Animation triggering through the API
|
||||
Instead of stairs activation by one of the sensors, you can also trigger the animation through
|
||||
the API. To simulate triggering the bottom sensor, use:
|
||||
|
||||
```bash
|
||||
curl -X POST -H "Content-Type: application/json" \
|
||||
-d '{"staircase":{"bottomsensor":true}}' \
|
||||
xxx.xxx.xxx.xxx/json/state
|
||||
```
|
||||
|
||||
Likewise, to trigger the top sensor, use:
|
||||
|
||||
```bash
|
||||
curl -X POST -H "Content-Type: application/json" \
|
||||
-d '{"staircase":{"topsensor":true}}' \
|
||||
xxx.xxx.xxx.xxx/json/state
|
||||
```
|
||||
|
||||
Have fun with this usermod.<br/>
|
||||
www.rolfje.com
|
||||
5
usermods/Artemis_reciever/readme.md
Normal file
@@ -0,0 +1,5 @@
|
||||
Usermod to allow WLED to receive via UDP port from RGB.NET (and therefore add as a device to be controlled within artemis on PC)
|
||||
|
||||
This is only a very simple code to support a single led strip, it does not support the full function of the RGB.NET sketch for esp8266 only what is needed to be used with Artemis. It will show as a ws281x device in artemis when you provide the correct hostname or ip. Artemis queries the number of LEDs via the web interface (/config) but communication to set the LEDs is all done via the UDP interface.
|
||||
|
||||
To install, copy the usermod.cpp file to wled00 folder and recompile
|
||||
93
usermods/Artemis_reciever/usermod.cpp
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* RGB.NET (artemis) receiver
|
||||
*
|
||||
* This works via the UDP, http is not supported apart from reporting LED count
|
||||
*
|
||||
*
|
||||
*/
|
||||
#include "wled.h"
|
||||
#include <WiFiUdp.h>
|
||||
|
||||
WiFiUDP UDP;
|
||||
const unsigned int RGBNET_localUdpPort = 1872; // local port to listen on
|
||||
unsigned char RGBNET_packet[770];
|
||||
long lastTime = 0;
|
||||
int delayMs = 10;
|
||||
bool isRGBNETUDPEnabled;
|
||||
|
||||
void RGBNET_readValues() {
|
||||
|
||||
int RGBNET_packetSize = UDP.parsePacket();
|
||||
if (RGBNET_packetSize) {
|
||||
// receive incoming UDP packets
|
||||
int sequenceNumber = UDP.read();
|
||||
int channel = UDP.read();
|
||||
|
||||
//channel data is not used we only supports one channel
|
||||
int len = UDP.read(RGBNET_packet, ledCount*3);
|
||||
if(len==0){
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < len; i=i+3) {
|
||||
strip.setPixelColor(i/3, RGBNET_packet[i], RGBNET_packet[i+1], RGBNET_packet[i+2], 0);
|
||||
}
|
||||
//strip.show();
|
||||
}
|
||||
}
|
||||
|
||||
//update LED strip
|
||||
void RGBNET_show() {
|
||||
strip.show();
|
||||
lastTime = millis();
|
||||
}
|
||||
|
||||
//This function provides a json with info on the number of LEDs connected
|
||||
// it is needed by artemis to know how many LEDs to display on the surface
|
||||
void handleConfig(AsyncWebServerRequest *request)
|
||||
{
|
||||
String config = (String)"{\
|
||||
\"channels\": [\
|
||||
{\
|
||||
\"channel\": 1,\
|
||||
\"leds\": " + ledCount + "\
|
||||
},\
|
||||
{\
|
||||
\"channel\": 2,\
|
||||
\"leds\": " + "0" + "\
|
||||
},\
|
||||
{\
|
||||
\"channel\": 3,\
|
||||
\"leds\": " + "0" + "\
|
||||
},\
|
||||
{\
|
||||
\"channel\": 4,\
|
||||
\"leds\": " + "0" + "\
|
||||
}\
|
||||
]\
|
||||
}";
|
||||
request->send(200, "application/json", config);
|
||||
}
|
||||
|
||||
|
||||
void userSetup()
|
||||
{
|
||||
server.on("/config", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
handleConfig(request);
|
||||
});
|
||||
}
|
||||
|
||||
void userConnected()
|
||||
{
|
||||
// new wifi, who dis?
|
||||
UDP.begin(RGBNET_localUdpPort);
|
||||
isRGBNETUDPEnabled = true;
|
||||
}
|
||||
|
||||
void userLoop()
|
||||
{
|
||||
RGBNET_readValues();
|
||||
if (millis()-lastTime > delayMs) {
|
||||
RGBNET_show();
|
||||
}
|
||||
}
|
||||
40
usermods/BME280_v2/README.md
Normal file
@@ -0,0 +1,40 @@
|
||||
Hello! I have written a v2 usermod for the BME280/BMP280 sensor based on the [existing v1 usermod](https://github.com/Aircoookie/WLED/blob/master/usermods/Wemos_D1_mini%2BWemos32_mini_shield/usermod_bme280.cpp). It is not just a refactor, there are many changes which I made to fit my use case, and I hope they will fit the use cases of others as well! Most notably, this usermod is *just* for the BME280 and does not control a display like in the v1 usermod designed for the WeMos shield.
|
||||
|
||||
- Requires libraries `BME280@~3.0.0` (by [finitespace](https://github.com/finitespace/BME280)) and `Wire`. Please add these under `lib_deps` in your `platform.ini` (or `platform_override.ini`).
|
||||
- Data is published over MQTT so make sure you've enabled the MQTT sync interface.
|
||||
- This usermod also writes to serial (GPIO1 on ESP8266). Please make sure nothing else listening on the serial TX pin of your board will get confused by log messages!
|
||||
|
||||
To enable, compile with `USERMOD_BME280` defined (i.e. `platformio_override.ini`)
|
||||
```ini
|
||||
build_flags =
|
||||
${common.build_flags_esp8266}
|
||||
-D USERMOD_BME280
|
||||
```
|
||||
or define `USERMOD_BME280` in `my_config.h`
|
||||
```c++
|
||||
#define USERMOD_BME280
|
||||
```
|
||||
|
||||
Changes include:
|
||||
- Adjustable measure intervals
|
||||
- Temperature and pressure have separate intervals due to pressure not frequently changing at any constant altitude
|
||||
- Adjustment of number of decimal places in published sensor values
|
||||
- Separate adjustment for temperature, humidity and pressure values
|
||||
- Values are rounded to the specified number of decimal places
|
||||
- Pressure measured in units of hPa instead of Pa
|
||||
- Calculation of heat index (apparent temperature) and dew point
|
||||
- These, along with humidity measurements, are disabled if the sensor is a BMP280
|
||||
- 16x oversampling of sensor during measurement
|
||||
- Values are only published if they are different from the previous value
|
||||
- Values are published on startup (continually until the MQTT broker acknowledges a successful publication)
|
||||
|
||||
Adjustments are made through preprocessor definitions at the start of the class definition.
|
||||
|
||||
MQTT topics are as follows:
|
||||
Measurement type | MQTT topic
|
||||
--- | ---
|
||||
Temperature | `<deviceTopic>/temperature`
|
||||
Humidity | `<deviceTopic>/humidity`
|
||||
Pressure | `<deviceTopic>/pressure`
|
||||
Heat index | `<deviceTopic>/heat_index`
|
||||
Dew point | `<deviceTopic>/dew_point`
|
||||
212
usermods/BME280_v2/usermod_bme280.h
Normal file
@@ -0,0 +1,212 @@
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
#include <BME280I2C.h> // BME280 sensor
|
||||
#include <EnvironmentCalculations.h> // BME280 extended measurements
|
||||
|
||||
class UsermodBME280 : public Usermod
|
||||
{
|
||||
private:
|
||||
// User-defined configuration
|
||||
#define Celsius // Show temperature mesaurement in Celcius. Comment out for Fahrenheit
|
||||
#define TemperatureDecimals 1 // Number of decimal places in published temperaure values
|
||||
#define HumidityDecimals 0 // Number of decimal places in published humidity values
|
||||
#define PressureDecimals 2 // Number of decimal places in published pressure values
|
||||
#define TemperatureInterval 5 // Interval to measure temperature (and humidity, dew point if available) in seconds
|
||||
#define PressureInterval 300 // Interval to measure pressure in seconds
|
||||
|
||||
// Sanity checks
|
||||
#if !defined(TemperatureDecimals) || TemperatureDecimals < 0
|
||||
#define TemperatureDecimals 0
|
||||
#endif
|
||||
#if !defined(HumidityDecimals) || HumidityDecimals < 0
|
||||
#define HumidityDecimals 0
|
||||
#endif
|
||||
#if !defined(PressureDecimals) || PressureDecimals < 0
|
||||
#define PressureDecimals 0
|
||||
#endif
|
||||
#if !defined(TemperatureInterval) || TemperatureInterval < 0
|
||||
#define TemperatureInterval 1
|
||||
#endif
|
||||
#if !defined(PressureInterval) || PressureInterval < 0
|
||||
#define PressureInterval TemperatureInterval
|
||||
#endif
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32 // ESP32 boards
|
||||
uint8_t SCL_PIN = 22;
|
||||
uint8_t SDA_PIN = 21;
|
||||
#else // ESP8266 boards
|
||||
uint8_t SCL_PIN = 5;
|
||||
uint8_t SDA_PIN = 4;
|
||||
//uint8_t RST_PIN = 16; // Uncoment for Heltec WiFi-Kit-8
|
||||
#endif
|
||||
|
||||
// BME280 sensor settings
|
||||
BME280I2C::Settings settings{
|
||||
BME280::OSR_X16, // Temperature oversampling x16
|
||||
BME280::OSR_X16, // Humidity oversampling x16
|
||||
BME280::OSR_X16, // Pressure oversampling x16
|
||||
// Defaults
|
||||
BME280::Mode_Forced,
|
||||
BME280::StandbyTime_1000ms,
|
||||
BME280::Filter_Off,
|
||||
BME280::SpiEnable_False,
|
||||
BME280I2C::I2CAddr_0x76 // I2C address. I2C specific. Default 0x76
|
||||
};
|
||||
|
||||
BME280I2C bme{settings};
|
||||
|
||||
uint8_t SensorType;
|
||||
|
||||
// Measurement timers
|
||||
long timer;
|
||||
long lastTemperatureMeasure = 0;
|
||||
long lastPressureMeasure = 0;
|
||||
|
||||
// Current sensor values
|
||||
float SensorTemperature;
|
||||
float SensorHumidity;
|
||||
float SensorHeatIndex;
|
||||
float SensorDewPoint;
|
||||
float SensorPressure;
|
||||
// Track previous sensor values
|
||||
float lastTemperature;
|
||||
float lastHumidity;
|
||||
float lastHeatIndex;
|
||||
float lastDewPoint;
|
||||
float lastPressure;
|
||||
|
||||
// Store packet IDs of MQTT publications
|
||||
uint16_t mqttTemperaturePub = 0;
|
||||
uint16_t mqttPressurePub = 0;
|
||||
|
||||
void UpdateBME280Data(int SensorType)
|
||||
{
|
||||
float _temperature, _humidity, _pressure;
|
||||
#ifdef Celsius
|
||||
BME280::TempUnit tempUnit(BME280::TempUnit_Celsius);
|
||||
EnvironmentCalculations::TempUnit envTempUnit(EnvironmentCalculations::TempUnit_Celsius);
|
||||
#else
|
||||
BME280::TempUnit tempUnit(BME280::TempUnit_Fahrenheit);
|
||||
EnvironmentCalculations::TempUnit envTempUnit(EnvironmentCalculations::TempUnit_Fahrenheit);
|
||||
#endif
|
||||
BME280::PresUnit presUnit(BME280::PresUnit_hPa);
|
||||
|
||||
bme.read(_pressure, _temperature, _humidity, tempUnit, presUnit);
|
||||
|
||||
SensorTemperature = _temperature;
|
||||
SensorHumidity = _humidity;
|
||||
SensorPressure = _pressure;
|
||||
if (SensorType == 1)
|
||||
{
|
||||
SensorHeatIndex = EnvironmentCalculations::HeatIndex(_temperature, _humidity, envTempUnit);
|
||||
SensorDewPoint = EnvironmentCalculations::DewPoint(_temperature, _humidity, envTempUnit);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
void setup()
|
||||
{
|
||||
Wire.begin(SDA_PIN, SCL_PIN);
|
||||
|
||||
if (!bme.begin())
|
||||
{
|
||||
SensorType = 0;
|
||||
Serial.println("Could not find BME280I2C sensor!");
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (bme.chipModel())
|
||||
{
|
||||
case BME280::ChipModel_BME280:
|
||||
SensorType = 1;
|
||||
Serial.println("Found BME280 sensor! Success.");
|
||||
break;
|
||||
case BME280::ChipModel_BMP280:
|
||||
SensorType = 2;
|
||||
Serial.println("Found BMP280 sensor! No Humidity available.");
|
||||
break;
|
||||
default:
|
||||
SensorType = 0;
|
||||
Serial.println("Found UNKNOWN sensor! Error!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// BME280 sensor MQTT publishing
|
||||
// Check if sensor present and MQTT Connected, otherwise it will crash the MCU
|
||||
if (SensorType != 0 && mqtt != nullptr)
|
||||
{
|
||||
// Timer to fetch new temperature, humidity and pressure data at intervals
|
||||
timer = millis();
|
||||
|
||||
if (timer - lastTemperatureMeasure >= TemperatureInterval * 1000 || mqttTemperaturePub == 0)
|
||||
{
|
||||
lastTemperatureMeasure = timer;
|
||||
|
||||
UpdateBME280Data(SensorType);
|
||||
|
||||
float Temperature = roundf(SensorTemperature * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals);
|
||||
float Humidity, HeatIndex, DewPoint;
|
||||
|
||||
// If temperature has changed since last measure, create string populated with device topic
|
||||
// from the UI and values read from sensor, then publish to broker
|
||||
if (Temperature != lastTemperature)
|
||||
{
|
||||
String topic = String(mqttDeviceTopic) + "/temperature";
|
||||
mqttTemperaturePub = mqtt->publish(topic.c_str(), 0, false, String(Temperature, TemperatureDecimals).c_str());
|
||||
}
|
||||
|
||||
lastTemperature = Temperature; // Update last sensor temperature for next loop
|
||||
|
||||
if (SensorType == 1) // Only if sensor is a BME280
|
||||
{
|
||||
Humidity = roundf(SensorHumidity * pow(10, HumidityDecimals)) / pow(10, HumidityDecimals);
|
||||
HeatIndex = roundf(SensorHeatIndex * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals);
|
||||
DewPoint = roundf(SensorDewPoint * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals);
|
||||
|
||||
if (Humidity != lastHumidity)
|
||||
{
|
||||
String topic = String(mqttDeviceTopic) + "/humidity";
|
||||
mqtt->publish(topic.c_str(), 0, false, String(Humidity, HumidityDecimals).c_str());
|
||||
}
|
||||
|
||||
if (HeatIndex != lastHeatIndex)
|
||||
{
|
||||
String topic = String(mqttDeviceTopic) + "/heat_index";
|
||||
mqtt->publish(topic.c_str(), 0, false, String(HeatIndex, TemperatureDecimals).c_str());
|
||||
}
|
||||
|
||||
if (DewPoint != lastDewPoint)
|
||||
{
|
||||
String topic = String(mqttDeviceTopic) + "/dew_point";
|
||||
mqtt->publish(topic.c_str(), 0, false, String(DewPoint, TemperatureDecimals).c_str());
|
||||
}
|
||||
|
||||
lastHumidity = Humidity;
|
||||
lastHeatIndex = HeatIndex;
|
||||
lastDewPoint = DewPoint;
|
||||
}
|
||||
}
|
||||
|
||||
if (timer - lastPressureMeasure >= PressureInterval * 1000 || mqttPressurePub == 0)
|
||||
{
|
||||
lastPressureMeasure = timer;
|
||||
|
||||
float Pressure = roundf(SensorPressure * pow(10, PressureDecimals)) / pow(10, PressureDecimals);
|
||||
|
||||
if (Pressure != lastPressure)
|
||||
{
|
||||
String topic = String(mqttDeviceTopic) + "/pressure";
|
||||
mqttPressurePub = mqtt->publish(topic.c_str(), 0, true, String(Pressure, PressureDecimals).c_str());
|
||||
}
|
||||
|
||||
lastPressure = Pressure;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
22
usermods/DHT/platformio_override.ini
Normal file
@@ -0,0 +1,22 @@
|
||||
; Options
|
||||
; -------
|
||||
; USERMOD_DHT - define this to have this user mod included wled00\usermods_list.cpp
|
||||
; USERMOD_DHT_DHTTYPE - DHT model: 11, 21, 22 for DHT11, DHT21, or DHT22, defaults to 22/DHT22
|
||||
; USERMOD_DHT_PIN - pin to which DTH is connected, defaults to Q2 pin on QuinLed Dig-Uno's board
|
||||
; USERMOD_DHT_CELSIUS - define this to report temperatures in degrees celsious, otherwise fahrenheit will be reported
|
||||
; USERMOD_DHT_MEASUREMENT_INTERVAL - the number of milliseconds between measurements, defaults to 60 seconds
|
||||
; USERMOD_DHT_FIRST_MEASUREMENT_AT - the number of milliseconds after boot to take first measurement, defaults to 90 seconds
|
||||
; USERMOD_DHT_STATS - For debug, report delay stats
|
||||
|
||||
[env:d1_mini_usermod_dht_C]
|
||||
extends = env:d1_mini
|
||||
build_flags = ${env:d1_mini.build_flags} -D USERMOD_DHT -D USERMOD_DHT_CELSIUS
|
||||
lib_deps = ${env.lib_deps}
|
||||
https://github.com/alwynallan/DHT_nonblocking
|
||||
|
||||
[env:custom32_LEDPIN_16_usermod_dht_C]
|
||||
extends = env:custom32_LEDPIN_16
|
||||
build_flags = ${env:custom32_LEDPIN_16.build_flags} -D USERMOD_DHT -D USERMOD_DHT_CELSIUS -D USERMOD_DHT_STATS
|
||||
lib_deps = ${env.lib_deps}
|
||||
https://github.com/alwynallan/DHT_nonblocking
|
||||
|
||||
41
usermods/DHT/readme.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# DHT Temperature/Humidity sensor usermod
|
||||
|
||||
This usermod will read from an attached DHT22 or DHT11 humidity and temperature sensor.
|
||||
The sensor readings are displayed in the Info section of the web UI.
|
||||
|
||||
If sensor is not detected after a while (10 update intervals), this usermod will be disabled.
|
||||
|
||||
## Installation
|
||||
|
||||
Copy the example `platformio_override.ini` to the root directory. This file should be placed in the same directory as `platformio.ini`.
|
||||
|
||||
### Define Your Options
|
||||
|
||||
* `USERMOD_DHT` - define this to have this user mod included wled00\usermods_list.cpp
|
||||
* `USERMOD_DHT_DHTTYPE` - DHT model: 11, 21, 22 for DHT11, DHT21, or DHT22, defaults to 22/DHT22
|
||||
* `USERMOD_DHT_PIN` - pin to which DTH is connected, defaults to Q2 pin on QuinLed Dig-Uno's board
|
||||
* `USERMOD_DHT_CELSIUS` - define this to report temperatures in degrees celsious, otherwise fahrenheit will be reported
|
||||
* `USERMOD_DHT_MEASUREMENT_INTERVAL` - the number of milliseconds between measurements, defaults to 60 seconds
|
||||
* `USERMOD_DHT_FIRST_MEASUREMENT_AT` - the number of milliseconds after boot to take first measurement, defaults to 90 seconds
|
||||
* `USERMOD_DHT_STATS` - For debug, report delay stats
|
||||
|
||||
## Project link
|
||||
|
||||
* [QuinLED-Dig-Uno](https://quinled.info/2018/09/15/quinled-dig-uno/) - Project link
|
||||
|
||||
### PlatformIO requirements
|
||||
|
||||
If you are using `platformio_override.ini`, you should be able to refresh the task list and see your custom task, for example `env:d1_mini_usermod_dht_C`. If not, you can add the libraries and dependencies into `platformio.ini` as you see fit.
|
||||
|
||||
|
||||
## Change Log
|
||||
|
||||
2020-02-04
|
||||
* Change default QuinLed pin to Q2
|
||||
* Instead of trying to keep updates at constant cadence, space readings out by measurement interval; hope this helps to avoid occasional bursts of readings with errors
|
||||
* Add some more (optional) stats
|
||||
2020-02-03
|
||||
* Due to poor readouts on ESP32 with previous DHT library, rewrote to use https://github.com/alwynallan/DHT_nonblocking
|
||||
* The new library serializes/delays up to 5ms for the sensor readout
|
||||
2020-02-02
|
||||
* Created
|
||||
216
usermods/DHT/usermod_dht.h
Normal file
@@ -0,0 +1,216 @@
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
|
||||
#include <dht_nonblocking.h>
|
||||
|
||||
// USERMOD_DHT_DHTTYPE:
|
||||
// 11 // DHT 11
|
||||
// 21 // DHT 21
|
||||
// 22 // DHT 22 (AM2302), AM2321 *** default
|
||||
#ifndef USERMOD_DHT_DHTTYPE
|
||||
#define USERMOD_DHT_DHTTYPE 22
|
||||
#endif
|
||||
|
||||
#if USERMOD_DHT_DHTTYPE == 11
|
||||
#define DHTTYPE DHT_TYPE_11
|
||||
#elif USERMOD_DHT_DHTTYPE == 21
|
||||
#define DHTTYPE DHT_TYPE_21
|
||||
#elif USERMOD_DHT_DHTTYPE == 22
|
||||
#define DHTTYPE DHT_TYPE_22
|
||||
#endif
|
||||
|
||||
// Connect pin 1 (on the left) of the sensor to +5V
|
||||
// NOTE: If using a board with 3.3V logic like an Arduino Due connect pin 1
|
||||
// to 3.3V instead of 5V!
|
||||
// Connect pin 2 of the sensor to whatever your DHTPIN is
|
||||
// NOTE: Pin defaults below are for QuinLed Dig-Uno's Q2 on the board
|
||||
// Connect pin 4 (on the right) of the sensor to GROUND
|
||||
// NOTE: If using a bare sensor (AM*), Connect a 10K resistor from pin 2
|
||||
// (data) to pin 1 (power) of the sensor. DHT* boards have the pullup already
|
||||
|
||||
#ifdef USERMOD_DHT_PIN
|
||||
#define DHTPIN USERMOD_DHT_PIN
|
||||
#else
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#define DHTPIN 21
|
||||
#else //ESP8266 boards
|
||||
#define DHTPIN 4
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// the frequency to check sensor, 1 minute
|
||||
#ifndef USERMOD_DHT_MEASUREMENT_INTERVAL
|
||||
#define USERMOD_DHT_MEASUREMENT_INTERVAL 60000
|
||||
#endif
|
||||
|
||||
// how many seconds after boot to take first measurement, 90 seconds
|
||||
// 90 gives enough time to OTA update firmware if this crashses
|
||||
#ifndef USERMOD_DHT_FIRST_MEASUREMENT_AT
|
||||
#define USERMOD_DHT_FIRST_MEASUREMENT_AT 90000
|
||||
#endif
|
||||
|
||||
// from COOLDOWN_TIME in dht_nonblocking.cpp
|
||||
#define DHT_TIMEOUT_TIME 10000
|
||||
|
||||
DHT_nonblocking dht_sensor(DHTPIN, DHTTYPE);
|
||||
|
||||
class UsermodDHT : public Usermod {
|
||||
private:
|
||||
unsigned long nextReadTime = 0;
|
||||
unsigned long lastReadTime = 0;
|
||||
float humidity, temperature = 0;
|
||||
bool initializing = true;
|
||||
bool disabled = false;
|
||||
#ifdef USERMOD_DHT_STATS
|
||||
unsigned long nextResetStatsTime = 0;
|
||||
uint16_t updates = 0;
|
||||
uint16_t clean_updates = 0;
|
||||
uint16_t errors = 0;
|
||||
unsigned long maxDelay = 0;
|
||||
unsigned long currentIteration = 0;
|
||||
unsigned long maxIteration = 0;
|
||||
#endif
|
||||
|
||||
public:
|
||||
void setup() {
|
||||
nextReadTime = millis() + USERMOD_DHT_FIRST_MEASUREMENT_AT;
|
||||
lastReadTime = millis();
|
||||
#ifdef USERMOD_DHT_STATS
|
||||
nextResetStatsTime = millis() + 60*60*1000;
|
||||
#endif
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
if (millis() < nextReadTime) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef USERMOD_DHT_STATS
|
||||
if (millis() >= nextResetStatsTime) {
|
||||
nextResetStatsTime += 60*60*1000;
|
||||
errors = 0;
|
||||
updates = 0;
|
||||
clean_updates = 0;
|
||||
}
|
||||
unsigned long dcalc = millis();
|
||||
if (currentIteration == 0) {
|
||||
currentIteration = millis();
|
||||
}
|
||||
#endif
|
||||
|
||||
float tempC;
|
||||
if (dht_sensor.measure(&tempC, &humidity)) {
|
||||
#ifdef USERMOD_DHT_CELSIUS
|
||||
temperature = tempC;
|
||||
#else
|
||||
temperature = tempC * 9 / 5 + 32;
|
||||
#endif
|
||||
|
||||
nextReadTime = millis() + USERMOD_DHT_MEASUREMENT_INTERVAL;
|
||||
lastReadTime = millis();
|
||||
initializing = false;
|
||||
|
||||
#ifdef USERMOD_DHT_STATS
|
||||
unsigned long icalc = millis() - currentIteration;
|
||||
if (icalc > maxIteration) {
|
||||
maxIteration = icalc;
|
||||
}
|
||||
if (icalc > DHT_TIMEOUT_TIME) {
|
||||
errors += icalc/DHT_TIMEOUT_TIME;
|
||||
} else {
|
||||
clean_updates += 1;
|
||||
}
|
||||
updates += 1;
|
||||
currentIteration = 0;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USERMOD_DHT_STATS
|
||||
dcalc = millis() - dcalc;
|
||||
if (dcalc > maxDelay) {
|
||||
maxDelay = dcalc;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (((millis() - lastReadTime) > 10*USERMOD_DHT_MEASUREMENT_INTERVAL)) {
|
||||
disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
void addToJsonInfo(JsonObject& root) {
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
JsonObject user = root["u"];
|
||||
if (user.isNull()) user = root.createNestedObject("u");
|
||||
|
||||
JsonArray temp = user.createNestedArray("Temperature");
|
||||
JsonArray hum = user.createNestedArray("Humidity");
|
||||
|
||||
#ifdef USERMOD_DHT_STATS
|
||||
JsonArray next = user.createNestedArray("next");
|
||||
if (nextReadTime >= millis()) {
|
||||
next.add((nextReadTime - millis()) / 1000);
|
||||
next.add(" sec until read");
|
||||
} else {
|
||||
next.add((millis() - nextReadTime) / 1000);
|
||||
next.add(" sec active reading");
|
||||
}
|
||||
|
||||
JsonArray last = user.createNestedArray("last");
|
||||
last.add((millis() - lastReadTime) / 60000);
|
||||
last.add(" min since read");
|
||||
|
||||
JsonArray err = user.createNestedArray("errors");
|
||||
err.add(errors);
|
||||
err.add(" Errors");
|
||||
|
||||
JsonArray upd = user.createNestedArray("updates");
|
||||
upd.add(updates);
|
||||
upd.add(" Updates");
|
||||
|
||||
JsonArray cupd = user.createNestedArray("cleanUpdates");
|
||||
cupd.add(clean_updates);
|
||||
cupd.add(" Updates");
|
||||
|
||||
JsonArray iter = user.createNestedArray("maxIter");
|
||||
iter.add(maxIteration);
|
||||
iter.add(" ms");
|
||||
|
||||
JsonArray delay = user.createNestedArray("maxDelay");
|
||||
delay.add(maxDelay);
|
||||
delay.add(" ms");
|
||||
#endif
|
||||
|
||||
if (initializing) {
|
||||
// if we haven't read the sensor yet, let the user know
|
||||
// that we are still waiting for the first measurement
|
||||
temp.add((nextReadTime - millis()) / 1000);
|
||||
temp.add(" sec until read");
|
||||
hum.add((nextReadTime - millis()) / 1000);
|
||||
hum.add(" sec until read");
|
||||
return;
|
||||
}
|
||||
|
||||
hum.add(humidity);
|
||||
hum.add("%");
|
||||
|
||||
temp.add(temperature);
|
||||
#ifdef USERMOD_DHT_CELSIUS
|
||||
temp.add("°C");
|
||||
#else
|
||||
temp.add("°F");
|
||||
#endif
|
||||
}
|
||||
|
||||
uint16_t getId()
|
||||
{
|
||||
return USERMOD_ID_DHT;
|
||||
}
|
||||
|
||||
};
|
||||
19
usermods/ESP32_TouchBrightnessControl/readme.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# ESP32 Touch Brightness Control
|
||||
|
||||
Toggle On/Off with a long press (800ms)
|
||||
Switch through 5 brightness levels (defined in usermod_touchbrightness.h, values 0-255) with a short (100ms) touch
|
||||
|
||||
## Installation
|
||||
|
||||
Copy 'usermod_touchbrightness.h' to the wled00 directory.
|
||||
in 'usermod_list.cpp' add this:
|
||||
|
||||
> #include "usermod_touchbrightness.h"
|
||||
above "void registerUsermods()"
|
||||
|
||||
and
|
||||
|
||||
> usermods.add(new TouchBrightnessControl());
|
||||
inside the "registerUsermods()" function
|
||||
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
//
|
||||
// usermod_touchbrightness.h
|
||||
// github.com/aircoookie/WLED
|
||||
//
|
||||
// Created by Justin Kühner on 14.09.2020.
|
||||
// Copyright © 2020 NeariX. All rights reserved.
|
||||
// https://github.com/NeariX67/
|
||||
// Discord: @NeariX#4799
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
|
||||
#define threshold 40 //Increase value if touches falsely accur. Decrease value if actual touches are not recognized
|
||||
#define touchPin T0 //T0 = D4 / GPIO4
|
||||
|
||||
//Define the 5 brightness levels
|
||||
//Long press to turn off / on
|
||||
#define brightness1 51
|
||||
#define brightness2 102
|
||||
#define brightness3 153
|
||||
#define brightness4 204
|
||||
#define brightness5 255
|
||||
|
||||
|
||||
#ifdef ESP32
|
||||
|
||||
|
||||
class TouchBrightnessControl : public Usermod {
|
||||
private:
|
||||
unsigned long lastTime = 0; //Interval
|
||||
unsigned long lastTouch = 0; //Timestamp of last Touch
|
||||
unsigned long lastRelease = 0; //Timestamp of last Touch release
|
||||
boolean released = true; //current Touch state (touched/released)
|
||||
uint16_t touchReading = 0; //sensor reading, maybe use uint8_t???
|
||||
uint16_t touchDuration = 0; //duration of last touch
|
||||
public:
|
||||
|
||||
void setup() {
|
||||
lastTouch = millis();
|
||||
lastRelease = millis();
|
||||
lastTime = millis();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (millis() - lastTime >= 50) { //Check every 50ms if a touch occurs
|
||||
lastTime = millis();
|
||||
touchReading = touchRead(touchPin); //Read touch sensor on pin T0 (GPIO4 / D4)
|
||||
|
||||
if(touchReading < threshold && released) { //Touch started
|
||||
released = false;
|
||||
lastTouch = millis();
|
||||
}
|
||||
else if(touchReading >= threshold && !released) { //Touch released
|
||||
released = true;
|
||||
lastRelease = millis();
|
||||
touchDuration = lastRelease - lastTouch; //Calculate duration
|
||||
}
|
||||
|
||||
//Serial.println(touchDuration);
|
||||
|
||||
if(touchDuration >= 800 && released) { //Toggle power if button press is longer than 800ms
|
||||
touchDuration = 0; //Reset touch duration to avoid multiple actions on same touch
|
||||
toggleOnOff();
|
||||
colorUpdated(2); //Refresh values
|
||||
}
|
||||
else if(touchDuration >= 100 && released) { //Switch to next brightness if touch is between 100 and 800ms
|
||||
touchDuration = 0; //Reset touch duration to avoid multiple actions on same touch
|
||||
if(bri < brightness1) {
|
||||
bri = brightness1;
|
||||
} else if(bri >= brightness1 && bri < brightness2) {
|
||||
bri = brightness2;
|
||||
} else if(bri >= brightness2 && bri < brightness3) {
|
||||
bri = brightness3;
|
||||
} else if(bri >= brightness3 && bri < brightness4) {
|
||||
bri = brightness4;
|
||||
} else if(bri >= brightness4 && bri < brightness5) {
|
||||
bri = brightness5;
|
||||
} else if(bri >= brightness5) {
|
||||
bri = brightness1;
|
||||
}
|
||||
colorUpdated(2); //Refresh values
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif
|
||||
@@ -103,7 +103,43 @@ class MyExampleUsermod : public Usermod {
|
||||
userVar0 = root["user0"] | userVar0; //if "user0" key exists in JSON, update, else keep old value
|
||||
//if (root["bri"] == 255) Serial.println(F("Don't burn down your garage!"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
JsonObject top = root.createNestedObject("exampleUsermod");
|
||||
top["great"] = userVar0; //save this var persistently whenever settings are saved
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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 :)
|
||||
*/
|
||||
void readFromConfig(JsonObject& root)
|
||||
{
|
||||
JsonObject top = root["top"];
|
||||
userVar0 = top["great"] | 42; //The value right of the pipe "|" is the default value in case your setting was not present in cfg.json (e.g. first boot)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
|
||||
|
||||
|
Before Width: | Height: | Size: 150 KiB After Width: | Height: | Size: 136 KiB |
|
Before Width: | Height: | Size: 235 KiB After Width: | Height: | Size: 201 KiB |
@@ -1,17 +1,32 @@
|
||||
# Fix unreachable net services V2
|
||||
|
||||
**Attention: This usermod compiles only for ESP8266**
|
||||
|
||||
This usermod-v2 modification performs a ping request to the local IP address every 60 seconds. By this procedure the net services of WLED remains accessible in some problematic WLAN environments.
|
||||
|
||||
The modification works with static or DHCP IP address configuration.
|
||||
|
||||
**Webinterface**: The number of pings and reconnects is displayed on the info page in the web interface.
|
||||
|
||||
_Story:_
|
||||
|
||||
Unfortunately, with all ESP projects where a web server or other network services are running, I have the problem that after some time the web server is no longer accessible. Now I found out that the connection is at least reestablished when a ping request is executed by the device.
|
||||
|
||||
With this modification, in the worst case, the network functions are not available for 60 seconds until the next ping request.
|
||||
|
||||
## Webinterface
|
||||
|
||||
The number of pings and reconnects is displayed on the info page in the web interface.
|
||||
The ping delay can be changed. Changes persist after a reboot.
|
||||
|
||||
## JSON API
|
||||
|
||||
The usermod supports the following state changes:
|
||||
|
||||
| JSON key | Value range | Description |
|
||||
|-------------|------------------|---------------------------------|
|
||||
| PingDelayMs | 5000 to 18000000 | Deactivdate/activate the sensor |
|
||||
|
||||
Changes also persist after a reboot.
|
||||
|
||||
## Installation
|
||||
|
||||
1. Copy the file `usermod_Fix_unreachable_netservices.h` to the `wled00` directory.
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
#if defined(ESP32)
|
||||
#warning "Usermod FixUnreachableNetServices works only with ESP8266 builds"
|
||||
class FixUnreachableNetServices : public Usermod
|
||||
{
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(ESP8266)
|
||||
#include <ping.h>
|
||||
|
||||
/*
|
||||
@@ -23,116 +31,138 @@
|
||||
* 2. Register the usermod by adding #include "usermod_filename.h" in the top and registerUsermod(new MyUsermodClass()) in the bottom of usermods_list.cpp
|
||||
*/
|
||||
|
||||
class FixUnreachableNetServices : public Usermod {
|
||||
private:
|
||||
//Private class members. You can declare variables and functions only accessible to your usermod here
|
||||
unsigned long m_lastTime = 0;
|
||||
class FixUnreachableNetServices : public Usermod
|
||||
{
|
||||
private:
|
||||
//Private class members. You can declare variables and functions only accessible to your usermod here
|
||||
unsigned long m_lastTime = 0;
|
||||
|
||||
// desclare required variables
|
||||
const unsigned int PingDelayMs = 60000;
|
||||
unsigned long m_connectedWiFi = 0;
|
||||
ping_option m_pingOpt;
|
||||
unsigned int m_pingCount = 0;
|
||||
// declare required variables
|
||||
unsigned long m_pingDelayMs = 60000;
|
||||
unsigned long m_connectedWiFi = 0;
|
||||
ping_option m_pingOpt;
|
||||
unsigned int m_pingCount = 0;
|
||||
bool m_updateConfig = false;
|
||||
|
||||
public:
|
||||
//Functions called by WLED
|
||||
public:
|
||||
//Functions called by WLED
|
||||
|
||||
/*
|
||||
* setup() is called once at boot. WiFi is not yet connected at this point.
|
||||
* You can use it to initialize variables, sensors or similar.
|
||||
*/
|
||||
void setup() {
|
||||
//Serial.println("Hello from my usermod!");
|
||||
}
|
||||
/**
|
||||
* setup() is called once at boot. WiFi is not yet connected at this point.
|
||||
* You can use it to initialize variables, sensors or similar.
|
||||
*/
|
||||
void setup()
|
||||
{
|
||||
//Serial.println("Hello from my usermod!");
|
||||
}
|
||||
|
||||
/**
|
||||
* connected() is called every time the WiFi is (re)connected
|
||||
* Use it to initialize network interfaces
|
||||
*/
|
||||
void connected()
|
||||
{
|
||||
//Serial.println("Connected to WiFi!");
|
||||
|
||||
/*
|
||||
* connected() is called every time the WiFi is (re)connected
|
||||
* Use it to initialize network interfaces
|
||||
*/
|
||||
void connected() {
|
||||
//Serial.println("Connected to WiFi!");
|
||||
++m_connectedWiFi;
|
||||
|
||||
++m_connectedWiFi;
|
||||
|
||||
// initialize ping_options structure
|
||||
memset(&m_pingOpt, 0, sizeof(struct ping_option));
|
||||
m_pingOpt.count = 1;
|
||||
m_pingOpt.ip = WiFi.localIP();
|
||||
// initialize ping_options structure
|
||||
memset(&m_pingOpt, 0, sizeof(struct ping_option));
|
||||
m_pingOpt.count = 1;
|
||||
m_pingOpt.ip = WiFi.localIP();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* loop() is called continuously. Here you can check for events, read sensors, etc.
|
||||
*
|
||||
* Tips:
|
||||
* 1. You can use "if (WLED_CONNECTED)" to check for a successful network connection.
|
||||
* Additionally, "if (WLED_MQTT_CONNECTED)" is available to check for a connection to an MQTT broker.
|
||||
*
|
||||
* 2. Try to avoid using the delay() function. NEVER use delays longer than 10 milliseconds.
|
||||
* Instead, use a timer check as shown here.
|
||||
*/
|
||||
void loop() {
|
||||
if (m_connectedWiFi > 0 && millis()-m_lastTime > PingDelayMs)
|
||||
{
|
||||
ping_start(&m_pingOpt);
|
||||
m_lastTime = millis();
|
||||
++m_pingCount;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
|
||||
* Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI.
|
||||
* Below it is shown how this could be used for e.g. a light sensor
|
||||
*/
|
||||
void addToJsonInfo(JsonObject& root)
|
||||
/**
|
||||
* loop
|
||||
*/
|
||||
void loop()
|
||||
{
|
||||
if (m_connectedWiFi > 0 && millis() - m_lastTime > m_pingDelayMs)
|
||||
{
|
||||
//this code adds "u":{"⚡ Ping fix pings": m_pingCount} to the info object
|
||||
JsonObject user = root["u"];
|
||||
if (user.isNull()) user = root.createNestedObject("u");
|
||||
|
||||
JsonArray infoArr = user.createNestedArray("⚡ Ping fix pings"); //name
|
||||
infoArr.add(m_pingCount); //value
|
||||
|
||||
//this code adds "u":{"⚡ Reconnects": m_connectedWiFi - 1} to the info object
|
||||
infoArr = user.createNestedArray("⚡ Reconnects"); //name
|
||||
infoArr.add(m_connectedWiFi - 1); //value
|
||||
ping_start(&m_pingOpt);
|
||||
m_lastTime = millis();
|
||||
++m_pingCount;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
|
||||
* Values in the state object may be modified by connected clients
|
||||
*/
|
||||
void addToJsonState(JsonObject& root)
|
||||
if (m_updateConfig)
|
||||
{
|
||||
//root["user0"] = userVar0;
|
||||
serializeConfig();
|
||||
m_updateConfig = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
|
||||
* Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI.
|
||||
* Below it is shown how this could be used for e.g. a light sensor
|
||||
*/
|
||||
void addToJsonInfo(JsonObject &root)
|
||||
{
|
||||
//this code adds "u":{"⚡ Ping fix pings": m_pingCount} to the info object
|
||||
JsonObject user = root["u"];
|
||||
if (user.isNull())
|
||||
user = root.createNestedObject("u");
|
||||
|
||||
/*
|
||||
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
|
||||
* Values in the state object may be modified by connected clients
|
||||
*/
|
||||
void readFromJsonState(JsonObject& root)
|
||||
String uiDomString = "⚡ Ping fix pings<span style=\"display:block;padding-left:25px;\">\
|
||||
Delay <input type=\"number\" min=\"5\" max=\"300\" value=\"";
|
||||
uiDomString += (unsigned long)(m_pingDelayMs / 1000);
|
||||
uiDomString += "\" onchange=\"requestJson({PingDelay:parseInt(this.value)});\">sec</span>";
|
||||
|
||||
JsonArray infoArr = user.createNestedArray(uiDomString); //name
|
||||
infoArr.add(m_pingCount); //value
|
||||
|
||||
//this code adds "u":{"⚡ Reconnects": m_connectedWiFi - 1} to the info object
|
||||
infoArr = user.createNestedArray("⚡ Reconnects"); //name
|
||||
infoArr.add(m_connectedWiFi - 1); //value
|
||||
}
|
||||
|
||||
/**
|
||||
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
|
||||
* Values in the state object may be modified by connected clients
|
||||
*/
|
||||
void addToJsonState(JsonObject &root)
|
||||
{
|
||||
root["PingDelay"] = (m_pingDelayMs/1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
|
||||
* Values in the state object may be modified by connected clients
|
||||
*/
|
||||
void readFromJsonState(JsonObject &root)
|
||||
{
|
||||
if (root["PingDelay"] != nullptr)
|
||||
{
|
||||
//userVar0 = root["user0"] | userVar0; //if "user0" key exists in JSON, update, else keep old value
|
||||
//if (root["bri"] == 255) Serial.println(F("Don't burn down your garage!"));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
|
||||
* This could be used in the future for the system to determine whether your usermod is installed.
|
||||
*/
|
||||
uint16_t getId()
|
||||
{
|
||||
return USERMOD_ID_FIXNETSERVICES;
|
||||
m_pingDelayMs = (1000 * max(1UL, min(300UL, root["PingDelay"].as<unsigned long>())));
|
||||
m_updateConfig = true;
|
||||
}
|
||||
}
|
||||
|
||||
//More methods can be added in the future, this example will then be extended.
|
||||
//Your usermod will remain compatible as it does not need to implement all methods from the Usermod base class!
|
||||
/**
|
||||
* provide the changeable values
|
||||
*/
|
||||
void addToConfig(JsonObject &root)
|
||||
{
|
||||
JsonObject top = root.createNestedObject("FixUnreachableNetServices");
|
||||
top["PingDelayMs"] = m_pingDelayMs;
|
||||
}
|
||||
|
||||
/**
|
||||
* restore the changeable values
|
||||
*/
|
||||
void readFromConfig(JsonObject &root)
|
||||
{
|
||||
JsonObject top = root["FixUnreachableNetServices"];
|
||||
m_pingDelayMs = top["PingDelayMs"] | m_pingDelayMs;
|
||||
m_pingDelayMs = max(5000UL, min(18000000UL, m_pingDelayMs));
|
||||
}
|
||||
|
||||
/**
|
||||
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
|
||||
* This could be used in the future for the system to determine whether your usermod is installed.
|
||||
*/
|
||||
uint16_t getId()
|
||||
{
|
||||
return USERMOD_ID_FIXNETSERVICES;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
# Fix unreachable Webserver
|
||||
|
||||
This modification performs a ping request to the local IP address every 60 seconds. By this procedure the web server remains accessible in some problematic WLAN environments.
|
||||
|
||||
The modification works with static or DHCP IP address configuration
|
||||
|
||||
_Story:_
|
||||
|
||||
Unfortunately, with all ESP projects where a web server or other network services are running, I have the problem that after some time the web server is no longer accessible. Now I found out that the connection is at least reestablished when a ping request is executed by the device.
|
||||
|
||||
With this modification, in the worst case, the network functions are not available for 60 seconds until the next ping request.
|
||||
|
||||
## Installation
|
||||
|
||||
Copy and replace the file `usermod.cpp` in wled00 directory.
|
||||
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
#include "wled.h"
|
||||
/*
|
||||
* This file allows you to add own functionality to WLED more easily
|
||||
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
|
||||
* EEPROM bytes 2750+ are reserved for your custom use case. (if you extend #define EEPSIZE in const.h)
|
||||
* bytes 2400+ are currently ununsed, but might be used for future wled features
|
||||
*/
|
||||
|
||||
#include <ping.h>
|
||||
|
||||
const int PingDelayMs = 60000;
|
||||
long lastCheckTime = 0;
|
||||
bool connectedWiFi = false;
|
||||
ping_option pingOpt;
|
||||
|
||||
//Use userVar0 and userVar1 (API calls &U0=,&U1=, uint16_t)
|
||||
|
||||
//gets called once at boot. Do all initialization that doesn't depend on network here
|
||||
void userSetup()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
//gets called every time WiFi is (re-)connected. Initialize own network interfaces here
|
||||
void userConnected()
|
||||
{
|
||||
connectedWiFi = true;
|
||||
// initialize ping_options structure
|
||||
memset(&pingOpt, 0, sizeof(struct ping_option));
|
||||
pingOpt.count = 1;
|
||||
pingOpt.ip = WiFi.localIP();
|
||||
}
|
||||
|
||||
//loop. You can use "if (WLED_CONNECTED)" to check for successful connection
|
||||
void userLoop()
|
||||
{
|
||||
if (connectedWiFi && millis()-lastCheckTime > PingDelayMs)
|
||||
{
|
||||
ping_start(&pingOpt);
|
||||
lastCheckTime = millis();
|
||||
}
|
||||
}
|
||||
347
usermods/PIR_sensor_switch/PIR_Highlight_Standby
Normal file
@@ -0,0 +1,347 @@
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
|
||||
/*
|
||||
* --------------------
|
||||
* Rawframe edit:
|
||||
* - TESTED ON WLED VS.0.10.1 - WHERE ONLY PRESET 16 SAVES SEGMENTS - some macros may not be needed if this changes.
|
||||
* - Code has been modified as my usage changed, as such it has poor use of functions vs if thens, but feel free to change it for me :)
|
||||
*
|
||||
* Edited to SWITCH between two lighting scenes/modes : STANDBY and HIGHLIGHT
|
||||
*
|
||||
* Usage:
|
||||
* - Standby is the default mode and Highlight is activated when the PIR detects activity.
|
||||
* - PIR delay now set to same value as Nightlight feature on boot but otherwise controlled as normal.
|
||||
* - Standby and Highlight brightness can be set on the fly (default values set on boot via macros calling presets).
|
||||
* - Macros are used to set Standby and Highlight states (macros can load saved presets etc).
|
||||
*
|
||||
* - Macro short button press = Highlight state default (used on boot only and sets default brightness).
|
||||
* - Macro double button press = Standby state default (used on boot only and sets default brightness).
|
||||
* - Macro long button press = Highlight state (after boot).
|
||||
* - Macro 16 = Standby state (after boot).
|
||||
*
|
||||
* ! It is advised not to set 'Apply preset at boot' or a boot macro (that activates a preset) as we will call our own macros on boot.
|
||||
*
|
||||
* - When the strip is off before PIR activates the strip will return to off for Standby mode, and vice versa.
|
||||
* - When the strip is turned off while in Highlight mode, it will return to standby mode. (This behaviour could be changed easily if for some reason you wanted the lights to go out when the pir is activated).
|
||||
* - Macros can be chained so you could do almost anything, such as have standby mode also turn on the nightlight function with a new time delay.
|
||||
*
|
||||
* Segment Notes:
|
||||
* - It's easier to save the segment selections in preset than apply via macro while we a limited to preset 16. (Ie, instead of selecting sections at the point of activating standby/highlight modes).
|
||||
* - Because only preset 16 saves segments, for now we are having to use addiotional macros to control segments where they are involved. Macros can be chained so this works but it would be better if macros also accepted json-api commands. (Testing http api segement behaviour of SS with SB left me a little confused).
|
||||
*
|
||||
* Future:
|
||||
* - Maybe a second timer/timetable that turns on/off standby mode also after set inactivity period / date & times. For now this can be achieved others ways so may not be worth eating more processing power.
|
||||
*
|
||||
* --------------------
|
||||
*
|
||||
* This usermod handles PIR sensor states.
|
||||
* The strip will be switched on and the off timer will be resetted when the sensor goes HIGH.
|
||||
* When the sensor state goes LOW, the off timer is started and when it expires, the strip is switched off.
|
||||
*
|
||||
*
|
||||
* Usermods allow you to add own functionality to WLED more easily
|
||||
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
|
||||
*
|
||||
* v2 usermods are class inheritance based and can (but don't have to) implement more functions, each of them is shown in this example.
|
||||
* Multiple v2 usermods can be added to one compilation easily.
|
||||
*
|
||||
* Creating a usermod:
|
||||
* This file serves as an example. If you want to create a usermod, it is recommended to use usermod_v2_empty.h from the usermods folder as a template.
|
||||
* Please remember to rename the class and file to a descriptive name.
|
||||
* You may also use multiple .h and .cpp files.
|
||||
*
|
||||
* Using a usermod:
|
||||
* 1. Copy the usermod into the sketch folder (same folder as wled00.ino)
|
||||
* 2. Register the usermod by adding #include "usermod_filename.h" in the top and registerUsermod(new MyUsermodClass()) in the bottom of usermods_list.cpp
|
||||
*/
|
||||
|
||||
class PIRsensorSwitch : public Usermod {
|
||||
private:
|
||||
// PIR sensor pin
|
||||
const uint8_t PIRsensorPin = 13; // D7 on D1 mini
|
||||
// notification mode for colorUpdated()
|
||||
const byte NotifyUpdateMode = NOTIFIER_CALL_MODE_NO_NOTIFY; // NOTIFIER_CALL_MODE_DIRECT_CHANGE
|
||||
// 1 min delay before switch off after the sensor state goes LOW
|
||||
uint32_t m_switchOffDelay = 60000;
|
||||
// off timer start time
|
||||
uint32_t m_offTimerStart = 0;
|
||||
// current PIR sensor pin state
|
||||
byte m_PIRsensorPinState = LOW;
|
||||
// PIR sensor enabled - ISR attached
|
||||
bool m_PIRenabled = true;
|
||||
// temp standby brightness store. initial value set as nightlight default target brightness
|
||||
byte briStandby _INIT(nightlightTargetBri);
|
||||
// temp hightlight brightness store. initial value set as current brightness
|
||||
byte briHighlight _INIT(bri);
|
||||
// highlight active/deactive monitor
|
||||
bool highlightActive = false;
|
||||
// wled on/off state in standby mode
|
||||
bool standbyoff = false;
|
||||
|
||||
/*
|
||||
* return or change if new PIR sensor state is available
|
||||
*/
|
||||
static volatile bool newPIRsensorState(bool changeState = false, bool newState = false) {
|
||||
static volatile bool s_PIRsensorState = false;
|
||||
if (changeState) {
|
||||
s_PIRsensorState = newState;
|
||||
}
|
||||
return s_PIRsensorState;
|
||||
}
|
||||
|
||||
/*
|
||||
* PIR sensor state has changed
|
||||
*/
|
||||
static void IRAM_ATTR ISR_PIRstateChange() {
|
||||
newPIRsensorState(true, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* switch strip on/off
|
||||
*/
|
||||
// now allowing adjustable standby and highlight brightness
|
||||
void switchStrip(bool switchOn) {
|
||||
//if (switchOn && bri == 0) {
|
||||
if (switchOn) { // **pir sensor is on and activated**
|
||||
//bri = briLast;
|
||||
if (bri != 0) { // is WLED currently on
|
||||
if (highlightActive) { // and is Highlight already on
|
||||
briHighlight = bri; // then update highlight brightness with current brightness
|
||||
}
|
||||
else {
|
||||
briStandby = bri; // else update standby brightness with current brightness
|
||||
}
|
||||
}
|
||||
else { // WLED is currently off
|
||||
if (!highlightActive) { // and Highlight is not already on
|
||||
briStandby = briLast; // then update standby brightness with last active brightness (before turned off)
|
||||
standbyoff = true;
|
||||
}
|
||||
else { // and Highlight is already on
|
||||
briHighlight = briLast; // then set hightlight brightness to last active brightness (before turned off)
|
||||
}
|
||||
}
|
||||
applyMacro(16); // apply highlight lighting without brightness
|
||||
if (bri != briHighlight) {
|
||||
bri = briHighlight; // set current highlight brightness to last set highlight brightness
|
||||
}
|
||||
colorUpdated(NotifyUpdateMode);
|
||||
highlightActive = true; // flag highlight is on
|
||||
}
|
||||
else { // **pir timer has elapsed**
|
||||
//briLast = bri;
|
||||
//bri = 0;
|
||||
if (bri != 0) { // is WLED currently on
|
||||
briHighlight = bri; // update highlight brightness with current brightness
|
||||
if (!standbyoff) { //
|
||||
bri = briStandby; // set standby brightness to last set standby brightness
|
||||
}
|
||||
else { //
|
||||
briLast = briStandby; // set standby off brightness
|
||||
bri = 0; // set power off in standby
|
||||
standbyoff = false; // turn off flag
|
||||
}
|
||||
applyMacro(macroLongPress); // apply standby lighting without brightness
|
||||
}
|
||||
else { // WLED is currently off
|
||||
briHighlight = briLast; // set last active brightness (before turned off) to highlight lighting brightness
|
||||
if (!standbyoff) { //
|
||||
bri = briStandby; // set standby brightness to last set standby brightness
|
||||
}
|
||||
else { //
|
||||
briLast = briStandby; // set standby off brightness
|
||||
bri = 0; // set power off in standby
|
||||
standbyoff = false; // turn off flag
|
||||
}
|
||||
applyMacro(macroLongPress); // apply standby lighting without brightness
|
||||
}
|
||||
colorUpdated(NotifyUpdateMode);
|
||||
highlightActive = false; // flag highlight is off
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read and update PIR sensor state.
|
||||
* Initilize/reset switch off timer
|
||||
*/
|
||||
bool updatePIRsensorState() {
|
||||
if (newPIRsensorState()) {
|
||||
m_PIRsensorPinState = digitalRead(PIRsensorPin);
|
||||
|
||||
if (m_PIRsensorPinState == HIGH) {
|
||||
m_offTimerStart = 0;
|
||||
switchStrip(true);
|
||||
}
|
||||
else if (bri != 0) {
|
||||
// start switch off timer
|
||||
m_offTimerStart = millis();
|
||||
}
|
||||
newPIRsensorState(true, false);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* switch off the strip if the delay has elapsed
|
||||
*/
|
||||
bool handleOffTimer() {
|
||||
if (m_offTimerStart > 0) {
|
||||
if ((millis() - m_offTimerStart > m_switchOffDelay) || bri == 0 ) { // now also checking for manual power off during highlight mode
|
||||
switchStrip(false);
|
||||
m_offTimerStart = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
//Functions called by WLED
|
||||
|
||||
/*
|
||||
* setup() is called once at boot. WiFi is not yet connected at this point.
|
||||
* You can use it to initialize variables, sensors or similar.
|
||||
*/
|
||||
void setup() {
|
||||
// PIR Sensor mode INPUT_PULLUP
|
||||
pinMode(PIRsensorPin, INPUT_PULLUP);
|
||||
// assign interrupt function and set CHANGE mode
|
||||
attachInterrupt(digitalPinToInterrupt(PIRsensorPin), ISR_PIRstateChange, CHANGE);
|
||||
// set delay to nightlight default duration on boot (after which json PIRoffSec overides if needed)
|
||||
m_switchOffDelay = (nightlightDelayMins*60000);
|
||||
applyMacro(macroButton); // apply default highlight lighting
|
||||
briHighlight = bri;
|
||||
applyMacro(macroDoublePress); // apply default standby lighting with brightness
|
||||
briStandby = bri;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* connected() is called every time the WiFi is (re)connected
|
||||
* Use it to initialize network interfaces
|
||||
*/
|
||||
void connected() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* loop() is called continuously. Here you can check for events, read sensors, etc.
|
||||
*/
|
||||
void loop() {
|
||||
if (!updatePIRsensorState()) {
|
||||
handleOffTimer();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
|
||||
*
|
||||
* Add PIR sensor state and switch off timer duration to jsoninfo
|
||||
*/
|
||||
void addToJsonInfo(JsonObject& root)
|
||||
{
|
||||
//this code adds "u":{"⏲ PIR sensor state":uiDomString} to the info object
|
||||
// the value contains a button to toggle the sensor enabled/disabled
|
||||
JsonObject user = root["u"];
|
||||
if (user.isNull()) user = root.createNestedObject("u");
|
||||
|
||||
JsonArray infoArr = user.createNestedArray("⏲ PIR sensor state"); //name
|
||||
String uiDomString = "<button class=\"btn infobtn\" onclick=\"requestJson({PIRenabled:";
|
||||
String sensorStateInfo;
|
||||
|
||||
// PIR sensor state
|
||||
if (m_PIRenabled) {
|
||||
uiDomString += "false";
|
||||
sensorStateInfo = (m_PIRsensorPinState != LOW ? "active" : "inactive"); //value
|
||||
} else {
|
||||
uiDomString += "true";
|
||||
sensorStateInfo = "Disabled !";
|
||||
}
|
||||
uiDomString += "});return false;\">";
|
||||
uiDomString += sensorStateInfo;
|
||||
uiDomString += "</button>";
|
||||
infoArr.add(uiDomString); //value
|
||||
|
||||
//this code adds "u":{"⏲ switch off timer":uiDomString} to the info object
|
||||
infoArr = user.createNestedArray("⏲ switch off timer"); //name
|
||||
|
||||
// off timer
|
||||
if (m_offTimerStart > 0) {
|
||||
uiDomString = "";
|
||||
unsigned int offSeconds = (m_switchOffDelay - (millis() - m_offTimerStart)) / 1000;
|
||||
if (offSeconds >= 3600) {
|
||||
uiDomString += (offSeconds / 3600);
|
||||
uiDomString += " hours ";
|
||||
offSeconds %= 3600;
|
||||
}
|
||||
if (offSeconds >= 60) {
|
||||
uiDomString += (offSeconds / 60);
|
||||
offSeconds %= 60;
|
||||
} else if (uiDomString.length() > 0){
|
||||
uiDomString += 0;
|
||||
}
|
||||
if (uiDomString.length() > 0){
|
||||
uiDomString += " min ";
|
||||
}
|
||||
uiDomString += (offSeconds);
|
||||
infoArr.add(uiDomString + " sec");
|
||||
} else {
|
||||
infoArr.add("inactive");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
|
||||
* Values in the state object may be modified by connected clients
|
||||
* Add "PIRenabled" to json state. This can be used to disable/enable the sensor.
|
||||
* Add "PIRoffSec" to json state. This can be used to adjust <m_switchOffDelay> milliseconds .
|
||||
*/
|
||||
void addToJsonState(JsonObject& root)
|
||||
{
|
||||
root["PIRenabled"] = m_PIRenabled;
|
||||
root["PIRoffSec"] = (m_switchOffDelay / 1000);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
|
||||
* Values in the state object may be modified by connected clients
|
||||
* Read "PIRenabled" from json state and switch enable/disable the PIR sensor.
|
||||
* Read "PIRoffSec" from json state and adjust <m_switchOffDelay> milliseconds .
|
||||
*/
|
||||
void readFromJsonState(JsonObject& root)
|
||||
{
|
||||
if (root["PIRoffSec"] != nullptr) {
|
||||
m_switchOffDelay = (1000 * max(60UL, min(43200UL, root["PIRoffSec"].as<unsigned long>())));
|
||||
}
|
||||
|
||||
if (root["PIRenabled"] != nullptr) {
|
||||
if (root["PIRenabled"] && !m_PIRenabled) {
|
||||
attachInterrupt(digitalPinToInterrupt(PIRsensorPin), ISR_PIRstateChange, CHANGE);
|
||||
newPIRsensorState(true, true);
|
||||
}
|
||||
else if(m_PIRenabled) {
|
||||
detachInterrupt(PIRsensorPin);
|
||||
}
|
||||
m_PIRenabled = root["PIRenabled"];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
|
||||
* This could be used in the future for the system to determine whether your usermod is installed.
|
||||
*/
|
||||
uint16_t getId()
|
||||
{
|
||||
return USERMOD_ID_PIRSWITCH;
|
||||
}
|
||||
|
||||
//More methods can be added in the future, this example will then be extended.
|
||||
//Your usermod will remain compatible as it does not need to implement all methods from the Usermod base class!
|
||||
};
|
||||
@@ -11,19 +11,21 @@ The LED strip is switched [using a relay](https://github.com/Aircoookie/WLED/wik
|
||||
|
||||
The info page in the web interface shows the items below
|
||||
|
||||
- the state of the sensor. By clicking on the state the sensor can be deactivated/activated.
|
||||
**I recommend to deactivate the sensor before installing an OTA update**.
|
||||
- the state of the sensor. By clicking on the state the sensor can be deactivated/activated. Changes persist after a reboot.
|
||||
**I recommend to deactivate the sensor before an OTA update and activate it again afterwards**.
|
||||
- the remaining time of the off timer.
|
||||
|
||||
## JSON API
|
||||
|
||||
The usermod supports the following state changes:
|
||||
The usermod supports the following state changes:
|
||||
|
||||
| JSON key | Value range | Description |
|
||||
|------------|-------------|---------------------------------|
|
||||
| PIRenabled | bool | Deactivdate/activate the sensor |
|
||||
| PIRoffSec | 60 to 43200 | Off timer seconds |
|
||||
|
||||
Changes also persist after a reboot.
|
||||
|
||||
## Sensor connection
|
||||
|
||||
My setup uses an HC-SR501 sensor, a HC-SR505 should also work.
|
||||
@@ -55,7 +57,7 @@ Example **usermods_list.cpp**:
|
||||
//#include "usermod_v2_example.h"
|
||||
//#include "usermod_temperature.h"
|
||||
//#include "usermod_v2_empty.h"
|
||||
#include "usermod_PIR_sensor_switch.h"
|
||||
#include "usermod_PIR_sensor_switch.h"
|
||||
|
||||
void registerUsermods()
|
||||
{
|
||||
@@ -72,4 +74,36 @@ void registerUsermods()
|
||||
}
|
||||
```
|
||||
|
||||
## API to enable/disable the PIR sensor from outside. For example from another usermod.
|
||||
|
||||
The class provides the static method `PIRsensorSwitch* PIRsensorSwitch::GetInstance()` to get a pointer to the usermod object.
|
||||
|
||||
To query or change the PIR sensor state the methods `bool PIRsensorEnabled()` and `void EnablePIRsensor(bool enable)` are available.
|
||||
|
||||
### There are two options to get access to the usermod instance:
|
||||
|
||||
1. Include `usermod_PIR_sensor_switch.h` **before** you include the other usermod in `usermods_list.cpp'
|
||||
|
||||
or
|
||||
|
||||
2. Use `#include "usermod_PIR_sensor_switch.h"` at the top of the `usermod.h` where you need it.
|
||||
|
||||
**Example usermod.h :**
|
||||
```cpp
|
||||
#include "wled.h"
|
||||
|
||||
#include "usermod_PIR_sensor_switch.h"
|
||||
|
||||
class MyUsermod : public Usermod {
|
||||
//...
|
||||
|
||||
void togglePIRSensor() {
|
||||
if (PIRsensorSwitch::GetInstance() != nullptr) {
|
||||
PIRsensorSwitch::GetInstance()->EnablePIRsensor(!PIRsensorSwitch::GetInstance()->PIRsensorEnabled());
|
||||
}
|
||||
}
|
||||
//...
|
||||
};
|
||||
```
|
||||
|
||||
Have fun - @gegu
|
||||
|
||||
@@ -24,226 +24,343 @@
|
||||
* 2. Register the usermod by adding #include "usermod_filename.h" in the top and registerUsermod(new MyUsermodClass()) in the bottom of usermods_list.cpp
|
||||
*/
|
||||
|
||||
class PIRsensorSwitch : public Usermod {
|
||||
private:
|
||||
// PIR sensor pin
|
||||
const uint8_t PIRsensorPin = 13; // D7 on D1 mini
|
||||
// notification mode for colorUpdated()
|
||||
const byte NotifyUpdateMode = NOTIFIER_CALL_MODE_NO_NOTIFY; // NOTIFIER_CALL_MODE_DIRECT_CHANGE
|
||||
// delay before switch off after the sensor state goes LOW
|
||||
uint32_t m_switchOffDelay = 600000;
|
||||
// off timer start time
|
||||
uint32_t m_offTimerStart = 0;
|
||||
// current PIR sensor pin state
|
||||
byte m_PIRsensorPinState = LOW;
|
||||
// PIR sensor enabled - ISR attached
|
||||
bool m_PIRenabled = true;
|
||||
class PIRsensorSwitch : public Usermod
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* constructor
|
||||
*/
|
||||
PIRsensorSwitch()
|
||||
{
|
||||
// set static instance pointer
|
||||
PIRsensorSwitchInstance(this);
|
||||
}
|
||||
/**
|
||||
* desctructor
|
||||
*/
|
||||
~PIRsensorSwitch()
|
||||
{
|
||||
PIRsensorSwitchInstance(nullptr, true);
|
||||
;
|
||||
}
|
||||
|
||||
/*
|
||||
* return or change if new PIR sensor state is available
|
||||
*/
|
||||
static volatile bool newPIRsensorState(bool changeState = false, bool newState = false) {
|
||||
static volatile bool s_PIRsensorState = false;
|
||||
if (changeState) {
|
||||
s_PIRsensorState = newState;
|
||||
/**
|
||||
* return the instance pointer of the class
|
||||
*/
|
||||
static PIRsensorSwitch *GetInstance() { return PIRsensorSwitchInstance(); }
|
||||
|
||||
/**
|
||||
* Enable/Disable the PIR sensor
|
||||
*/
|
||||
void EnablePIRsensor(bool enable) { m_PIRenabled = enable; }
|
||||
/**
|
||||
* Get PIR sensor enabled/disabled state
|
||||
*/
|
||||
bool PIRsensorEnabled() { return m_PIRenabled; }
|
||||
|
||||
private:
|
||||
// PIR sensor pin
|
||||
const uint8_t PIRsensorPin = 13; // D7 on D1 mini
|
||||
// notification mode for colorUpdated()
|
||||
const byte NotifyUpdateMode = NOTIFIER_CALL_MODE_NO_NOTIFY; // NOTIFIER_CALL_MODE_DIRECT_CHANGE
|
||||
// delay before switch off after the sensor state goes LOW
|
||||
uint32_t m_switchOffDelay = 600000;
|
||||
// off timer start time
|
||||
uint32_t m_offTimerStart = 0;
|
||||
// current PIR sensor pin state
|
||||
byte m_PIRsensorPinState = LOW;
|
||||
// PIR sensor enabled - ISR attached
|
||||
bool m_PIRenabled = true;
|
||||
// state if serializeConfig() should be called
|
||||
bool m_updateConfig = false;
|
||||
|
||||
/**
|
||||
* return or change if new PIR sensor state is available
|
||||
*/
|
||||
static volatile bool newPIRsensorState(bool changeState = false, bool newState = false);
|
||||
|
||||
/**
|
||||
* PIR sensor state has changed
|
||||
*/
|
||||
static void IRAM_ATTR ISR_PIRstateChange();
|
||||
|
||||
/**
|
||||
* Set/get instance pointer
|
||||
*/
|
||||
static PIRsensorSwitch *PIRsensorSwitchInstance(PIRsensorSwitch *pInstance = nullptr, bool bRemoveInstance = false);
|
||||
|
||||
/**
|
||||
* switch strip on/off
|
||||
*/
|
||||
void switchStrip(bool switchOn)
|
||||
{
|
||||
if (switchOn && bri == 0)
|
||||
{
|
||||
bri = briLast;
|
||||
colorUpdated(NotifyUpdateMode);
|
||||
}
|
||||
else if (!switchOn && bri != 0)
|
||||
{
|
||||
briLast = bri;
|
||||
bri = 0;
|
||||
colorUpdated(NotifyUpdateMode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and update PIR sensor state.
|
||||
* Initilize/reset switch off timer
|
||||
*/
|
||||
bool updatePIRsensorState()
|
||||
{
|
||||
if (newPIRsensorState())
|
||||
{
|
||||
m_PIRsensorPinState = digitalRead(PIRsensorPin);
|
||||
|
||||
if (m_PIRsensorPinState == HIGH)
|
||||
{
|
||||
m_offTimerStart = 0;
|
||||
switchStrip(true);
|
||||
}
|
||||
return s_PIRsensorState;
|
||||
}
|
||||
|
||||
/*
|
||||
* PIR sensor state has changed
|
||||
*/
|
||||
static void IRAM_ATTR ISR_PIRstateChange() {
|
||||
newPIRsensorState(true, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* switch strip on/off
|
||||
*/
|
||||
void switchStrip(bool switchOn) {
|
||||
if (switchOn && bri == 0) {
|
||||
bri = briLast;
|
||||
colorUpdated(NotifyUpdateMode);
|
||||
}
|
||||
else if (!switchOn && bri != 0) {
|
||||
briLast = bri;
|
||||
bri = 0;
|
||||
colorUpdated(NotifyUpdateMode);
|
||||
else if (bri != 0)
|
||||
{
|
||||
// start switch off timer
|
||||
m_offTimerStart = millis();
|
||||
}
|
||||
newPIRsensorState(true, false);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read and update PIR sensor state.
|
||||
* Initilize/reset switch off timer
|
||||
*/
|
||||
bool updatePIRsensorState() {
|
||||
if (newPIRsensorState()) {
|
||||
m_PIRsensorPinState = digitalRead(PIRsensorPin);
|
||||
|
||||
if (m_PIRsensorPinState == HIGH) {
|
||||
m_offTimerStart = 0;
|
||||
switchStrip(true);
|
||||
}
|
||||
else if (bri != 0) {
|
||||
// start switch off timer
|
||||
m_offTimerStart = millis();
|
||||
}
|
||||
newPIRsensorState(true, false);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* switch off the strip if the delay has elapsed
|
||||
*/
|
||||
bool handleOffTimer() {
|
||||
if (m_offTimerStart > 0 && millis() - m_offTimerStart > m_switchOffDelay) {
|
||||
/**
|
||||
* switch off the strip if the delay has elapsed
|
||||
*/
|
||||
bool handleOffTimer()
|
||||
{
|
||||
if (m_offTimerStart > 0 && millis() - m_offTimerStart > m_switchOffDelay)
|
||||
{
|
||||
if (m_PIRenabled == true)
|
||||
{
|
||||
switchStrip(false);
|
||||
m_offTimerStart = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
m_offTimerStart = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
//Functions called by WLED
|
||||
public:
|
||||
//Functions called by WLED
|
||||
|
||||
/*
|
||||
* setup() is called once at boot. WiFi is not yet connected at this point.
|
||||
* You can use it to initialize variables, sensors or similar.
|
||||
*/
|
||||
void setup() {
|
||||
// PIR Sensor mode INPUT_PULLUP
|
||||
pinMode(PIRsensorPin, INPUT_PULLUP);
|
||||
/**
|
||||
* setup() is called once at boot. WiFi is not yet connected at this point.
|
||||
* You can use it to initialize variables, sensors or similar.
|
||||
*/
|
||||
void setup()
|
||||
{
|
||||
// PIR Sensor mode INPUT_PULLUP
|
||||
pinMode(PIRsensorPin, INPUT_PULLUP);
|
||||
if (m_PIRenabled)
|
||||
{
|
||||
// assign interrupt function and set CHANGE mode
|
||||
attachInterrupt(digitalPinToInterrupt(PIRsensorPin), ISR_PIRstateChange, CHANGE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* connected() is called every time the WiFi is (re)connected
|
||||
* Use it to initialize network interfaces
|
||||
*/
|
||||
void connected()
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* connected() is called every time the WiFi is (re)connected
|
||||
* Use it to initialize network interfaces
|
||||
*/
|
||||
void connected() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* loop() is called continuously. Here you can check for events, read sensors, etc.
|
||||
*/
|
||||
void loop() {
|
||||
if (!updatePIRsensorState()) {
|
||||
handleOffTimer();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
|
||||
*
|
||||
* Add PIR sensor state and switch off timer duration to jsoninfo
|
||||
*/
|
||||
void addToJsonInfo(JsonObject& root)
|
||||
/**
|
||||
* loop() is called continuously. Here you can check for events, read sensors, etc.
|
||||
*/
|
||||
void loop()
|
||||
{
|
||||
if (!updatePIRsensorState())
|
||||
{
|
||||
//this code adds "u":{"⏲ PIR sensor state":uiDomString} to the info object
|
||||
// the value contains a button to toggle the sensor enabled/disabled
|
||||
JsonObject user = root["u"];
|
||||
if (user.isNull()) user = root.createNestedObject("u");
|
||||
|
||||
JsonArray infoArr = user.createNestedArray("⏲ PIR sensor state"); //name
|
||||
String uiDomString = "<button class=\"btn infobtn\" onclick=\"requestJson({PIRenabled:";
|
||||
String sensorStateInfo;
|
||||
|
||||
// PIR sensor state
|
||||
if (m_PIRenabled) {
|
||||
uiDomString += "false";
|
||||
sensorStateInfo = (m_PIRsensorPinState != LOW ? "active" : "inactive"); //value
|
||||
} else {
|
||||
uiDomString += "true";
|
||||
sensorStateInfo = "Disabled !";
|
||||
}
|
||||
uiDomString += "});return false;\">";
|
||||
uiDomString += sensorStateInfo;
|
||||
uiDomString += "</button>";
|
||||
infoArr.add(uiDomString); //value
|
||||
|
||||
//this code adds "u":{"⏲ switch off timer":uiDomString} to the info object
|
||||
infoArr = user.createNestedArray("⏲ switch off timer"); //name
|
||||
|
||||
// off timer
|
||||
if (m_offTimerStart > 0) {
|
||||
uiDomString = "";
|
||||
unsigned int offSeconds = (m_switchOffDelay - (millis() - m_offTimerStart)) / 1000;
|
||||
if (offSeconds >= 3600) {
|
||||
uiDomString += (offSeconds / 3600);
|
||||
uiDomString += " hours ";
|
||||
offSeconds %= 3600;
|
||||
}
|
||||
if (offSeconds >= 60) {
|
||||
uiDomString += (offSeconds / 60);
|
||||
offSeconds %= 60;
|
||||
} else if (uiDomString.length() > 0){
|
||||
uiDomString += 0;
|
||||
}
|
||||
if (uiDomString.length() > 0){
|
||||
uiDomString += " min ";
|
||||
}
|
||||
uiDomString += (offSeconds);
|
||||
infoArr.add(uiDomString + " sec");
|
||||
} else {
|
||||
infoArr.add("inactive");
|
||||
handleOffTimer();
|
||||
if (m_updateConfig)
|
||||
{
|
||||
serializeConfig();
|
||||
m_updateConfig = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
|
||||
*
|
||||
* Add PIR sensor state and switch off timer duration to jsoninfo
|
||||
*/
|
||||
void addToJsonInfo(JsonObject &root)
|
||||
{
|
||||
//this code adds "u":{"⏲ PIR sensor state":uiDomString} to the info object
|
||||
// the value contains a button to toggle the sensor enabled/disabled
|
||||
JsonObject user = root["u"];
|
||||
if (user.isNull())
|
||||
user = root.createNestedObject("u");
|
||||
|
||||
/*
|
||||
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
|
||||
* Values in the state object may be modified by connected clients
|
||||
* Add "PIRenabled" to json state. This can be used to disable/enable the sensor.
|
||||
* Add "PIRoffSec" to json state. This can be used to adjust <m_switchOffDelay> milliseconds .
|
||||
*/
|
||||
void addToJsonState(JsonObject& root)
|
||||
JsonArray infoArr = user.createNestedArray("⏲ PIR sensor state"); //name
|
||||
String uiDomString = "<button class=\"btn infobtn\" onclick=\"requestJson({PIRenabled:";
|
||||
String sensorStateInfo;
|
||||
|
||||
// PIR sensor state
|
||||
if (m_PIRenabled)
|
||||
{
|
||||
root["PIRenabled"] = m_PIRenabled;
|
||||
root["PIRoffSec"] = (m_switchOffDelay / 1000);
|
||||
uiDomString += "false";
|
||||
sensorStateInfo = (m_PIRsensorPinState != LOW ? "active" : "inactive"); //value
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
|
||||
* Values in the state object may be modified by connected clients
|
||||
* Read "PIRenabled" from json state and switch enable/disable the PIR sensor.
|
||||
* Read "PIRoffSec" from json state and adjust <m_switchOffDelay> milliseconds .
|
||||
*/
|
||||
void readFromJsonState(JsonObject& root)
|
||||
else
|
||||
{
|
||||
if (root["PIRoffSec"] != nullptr) {
|
||||
m_switchOffDelay = (1000 * max(60UL, min(43200UL, root["PIRoffSec"].as<unsigned long>())));
|
||||
}
|
||||
|
||||
if (root["PIRenabled"] != nullptr) {
|
||||
if (root["PIRenabled"] && !m_PIRenabled) {
|
||||
attachInterrupt(digitalPinToInterrupt(PIRsensorPin), ISR_PIRstateChange, CHANGE);
|
||||
newPIRsensorState(true, true);
|
||||
}
|
||||
else if(m_PIRenabled) {
|
||||
detachInterrupt(PIRsensorPin);
|
||||
}
|
||||
m_PIRenabled = root["PIRenabled"];
|
||||
}
|
||||
uiDomString += "true";
|
||||
sensorStateInfo = "Disabled !";
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
|
||||
* This could be used in the future for the system to determine whether your usermod is installed.
|
||||
*/
|
||||
uint16_t getId()
|
||||
uiDomString += "});return false;\">";
|
||||
uiDomString += sensorStateInfo;
|
||||
uiDomString += "</button>";
|
||||
infoArr.add(uiDomString); //value
|
||||
|
||||
//this code adds "u":{"⏲ switch off timer":uiDomString} to the info object
|
||||
uiDomString = "⏲ switch off timer<span style=\"display:block;padding-left:25px;\">\
|
||||
after <input type=\"number\" min=\"1\" max=\"720\" value=\"";
|
||||
uiDomString += (m_switchOffDelay / 60000);
|
||||
uiDomString += "\" onchange=\"requestJson({PIRoffSec:parseInt(this.value)*60});\">min</span>";
|
||||
infoArr = user.createNestedArray(uiDomString); //name
|
||||
|
||||
// off timer
|
||||
if (m_offTimerStart > 0)
|
||||
{
|
||||
return USERMOD_ID_PIRSWITCH;
|
||||
uiDomString = "";
|
||||
unsigned int offSeconds = (m_switchOffDelay - (millis() - m_offTimerStart)) / 1000;
|
||||
if (offSeconds >= 3600)
|
||||
{
|
||||
uiDomString += (offSeconds / 3600);
|
||||
uiDomString += " hours ";
|
||||
offSeconds %= 3600;
|
||||
}
|
||||
if (offSeconds >= 60)
|
||||
{
|
||||
uiDomString += (offSeconds / 60);
|
||||
offSeconds %= 60;
|
||||
}
|
||||
else if (uiDomString.length() > 0)
|
||||
{
|
||||
uiDomString += 0;
|
||||
}
|
||||
if (uiDomString.length() > 0)
|
||||
{
|
||||
uiDomString += " min ";
|
||||
}
|
||||
uiDomString += (offSeconds);
|
||||
infoArr.add(uiDomString + " sec");
|
||||
}
|
||||
else
|
||||
{
|
||||
infoArr.add("inactive");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
|
||||
* Values in the state object may be modified by connected clients
|
||||
* Add "PIRenabled" to json state. This can be used to disable/enable the sensor.
|
||||
* Add "PIRoffSec" to json state. This can be used to adjust <m_switchOffDelay> milliseconds.
|
||||
*/
|
||||
void addToJsonState(JsonObject &root)
|
||||
{
|
||||
root["PIRenabled"] = m_PIRenabled;
|
||||
root["PIRoffSec"] = (m_switchOffDelay / 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
|
||||
* Values in the state object may be modified by connected clients
|
||||
* Read "PIRenabled" from json state and switch enable/disable the PIR sensor.
|
||||
* Read "PIRoffSec" from json state and adjust <m_switchOffDelay> milliseconds.
|
||||
*/
|
||||
void readFromJsonState(JsonObject &root)
|
||||
{
|
||||
if (root["PIRoffSec"] != nullptr)
|
||||
{
|
||||
m_switchOffDelay = (1000 * max(60UL, min(43200UL, root["PIRoffSec"].as<unsigned long>())));
|
||||
m_updateConfig = true;
|
||||
}
|
||||
|
||||
//More methods can be added in the future, this example will then be extended.
|
||||
//Your usermod will remain compatible as it does not need to implement all methods from the Usermod base class!
|
||||
if (root["PIRenabled"] != nullptr)
|
||||
{
|
||||
if (root["PIRenabled"] && !m_PIRenabled)
|
||||
{
|
||||
attachInterrupt(digitalPinToInterrupt(PIRsensorPin), ISR_PIRstateChange, CHANGE);
|
||||
newPIRsensorState(true, true);
|
||||
}
|
||||
else if (m_PIRenabled)
|
||||
{
|
||||
detachInterrupt(PIRsensorPin);
|
||||
}
|
||||
m_PIRenabled = root["PIRenabled"];
|
||||
m_updateConfig = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* provide the changeable values
|
||||
*/
|
||||
void addToConfig(JsonObject &root)
|
||||
{
|
||||
JsonObject top = root.createNestedObject("PIRsensorSwitch");
|
||||
top["PIRenabled"] = m_PIRenabled;
|
||||
top["PIRoffSec"] = m_switchOffDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
* restore the changeable values
|
||||
*/
|
||||
void readFromConfig(JsonObject &root)
|
||||
{
|
||||
JsonObject top = root["PIRsensorSwitch"];
|
||||
m_PIRenabled = (top["PIRenabled"] != nullptr ? top["PIRenabled"] : true);
|
||||
m_switchOffDelay = top["PIRoffSec"] | m_switchOffDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
|
||||
* This could be used in the future for the system to determine whether your usermod is installed.
|
||||
*/
|
||||
uint16_t getId()
|
||||
{
|
||||
return USERMOD_ID_PIRSWITCH;
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// PIRsensorSwitch static method implementations
|
||||
|
||||
volatile bool PIRsensorSwitch::newPIRsensorState(bool changeState, bool newState)
|
||||
{
|
||||
static volatile bool s_PIRsensorState = false;
|
||||
if (changeState)
|
||||
{
|
||||
s_PIRsensorState = newState;
|
||||
}
|
||||
return s_PIRsensorState;
|
||||
}
|
||||
|
||||
void IRAM_ATTR PIRsensorSwitch::ISR_PIRstateChange()
|
||||
{
|
||||
newPIRsensorState(true, true);
|
||||
}
|
||||
|
||||
PIRsensorSwitch *PIRsensorSwitch::PIRsensorSwitchInstance(PIRsensorSwitch *pInstance, bool bRemoveInstance)
|
||||
{
|
||||
static PIRsensorSwitch *s_pPIRsensorSwitch = nullptr;
|
||||
if (pInstance != nullptr || bRemoveInstance)
|
||||
{
|
||||
s_pPIRsensorSwitch = pInstance;
|
||||
}
|
||||
return s_pPIRsensorSwitch;
|
||||
}
|
||||
|
||||
@@ -3,14 +3,24 @@ This usermod allows use of the TTGO T-Display ESP32 module with integrated 240x1
|
||||
for controlling WLED and showing the following information:
|
||||
* Current SSID
|
||||
* IP address if obtained
|
||||
* in AP mode and turned off lightning AP password is shown
|
||||
* If connected to a network, current brightness % is shown
|
||||
* in AP mode AP IP and password are shown
|
||||
* Current effect
|
||||
* Current palette
|
||||
* Estimated current in mA is shown (NOTE: for this to be a reasonable value, the correct LED type must be specified in the LED Prefs section)
|
||||
|
||||
Button pin is mapped to the onboard button next to the side actuated reset button of the TTGO T-Display board.
|
||||
|
||||
I have designed a 3D printed case around this board and an ["ElectroCookie"](https://amzn.to/2WCNeeA) project board, a [level shifter](https://amzn.to/3hbKu18), a [buck regulator](https://amzn.to/3mLMy0W), and a DC [power jack](https://amzn.to/3phj9NZ). I use 12V WS2815 LED strips for my projects, and power them with 12V power supplies, so the regulator drops the voltage to the 5V level I need to power the ESP module and the level shifter. If there is any interest in this case, which elevates the board and display on some custom extended headers to make place the screen at the top of the enclosure (with accessible buttons), let me know, and I could post the STL files. It is a bit tricky to get the height correct, so I also designed a one-time use 3D printed solder fixture to set the board in the right location and at the correct height for the housing. (It is one-time use because it has to be cut off after soldering to be able to remove it). I didn't think the effort to make it in multiple pieces was worthwhile.
|
||||
|
||||
Usermod based on a rework of the ssd1306_i2c_oled_u8g2 usermod from the WLED repo.
|
||||
|
||||
## Hardware
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
## Github reference for TTGO-Tdisplay
|
||||
|
||||
@@ -20,7 +30,11 @@ Usermod based on a rework of the ssd1306_i2c_oled_u8g2 usermod from the WLED rep
|
||||
Functionality checked with:
|
||||
* TTGO T-Display
|
||||
* PlatformIO
|
||||
* Group of 4 individual Neopixels from Adafruit, and a full string of 68 LEDs.
|
||||
* Group of 4 individual Neopixels from Adafruit, and a several full strings of 12v WS2815 LEDs.
|
||||
* The hardware design shown above should be limited to shorter strings. For larger strings, I use a different setup with a dedicated 12v power supply and power them directly off the supply (in addition to dropping the 12v supply down to 5v with a buck regulator for the ESP module and level shifter).
|
||||
|
||||
## Setup Needed:
|
||||
* As with all usermods, copy the usermod.cpp file from the TTGO-T-Display usermod folder to the wled00 folder (replacing the default usermod.cpp file).
|
||||
|
||||
## Platformio Requirements
|
||||
### Platformio.ini changes
|
||||
|
||||
BIN
usermods/TTGO-T-Display/assets/ttgo-tdisplay-enclosure1a.png
Normal file
|
After Width: | Height: | Size: 708 KiB |
BIN
usermods/TTGO-T-Display/assets/ttgo-tdisplay-enclosure2a.png
Normal file
|
After Width: | Height: | Size: 848 KiB |
BIN
usermods/TTGO-T-Display/assets/ttgo-tdisplay-enclosure3a.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
usermods/TTGO-T-Display/assets/ttgo-tdisplay-enclosure4a.png
Normal file
|
After Width: | Height: | Size: 876 KiB |
|
Before Width: | Height: | Size: 686 KiB After Width: | Height: | Size: 613 KiB |
@@ -3,6 +3,6 @@ build_flags = ${common.build_flags_esp32}
|
||||
; PIN defines - uncomment and change, if needed:
|
||||
; -D LEDPIN=2
|
||||
-D BTNPIN=35
|
||||
; -D IR_PIN=4
|
||||
; -D IRPIN=4
|
||||
; -D RLYPIN=12
|
||||
; -D RLYMDE=1
|
||||
|
||||
@@ -56,7 +56,7 @@ void userSetup() {
|
||||
tft.setTextColor(TFT_WHITE);
|
||||
tft.setCursor(1, 10);
|
||||
tft.setTextDatum(MC_DATUM);
|
||||
tft.setTextSize(2);
|
||||
tft.setTextSize(3);
|
||||
tft.print("Loading...");
|
||||
|
||||
if (TFT_BL > 0) { // TFT_BL has been set in the TFT_eSPI library in the User Setup file TTGO_T_Display.h
|
||||
@@ -142,22 +142,41 @@ void userLoop() {
|
||||
tft.fillScreen(TFT_BLACK);
|
||||
tft.setTextSize(2);
|
||||
// First row with Wifi name
|
||||
tft.setCursor(1, 10);
|
||||
tft.setCursor(1, 1);
|
||||
tft.print(knownSsid.substring(0, tftcharwidth > 1 ? tftcharwidth - 1 : 0));
|
||||
// Print `~` char to indicate that SSID is longer, than our dicplay
|
||||
if (knownSsid.length() > tftcharwidth)
|
||||
tft.print("~");
|
||||
|
||||
// Second row with IP or Psssword
|
||||
tft.setCursor(1, 40);
|
||||
// Print password in AP mode and if led is OFF.
|
||||
if (apActive && bri == 0)
|
||||
tft.print(apPass);
|
||||
else
|
||||
// Second row with AP IP and Password or IP
|
||||
tft.setTextSize(2);
|
||||
tft.setCursor(1, 24);
|
||||
// Print AP IP and password in AP mode or knownIP if AP not active.
|
||||
// if (apActive && bri == 0)
|
||||
// tft.print(apPass);
|
||||
// else
|
||||
// tft.print(knownIp);
|
||||
|
||||
if (apActive) {
|
||||
tft.print("AP IP: ");
|
||||
tft.print(knownIp);
|
||||
tft.setCursor(1,46);
|
||||
tft.print("AP Pass:");
|
||||
tft.print(apPass);
|
||||
}
|
||||
else {
|
||||
tft.print("IP: ");
|
||||
tft.print(knownIp);
|
||||
tft.setCursor(1,46);
|
||||
//tft.print("Signal Strength: ");
|
||||
//tft.print(i.wifi.signal);
|
||||
tft.print("Brightness: ");
|
||||
tft.print(((float(bri)/255)*100));
|
||||
tft.print("%");
|
||||
}
|
||||
|
||||
// Third row with mode name
|
||||
tft.setCursor(1, 70);
|
||||
tft.setCursor(1, 68);
|
||||
uint8_t qComma = 0;
|
||||
bool insideQuotes = false;
|
||||
uint8_t printedChars = 0;
|
||||
@@ -184,7 +203,7 @@ void userLoop() {
|
||||
break;
|
||||
}
|
||||
// Fourth row with palette name
|
||||
tft.setCursor(1, 100);
|
||||
tft.setCursor(1, 90);
|
||||
qComma = 0;
|
||||
insideQuotes = false;
|
||||
printedChars = 0;
|
||||
@@ -210,5 +229,10 @@ void userLoop() {
|
||||
if ((qComma > knownPalette) || (printedChars > tftcharwidth - 1))
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
// Fifth row with estimated mA usage
|
||||
tft.setCursor(1, 112);
|
||||
// Print estimated milliamp usage (must specify the LED type in LED prefs for this to be a reasonable estimate).
|
||||
tft.print(strip.currentMilliamps);
|
||||
tft.print("mA (estimated)");
|
||||
|
||||
}
|
||||
|
||||
13
usermods/Temperature/platformio_override.ini
Normal file
@@ -0,0 +1,13 @@
|
||||
; Options
|
||||
; -------
|
||||
; USERMOD_DALLASTEMPERATURE - define this to have this user mod included wled00\usermods_list.cpp
|
||||
; USERMOD_DALLASTEMPERATURE_CELSIUS - define this to report temperatures in degrees celsius, otherwise fahrenheit will be reported
|
||||
; USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL - the number of milliseconds between measurements, defaults to 60 seconds
|
||||
; USERMOD_DALLASTEMPERATURE_FIRST_MEASUREMENT_AT - the number of milliseconds after boot to take first measurement, defaults to 20 seconds
|
||||
;
|
||||
[env:d1_mini_usermod_dallas_temperature_C]
|
||||
extends = env:d1_mini
|
||||
build_flags = ${common.build_flags_esp8266} -D USERMOD_DALLASTEMPERATURE -D USERMOD_DALLASTEMPERATURE_CELSIUS
|
||||
lib_deps = ${env.lib_deps}
|
||||
milesburton/DallasTemperature@^3.9.0
|
||||
OneWire@~2.3.5
|
||||
@@ -5,11 +5,18 @@ This usermod will read from an attached DS18B20 temperature sensor (as available
|
||||
The temperature is displayed both in the Info section of the web UI as well as published to the `/temperature` MQTT topic if enabled.
|
||||
This usermod will be expanded with support for different sensor types in the future.
|
||||
|
||||
If temperature sensor is not detected during boot, this usermod will be disabled.
|
||||
|
||||
## Installation
|
||||
|
||||
Copy `usermod_temperature.h` to the wled00 directory.
|
||||
Uncomment the corresponding lines in `usermods_list.cpp` and compile!
|
||||
If this is the only v2 usermod you plan to use, you can alternatively replace `usermods_list.h` in wled00 with the one in this folder.
|
||||
Copy the example `platformio_override.ini` to the root directory. This file should be placed in the same directory as `platformio.ini`.
|
||||
|
||||
### Define Your Options
|
||||
|
||||
* `USERMOD_DALLASTEMPERATURE` - define this to have this user mod included wled00\usermods_list.cpp
|
||||
* `USERMOD_DALLASTEMPERATURE_CELSIUS` - define this to report temperatures in degrees celsious, otherwise fahrenheit will be reported
|
||||
* `USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL` - the number of milliseconds between measurements, defaults to 60 seconds
|
||||
* `USERMOD_DALLASTEMPERATURE_FIRST_MEASUREMENT_AT` - the number of milliseconds after boot to take first measurement, defaults to 20 seconds
|
||||
|
||||
## Project link
|
||||
|
||||
@@ -17,7 +24,10 @@ If this is the only v2 usermod you plan to use, you can alternatively replace `u
|
||||
|
||||
### PlatformIO requirements
|
||||
|
||||
You might have to uncomment `DallasTemperature@~3.8.0`,`OneWire@~2.3.5 under` `[common]` section in `platformio.ini`:
|
||||
If you are using `platformio_override.ini`, you should be able to refresh the task list and see your custom task, for example `env:d1_mini_usermod_dallas_temperature_C`.
|
||||
|
||||
|
||||
If you are not using `platformio_override.ini`, you might have to uncomment `DallasTemperature@~3.8.0`,`OneWire@~2.3.5 under` `[common]` section in `platformio.ini`:
|
||||
|
||||
```ini
|
||||
# platformio.ini
|
||||
@@ -29,7 +39,7 @@ default_envs = d1_mini
|
||||
...
|
||||
[common]
|
||||
...
|
||||
lib_deps_external =
|
||||
lib_deps =
|
||||
...
|
||||
#For use SSD1306 OLED display uncomment following
|
||||
U8g2@~2.27.3
|
||||
@@ -38,3 +48,11 @@ lib_deps_external =
|
||||
OneWire@~2.3.5
|
||||
...
|
||||
```
|
||||
|
||||
## Change Log
|
||||
|
||||
2020-09-12
|
||||
* Changed to use async, non-blocking implementation
|
||||
* Do not report low temperatures that indicate an error to mqtt
|
||||
* Disable plugin if temperature sensor not detected
|
||||
* Report the number of seconds until the first read in the info screen instead of sensor error
|
||||
|
||||
@@ -5,70 +5,164 @@
|
||||
#include <DallasTemperature.h> //DS18B20
|
||||
|
||||
//Pin defaults for QuinLed Dig-Uno
|
||||
#ifndef TEMPERATURE_PIN
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#define TEMPERATURE_PIN 18
|
||||
#else //ESP8266 boards
|
||||
#define TEMPERATURE_PIN 14
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define TEMP_CELSIUS // Comment out for Fahrenheit
|
||||
// the frequency to check temperature, 1 minute
|
||||
#ifndef USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL
|
||||
#define USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL 60000
|
||||
#endif
|
||||
|
||||
#define MEASUREMENT_INTERVAL 60000 //1 Minute
|
||||
// how many seconds after boot to take first measurement, 20 seconds
|
||||
#ifndef USERMOD_DALLASTEMPERATURE_FIRST_MEASUREMENT_AT
|
||||
#define USERMOD_DALLASTEMPERATURE_FIRST_MEASUREMENT_AT 20000
|
||||
#endif
|
||||
|
||||
OneWire oneWire(TEMPERATURE_PIN);
|
||||
DallasTemperature sensor(&oneWire);
|
||||
|
||||
class UsermodTemperature : public Usermod {
|
||||
private:
|
||||
//set last reading as "40 sec before boot", so first reading is taken after 20 sec
|
||||
unsigned long lastMeasurement = UINT32_MAX - 40000;
|
||||
float temperature = 0.0f;
|
||||
public:
|
||||
void getReading() {
|
||||
sensor.requestTemperatures();
|
||||
#ifdef TEMP_CELSIUS
|
||||
temperature = sensor.getTempCByIndex(0);
|
||||
#else
|
||||
temperature = sensor.getTempFByIndex(0);
|
||||
#endif
|
||||
// The device's unique 64-bit serial code stored in on-board ROM.
|
||||
// Reading directly from the sensor device address is faster than
|
||||
// reading from index. When reading by index, DallasTemperature
|
||||
// must first look up the device address at the specified index.
|
||||
DeviceAddress sensorDeviceAddress;
|
||||
// set last reading as "40 sec before boot", so first reading is taken after 20 sec
|
||||
unsigned long lastMeasurement = UINT32_MAX - (USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL - USERMOD_DALLASTEMPERATURE_FIRST_MEASUREMENT_AT);
|
||||
// last time requestTemperatures was called
|
||||
// used to determine when we can read the sensors temperature
|
||||
// we have to wait at least 93.75 ms after requestTemperatures() is called
|
||||
unsigned long lastTemperaturesRequest;
|
||||
float temperature = -100; // default to -100, DS18B20 only goes down to -50C
|
||||
// indicates requestTemperatures has been called but the sensor measurement is not complete
|
||||
bool waitingForConversion = false;
|
||||
// flag to indicate we have finished the first getTemperature call
|
||||
// allows this library to report to the user how long until the first
|
||||
// measurement
|
||||
bool getTemperatureComplete = false;
|
||||
// flag set at startup if DS18B20 sensor not found, avoids trying to keep getting
|
||||
// temperature if flashed to a board without a sensor attached
|
||||
bool disabled = false;
|
||||
|
||||
void requestTemperatures() {
|
||||
// there is requestTemperaturesByAddress however it
|
||||
// appears to do more work,
|
||||
// TODO: measure exection time difference
|
||||
sensor.requestTemperatures();
|
||||
lastTemperaturesRequest = millis();
|
||||
waitingForConversion = true;
|
||||
}
|
||||
|
||||
void getTemperature() {
|
||||
if (strip.isUpdating()) return;
|
||||
#ifdef USERMOD_DALLASTEMPERATURE_CELSIUS
|
||||
temperature = sensor.getTempC(sensorDeviceAddress);
|
||||
#else
|
||||
temperature = sensor.getTempF(sensorDeviceAddress);
|
||||
#endif
|
||||
|
||||
lastMeasurement = millis();
|
||||
waitingForConversion = false;
|
||||
getTemperatureComplete = true;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
|
||||
void setup() {
|
||||
sensor.begin();
|
||||
sensor.setResolution(9);
|
||||
|
||||
// get the unique 64-bit serial code stored in on-board ROM
|
||||
// if getAddress returns false, the sensor was not found
|
||||
disabled = !sensor.getAddress(sensorDeviceAddress, 0);
|
||||
|
||||
if (!disabled) {
|
||||
DEBUG_PRINTLN(F("Dallas Temperature found"));
|
||||
// set the resolution for this specific device
|
||||
sensor.setResolution(sensorDeviceAddress, 9, true);
|
||||
// do not block waiting for reading
|
||||
sensor.setWaitForConversion(false);
|
||||
// allocate pin & prevent other use
|
||||
if (!pinManager.allocatePin(TEMPERATURE_PIN,false))
|
||||
disabled = true;
|
||||
} else {
|
||||
DEBUG_PRINTLN(F("Dallas Temperature not found"));
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (millis() - lastMeasurement > MEASUREMENT_INTERVAL)
|
||||
{
|
||||
getReading();
|
||||
if (disabled || strip.isUpdating()) return;
|
||||
|
||||
unsigned long now = millis();
|
||||
|
||||
// check to see if we are due for taking a measurement
|
||||
// lastMeasurement will not be updated until the conversion
|
||||
// is complete the the reading is finished
|
||||
if (now - lastMeasurement < USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL) return;
|
||||
|
||||
// we are due for a measurement, if we are not already waiting
|
||||
// for a conversion to complete, then make a new request for temps
|
||||
if (!waitingForConversion)
|
||||
{
|
||||
requestTemperatures();
|
||||
return;
|
||||
}
|
||||
|
||||
// we were waiting for a conversion to complete, have we waited log enough?
|
||||
if (now - lastTemperaturesRequest >= 94 /* 93.75ms per the datasheet */)
|
||||
{
|
||||
getTemperature();
|
||||
|
||||
if (WLED_MQTT_CONNECTED) {
|
||||
char subuf[38];
|
||||
strcpy(subuf, mqttDeviceTopic);
|
||||
strcat(subuf, "/temperature");
|
||||
mqtt->publish(subuf, 0, true, String(temperature).c_str());
|
||||
if (-100 <= temperature) {
|
||||
// dont publish super low temperature as the graph will get messed up
|
||||
// the DallasTemperature library returns -127C or -196.6F when problem
|
||||
// reading the sensor
|
||||
strcat_P(subuf, PSTR("/temperature"));
|
||||
mqtt->publish(subuf, 0, true, String(temperature).c_str());
|
||||
} else {
|
||||
// publish something else to indicate status?
|
||||
}
|
||||
}
|
||||
lastMeasurement = millis();
|
||||
}
|
||||
}
|
||||
|
||||
void addToJsonInfo(JsonObject& root) {
|
||||
JsonObject user = root["u"];
|
||||
if (user.isNull()) user = root.createNestedObject("u");
|
||||
// dont add temperature to info if we are disabled
|
||||
if (disabled) return;
|
||||
|
||||
JsonArray temp = user.createNestedArray("Temperature");
|
||||
if (temperature == DEVICE_DISCONNECTED_C) {
|
||||
JsonObject user = root[F("u")];
|
||||
if (user.isNull()) user = root.createNestedObject(F("u"));
|
||||
|
||||
JsonArray temp = user.createNestedArray(F("Temperature"));
|
||||
|
||||
if (!getTemperatureComplete) {
|
||||
// if we haven't read the sensor yet, let the user know
|
||||
// that we are still waiting for the first measurement
|
||||
temp.add((USERMOD_DALLASTEMPERATURE_FIRST_MEASUREMENT_AT - millis()) / 1000);
|
||||
temp.add(F(" sec until read"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (temperature <= -100) {
|
||||
temp.add(0);
|
||||
temp.add(" Sensor Error!");
|
||||
temp.add(F(" Sensor Error!"));
|
||||
return;
|
||||
}
|
||||
|
||||
temp.add(temperature);
|
||||
#ifdef TEMP_CELSIUS
|
||||
temp.add("°C");
|
||||
#ifdef USERMOD_DALLASTEMPERATURE_CELSIUS
|
||||
temp.add(F("°C"));
|
||||
#else
|
||||
temp.add("°F");
|
||||
temp.add(F("°F"));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -76,4 +170,4 @@ class UsermodTemperature : public Usermod {
|
||||
{
|
||||
return USERMOD_ID_TEMPERATURE;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -9,7 +9,10 @@
|
||||
* \/ \/ \/
|
||||
*/
|
||||
//#include "usermod_v2_example.h"
|
||||
#include "usermod_temperature.h"
|
||||
#ifdef USERMOD_DALLASTEMPERATURE
|
||||
#include "../usermods/Temperature/usermod_temperature.h"
|
||||
#endif
|
||||
|
||||
//#include "usermod_v2_empty.h"
|
||||
|
||||
void registerUsermods()
|
||||
@@ -20,6 +23,9 @@ void registerUsermods()
|
||||
* \/ \/ \/
|
||||
*/
|
||||
//usermods.add(new MyExampleUsermod());
|
||||
#ifdef USERMOD_DALLASTEMPERATURE
|
||||
usermods.add(new UsermodTemperature());
|
||||
#endif
|
||||
|
||||
//usermods.add(new UsermodRenameMe());
|
||||
}
|
||||
|
Before Width: | Height: | Size: 319 KiB After Width: | Height: | Size: 299 KiB |
|
Before Width: | Height: | Size: 250 KiB After Width: | Height: | Size: 236 KiB |
|
Before Width: | Height: | Size: 344 KiB After Width: | Height: | Size: 323 KiB |
81
usermods/buzzer/usermod_v2_buzzer.h
Normal file
@@ -0,0 +1,81 @@
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
#include "Arduino.h"
|
||||
|
||||
#include <deque>
|
||||
|
||||
#define USERMOD_ID_BUZZER 900
|
||||
#ifndef USERMOD_BUZZER_PIN
|
||||
#define USERMOD_BUZZER_PIN GPIO_NUM_32
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Usermods allow you to add own functionality to WLED more easily
|
||||
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
|
||||
*
|
||||
* Using a usermod:
|
||||
* 1. Copy the usermod into the sketch folder (same folder as wled00.ino)
|
||||
* 2. Register the usermod by adding #include "usermod_filename.h" in the top and registerUsermod(new MyUsermodClass()) in the bottom of usermods_list.cpp
|
||||
*/
|
||||
|
||||
class BuzzerUsermod : public Usermod {
|
||||
private:
|
||||
unsigned long lastTime_ = 0;
|
||||
unsigned long delay_ = 0;
|
||||
std::deque<std::pair<uint8_t, unsigned long>> sequence_ {};
|
||||
public:
|
||||
/*
|
||||
* setup() is called once at boot. WiFi is not yet connected at this point.
|
||||
* You can use it to initialize variables, sensors or similar.
|
||||
*/
|
||||
void setup() {
|
||||
// Setup the pin, and default to LOW
|
||||
pinMode(USERMOD_BUZZER_PIN, OUTPUT);
|
||||
digitalWrite(USERMOD_BUZZER_PIN, LOW);
|
||||
|
||||
// Beep on startup
|
||||
sequence_.push_back({ HIGH, 50 });
|
||||
sequence_.push_back({ LOW, 0 });
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* connected() is called every time the WiFi is (re)connected
|
||||
* Use it to initialize network interfaces
|
||||
*/
|
||||
void connected() {
|
||||
// Double beep on WiFi
|
||||
sequence_.push_back({ LOW, 100 });
|
||||
sequence_.push_back({ HIGH, 50 });
|
||||
sequence_.push_back({ LOW, 30 });
|
||||
sequence_.push_back({ HIGH, 50 });
|
||||
sequence_.push_back({ LOW, 0 });
|
||||
}
|
||||
|
||||
/*
|
||||
* loop() is called continuously. Here you can check for events, read sensors, etc.
|
||||
*/
|
||||
void loop() {
|
||||
if (sequence_.size() < 1) return; // Wait until there is a sequence
|
||||
if (millis() - lastTime_ <= delay_) return; // Wait until delay has elapsed
|
||||
|
||||
auto event = sequence_.front();
|
||||
sequence_.pop_front();
|
||||
|
||||
digitalWrite(USERMOD_BUZZER_PIN, event.first);
|
||||
delay_ = event.second;
|
||||
|
||||
lastTime_ = millis();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
|
||||
* This could be used in the future for the system to determine whether your usermod is installed.
|
||||
*/
|
||||
uint16_t getId()
|
||||
{
|
||||
return USERMOD_ID_BUZZER;
|
||||
}
|
||||
};
|
||||
515
usermods/esp32_multistrip/NpbWrapper.h
Normal file
@@ -0,0 +1,515 @@
|
||||
//this code is a modified version of https://github.com/Makuna/NeoPixelBus/issues/103
|
||||
#ifndef NpbWrapper_h
|
||||
#define NpbWrapper_h
|
||||
|
||||
// make sure we're using esp32 platform
|
||||
#ifndef ARDUINO_ARCH_ESP32
|
||||
#error This version of NbpWrapper.h only works with ESP32 hardware.
|
||||
#endif
|
||||
|
||||
#ifndef NUM_STRIPS
|
||||
#error Need to define number of LED strips using build flag -D NUM_STRIPS=4 for 4 LED strips
|
||||
#endif
|
||||
|
||||
#ifndef PIXEL_COUNTS
|
||||
#error Need to define pixel counts using build flag -D PIXEL_COUNTS="25, 25, 25, 25" for 4 LED strips with 25 LEDs each
|
||||
#endif
|
||||
|
||||
#ifndef DATA_PINS
|
||||
#error Need to define data pins using build flag -D DATA_PINS="1, 2, 3, 4" if LED strips are on data pins 1, 2, 3, and 4
|
||||
#endif
|
||||
|
||||
// //PIN CONFIGURATION
|
||||
#ifndef LEDPIN
|
||||
#define LEDPIN 1 // Legacy pin def required by some other portions of code. This pin is not used do drive LEDs.
|
||||
#endif
|
||||
|
||||
#ifndef IRPIN
|
||||
#define IRPIN -1 //infrared pin (-1 to disable) MagicHome: 4, H801 Wifi: 0
|
||||
#endif
|
||||
|
||||
#ifndef RLYPIN
|
||||
#define RLYPIN -1 //pin for relay, will be set HIGH if LEDs are on (-1 to disable). Also usable for standby leds, triggers,...
|
||||
#endif
|
||||
|
||||
#ifndef AUXPIN
|
||||
#define AUXPIN -1 //debug auxiliary output pin (-1 to disable)
|
||||
#endif
|
||||
|
||||
#ifndef RLYMDE
|
||||
#define RLYMDE 1 //mode for relay, 0: LOW if LEDs are on 1: HIGH if LEDs are on
|
||||
#endif
|
||||
|
||||
#include <NeoPixelBrightnessBus.h>
|
||||
#include "const.h"
|
||||
|
||||
const uint8_t numStrips = NUM_STRIPS; // max 8 strips allowed on esp32
|
||||
const uint16_t pixelCounts[numStrips] = {PIXEL_COUNTS}; // number of pixels on each strip
|
||||
const uint8_t dataPins[numStrips] = {DATA_PINS}; // change these pins based on your board
|
||||
|
||||
#define PIXELFEATURE3 NeoGrbFeature
|
||||
#define PIXELFEATURE4 NeoGrbwFeature
|
||||
|
||||
// ESP32 has 8 RMT interfaces available, each of which can drive a strip of pixels
|
||||
// Convenience #defines for creating NeoPixelBrightnessBus on each RMT interface for both GRB and GRBW LED strips
|
||||
#define NeoPixelBrightnessBusGrbRmt0 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt0Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbRmt1 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt1Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbRmt2 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt2Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbRmt3 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt3Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbRmt4 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt4Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbRmt5 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt5Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbRmt6 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt6Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbRmt7 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt7Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbwRmt0 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt0Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbwRmt1 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt1Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbwRmt2 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt2Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbwRmt3 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt3Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbwRmt4 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt4Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbwRmt5 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt5Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbwRmt6 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt6Ws2812xMethod>
|
||||
#define NeoPixelBrightnessBusGrbwRmt7 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt7Ws2812xMethod>
|
||||
|
||||
enum NeoPixelType
|
||||
{
|
||||
NeoPixelType_None = 0,
|
||||
NeoPixelType_Grb = 1,
|
||||
NeoPixelType_Grbw = 2,
|
||||
NeoPixelType_End = 3
|
||||
};
|
||||
|
||||
class NeoPixelWrapper
|
||||
{
|
||||
public:
|
||||
NeoPixelWrapper() :
|
||||
_type(NeoPixelType_None)
|
||||
{
|
||||
// On initialization fill in the pixelStripStartIdx array with the beginning index of each strip
|
||||
// relative to th entire array.
|
||||
uint16_t totalPixels = 0;
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
pixelStripStartIdx[idx] = totalPixels;
|
||||
totalPixels += pixelCounts[idx];
|
||||
}
|
||||
}
|
||||
|
||||
~NeoPixelWrapper()
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
|
||||
void Begin(NeoPixelType type, uint16_t pixelCount)
|
||||
{
|
||||
|
||||
cleanup();
|
||||
|
||||
_type = type;
|
||||
|
||||
switch (_type)
|
||||
{
|
||||
case NeoPixelType_Grb:
|
||||
{
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0: pGrb0 = new NeoPixelBrightnessBusGrbRmt0(pixelCounts[idx], dataPins[idx]); pGrb0->Begin(); break;
|
||||
case 1: pGrb1 = new NeoPixelBrightnessBusGrbRmt1(pixelCounts[idx], dataPins[idx]); pGrb1->Begin(); break;
|
||||
case 2: pGrb2 = new NeoPixelBrightnessBusGrbRmt2(pixelCounts[idx], dataPins[idx]); pGrb2->Begin(); break;
|
||||
case 3: pGrb3 = new NeoPixelBrightnessBusGrbRmt3(pixelCounts[idx], dataPins[idx]); pGrb3->Begin(); break;
|
||||
case 4: pGrb4 = new NeoPixelBrightnessBusGrbRmt4(pixelCounts[idx], dataPins[idx]); pGrb4->Begin(); break;
|
||||
case 5: pGrb5 = new NeoPixelBrightnessBusGrbRmt5(pixelCounts[idx], dataPins[idx]); pGrb5->Begin(); break;
|
||||
case 6: pGrb6 = new NeoPixelBrightnessBusGrbRmt6(pixelCounts[idx], dataPins[idx]); pGrb6->Begin(); break;
|
||||
case 7: pGrb7 = new NeoPixelBrightnessBusGrbRmt7(pixelCounts[idx], dataPins[idx]); pGrb7->Begin(); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case NeoPixelType_Grbw:
|
||||
{
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0: pGrbw0 = new NeoPixelBrightnessBusGrbwRmt0(pixelCounts[idx], dataPins[idx]); pGrbw0->Begin(); break;
|
||||
case 1: pGrbw1 = new NeoPixelBrightnessBusGrbwRmt1(pixelCounts[idx], dataPins[idx]); pGrbw1->Begin(); break;
|
||||
case 2: pGrbw2 = new NeoPixelBrightnessBusGrbwRmt2(pixelCounts[idx], dataPins[idx]); pGrbw2->Begin(); break;
|
||||
case 3: pGrbw3 = new NeoPixelBrightnessBusGrbwRmt3(pixelCounts[idx], dataPins[idx]); pGrbw3->Begin(); break;
|
||||
case 4: pGrbw4 = new NeoPixelBrightnessBusGrbwRmt4(pixelCounts[idx], dataPins[idx]); pGrbw4->Begin(); break;
|
||||
case 5: pGrbw5 = new NeoPixelBrightnessBusGrbwRmt5(pixelCounts[idx], dataPins[idx]); pGrbw5->Begin(); break;
|
||||
case 6: pGrbw6 = new NeoPixelBrightnessBusGrbwRmt6(pixelCounts[idx], dataPins[idx]); pGrbw6->Begin(); break;
|
||||
case 7: pGrbw7 = new NeoPixelBrightnessBusGrbwRmt7(pixelCounts[idx], dataPins[idx]); pGrbw7->Begin(); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Show()
|
||||
{
|
||||
switch (_type)
|
||||
{
|
||||
case NeoPixelType_Grb:
|
||||
{
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0: pGrb0->Show(); break;
|
||||
case 1: pGrb1->Show(); break;
|
||||
case 2: pGrb2->Show(); break;
|
||||
case 3: pGrb3->Show(); break;
|
||||
case 4: pGrb4->Show(); break;
|
||||
case 5: pGrb5->Show(); break;
|
||||
case 6: pGrb6->Show(); break;
|
||||
case 7: pGrb7->Show(); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NeoPixelType_Grbw:
|
||||
{
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0: pGrbw0->Show(); break;
|
||||
case 1: pGrbw1->Show(); break;
|
||||
case 2: pGrbw2->Show(); break;
|
||||
case 3: pGrbw3->Show(); break;
|
||||
case 4: pGrbw4->Show(); break;
|
||||
case 5: pGrbw5->Show(); break;
|
||||
case 6: pGrbw6->Show(); break;
|
||||
case 7: pGrbw7->Show(); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CanShow()
|
||||
{
|
||||
bool canShow = true;
|
||||
switch (_type)
|
||||
{
|
||||
case NeoPixelType_Grb:
|
||||
{
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0: canShow &= pGrb0->CanShow(); break;
|
||||
case 1: canShow &= pGrb1->CanShow(); break;
|
||||
case 2: canShow &= pGrb2->CanShow(); break;
|
||||
case 3: canShow &= pGrb3->CanShow(); break;
|
||||
case 4: canShow &= pGrb4->CanShow(); break;
|
||||
case 5: canShow &= pGrb5->CanShow(); break;
|
||||
case 6: canShow &= pGrb6->CanShow(); break;
|
||||
case 7: canShow &= pGrb7->CanShow(); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NeoPixelType_Grbw:
|
||||
{
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0: canShow &= pGrbw0->CanShow(); break;
|
||||
case 1: canShow &= pGrbw1->CanShow(); break;
|
||||
case 2: canShow &= pGrbw2->CanShow(); break;
|
||||
case 3: canShow &= pGrbw3->CanShow(); break;
|
||||
case 4: canShow &= pGrbw4->CanShow(); break;
|
||||
case 5: canShow &= pGrbw5->CanShow(); break;
|
||||
case 6: canShow &= pGrbw6->CanShow(); break;
|
||||
case 7: canShow &= pGrbw7->CanShow(); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return canShow;
|
||||
}
|
||||
|
||||
void SetPixelColorRaw(uint16_t indexPixel, RgbwColor c)
|
||||
{
|
||||
// figure out which strip this pixel index is on
|
||||
uint8_t stripIdx = 0;
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
if (indexPixel >= pixelStripStartIdx[idx])
|
||||
{
|
||||
stripIdx = idx;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
// subtract strip start index so we're addressing just this strip instead of all pixels on all strips
|
||||
indexPixel -= pixelStripStartIdx[stripIdx];
|
||||
switch (_type)
|
||||
{
|
||||
case NeoPixelType_Grb:
|
||||
{
|
||||
RgbColor rgb = RgbColor(c.R, c.G, c.B);
|
||||
switch (stripIdx)
|
||||
{
|
||||
case 0: pGrb0->SetPixelColor(indexPixel, rgb); break;
|
||||
case 1: pGrb1->SetPixelColor(indexPixel, rgb); break;
|
||||
case 2: pGrb2->SetPixelColor(indexPixel, rgb); break;
|
||||
case 3: pGrb3->SetPixelColor(indexPixel, rgb); break;
|
||||
case 4: pGrb4->SetPixelColor(indexPixel, rgb); break;
|
||||
case 5: pGrb5->SetPixelColor(indexPixel, rgb); break;
|
||||
case 6: pGrb6->SetPixelColor(indexPixel, rgb); break;
|
||||
case 7: pGrb7->SetPixelColor(indexPixel, rgb); break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NeoPixelType_Grbw:
|
||||
{
|
||||
switch (stripIdx)
|
||||
{
|
||||
case 0: pGrbw0->SetPixelColor(indexPixel, c); break;
|
||||
case 1: pGrbw1->SetPixelColor(indexPixel, c); break;
|
||||
case 2: pGrbw2->SetPixelColor(indexPixel, c); break;
|
||||
case 3: pGrbw3->SetPixelColor(indexPixel, c); break;
|
||||
case 4: pGrbw4->SetPixelColor(indexPixel, c); break;
|
||||
case 5: pGrbw5->SetPixelColor(indexPixel, c); break;
|
||||
case 6: pGrbw6->SetPixelColor(indexPixel, c); break;
|
||||
case 7: pGrbw7->SetPixelColor(indexPixel, c); break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetPixelColor(uint16_t indexPixel, RgbwColor c)
|
||||
{
|
||||
/*
|
||||
Set pixel color with necessary color order conversion.
|
||||
*/
|
||||
|
||||
RgbwColor col;
|
||||
|
||||
uint8_t co = _colorOrder;
|
||||
#ifdef COLOR_ORDER_OVERRIDE
|
||||
if (indexPixel >= COO_MIN && indexPixel < COO_MAX) co = COO_ORDER;
|
||||
#endif
|
||||
|
||||
//reorder channels to selected order
|
||||
switch (co)
|
||||
{
|
||||
case 0: col.G = c.G; col.R = c.R; col.B = c.B; break; //0 = GRB, default
|
||||
case 1: col.G = c.R; col.R = c.G; col.B = c.B; break; //1 = RGB, common for WS2811
|
||||
case 2: col.G = c.B; col.R = c.R; col.B = c.G; break; //2 = BRG
|
||||
case 3: col.G = c.R; col.R = c.B; col.B = c.G; break; //3 = RBG
|
||||
case 4: col.G = c.B; col.R = c.G; col.B = c.R; break; //4 = BGR
|
||||
default: col.G = c.G; col.R = c.B; col.B = c.R; break; //5 = GBR
|
||||
}
|
||||
col.W = c.W;
|
||||
|
||||
SetPixelColorRaw(indexPixel, col);
|
||||
}
|
||||
|
||||
void SetBrightness(byte b)
|
||||
{
|
||||
switch (_type)
|
||||
{
|
||||
case NeoPixelType_Grb:
|
||||
{
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0: pGrb0->SetBrightness(b); break;
|
||||
case 1: pGrb1->SetBrightness(b); break;
|
||||
case 2: pGrb2->SetBrightness(b); break;
|
||||
case 3: pGrb3->SetBrightness(b); break;
|
||||
case 4: pGrb4->SetBrightness(b); break;
|
||||
case 5: pGrb5->SetBrightness(b); break;
|
||||
case 6: pGrb6->SetBrightness(b); break;
|
||||
case 7: pGrb7->SetBrightness(b); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NeoPixelType_Grbw:
|
||||
{
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0: pGrbw0->SetBrightness(b); break;
|
||||
case 1: pGrbw1->SetBrightness(b); break;
|
||||
case 2: pGrbw2->SetBrightness(b); break;
|
||||
case 3: pGrbw3->SetBrightness(b); break;
|
||||
case 4: pGrbw4->SetBrightness(b); break;
|
||||
case 5: pGrbw5->SetBrightness(b); break;
|
||||
case 6: pGrbw6->SetBrightness(b); break;
|
||||
case 7: pGrbw7->SetBrightness(b); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetColorOrder(byte colorOrder)
|
||||
{
|
||||
_colorOrder = colorOrder;
|
||||
}
|
||||
|
||||
uint8_t GetColorOrder()
|
||||
{
|
||||
return _colorOrder;
|
||||
}
|
||||
|
||||
RgbwColor GetPixelColorRaw(uint16_t indexPixel) const
|
||||
{
|
||||
// figure out which strip this pixel index is on
|
||||
uint8_t stripIdx = 0;
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
if (indexPixel >= pixelStripStartIdx[idx])
|
||||
{
|
||||
stripIdx = idx;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
// subtract strip start index so we're addressing just this strip instead of all pixels on all strips
|
||||
indexPixel -= pixelStripStartIdx[stripIdx];
|
||||
switch (_type)
|
||||
{
|
||||
case NeoPixelType_Grb:
|
||||
{
|
||||
switch (stripIdx)
|
||||
{
|
||||
case 0: return pGrb0->GetPixelColor(indexPixel);
|
||||
case 1: return pGrb1->GetPixelColor(indexPixel);
|
||||
case 2: return pGrb2->GetPixelColor(indexPixel);
|
||||
case 3: return pGrb3->GetPixelColor(indexPixel);
|
||||
case 4: return pGrb4->GetPixelColor(indexPixel);
|
||||
case 5: return pGrb5->GetPixelColor(indexPixel);
|
||||
case 6: return pGrb6->GetPixelColor(indexPixel);
|
||||
case 7: return pGrb7->GetPixelColor(indexPixel);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NeoPixelType_Grbw:
|
||||
switch (stripIdx)
|
||||
{
|
||||
case 0: return pGrbw0->GetPixelColor(indexPixel);
|
||||
case 1: return pGrbw1->GetPixelColor(indexPixel);
|
||||
case 2: return pGrbw2->GetPixelColor(indexPixel);
|
||||
case 3: return pGrbw3->GetPixelColor(indexPixel);
|
||||
case 4: return pGrbw4->GetPixelColor(indexPixel);
|
||||
case 5: return pGrbw5->GetPixelColor(indexPixel);
|
||||
case 6: return pGrbw6->GetPixelColor(indexPixel);
|
||||
case 7: return pGrbw7->GetPixelColor(indexPixel);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: Due to feature differences, some support RGBW but the method name
|
||||
// here needs to be unique, thus GetPixeColorRgbw
|
||||
uint32_t GetPixelColorRgbw(uint16_t indexPixel) const
|
||||
{
|
||||
RgbwColor col = GetPixelColorRaw(indexPixel);
|
||||
uint8_t co = _colorOrder;
|
||||
#ifdef COLOR_ORDER_OVERRIDE
|
||||
if (indexPixel >= COO_MIN && indexPixel < COO_MAX) co = COO_ORDER;
|
||||
#endif
|
||||
|
||||
switch (co)
|
||||
{
|
||||
// W G R B
|
||||
case 0: return ((col.W << 24) | (col.G << 8) | (col.R << 16) | (col.B)); //0 = GRB, default
|
||||
case 1: return ((col.W << 24) | (col.R << 8) | (col.G << 16) | (col.B)); //1 = RGB, common for WS2811
|
||||
case 2: return ((col.W << 24) | (col.B << 8) | (col.R << 16) | (col.G)); //2 = BRG
|
||||
case 3: return ((col.W << 24) | (col.B << 8) | (col.G << 16) | (col.R)); //3 = RBG
|
||||
case 4: return ((col.W << 24) | (col.R << 8) | (col.B << 16) | (col.G)); //4 = BGR
|
||||
case 5: return ((col.W << 24) | (col.G << 8) | (col.B << 16) | (col.R)); //5 = GBR
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
NeoPixelType _type;
|
||||
byte _colorOrder = 0;
|
||||
|
||||
uint16_t pixelStripStartIdx[numStrips];
|
||||
|
||||
// pointers for every possible type for up to 8 strips
|
||||
NeoPixelBrightnessBusGrbRmt0 *pGrb0;
|
||||
NeoPixelBrightnessBusGrbRmt1 *pGrb1;
|
||||
NeoPixelBrightnessBusGrbRmt2 *pGrb2;
|
||||
NeoPixelBrightnessBusGrbRmt3 *pGrb3;
|
||||
NeoPixelBrightnessBusGrbRmt4 *pGrb4;
|
||||
NeoPixelBrightnessBusGrbRmt5 *pGrb5;
|
||||
NeoPixelBrightnessBusGrbRmt6 *pGrb6;
|
||||
NeoPixelBrightnessBusGrbRmt7 *pGrb7;
|
||||
NeoPixelBrightnessBusGrbwRmt0 *pGrbw0;
|
||||
NeoPixelBrightnessBusGrbwRmt1 *pGrbw1;
|
||||
NeoPixelBrightnessBusGrbwRmt2 *pGrbw2;
|
||||
NeoPixelBrightnessBusGrbwRmt3 *pGrbw3;
|
||||
NeoPixelBrightnessBusGrbwRmt4 *pGrbw4;
|
||||
NeoPixelBrightnessBusGrbwRmt5 *pGrbw5;
|
||||
NeoPixelBrightnessBusGrbwRmt6 *pGrbw6;
|
||||
NeoPixelBrightnessBusGrbwRmt7 *pGrbw7;
|
||||
|
||||
void cleanup()
|
||||
{
|
||||
switch (_type)
|
||||
{
|
||||
case NeoPixelType_Grb:
|
||||
{
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0: delete pGrb0; pGrb0 = NULL; break;
|
||||
case 1: delete pGrb1; pGrb1 = NULL; break;
|
||||
case 2: delete pGrb2; pGrb2 = NULL; break;
|
||||
case 3: delete pGrb3; pGrb3 = NULL; break;
|
||||
case 4: delete pGrb4; pGrb4 = NULL; break;
|
||||
case 5: delete pGrb5; pGrb5 = NULL; break;
|
||||
case 6: delete pGrb6; pGrb6 = NULL; break;
|
||||
case 7: delete pGrb7; pGrb7 = NULL; break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NeoPixelType_Grbw:
|
||||
{
|
||||
for (uint8_t idx = 0; idx < numStrips; idx++)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0: delete pGrbw0; pGrbw0 = NULL; break;
|
||||
case 1: delete pGrbw1; pGrbw1 = NULL; break;
|
||||
case 2: delete pGrbw2; pGrbw2 = NULL; break;
|
||||
case 3: delete pGrbw3; pGrbw3 = NULL; break;
|
||||
case 4: delete pGrbw4; pGrbw4 = NULL; break;
|
||||
case 5: delete pGrbw5; pGrbw5 = NULL; break;
|
||||
case 6: delete pGrbw6; pGrbw6 = NULL; break;
|
||||
case 7: delete pGrbw7; pGrbw7 = NULL; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif
|
||||
22
usermods/esp32_multistrip/README.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# esp32_multistrip
|
||||
|
||||
This usermod enables up to 8 data pins to be used from an esp32 module to drive separate LED strands. This only works with one-wire LEDs like the WS2812.
|
||||
|
||||
The esp32 RMT hardware is used for data output. See here for hardware driver implementation details: https://github.com/Makuna/NeoPixelBus/wiki/ESP32-NeoMethods#neoesp32rmt-methods
|
||||
|
||||
Pass the following variables to the compiler as build flags:
|
||||
|
||||
- `ESP32_MULTISTRIP`
|
||||
- Define this to use usermod NpbWrapper.h instead of default one in WLED.
|
||||
- `NUM_STRIPS`
|
||||
- Number of strips in use
|
||||
- `PIXEL_COUNTS`
|
||||
- List of pixel counts in each strip
|
||||
- `DATA_PINS`
|
||||
- List of data pins each strip is attached to. There may be board-specific restrictions on which pins can be used for RTM.
|
||||
|
||||
From the perspective of WLED software, the LEDs are addressed as one long strand. The modified NbpWrapper.h file addresses the appropriate strand from the overall LED index based on the number of LEDs defined in each strand.
|
||||
|
||||
See `platformio_override.ini` for example configuration.
|
||||
|
||||
Tested on low cost ESP-WROOM-32 dev boards from Amazon, such as those sold by KeeYees.
|
||||
16
usermods/esp32_multistrip/platformio_override.ini
Normal file
@@ -0,0 +1,16 @@
|
||||
; Example platformio_override.ini that shows how to configure your environment to use the multistrip usermod.
|
||||
; Copy this file to the base wled directory that contains platformio.ini.
|
||||
; Multistrip requires ESP32 because it has many more pins that can be used as LED outputs.
|
||||
; Need to define NUM_STRIPS, PIXEL_COUNTS, and DATA_PINS as shown below.
|
||||
|
||||
[platformio]
|
||||
default_envs = esp32_multistrip
|
||||
|
||||
[env:esp32_multistrip]
|
||||
extends=env:esp32dev
|
||||
build_flags = ${env:esp32dev.build_flags}
|
||||
-D ESP32_MULTISTRIP ; define this variable to use ESP32_MULTISTRIP usermod
|
||||
-D NUM_STRIPS=4 ; number of pixel strips in use
|
||||
-D PIXEL_COUNTS="50, 50, 50, 50" ; number of pixels in each strip
|
||||
-D DATA_PINS="25, 26, 32, 33" ; esp32 pins used for each pixel strip. available pins depends on esp32 module.
|
||||
|
||||
50
usermods/mqtt_switch_v2/README.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# MQTT controllable switches
|
||||
This usermod allows controlling switches (e.g. relays) via MQTT.
|
||||
|
||||
## Usermod installation
|
||||
|
||||
1. Copy the file `usermod_mqtt_switch.h` to the `wled00` directory.
|
||||
2. Register the usermod by adding `#include "usermod_mqtt_switch.h"` in the top and `registerUsermod(new UsermodMqttSwitch());` in the bottom of `usermods_list.cpp`.
|
||||
|
||||
|
||||
Example `usermods_list.cpp`:
|
||||
|
||||
```
|
||||
#include "wled.h"
|
||||
#include "usermod_mqtt_switch.h"
|
||||
|
||||
void registerUsermods()
|
||||
{
|
||||
usermods.add(new UsermodMqttSwitch());
|
||||
}
|
||||
```
|
||||
|
||||
## Define pins
|
||||
Add a define for MQTTSWITCHPINS to platformio_override.ini.
|
||||
The following example defines 3 switches connected to the GPIO pins 13, 5 and 2:
|
||||
|
||||
```
|
||||
[env:livingroom]
|
||||
board = esp12e
|
||||
platform = ${common.platform_wled_default}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_flags = ${common.build_flags_esp8266}
|
||||
-D LEDPIN=3
|
||||
-D BTNPIN=4
|
||||
-D RLYPIN=12
|
||||
-D RLYMDE=1
|
||||
-D STATUSPIN=15
|
||||
-D MQTTSWITCHPINS="13, 5, 2"
|
||||
```
|
||||
|
||||
Pins can be inverted by setting `MQTTSWITCHINVERT`. For example `-D MQTTSWITCHINVERT="false, false, true"` would invert the switch on pin 2 in the previous example.
|
||||
|
||||
The default state after booting before any MQTT message can be set by `MQTTSWITCHDEFAULTS`. For example `-D MQTTSWITCHDEFAULTS="ON, OFF, OFF"` would power on the switch on pin 13 and power off switches on pins 5 and 2.
|
||||
|
||||
## MQTT topics
|
||||
This usermod listens on `[mqttDeviceTopic]/switch/0/set` (where 0 is replaced with the index of the switch) for commands. Anything starting with `ON` turns on the switch, everything else turns it off.
|
||||
Feedback about the current state is provided at `[mqttDeviceTopic]/switch/0/state`.
|
||||
|
||||
### Home Assistant auto-discovery
|
||||
Auto-discovery information is automatically published and you shoudn't have to do anything to register the switches in Home Assistant.
|
||||
|
||||
157
usermods/mqtt_switch_v2/usermod_mqtt_switch.h
Normal file
@@ -0,0 +1,157 @@
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
#ifndef WLED_ENABLE_MQTT
|
||||
#error "This user mod requires MQTT to be enabled."
|
||||
#endif
|
||||
|
||||
#ifndef MQTTSWITCHPINS
|
||||
#error "Please define MQTTSWITCHPINS in platformio_override.ini. e.g. -D MQTTSWITCHPINS="12, 0, 2" "
|
||||
// The following define helps Eclipse's C++ parser but is never used in production due to the #error statement on the line before
|
||||
#define MQTTSWITCHPINS 12, 0, 2
|
||||
#endif
|
||||
|
||||
// Default behavior: All outputs active high
|
||||
#ifndef MQTTSWITCHINVERT
|
||||
#define MQTTSWITCHINVERT
|
||||
#endif
|
||||
|
||||
// Default behavior: All outputs off
|
||||
#ifndef MQTTSWITCHDEFAULTS
|
||||
#define MQTTSWITCHDEFAULTS
|
||||
#endif
|
||||
|
||||
static const uint8_t switchPins[] = { MQTTSWITCHPINS };
|
||||
//This is a hack to get the number of pins defined by the user
|
||||
#define NUM_SWITCH_PINS (sizeof(switchPins))
|
||||
static const bool switchInvert[NUM_SWITCH_PINS] = { MQTTSWITCHINVERT};
|
||||
//Make settings in config file more readable
|
||||
#define ON 1
|
||||
#define OFF 0
|
||||
static const bool switchDefaults[NUM_SWITCH_PINS] = { MQTTSWITCHDEFAULTS};
|
||||
#undef ON
|
||||
#undef OFF
|
||||
|
||||
class UsermodMqttSwitch: public Usermod
|
||||
{
|
||||
private:
|
||||
bool mqttInitialized;
|
||||
bool switchState[NUM_SWITCH_PINS];
|
||||
|
||||
public:
|
||||
UsermodMqttSwitch() :
|
||||
mqttInitialized(false)
|
||||
{
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
for (int pinNr = 0; pinNr < NUM_SWITCH_PINS; pinNr++) {
|
||||
setState(pinNr, switchDefaults[pinNr]);
|
||||
pinMode(switchPins[pinNr], OUTPUT);
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (!mqttInitialized) {
|
||||
mqttInit();
|
||||
return; // Try again in next loop iteration
|
||||
}
|
||||
}
|
||||
|
||||
void mqttInit()
|
||||
{
|
||||
if (!mqtt)
|
||||
return;
|
||||
mqtt->onMessage(
|
||||
std::bind(&UsermodMqttSwitch::onMqttMessage, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4,
|
||||
std::placeholders::_5, std::placeholders::_6));
|
||||
mqtt->onConnect(std::bind(&UsermodMqttSwitch::onMqttConnect, this, std::placeholders::_1));
|
||||
mqttInitialized = true;
|
||||
}
|
||||
|
||||
void onMqttConnect(bool sessionPresent);
|
||||
|
||||
void onMqttMessage(char *topic, char *payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total);
|
||||
void updateState(uint8_t pinNr);
|
||||
|
||||
void setState(uint8_t pinNr, bool active)
|
||||
{
|
||||
if (pinNr > NUM_SWITCH_PINS)
|
||||
return;
|
||||
switchState[pinNr] = active;
|
||||
digitalWrite((char) switchPins[pinNr], (char) (switchInvert[pinNr] ? !active : active));
|
||||
updateState(pinNr);
|
||||
}
|
||||
};
|
||||
|
||||
inline void UsermodMqttSwitch::onMqttConnect(bool sessionPresent)
|
||||
{
|
||||
if (mqttDeviceTopic[0] == 0)
|
||||
return;
|
||||
|
||||
for (int pinNr = 0; pinNr < NUM_SWITCH_PINS; pinNr++) {
|
||||
char buf[128];
|
||||
StaticJsonDocument<1024> json;
|
||||
sprintf(buf, "%s Switch %d", serverDescription, pinNr + 1);
|
||||
json[F("name")] = buf;
|
||||
|
||||
sprintf(buf, "%s/switch/%d", mqttDeviceTopic, pinNr);
|
||||
json["~"] = buf;
|
||||
strcat(buf, "/set");
|
||||
mqtt->subscribe(buf, 0);
|
||||
|
||||
json[F("stat_t")] = "~/state";
|
||||
json[F("cmd_t")] = "~/set";
|
||||
json[F("pl_off")] = F("OFF");
|
||||
json[F("pl_on")] = F("ON");
|
||||
|
||||
char uid[16];
|
||||
sprintf(uid, "%s_sw%d", escapedMac.c_str(), pinNr);
|
||||
json[F("unique_id")] = uid;
|
||||
|
||||
strcpy(buf, mqttDeviceTopic);
|
||||
strcat(buf, "/status");
|
||||
json[F("avty_t")] = buf;
|
||||
json[F("pl_avail")] = F("online");
|
||||
json[F("pl_not_avail")] = F("offline");
|
||||
//TODO: dev
|
||||
sprintf(buf, "homeassistant/switch/%s/config", uid);
|
||||
char json_str[1024];
|
||||
size_t payload_size = serializeJson(json, json_str);
|
||||
mqtt->publish(buf, 0, true, json_str, payload_size);
|
||||
updateState(pinNr);
|
||||
}
|
||||
}
|
||||
|
||||
inline void UsermodMqttSwitch::onMqttMessage(char *topic, char *payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total)
|
||||
{
|
||||
//Note: Payload is not necessarily null terminated. Check "len" instead.
|
||||
for (int pinNr = 0; pinNr < NUM_SWITCH_PINS; pinNr++) {
|
||||
char buf[64];
|
||||
sprintf(buf, "%s/switch/%d/set", mqttDeviceTopic, pinNr);
|
||||
if (strcmp(topic, buf) == 0) {
|
||||
//Any string starting with "ON" is interpreted as ON, everything else as OFF
|
||||
setState(pinNr, len >= 2 && payload[0] == 'O' && payload[1] == 'N');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void UsermodMqttSwitch::updateState(uint8_t pinNr)
|
||||
{
|
||||
if (!mqttInitialized)
|
||||
return;
|
||||
|
||||
if (pinNr > NUM_SWITCH_PINS)
|
||||
return;
|
||||
|
||||
char buf[64];
|
||||
sprintf(buf, "%s/switch/%d/state", mqttDeviceTopic, pinNr);
|
||||
if (switchState[pinNr]) {
|
||||
mqtt->publish(buf, 0, false, "ON");
|
||||
} else {
|
||||
mqtt->publish(buf, 0, false, "OFF");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
# QuinLED-Dig-Quad Preassembled Unofficial Build
|
||||
|
||||
This usermod targets the [Preassembled QuinLED-Dig-Quad](https://quinled.info/pre-assembled-quinled-dig-quad/). Tested on board revision v1r6b,
|
||||
and includes the following features:
|
||||
|
||||
* **Multi-channel Support** - enabling use of LED1, LED2, LED3, LED4 pins to work using segments
|
||||
* **Temperature Sensor Support** - pulls readings from the built-in temperature sensor and adds the reading to the *Info* page in the UI
|
||||
|
||||
## Background
|
||||
|
||||
As a starting point, you should check out this awesome video from Quindor: [How to compile WLED yourself](https://quinled.info/2020/12/22/livestream-wled-compile/). The usermod you are reading now just provides some shortcuts for parts of what were covered in that video.
|
||||
|
||||
## Build Firmware with Multi-channel and Temp Support
|
||||
|
||||
1. Copy the `platformio_override.ini` file to the project's root directory
|
||||
1. If using VS Code with the PlatformIO plugin like in the video, you will now see this new project task listed in the PLATFORMIO panel at the bottom as `env:QL-DigQuad-Pre-v0.1` (you probably need to hit the refresh button)
|
||||
|
||||
<img src="images/pio-screenshot.png" width="400px"/>
|
||||
|
||||
1. Edit this file from the root directory as needed:
|
||||
|
||||
<img src="images/params.png" width="400px"/>
|
||||
|
||||
* `PIXEL_COUNTS` may need to be adjusted for your set-up. E.g. I have lots of LEDs in Channel 1, but that's probably unusual for most
|
||||
* `DATA_PINS` may need to be changed to "16,3,1,26" instead of "16,1,3,26" apparently depending on the board revision or some such
|
||||
|
||||
1. Build the mod (e.g. click `Build` from the project task circled above) and update your firmware using the `QL-DigQuad-Pre-v0.1` file, e.g. using _Manual OTA_ from the Config menu. Based on the video and my own experience, you might need to build twice 🤷♂️.
|
||||
|
||||
## Observing Temperature
|
||||
|
||||
Hopefully you can now see the Temperature listed in the Info page. If not, use Chrome Developer Tools to find the current temperature
|
||||
|
||||
1. Open the Developer Tools Console
|
||||
2. Enter `lastinfo.u.Temperature` to view the Temperature array
|
||||
|
||||
<img src="images/json-temp.png" width="300px"/>
|
||||
|
||||
|
After Width: | Height: | Size: 296 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 321 KiB |
@@ -0,0 +1,16 @@
|
||||
; QuinLED-Dig-Quad Preassembled Unofficial
|
||||
|
||||
[env:QL-DigQuad-Pre-v0.1]
|
||||
extends = env:esp32dev
|
||||
build_flags = ${common.build_flags_esp32}
|
||||
-D ESP32_MULTISTRIP
|
||||
-D NUM_STRIPS=4
|
||||
-D PIXEL_COUNTS="600, 300, 300, 300"
|
||||
-D DATA_PINS="16,1,3,26"
|
||||
-D RLYPIN=19
|
||||
-D BTNPIN=17
|
||||
-D USERMOD_DALLASTEMPERATURE
|
||||
-D USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL=10000
|
||||
lib_deps = ${env.lib_deps}
|
||||
milesburton/DallasTemperature@^3.9.0
|
||||
OneWire@~2.3.5
|
||||
87
usermods/sensors_to_mqtt/readme.md
Normal file
@@ -0,0 +1,87 @@
|
||||
# Sensors To Home Assistant (or mqtt)
|
||||
|
||||
This usermod will publish values of the BMP280, CCS811 and Si7021 sensors to Home Assistant via MQTT.
|
||||
|
||||
Its using home assistant automatic device discovery feature.
|
||||
|
||||
The use of Home Assistant is not mandatory; it will publish the sensor values via MQTT just fine without it.
|
||||
|
||||
Its resusing the mqtt connection set in the WLED web user interface.
|
||||
|
||||
## Maintainer
|
||||
|
||||
twitter.com/mpronk89
|
||||
|
||||
## Features
|
||||
|
||||
- Reads BMP280, CCS811 and Si7021 senors
|
||||
- Publishes via MQTT, configured via webui of wled
|
||||
- Announces device in Home Assistant for easy setup
|
||||
- Efficient energy usage
|
||||
- Updates every 60 seconds
|
||||
|
||||
## Example mqtt topics:
|
||||
|
||||
`$mqttDeviceTopic` is set in webui of WLED!
|
||||
|
||||
```
|
||||
temperature: $mqttDeviceTopic/temperature
|
||||
pressure: $mqttDeviceTopic/pressure
|
||||
humidity: $mqttDeviceTopic/humidity
|
||||
tvoc: $mqttDeviceTopic/tvoc
|
||||
eCO2: $mqttDeviceTopic/eco2
|
||||
IAQ: $mqttDeviceTopic/iaq
|
||||
```
|
||||
|
||||
# Installation
|
||||
|
||||
## Hardware
|
||||
|
||||
### Requirements
|
||||
|
||||
1. BMP280/CCS811/Si7021 sensor. E.g. https://aliexpress.com/item/32979998543.html
|
||||
2. A microcontroller which can talk i2c, e.g. esp32
|
||||
|
||||
### installation
|
||||
|
||||
Attach the sensor to the i2c interface.
|
||||
|
||||
Default PINs esp32:
|
||||
|
||||
```
|
||||
SCL_PIN = 22;
|
||||
SDA_PIN = 21;
|
||||
```
|
||||
|
||||
Default PINs ESP8266:
|
||||
|
||||
```
|
||||
SCL_PIN = 5;
|
||||
SDA_PIN = 4;
|
||||
```
|
||||
|
||||
## Enable in WLED
|
||||
|
||||
1. Copy `usermod_v2_SensorsToMqtt.h` into the `wled00` directory.
|
||||
2. Add to `build_flags` in platformio.ini:
|
||||
|
||||
```
|
||||
-D USERMOD_SENSORSTOMQTT
|
||||
```
|
||||
|
||||
3. And add to `lib_deps` in platformio.ini:
|
||||
|
||||
```
|
||||
adafruit/Adafruit BMP280 Library @ 2.1.0
|
||||
adafruit/Adafruit CCS811 Library @ 1.0.4
|
||||
adafruit/Adafruit Si7021 Library @ 1.4.0
|
||||
```
|
||||
|
||||
The #ifdefs in `usermods_list.cpp` should do the rest :)
|
||||
|
||||
# Credits
|
||||
|
||||
- Aircoookie for making WLED
|
||||
- Other usermod creators for example code
|
||||
- Bouke_Regnerus for https://community.home-assistant.io/t/example-indoor-air-quality-text-sensor-using-ccs811-sensor/125854
|
||||
- You, for reading this
|
||||
284
usermods/sensors_to_mqtt/usermod_v2_SensorsToMqtt.h
Normal file
@@ -0,0 +1,284 @@
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_Sensor.h>
|
||||
#include <Adafruit_BMP280.h>
|
||||
#include <Adafruit_CCS811.h>
|
||||
#include <Adafruit_Si7021.h>
|
||||
|
||||
Adafruit_BMP280 bmp;
|
||||
Adafruit_Si7021 si7021;
|
||||
Adafruit_CCS811 ccs811;
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32 //ESP32 boards
|
||||
uint8_t SCL_PIN = 22;
|
||||
uint8_t SDA_PIN = 21;
|
||||
#else //ESP8266 boards
|
||||
uint8_t SCL_PIN = 5;
|
||||
uint8_t SDA_PIN = 4;
|
||||
#endif
|
||||
|
||||
class UserMod_SensorsToMQTT : public Usermod
|
||||
{
|
||||
private:
|
||||
bool initialized = false;
|
||||
bool mqttInitialized = false;
|
||||
float SensorPressure = 0;
|
||||
float SensorTemperature = 0;
|
||||
float SensorHumidity = 0;
|
||||
char *SensorIaq = "Unknown";
|
||||
String mqttTemperatureTopic = "";
|
||||
String mqttHumidityTopic = "";
|
||||
String mqttPressureTopic = "";
|
||||
String mqttTvocTopic = "";
|
||||
String mqttEco2Topic = "";
|
||||
String mqttIaqTopic = "";
|
||||
unsigned int SensorTvoc = 0;
|
||||
unsigned int SensorEco2 = 0;
|
||||
unsigned long nextMeasure = 0;
|
||||
|
||||
void _initialize()
|
||||
{
|
||||
initialized = bmp.begin(BMP280_ADDRESS_ALT);
|
||||
bmp.setSampling(Adafruit_BMP280::MODE_NORMAL, /* Operating Mode. */
|
||||
Adafruit_BMP280::SAMPLING_X16, /* Temp. oversampling */
|
||||
Adafruit_BMP280::SAMPLING_X16, /* Pressure oversampling */
|
||||
Adafruit_BMP280::FILTER_X16, /* Filtering. */
|
||||
Adafruit_BMP280::STANDBY_MS_2000); /* Refresh values every 20 seconds */
|
||||
|
||||
initialized &= si7021.begin();
|
||||
initialized &= ccs811.begin();
|
||||
ccs811.setDriveMode(CCS811_DRIVE_MODE_10SEC); /* Refresh values every 10s */
|
||||
Serial.print(initialized);
|
||||
}
|
||||
|
||||
void _mqttInitialize()
|
||||
{
|
||||
mqttTemperatureTopic = String(mqttDeviceTopic) + "/temperature";
|
||||
mqttPressureTopic = String(mqttDeviceTopic) + "/pressure";
|
||||
mqttHumidityTopic = String(mqttDeviceTopic) + "/humidity";
|
||||
mqttTvocTopic = String(mqttDeviceTopic) + "/tvoc";
|
||||
mqttEco2Topic = String(mqttDeviceTopic) + "/eco2";
|
||||
mqttIaqTopic = String(mqttDeviceTopic) + "/iaq";
|
||||
|
||||
String t = String("homeassistant/sensor/") + mqttClientID + "/temperature/config";
|
||||
|
||||
_createMqttSensor("temperature", mqttTemperatureTopic, "temperature", "°C");
|
||||
_createMqttSensor("pressure", mqttPressureTopic, "pressure", "hPa");
|
||||
_createMqttSensor("humidity", mqttHumidityTopic, "humidity", "%");
|
||||
_createMqttSensor("tvoc", mqttTvocTopic, "", "ppb");
|
||||
_createMqttSensor("eco2", mqttEco2Topic, "", "ppm");
|
||||
_createMqttSensor("iaq", mqttIaqTopic, "", "");
|
||||
}
|
||||
|
||||
void _createMqttSensor(const String &name, const String &topic, const String &deviceClass, const String &unitOfMeasurement)
|
||||
{
|
||||
String t = String("homeassistant/sensor/") + mqttClientID + "/" + name + "/config";
|
||||
|
||||
StaticJsonDocument<300> doc;
|
||||
|
||||
doc["name"] = name;
|
||||
doc["state_topic"] = topic;
|
||||
doc["unique_id"] = String(mqttClientID) + name;
|
||||
if (unitOfMeasurement != "")
|
||||
doc["unit_of_measurement"] = unitOfMeasurement;
|
||||
if (deviceClass != "")
|
||||
doc["device_class"] = deviceClass;
|
||||
doc["expire_after"] = 1800;
|
||||
|
||||
JsonObject device = doc.createNestedObject("device"); // attach the sensor to the same device
|
||||
device["identifiers"] = String("wled-sensor-") + mqttClientID;
|
||||
device["manufacturer"] = "Aircoookie";
|
||||
device["model"] = "WLED";
|
||||
device["sw_version"] = VERSION;
|
||||
device["name"] = mqttClientID;
|
||||
|
||||
String temp;
|
||||
serializeJson(doc, temp);
|
||||
Serial.println(t);
|
||||
Serial.println(temp);
|
||||
|
||||
mqtt->publish(t.c_str(), 0, true, temp.c_str());
|
||||
}
|
||||
|
||||
void _updateSensorData()
|
||||
{
|
||||
SensorTemperature = bmp.readTemperature();
|
||||
SensorHumidity = si7021.readHumidity();
|
||||
SensorPressure = (bmp.readPressure() / 100.0F);
|
||||
ccs811.setEnvironmentalData(SensorHumidity, SensorTemperature);
|
||||
ccs811.readData();
|
||||
SensorTvoc = ccs811.getTVOC();
|
||||
SensorEco2 = ccs811.geteCO2();
|
||||
SensorIaq = _getIaqIndex(SensorHumidity, SensorTvoc, SensorEco2);
|
||||
|
||||
Serial.printf("%f c, %f humidity, %f hPA, %u tvoc, %u Eco2, %s iaq\n",
|
||||
SensorTemperature, SensorHumidity, SensorPressure,
|
||||
SensorTvoc, SensorEco2, SensorIaq);
|
||||
}
|
||||
|
||||
/**
|
||||
* Credits: Bouke_Regnerus @ https://community.home-assistant.io/t/example-indoor-air-quality-text-sensor-using-ccs811-sensor/125854
|
||||
*/
|
||||
char *_getIaqIndex(float humidity, int tvoc, int eco2)
|
||||
{
|
||||
int iaq_index = 0;
|
||||
|
||||
/*
|
||||
* Transform indoor humidity values to IAQ points according to Indoor Air Quality UK:
|
||||
* http://www.iaquk.org.uk/
|
||||
*/
|
||||
if (humidity < 10 or humidity > 90)
|
||||
{
|
||||
iaq_index += 1;
|
||||
}
|
||||
else if (humidity < 20 or humidity > 80)
|
||||
{
|
||||
iaq_index += 2;
|
||||
}
|
||||
else if (humidity < 30 or humidity > 70)
|
||||
{
|
||||
iaq_index += 3;
|
||||
}
|
||||
else if (humidity < 40 or humidity > 60)
|
||||
{
|
||||
iaq_index += 4;
|
||||
}
|
||||
else if (humidity >= 40 and humidity <= 60)
|
||||
{
|
||||
iaq_index += 5;
|
||||
}
|
||||
|
||||
/*
|
||||
* Transform eCO2 values to IAQ points according to Indoor Air Quality UK:
|
||||
* http://www.iaquk.org.uk/
|
||||
*/
|
||||
if (eco2 <= 600)
|
||||
{
|
||||
iaq_index += 5;
|
||||
}
|
||||
else if (eco2 <= 800)
|
||||
{
|
||||
iaq_index += 4;
|
||||
}
|
||||
else if (eco2 <= 1500)
|
||||
{
|
||||
iaq_index += 3;
|
||||
}
|
||||
else if (eco2 <= 1800)
|
||||
{
|
||||
iaq_index += 2;
|
||||
}
|
||||
else if (eco2 > 1800)
|
||||
{
|
||||
iaq_index += 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Transform TVOC values to IAQ points according to German environmental guidelines:
|
||||
* https://www.repcomsrl.com/wp-content/uploads/2017/06/Environmental_Sensing_VOC_Product_Brochure_EN.pdf
|
||||
*/
|
||||
if (tvoc <= 65)
|
||||
{
|
||||
iaq_index += 5;
|
||||
}
|
||||
else if (tvoc <= 220)
|
||||
{
|
||||
iaq_index += 4;
|
||||
}
|
||||
else if (tvoc <= 660)
|
||||
{
|
||||
iaq_index += 3;
|
||||
}
|
||||
else if (tvoc <= 2200)
|
||||
{
|
||||
iaq_index += 2;
|
||||
}
|
||||
else if (tvoc > 2200)
|
||||
{
|
||||
iaq_index += 1;
|
||||
}
|
||||
|
||||
if (iaq_index <= 6)
|
||||
{
|
||||
return "Unhealty";
|
||||
}
|
||||
else if (iaq_index <= 9)
|
||||
{
|
||||
return "Poor";
|
||||
}
|
||||
else if (iaq_index <= 12)
|
||||
{
|
||||
return "Moderate";
|
||||
}
|
||||
else if (iaq_index <= 14)
|
||||
{
|
||||
return "Good";
|
||||
}
|
||||
else if (iaq_index > 14)
|
||||
{
|
||||
return "Excellent";
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
void setup()
|
||||
{
|
||||
Serial.println("Starting!");
|
||||
Wire.begin(SDA_PIN, SCL_PIN);
|
||||
Serial.println("Initializing sensors.. ");
|
||||
_initialize();
|
||||
}
|
||||
|
||||
// gets called every time WiFi is (re-)connected.
|
||||
void connected()
|
||||
{
|
||||
nextMeasure = millis() + 5000; // Schedule next measure in 5 seconds
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
unsigned long tempTimer = millis();
|
||||
|
||||
if (tempTimer > nextMeasure)
|
||||
{
|
||||
nextMeasure = tempTimer + 60000; // Schedule next measure in 60 seconds
|
||||
|
||||
if (!initialized)
|
||||
{
|
||||
Serial.println("Error! Sensors not initialized in loop()!");
|
||||
_initialize();
|
||||
return; // lets try again next loop
|
||||
}
|
||||
|
||||
if (mqtt != nullptr && mqtt->connected())
|
||||
{
|
||||
if (!mqttInitialized)
|
||||
{
|
||||
_mqttInitialize();
|
||||
mqttInitialized = true;
|
||||
}
|
||||
|
||||
// Update sensor data
|
||||
_updateSensorData();
|
||||
|
||||
// Create string populated with user defined device topic from the UI,
|
||||
// and the read temperature, humidity and pressure.
|
||||
// Then publish to MQTT server.
|
||||
mqtt->publish(mqttTemperatureTopic.c_str(), 0, true, String(SensorTemperature).c_str());
|
||||
mqtt->publish(mqttPressureTopic.c_str(), 0, true, String(SensorPressure).c_str());
|
||||
mqtt->publish(mqttHumidityTopic.c_str(), 0, true, String(SensorHumidity).c_str());
|
||||
mqtt->publish(mqttTvocTopic.c_str(), 0, true, String(SensorTvoc).c_str());
|
||||
mqtt->publish(mqttEco2Topic.c_str(), 0, true, String(SensorEco2).c_str());
|
||||
mqtt->publish(mqttIaqTopic.c_str(), 0, true, String(SensorIaq).c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Missing MQTT connection. Not publishing data");
|
||||
mqttInitialized = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
136
usermods/stairway_wipe_basic/stairway-wipe-usermod-v2.h
Normal file
@@ -0,0 +1,136 @@
|
||||
#include "wled.h"
|
||||
|
||||
/*
|
||||
* Usermods allow you to add own functionality to WLED more easily
|
||||
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
|
||||
*
|
||||
* This is Stairway-Wipe as a v2 usermod.
|
||||
*
|
||||
* Using this usermod:
|
||||
* 1. Copy the usermod into the sketch folder (same folder as wled00.ino)
|
||||
* 2. Register the usermod by adding #include "stairway-wipe-usermod-v2.h" in the top and registerUsermod(new StairwayWipeUsermod()) in the bottom of usermods_list.cpp
|
||||
*/
|
||||
|
||||
class StairwayWipeUsermod : public Usermod {
|
||||
private:
|
||||
//Private class members. You can declare variables and functions only accessible to your usermod here
|
||||
unsigned long lastTime = 0;
|
||||
byte wipeState = 0; //0: inactive 1: wiping 2: solid
|
||||
unsigned long timeStaticStart = 0;
|
||||
uint16_t previousUserVar0 = 0;
|
||||
|
||||
//comment this out if you want the turn off effect to be just fading out instead of reverse wipe
|
||||
#define STAIRCASE_WIPE_OFF
|
||||
public:
|
||||
|
||||
void loop() {
|
||||
//userVar0 (U0 in HTTP API):
|
||||
//has to be set to 1 if movement is detected on the PIR that is the same side of the staircase as the ESP8266
|
||||
//has to be set to 2 if movement is detected on the PIR that is the opposite side
|
||||
//can be set to 0 if no movement is detected. Otherwise LEDs will turn off after a configurable timeout (userVar1 seconds)
|
||||
|
||||
if (userVar0 > 0)
|
||||
{
|
||||
if ((previousUserVar0 == 1 && userVar0 == 2) || (previousUserVar0 == 2 && userVar0 == 1)) wipeState = 3; //turn off if other PIR triggered
|
||||
previousUserVar0 = userVar0;
|
||||
|
||||
if (wipeState == 0) {
|
||||
startWipe();
|
||||
wipeState = 1;
|
||||
} else if (wipeState == 1) { //wiping
|
||||
uint32_t cycleTime = 360 + (255 - effectSpeed)*75; //this is how long one wipe takes (minus 25 ms to make sure we switch in time)
|
||||
if (millis() + strip.timebase > (cycleTime - 25)) { //wipe complete
|
||||
effectCurrent = FX_MODE_STATIC;
|
||||
timeStaticStart = millis();
|
||||
colorUpdated(NOTIFIER_CALL_MODE_NOTIFICATION);
|
||||
wipeState = 2;
|
||||
}
|
||||
} else if (wipeState == 2) { //static
|
||||
if (userVar1 > 0) //if U1 is not set, the light will stay on until second PIR or external command is triggered
|
||||
{
|
||||
if (millis() - timeStaticStart > userVar1*1000) wipeState = 3;
|
||||
}
|
||||
} else if (wipeState == 3) { //switch to wipe off
|
||||
#ifdef STAIRCASE_WIPE_OFF
|
||||
effectCurrent = FX_MODE_COLOR_WIPE;
|
||||
strip.timebase = 360 + (255 - effectSpeed)*75 - millis(); //make sure wipe starts fully lit
|
||||
colorUpdated(NOTIFIER_CALL_MODE_NOTIFICATION);
|
||||
wipeState = 4;
|
||||
#else
|
||||
turnOff();
|
||||
#endif
|
||||
} else { //wiping off
|
||||
if (millis() + strip.timebase > (725 + (255 - effectSpeed)*150)) turnOff(); //wipe complete
|
||||
}
|
||||
} else {
|
||||
wipeState = 0; //reset for next time
|
||||
if (previousUserVar0) {
|
||||
#ifdef STAIRCASE_WIPE_OFF
|
||||
userVar0 = previousUserVar0;
|
||||
wipeState = 3;
|
||||
#else
|
||||
turnOff();
|
||||
#endif
|
||||
}
|
||||
previousUserVar0 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void readFromJsonState(JsonObject& root)
|
||||
{
|
||||
userVar0 = root["user0"] | userVar0; //if "user0" key exists in JSON, update, else keep old value
|
||||
//if (root["bri"] == 255) Serial.println(F("Don't burn down your garage!"));
|
||||
}
|
||||
|
||||
void addToConfig(JsonObject& root)
|
||||
{
|
||||
JsonObject top = root.createNestedObject("exampleUsermod");
|
||||
top["great"] = userVar0; //save this var persistently whenever settings are saved
|
||||
}
|
||||
|
||||
void readFromConfig(JsonObject& root)
|
||||
{
|
||||
JsonObject top = root["top"];
|
||||
userVar0 = top["great"] | 42; //The value right of the pipe "|" is the default value in case your setting was not present in cfg.json (e.g. first boot)
|
||||
}
|
||||
|
||||
uint16_t getId()
|
||||
{
|
||||
return USERMOD_ID_EXAMPLE;
|
||||
}
|
||||
|
||||
|
||||
void startWipe()
|
||||
{
|
||||
bri = briLast; //turn on
|
||||
transitionDelayTemp = 0; //no transition
|
||||
effectCurrent = FX_MODE_COLOR_WIPE;
|
||||
resetTimebase(); //make sure wipe starts from beginning
|
||||
|
||||
//set wipe direction
|
||||
WS2812FX::Segment& seg = strip.getSegment(0);
|
||||
bool doReverse = (userVar0 == 2);
|
||||
seg.setOption(1, doReverse);
|
||||
|
||||
colorUpdated(NOTIFIER_CALL_MODE_NOTIFICATION);
|
||||
}
|
||||
|
||||
void turnOff()
|
||||
{
|
||||
#ifdef STAIRCASE_WIPE_OFF
|
||||
transitionDelayTemp = 0; //turn off immediately after wipe completed
|
||||
#else
|
||||
transitionDelayTemp = 4000; //fade out slowly
|
||||
#endif
|
||||
bri = 0;
|
||||
colorUpdated(NOTIFIER_CALL_MODE_NOTIFICATION);
|
||||
wipeState = 0;
|
||||
userVar0 = 0;
|
||||
previousUserVar0 = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//More methods can be added in the future, this example will then be extended.
|
||||
//Your usermod will remain compatible as it does not need to implement all methods from the Usermod base class!
|
||||
};
|
||||
45
usermods/usermod_v2_auto_save/readme.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# Auto Save
|
||||
|
||||
v2 Usermod to automatically save settings
|
||||
to preset number AUTOSAVE_PRESET_NUM after a change to any of
|
||||
|
||||
* brightness
|
||||
* effect speed
|
||||
* effect intensity
|
||||
* mode (effect)
|
||||
* palette
|
||||
|
||||
but it will wait for AUTOSAVE_SETTLE_MS milliseconds, a "settle"
|
||||
period in case there are other changes (any change will
|
||||
extend the "settle" window).
|
||||
|
||||
It will additionally load preset AUTOSAVE_PRESET_NUM at startup.
|
||||
during the first `loop()`. Reasoning below.
|
||||
|
||||
AutoSaveUsermod is standalone, but if FourLineDisplayUsermod is installed, it will notify the user of the saved changes.
|
||||
|
||||
Note: I don't love that WLED doesn't respect the brightness of the preset being auto loaded, so the AutoSaveUsermod will set the AUTOSAVE_PRESET_NUM preset in the first loop, so brightness IS honored. This means WLED will effectively ignore Default brightness and Apply N preset at boot when the AutoSaveUsermod is installed.
|
||||
|
||||
## Installation
|
||||
|
||||
Copy and update the example `platformio_override.ini.sample`
|
||||
from the Rotary Encoder UI usermode folder to the root directory of your particular build.
|
||||
This file should be placed in the same directory as `platformio.ini`.
|
||||
|
||||
### Define Your Options
|
||||
|
||||
* `USERMOD_AUTO_SAVE` - define this to have this the Auto Save usermod included wled00\usermods_list.cpp
|
||||
* `USERMOD_FOUR_LINE_DISLAY` - 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)
|
||||
* `AUTOSAVE_SETTLE_MS` - Minimum time to wave before auto saving, defaults to 10000 (10s)
|
||||
* `AUTOSAVE_PRESET_NUM` - Preset number to auto-save to, auto-load at startup from, defaults to 99
|
||||
|
||||
### PlatformIO requirements
|
||||
|
||||
No special requirements.
|
||||
|
||||
Note: the Four Line Display usermod requires the libraries `U8g2` and `Wire`.
|
||||
|
||||
## Change Log
|
||||
|
||||
2021-02
|
||||
* First public release
|
||||
192
usermods/usermod_v2_auto_save/usermod_v2_auto_save.h
Normal file
@@ -0,0 +1,192 @@
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
|
||||
//
|
||||
// v2 Usermod to automatically save settings
|
||||
// to preset number AUTOSAVE_PRESET_NUM after a change to any of
|
||||
//
|
||||
// * brightness
|
||||
// * effect speed
|
||||
// * effect intensity
|
||||
// * mode (effect)
|
||||
// * palette
|
||||
//
|
||||
// but it will wait for AUTOSAVE_SETTLE_MS milliseconds, a "settle"
|
||||
// period in case there are other changes (any change will
|
||||
// extend the "settle" window).
|
||||
//
|
||||
// It will additionally load preset AUTOSAVE_PRESET_NUM at startup.
|
||||
// during the first `loop()`. Reasoning below.
|
||||
//
|
||||
// AutoSaveUsermod is standalone, but if FourLineDisplayUsermod
|
||||
// is installed, it will notify the user of the saved changes.
|
||||
//
|
||||
// Note: I don't love that WLED doesn't respect the brightness
|
||||
// of the preset being auto loaded, so the AutoSaveUsermod
|
||||
// will set the AUTOSAVE_PRESET_NUM preset in the first loop,
|
||||
// so brightness IS honored. This means WLED will effectively
|
||||
// ignore Default brightness and Apply N preset at boot when
|
||||
// the AutoSaveUsermod is installed.
|
||||
|
||||
//How long to wait after settings change to auto-save
|
||||
#ifndef AUTOSAVE_SETTLE_MS
|
||||
#define AUTOSAVE_SETTLE_MS 10*1000
|
||||
#endif
|
||||
|
||||
//Preset number to save to
|
||||
#ifndef AUTOSAVE_PRESET_NUM
|
||||
#define AUTOSAVE_PRESET_NUM 99
|
||||
#endif
|
||||
|
||||
// "Auto save MM-DD HH:MM:SS"
|
||||
#define PRESET_NAME_BUFFER_SIZE 25
|
||||
|
||||
class AutoSaveUsermod : public Usermod {
|
||||
private:
|
||||
// If we've detected the need to auto save, this will
|
||||
// be non zero.
|
||||
unsigned long autoSaveAfter = 0;
|
||||
|
||||
char presetNameBuffer[PRESET_NAME_BUFFER_SIZE];
|
||||
|
||||
bool firstLoop = true;
|
||||
|
||||
uint8_t knownBrightness = 0;
|
||||
uint8_t knownEffectSpeed = 0;
|
||||
uint8_t knownEffectIntensity = 0;
|
||||
uint8_t knownMode = 0;
|
||||
uint8_t knownPalette = 0;
|
||||
|
||||
#ifdef USERMOD_FOUR_LINE_DISLAY
|
||||
FourLineDisplayUsermod* display;
|
||||
#endif
|
||||
|
||||
public:
|
||||
// gets called once at boot. Do all initialization that doesn't depend on
|
||||
// network here
|
||||
void setup() {
|
||||
#ifdef USERMOD_FOUR_LINE_DISLAY
|
||||
// This Usermod has enhanced funcionality if
|
||||
// FourLineDisplayUsermod is available.
|
||||
display = (FourLineDisplayUsermod*) usermods.lookup(USERMOD_ID_FOUR_LINE_DISP);
|
||||
#endif
|
||||
}
|
||||
|
||||
// gets called every time WiFi is (re-)connected. Initialize own network
|
||||
// interfaces here
|
||||
void connected() {}
|
||||
|
||||
/**
|
||||
* Da loop.
|
||||
*/
|
||||
void loop() {
|
||||
unsigned long now = millis();
|
||||
uint8_t currentMode = strip.getMode();
|
||||
uint8_t currentPalette = strip.getSegment(0).palette;
|
||||
if (firstLoop) {
|
||||
firstLoop = false;
|
||||
applyPreset(AUTOSAVE_PRESET_NUM);
|
||||
knownBrightness = bri;
|
||||
knownEffectSpeed = effectSpeed;
|
||||
knownEffectIntensity = effectIntensity;
|
||||
knownMode = currentMode;
|
||||
knownPalette = currentPalette;
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned long wouldAutoSaveAfter = now + AUTOSAVE_SETTLE_MS;
|
||||
if (knownBrightness != bri) {
|
||||
knownBrightness = bri;
|
||||
autoSaveAfter = wouldAutoSaveAfter;
|
||||
} else if (knownEffectSpeed != effectSpeed) {
|
||||
knownEffectSpeed = effectSpeed;
|
||||
autoSaveAfter = wouldAutoSaveAfter;
|
||||
} else if (knownEffectIntensity != effectIntensity) {
|
||||
knownEffectIntensity = effectIntensity;
|
||||
autoSaveAfter = wouldAutoSaveAfter;
|
||||
} else if (knownMode != currentMode) {
|
||||
knownMode = currentMode;
|
||||
autoSaveAfter = wouldAutoSaveAfter;
|
||||
} else if (knownPalette != currentPalette) {
|
||||
knownPalette = currentPalette;
|
||||
autoSaveAfter = wouldAutoSaveAfter;
|
||||
}
|
||||
|
||||
if (autoSaveAfter && now > autoSaveAfter) {
|
||||
autoSaveAfter = 0;
|
||||
// Time to auto save. You may have some flickry?
|
||||
saveSettings();
|
||||
displayOverlay();
|
||||
}
|
||||
}
|
||||
|
||||
void saveSettings() {
|
||||
updateLocalTime();
|
||||
sprintf(presetNameBuffer,
|
||||
"Auto save %02d-%02d %02d:%02d:%02d",
|
||||
month(localTime), day(localTime),
|
||||
hour(localTime), minute(localTime), second(localTime));
|
||||
savePreset(AUTOSAVE_PRESET_NUM, true, presetNameBuffer);
|
||||
}
|
||||
|
||||
void displayOverlay() {
|
||||
#ifdef USERMOD_FOUR_LINE_DISLAY
|
||||
if (display != nullptr) {
|
||||
display->wakeDisplay();
|
||||
display->overlay("Settings", "Auto Saved", 1500);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
|
||||
* Values in the state object may be modified by connected clients
|
||||
*/
|
||||
void addToJsonState(JsonObject& root) {
|
||||
}
|
||||
|
||||
/*
|
||||
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
|
||||
* Values in the state object may be modified by connected clients
|
||||
*/
|
||||
void readFromJsonState(JsonObject& root) {
|
||||
}
|
||||
|
||||
/*
|
||||
* 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) {
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 :)
|
||||
*/
|
||||
void readFromConfig(JsonObject& root) {
|
||||
}
|
||||
|
||||
/*
|
||||
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
|
||||
* This could be used in the future for the system to determine whether your usermod is installed.
|
||||
*/
|
||||
uint16_t getId() {
|
||||
return USERMOD_ID_AUTO_SAVE;
|
||||
}
|
||||
|
||||
};
|
||||
39
usermods/usermod_v2_four_line_display/readme.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# Rotary Encoder UI Usermod
|
||||
|
||||
First, thanks to the authors of the ssd11306_i2c_oled_u8g2 mod.
|
||||
|
||||
This usermod provides a four line display using either
|
||||
128x32 or 128x64 OLED displays.
|
||||
It's can operate independently, but starts to provide
|
||||
a relatively complete on-device UI when paired with the
|
||||
Rotary Encoder UI usermod. I strongly encourage you to use
|
||||
them together.
|
||||
|
||||
[See the pair of usermods in action](https://www.youtube.com/watch?v=tITQY80rIOA)
|
||||
|
||||
## Installation
|
||||
|
||||
Copy and update the example `platformio_override.ini.sample`
|
||||
from the Rotary Encoder UI usermode folder to the root directory of your particular build.
|
||||
This file should be placed in the same directory as `platformio.ini`.
|
||||
|
||||
### Define Your Options
|
||||
|
||||
* `USERMOD_FOUR_LINE_DISLAY` - define this to have this the Four Line Display mod included wled00\usermods_list.cpp - also tells Rotary Encoder usermod, if installed, that the display is available
|
||||
* `FLD_PIN_SCL` - The display SCL pin, defaults to 5
|
||||
* `FLD_PIN_SDA` - The display SDA pin, defaults to 4
|
||||
* `FLIP_MODE` - Set to 0 or 1
|
||||
* `LINE_HEIGHT` - Set to 1 or 2
|
||||
|
||||
There are other `#define` values in the Usermod that might be of interest.
|
||||
|
||||
### PlatformIO requirements
|
||||
|
||||
This usermod requires the `U8g2` and `Wire` libraries. See the
|
||||
`platformio_override.ini.sample` found in the Rotary Encoder
|
||||
UI usermod folder for how to include these using `platformio_override.ini`.
|
||||
|
||||
## Change Log
|
||||
|
||||
2021-02
|
||||
* First public release
|
||||
@@ -0,0 +1,526 @@
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
#include <U8x8lib.h> // from https://github.com/olikraus/u8g2/
|
||||
|
||||
//
|
||||
// Insired by the v1 usermod: ssd1306_i2c_oled_u8g2
|
||||
//
|
||||
// v2 usermod for using 128x32 or 128x64 i2c
|
||||
// OLED displays to provide a four line display
|
||||
// for WLED.
|
||||
//
|
||||
// Dependencies
|
||||
// * This usermod REQURES the ModeSortUsermod
|
||||
// * This Usermod works best, by far, when coupled
|
||||
// with RotaryEncoderUIUsermod.
|
||||
//
|
||||
// Make sure to enable NTP and set your time zone in WLED Config | Time.
|
||||
//
|
||||
// REQUIREMENT: You must add the following requirements to
|
||||
// REQUIREMENT: "lib_deps" within platformio.ini / platformio_override.ini
|
||||
// REQUIREMENT: * U8g2 (the version already in platformio.ini is fine)
|
||||
// REQUIREMENT: * Wire
|
||||
//
|
||||
|
||||
//The SCL and SDA pins are defined here.
|
||||
#ifndef FLD_PIN_SCL
|
||||
#define FLD_PIN_SCL 5
|
||||
#endif
|
||||
|
||||
#ifndef FLD_PIN_SDA
|
||||
#define FLD_PIN_SDA 4
|
||||
#endif
|
||||
|
||||
// U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(
|
||||
// U8X8_PIN_NONE, FLD_PIN_SCL, FLD_PIN_SDA);
|
||||
U8X8_SH1106_128X64_WINSTAR_HW_I2C u8x8(
|
||||
U8X8_PIN_NONE, FLD_PIN_SCL, FLD_PIN_SDA);
|
||||
|
||||
// Screen upside down? Change to 0 or 1
|
||||
#ifndef FLIP_MODE
|
||||
#define FLIP_MODE 0
|
||||
#endif
|
||||
|
||||
// LINE_HEIGHT 1 is single height, for 128x32 displays.
|
||||
// LINE_HEIGHT 2 makes the 128x64 screen display at double height.
|
||||
#ifndef LINE_HEIGHT
|
||||
#define LINE_HEIGHT 2
|
||||
#endif
|
||||
|
||||
// If you aren't also including RotaryEncoderUIUsermod
|
||||
// you probably want to set both
|
||||
// SLEEP_MODE_ENABLED false
|
||||
// CLOCK_MODE_ENABLED false
|
||||
// as you will never be able wake the display / disable the clock.
|
||||
#ifdef USERMOD_ROTARY_ENCODER_UI
|
||||
#ifndef SLEEP_MODE_ENABLED
|
||||
#define SLEEP_MODE_ENABLED true
|
||||
#endif
|
||||
#ifndef CLOCK_MODE_ENABLED
|
||||
#define CLOCK_MODE_ENABLED true
|
||||
#endif
|
||||
#else
|
||||
#define SLEEP_MODE_ENABLED false
|
||||
#define CLOCK_MODE_ENABLED false
|
||||
#endif
|
||||
|
||||
// When to time out to the clock or blank the screen
|
||||
// if SLEEP_MODE_ENABLED.
|
||||
#define SCREEN_TIMEOUT_MS 15*1000
|
||||
|
||||
#define TIME_INDENT 0
|
||||
#define DATE_INDENT 2
|
||||
|
||||
// Minimum time between redrawing screen in ms
|
||||
#define USER_LOOP_REFRESH_RATE_MS 1000
|
||||
|
||||
#if LINE_HEIGHT == 2
|
||||
#define DRAW_STRING draw1x2String
|
||||
#define DRAW_GLYPH draw1x2Glyph
|
||||
#define DRAW_BIG_STRING draw2x2String
|
||||
#else
|
||||
#define DRAW_STRING drawString
|
||||
#define DRAW_GLYPH drawGlyph
|
||||
#define DRAW_BIG_STRING draw2x2String
|
||||
#endif
|
||||
|
||||
// Extra char (+1) for null
|
||||
#define LINE_BUFFER_SIZE 16+1
|
||||
#define FLD_LINE_3_BRIGHTNESS 0
|
||||
#define FLD_LINE_3_EFFECT_SPEED 1
|
||||
#define FLD_LINE_3_EFFECT_INTENSITY 2
|
||||
#define FLD_LINE_3_PALETTE 3
|
||||
|
||||
#if LINE_HEIGHT == 2
|
||||
#define TIME_LINE 1
|
||||
#else
|
||||
#define TIME_LINE 0
|
||||
#endif
|
||||
|
||||
class FourLineDisplayUsermod : public Usermod {
|
||||
private:
|
||||
unsigned long lastTime = 0;
|
||||
|
||||
// needRedraw marks if redraw is required to prevent often redrawing.
|
||||
bool needRedraw = true;
|
||||
|
||||
// Next variables hold the previous known values to determine if redraw is
|
||||
// required.
|
||||
String knownSsid = "";
|
||||
IPAddress knownIp;
|
||||
uint8_t knownBrightness = 0;
|
||||
uint8_t knownEffectSpeed = 0;
|
||||
uint8_t knownEffectIntensity = 0;
|
||||
uint8_t knownMode = 0;
|
||||
uint8_t knownPalette = 0;
|
||||
uint8_t knownMinute = 99;
|
||||
uint8_t knownHour = 99;
|
||||
|
||||
bool displayTurnedOff = false;
|
||||
long lastUpdate = 0;
|
||||
long lastRedraw = 0;
|
||||
long overlayUntil = 0;
|
||||
byte lineThreeType = FLD_LINE_3_BRIGHTNESS;
|
||||
// Set to 2 or 3 to mark lines 2 or 3. Other values ignored.
|
||||
byte markLineNum = 0;
|
||||
|
||||
char lineBuffer[LINE_BUFFER_SIZE];
|
||||
|
||||
char **modes_qstrings = nullptr;
|
||||
char **palettes_qstrings = nullptr;
|
||||
|
||||
// If display does not work or looks corrupted check the
|
||||
// constructor reference:
|
||||
// https://github.com/olikraus/u8g2/wiki/u8x8setupcpp
|
||||
// or check the gallery:
|
||||
// https://github.com/olikraus/u8g2/wiki/gallery
|
||||
public:
|
||||
|
||||
// gets called once at boot. Do all initialization that doesn't depend on
|
||||
// network here
|
||||
void setup() {
|
||||
u8x8.begin();
|
||||
u8x8.setFlipMode(FLIP_MODE);
|
||||
u8x8.setPowerSave(0);
|
||||
u8x8.setContrast(10); //Contrast setup will help to preserve OLED lifetime. In case OLED need to be brighter increase number up to 255
|
||||
u8x8.setFont(u8x8_font_chroma48medium8_r);
|
||||
u8x8.DRAW_STRING(0, 0*LINE_HEIGHT, "Loading...");
|
||||
|
||||
ModeSortUsermod *modeSortUsermod = (ModeSortUsermod*) usermods.lookup(USERMOD_ID_MODE_SORT);
|
||||
modes_qstrings = modeSortUsermod->getModesQStrings();
|
||||
palettes_qstrings = modeSortUsermod->getPalettesQStrings();
|
||||
}
|
||||
|
||||
// gets called every time WiFi is (re-)connected. Initialize own network
|
||||
// interfaces here
|
||||
void connected() {}
|
||||
|
||||
/**
|
||||
* Da loop.
|
||||
*/
|
||||
void loop() {
|
||||
if (millis() - lastUpdate < USER_LOOP_REFRESH_RATE_MS) {
|
||||
return;
|
||||
}
|
||||
lastUpdate = millis();
|
||||
|
||||
redraw(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Redraw the screen (but only if things have changed
|
||||
* or if forceRedraw).
|
||||
*/
|
||||
void redraw(bool forceRedraw) {
|
||||
if (overlayUntil > 0) {
|
||||
if (millis() >= overlayUntil) {
|
||||
// Time to display the overlay has elapsed.
|
||||
overlayUntil = 0;
|
||||
forceRedraw = true;
|
||||
}
|
||||
else {
|
||||
// We are still displaying the overlay
|
||||
// Don't redraw.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if values which are shown on display changed from the last time.
|
||||
if (forceRedraw) {
|
||||
needRedraw = true;
|
||||
} else if (((apActive) ? String(apSSID) : WiFi.SSID()) != knownSsid) {
|
||||
needRedraw = true;
|
||||
} else if (knownIp != (apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP())) {
|
||||
needRedraw = true;
|
||||
} else if (knownBrightness != bri) {
|
||||
needRedraw = true;
|
||||
} else if (knownEffectSpeed != effectSpeed) {
|
||||
needRedraw = true;
|
||||
} else if (knownEffectIntensity != effectIntensity) {
|
||||
needRedraw = true;
|
||||
} else if (knownMode != strip.getMode()) {
|
||||
needRedraw = true;
|
||||
} else if (knownPalette != strip.getSegment(0).palette) {
|
||||
needRedraw = true;
|
||||
}
|
||||
|
||||
if (!needRedraw) {
|
||||
// Nothing to change.
|
||||
// Turn off display after 3 minutes with no change.
|
||||
if(SLEEP_MODE_ENABLED && !displayTurnedOff &&
|
||||
(millis() - lastRedraw > SCREEN_TIMEOUT_MS)) {
|
||||
// We will still check if there is a change in redraw()
|
||||
// and turn it back on if it changed.
|
||||
sleepOrClock(true);
|
||||
}
|
||||
else if (displayTurnedOff && CLOCK_MODE_ENABLED) {
|
||||
showTime();
|
||||
}
|
||||
return;
|
||||
}
|
||||
needRedraw = false;
|
||||
lastRedraw = millis();
|
||||
|
||||
if (displayTurnedOff)
|
||||
{
|
||||
// Turn the display back on
|
||||
sleepOrClock(false);
|
||||
}
|
||||
|
||||
// Update last known values.
|
||||
#if defined(ESP8266)
|
||||
knownSsid = apActive ? WiFi.softAPSSID() : WiFi.SSID();
|
||||
#else
|
||||
knownSsid = WiFi.SSID();
|
||||
#endif
|
||||
knownIp = apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP();
|
||||
knownBrightness = bri;
|
||||
knownMode = strip.getMode();
|
||||
knownPalette = strip.getSegment(0).palette;
|
||||
knownEffectSpeed = effectSpeed;
|
||||
knownEffectIntensity = effectIntensity;
|
||||
|
||||
// Do the actual drawing
|
||||
u8x8.clear();
|
||||
u8x8.setFont(u8x8_font_chroma48medium8_r);
|
||||
|
||||
// First row with Wifi name
|
||||
String ssidString = knownSsid.substring(0, u8x8.getCols() > 1 ? u8x8.getCols() - 2 : 0);
|
||||
u8x8.DRAW_STRING(1, 0*LINE_HEIGHT, ssidString.c_str());
|
||||
// Print `~` char to indicate that SSID is longer, than owr dicplay
|
||||
if (knownSsid.length() > u8x8.getCols()) {
|
||||
u8x8.DRAW_STRING(u8x8.getCols() - 1, 0*LINE_HEIGHT, "~");
|
||||
}
|
||||
|
||||
// Second row with IP or Psssword
|
||||
// Print password in AP mode and if led is OFF.
|
||||
if (apActive && bri == 0) {
|
||||
u8x8.DRAW_STRING(1, 1*LINE_HEIGHT, apPass);
|
||||
}
|
||||
else {
|
||||
String ipString = knownIp.toString();
|
||||
u8x8.DRAW_STRING(1, 1*LINE_HEIGHT, ipString.c_str());
|
||||
}
|
||||
|
||||
// Third row with mode name
|
||||
showCurrentEffectOrPalette(modes_qstrings[knownMode], 2);
|
||||
|
||||
switch(lineThreeType) {
|
||||
case FLD_LINE_3_BRIGHTNESS:
|
||||
sprintf(lineBuffer, "Brightness %d", bri);
|
||||
u8x8.DRAW_STRING(1, 3*LINE_HEIGHT, lineBuffer);
|
||||
break;
|
||||
case FLD_LINE_3_EFFECT_SPEED:
|
||||
sprintf(lineBuffer, "FX Speed %d", effectSpeed);
|
||||
u8x8.DRAW_STRING(1, 3*LINE_HEIGHT, lineBuffer);
|
||||
break;
|
||||
case FLD_LINE_3_EFFECT_INTENSITY:
|
||||
sprintf(lineBuffer, "FX Intense %d", effectIntensity);
|
||||
u8x8.DRAW_STRING(1, 3*LINE_HEIGHT, lineBuffer);
|
||||
break;
|
||||
case FLD_LINE_3_PALETTE:
|
||||
showCurrentEffectOrPalette(palettes_qstrings[knownPalette], 3);
|
||||
break;
|
||||
}
|
||||
|
||||
u8x8.setFont(u8x8_font_open_iconic_arrow_1x1);
|
||||
u8x8.DRAW_GLYPH(0, markLineNum*LINE_HEIGHT, 66); // arrow icon
|
||||
|
||||
u8x8.setFont(u8x8_font_open_iconic_embedded_1x1);
|
||||
u8x8.DRAW_GLYPH(0, 0*LINE_HEIGHT, 80); // wifi icon
|
||||
u8x8.DRAW_GLYPH(0, 1*LINE_HEIGHT, 68); // home icon
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the current effect or palette (desiredEntry)
|
||||
* on the appropriate line (row).
|
||||
*
|
||||
* TODO: Should we cache the current effect and
|
||||
* TODO: palette name? This seems expensive.
|
||||
*/
|
||||
void showCurrentEffectOrPalette(char *qstring, uint8_t row) {
|
||||
uint8_t printedChars = 1;
|
||||
char singleJsonSymbol;
|
||||
int i = 0;
|
||||
while (true) {
|
||||
singleJsonSymbol = pgm_read_byte_near(qstring + i);
|
||||
if (singleJsonSymbol == '"' || singleJsonSymbol == '\0' ) {
|
||||
break;
|
||||
}
|
||||
u8x8.DRAW_GLYPH(printedChars, row * LINE_HEIGHT, singleJsonSymbol);
|
||||
printedChars++;
|
||||
if ( (printedChars > u8x8.getCols() - 2)) {
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If there screen is off or in clock is displayed,
|
||||
* this will return true. This allows us to throw away
|
||||
* the first input from the rotary encoder but
|
||||
* to wake up the screen.
|
||||
*/
|
||||
bool wakeDisplay() {
|
||||
if (displayTurnedOff) {
|
||||
// Turn the display back on
|
||||
sleepOrClock(false);
|
||||
redraw(true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows you to show up to two lines as overlay for a
|
||||
* period of time.
|
||||
* Clears the screen and prints on the middle two lines.
|
||||
*/
|
||||
void overlay(const char* line1, const char *line2, long showHowLong) {
|
||||
if (displayTurnedOff) {
|
||||
// Turn the display back on
|
||||
sleepOrClock(false);
|
||||
}
|
||||
|
||||
// Print the overlay
|
||||
u8x8.clear();
|
||||
u8x8.setFont(u8x8_font_chroma48medium8_r);
|
||||
if (line1) {
|
||||
u8x8.DRAW_STRING(0, 1*LINE_HEIGHT, line1);
|
||||
}
|
||||
if (line2) {
|
||||
u8x8.DRAW_STRING(0, 2*LINE_HEIGHT, line2);
|
||||
}
|
||||
overlayUntil = millis() + showHowLong;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify what data should be defined on line 3
|
||||
* (the last line).
|
||||
*/
|
||||
void setLineThreeType(byte newLineThreeType) {
|
||||
if (newLineThreeType == FLD_LINE_3_BRIGHTNESS ||
|
||||
newLineThreeType == FLD_LINE_3_EFFECT_SPEED ||
|
||||
newLineThreeType == FLD_LINE_3_EFFECT_INTENSITY ||
|
||||
newLineThreeType == FLD_LINE_3_PALETTE) {
|
||||
lineThreeType = newLineThreeType;
|
||||
}
|
||||
else {
|
||||
// Unknown value.
|
||||
lineThreeType = FLD_LINE_3_BRIGHTNESS;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Line 2 or 3 (last two lines) can be marked with an
|
||||
* arrow in the first column. Pass 2 or 3 to this to
|
||||
* specify which line to mark with an arrow.
|
||||
* Any other values are ignored.
|
||||
*/
|
||||
void setMarkLine(byte newMarkLineNum) {
|
||||
if (newMarkLineNum == 2 || newMarkLineNum == 3) {
|
||||
markLineNum = newMarkLineNum;
|
||||
}
|
||||
else {
|
||||
markLineNum = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
|
||||
* Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI.
|
||||
* Below it is shown how this could be used for e.g. a light sensor
|
||||
*/
|
||||
/*
|
||||
void addToJsonInfo(JsonObject& root)
|
||||
{
|
||||
int reading = 20;
|
||||
//this code adds "u":{"Light":[20," lux"]} to the info object
|
||||
JsonObject user = root["u"];
|
||||
if (user.isNull()) user = root.createNestedObject("u");
|
||||
|
||||
JsonArray lightArr = user.createNestedArray("Light"); //name
|
||||
lightArr.add(reading); //value
|
||||
lightArr.add(" lux"); //unit
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Enable sleep (turn the display off) or clock mode.
|
||||
*/
|
||||
void sleepOrClock(bool enabled) {
|
||||
if (enabled) {
|
||||
if (CLOCK_MODE_ENABLED) {
|
||||
showTime();
|
||||
}
|
||||
else {
|
||||
u8x8.setPowerSave(1);
|
||||
}
|
||||
displayTurnedOff = true;
|
||||
}
|
||||
else {
|
||||
if (!CLOCK_MODE_ENABLED) {
|
||||
u8x8.setPowerSave(0);
|
||||
}
|
||||
displayTurnedOff = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the current date and time in large characters
|
||||
* on the middle rows. Based 24 or 12 hour depending on
|
||||
* the useAMPM configuration.
|
||||
*/
|
||||
void showTime() {
|
||||
updateLocalTime();
|
||||
byte minuteCurrent = minute(localTime);
|
||||
byte hourCurrent = hour(localTime);
|
||||
if (knownMinute == minuteCurrent && knownHour == hourCurrent) {
|
||||
// Time hasn't changed.
|
||||
return;
|
||||
}
|
||||
knownMinute = minuteCurrent;
|
||||
knownHour = hourCurrent;
|
||||
|
||||
u8x8.clear();
|
||||
u8x8.setFont(u8x8_font_chroma48medium8_r);
|
||||
|
||||
int currentMonth = month(localTime);
|
||||
sprintf(lineBuffer, "%s %d", monthShortStr(currentMonth), day(localTime));
|
||||
u8x8.DRAW_BIG_STRING(DATE_INDENT, TIME_LINE*LINE_HEIGHT, lineBuffer);
|
||||
|
||||
byte showHour = hourCurrent;
|
||||
boolean isAM = false;
|
||||
if (useAMPM) {
|
||||
if (showHour == 0) {
|
||||
showHour = 12;
|
||||
isAM = true;
|
||||
}
|
||||
else if (showHour > 12) {
|
||||
showHour -= 12;
|
||||
isAM = false;
|
||||
}
|
||||
else {
|
||||
isAM = true;
|
||||
}
|
||||
}
|
||||
|
||||
sprintf(lineBuffer, "%02d:%02d %s", showHour, minuteCurrent, useAMPM ? (isAM ? "AM" : "PM") : "");
|
||||
// For time, we always use LINE_HEIGHT of 2 since
|
||||
// we are printing it big.
|
||||
u8x8.DRAW_BIG_STRING(TIME_INDENT + (useAMPM ? 0 : 2), (TIME_LINE + 1) * 2, lineBuffer);
|
||||
}
|
||||
|
||||
/*
|
||||
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
|
||||
* Values in the state object may be modified by connected clients
|
||||
*/
|
||||
void addToJsonState(JsonObject& root) {
|
||||
}
|
||||
|
||||
/*
|
||||
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
|
||||
* Values in the state object may be modified by connected clients
|
||||
*/
|
||||
void readFromJsonState(JsonObject& root) {
|
||||
}
|
||||
|
||||
/*
|
||||
* 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) {
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 :)
|
||||
*/
|
||||
void readFromConfig(JsonObject& root) {
|
||||
}
|
||||
|
||||
/*
|
||||
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
|
||||
* This could be used in the future for the system to determine whether your usermod is installed.
|
||||
*/
|
||||
uint16_t getId() {
|
||||
return USERMOD_ID_FOUR_LINE_DISP;
|
||||
}
|
||||
|
||||
};
|
||||
33
usermods/usermod_v2_mode_sort/readme.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# Mode Sort
|
||||
|
||||
v2 usermod that provides data about modes and
|
||||
palettes to other usermods. Notably it provides:
|
||||
* A direct method for a mode or palette name
|
||||
* Ability to retrieve mode and palette names in
|
||||
alphabetical order
|
||||
|
||||
```char **getModesQStrings()```
|
||||
|
||||
Provides an array of char* (pointers) to the names of the
|
||||
palettes within JSON_mode_names, in the same order as
|
||||
JSON_mode_names. These strings end in double quote (")
|
||||
(or \0 if there is a problem).
|
||||
|
||||
```byte *getModesAlphaIndexes()```
|
||||
|
||||
An array of byte designating the indexes of names of the
|
||||
modes in alphabetical order. "Solid" will always remain
|
||||
at the front of the list.
|
||||
|
||||
```char **getPalettesQStrings()```
|
||||
|
||||
Provides an array of char* (pointers) to the names of the
|
||||
palettes within JSON_palette_names, in the same order as
|
||||
JSON_palette_names. These strings end in double quote (")
|
||||
(or \0 if there is a problem).
|
||||
|
||||
```byte *getPalettesAlphaIndexes()```
|
||||
|
||||
An array of byte designating the indexes of names of the
|
||||
palettes in alphabetical order. "Default" and those
|
||||
starting with "(" will always remain at the front of the list.
|
||||
248
usermods/usermod_v2_mode_sort/usermod_v2_mode_sort.h
Normal file
@@ -0,0 +1,248 @@
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
|
||||
//
|
||||
// v2 usermod that provides data about modes and
|
||||
// palettes to other usermods. Notably it provides:
|
||||
// * A direct method for a mode or palette name
|
||||
// * Ability to retrieve mode and palette names in
|
||||
// alphabetical order
|
||||
//
|
||||
// char **getModesQStrings()
|
||||
// Provides an array of char* (pointers) to the names of the
|
||||
// palettes within JSON_mode_names, in the same order as
|
||||
// JSON_mode_names. These strings end in double quote (")
|
||||
// (or \0 if there is a problem).
|
||||
//
|
||||
// byte *getModesAlphaIndexes()
|
||||
// An array of byte designating the indexes of names of the
|
||||
// modes in alphabetical order. "Solid" will always remain
|
||||
// at the front of the list.
|
||||
//
|
||||
// char **getPalettesQStrings()
|
||||
// Provides an array of char* (pointers) to the names of the
|
||||
// palettes within JSON_palette_names, in the same order as
|
||||
// JSON_palette_names. These strings end in double quote (")
|
||||
// (or \0 if there is a problem).
|
||||
//
|
||||
// byte *getPalettesAlphaIndexes()
|
||||
// An array of byte designating the indexes of names of the
|
||||
// palettes in alphabetical order. "Default" and those
|
||||
// starting with "(" will always remain at the front of the list.
|
||||
//
|
||||
|
||||
// Number of modes at the start of the list to not sort
|
||||
#define MODE_SORT_SKIP_COUNT 1
|
||||
|
||||
// Which list is being sorted
|
||||
char **listBeingSorted = nullptr;
|
||||
|
||||
/**
|
||||
* Modes and palettes are stored as strings that
|
||||
* end in a quote character. Compare two of them.
|
||||
* We are comparing directly within either
|
||||
* JSON_mode_names or JSON_palette_names.
|
||||
*/
|
||||
int re_qstringCmp(const void *ap, const void *bp) {
|
||||
char *a = listBeingSorted[*((byte *)ap)];
|
||||
char *b = listBeingSorted[*((byte *)bp)];
|
||||
int i = 0;
|
||||
do {
|
||||
char aVal = pgm_read_byte_near(a + i);
|
||||
if (aVal >= 97 && aVal <= 122) {
|
||||
// Lowercase
|
||||
aVal -= 32;
|
||||
}
|
||||
char bVal = pgm_read_byte_near(b + i);
|
||||
if (bVal >= 97 && bVal <= 122) {
|
||||
// Lowercase
|
||||
bVal -= 32;
|
||||
}
|
||||
// Relly we shouldn't ever get to '\0'
|
||||
if (aVal == '"' || bVal == '"' || aVal == '\0' || bVal == '\0') {
|
||||
// We're done. one is a substring of the other
|
||||
// or something happenend and the quote didn't stop us.
|
||||
if (aVal == bVal) {
|
||||
// Same value, probably shouldn't happen
|
||||
// with this dataset
|
||||
return 0;
|
||||
}
|
||||
else if (aVal == '"' || aVal == '\0') {
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (aVal == bVal) {
|
||||
// Same characters. Move to the next.
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
// We're done
|
||||
if (aVal < bVal) {
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
return 1;
|
||||
}
|
||||
} while (true);
|
||||
// We shouldn't get here.
|
||||
return 0;
|
||||
}
|
||||
|
||||
class ModeSortUsermod : public Usermod {
|
||||
private:
|
||||
|
||||
// Pointers the start of the mode names within JSON_mode_names
|
||||
char **modes_qstrings = nullptr;
|
||||
|
||||
// Array of mode indexes in alphabetical order.
|
||||
byte *modes_alpha_indexes = nullptr;
|
||||
|
||||
// Pointers the start of the palette names within JSON_palette_names
|
||||
char **palettes_qstrings = nullptr;
|
||||
|
||||
// Array of palette indexes in alphabetical order.
|
||||
byte *palettes_alpha_indexes = nullptr;
|
||||
|
||||
public:
|
||||
/**
|
||||
* setup() is called once at boot. WiFi is not yet connected at this point.
|
||||
* You can use it to initialize variables, sensors or similar.
|
||||
*/
|
||||
void setup() {
|
||||
// Sort the modes and palettes on startup
|
||||
// as they are guarantted to change.
|
||||
sortModesAndPalettes();
|
||||
}
|
||||
|
||||
char **getModesQStrings() {
|
||||
return modes_qstrings;
|
||||
}
|
||||
|
||||
byte *getModesAlphaIndexes() {
|
||||
return modes_alpha_indexes;
|
||||
}
|
||||
|
||||
char **getPalettesQStrings() {
|
||||
return palettes_qstrings;
|
||||
}
|
||||
|
||||
byte *getPalettesAlphaIndexes() {
|
||||
return palettes_alpha_indexes;
|
||||
}
|
||||
|
||||
/**
|
||||
* This Usermod doesn't have anything for loop.
|
||||
*/
|
||||
void loop() {}
|
||||
|
||||
/**
|
||||
* Sort the modes and palettes to the index arrays
|
||||
* modes_alpha_indexes and palettes_alpha_indexes.
|
||||
*/
|
||||
void sortModesAndPalettes() {
|
||||
modes_qstrings = re_findModeStrings(JSON_mode_names, strip.getModeCount());
|
||||
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());
|
||||
palettes_alpha_indexes = re_initIndexArray(strip.getPaletteCount());
|
||||
|
||||
int skipPaletteCount = 1;
|
||||
while (true) {
|
||||
// How many palette names start with '*' and should not be sorted?
|
||||
// (Also skipping the first one, 'Default').
|
||||
if (pgm_read_byte_near(palettes_qstrings[skipPaletteCount]) == '*') {
|
||||
skipPaletteCount++;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
re_sortModes(palettes_qstrings, palettes_alpha_indexes, strip.getPaletteCount(), skipPaletteCount);
|
||||
}
|
||||
|
||||
byte *re_initIndexArray(int numModes) {
|
||||
byte *indexes = (byte *)malloc(sizeof(byte) * numModes);
|
||||
for (byte i = 0; i < numModes; i++) {
|
||||
indexes[i] = i;
|
||||
}
|
||||
return indexes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of mode or palette names from the JSON string.
|
||||
* They don't end in '\0', they end in '"'.
|
||||
*/
|
||||
char **re_findModeStrings(const char json[], int numModes) {
|
||||
char **modeStrings = (char **)malloc(sizeof(char *) * numModes);
|
||||
uint8_t modeIndex = 0;
|
||||
bool insideQuotes = false;
|
||||
// advance past the mark for markLineNum that may exist.
|
||||
char singleJsonSymbol;
|
||||
|
||||
// Find the mode name in JSON
|
||||
bool complete = false;
|
||||
for (size_t i = 0; i < strlen_P(json); i++) {
|
||||
singleJsonSymbol = pgm_read_byte_near(json + i);
|
||||
switch (singleJsonSymbol) {
|
||||
case '"':
|
||||
insideQuotes = !insideQuotes;
|
||||
if (insideQuotes) {
|
||||
// We have a new mode or palette
|
||||
modeStrings[modeIndex] = (char *)(json + i + 1);
|
||||
}
|
||||
break;
|
||||
case '[':
|
||||
break;
|
||||
case ']':
|
||||
complete = true;
|
||||
break;
|
||||
case ',':
|
||||
modeIndex++;
|
||||
default:
|
||||
if (!insideQuotes) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (complete) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return modeStrings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort either the modes or the palettes using quicksort.
|
||||
*/
|
||||
void re_sortModes(char **modeNames, byte *indexes, int count, int numSkip) {
|
||||
listBeingSorted = modeNames;
|
||||
qsort(indexes + numSkip, count - numSkip, sizeof(byte), re_qstringCmp);
|
||||
listBeingSorted = nullptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
|
||||
* Values in the state object may be modified by connected clients
|
||||
*/
|
||||
void addToJsonState(JsonObject &root) {}
|
||||
|
||||
/*
|
||||
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
|
||||
* Values in the state object may be modified by connected clients
|
||||
*/
|
||||
void readFromJsonState(JsonObject &root) {}
|
||||
|
||||
/*
|
||||
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
|
||||
* This could be used in the future for the system to determine whether your usermod is installed.
|
||||
*/
|
||||
uint16_t getId()
|
||||
{
|
||||
return USERMOD_ID_MODE_SORT;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,48 @@
|
||||
[platformio]
|
||||
default_envs = d1_mini
|
||||
; default_envs = esp32dev
|
||||
|
||||
[env:esp32dev]
|
||||
board = esp32dev
|
||||
platform = espressif32@3.2
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags =
|
||||
${common.build_flags_esp32}
|
||||
-D USERMOD_MODE_SORT
|
||||
-D USERMOD_FOUR_LINE_DISLAY -D FLD_PIN_SCL=22 -D FLD_PIN_SDA=21
|
||||
-D USERMOD_ROTARY_ENCODER_UI -D ENCODER_DT_PIN=18 -D ENCODER_CLK_PIN=5 -D ENCODER_SW_PIN=19
|
||||
-D USERMOD_AUTO_SAVE -D AUTOSAVE_PRESET_NUM=1
|
||||
-D LEDPIN=16 -D BTNPIN=13
|
||||
upload_speed = 460800
|
||||
lib_ignore =
|
||||
ESPAsyncTCP
|
||||
ESPAsyncUDP
|
||||
|
||||
[env:d1_mini]
|
||||
board = d1_mini
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
upload_speed = 460800
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags =
|
||||
${common.build_flags_esp8266}
|
||||
-D USERMOD_MODE_SORT
|
||||
-D USERMOD_FOUR_LINE_DISLAY -D FLD_PIN_SCL=5 -D FLD_PIN_SDA=4
|
||||
-D USERMOD_ROTARY_ENCODER_UI -D ENCODER_DT_PIN=12 -D ENCODER_CLK_PIN=14 -D ENCODER_SW_PIN=13
|
||||
-D USERMOD_AUTO_SAVE -D AUTOSAVE_PRESET_NUM=1
|
||||
-D LEDPIN=3 -D BTNPIN=0
|
||||
monitor_filters = esp8266_exception_decoder
|
||||
|
||||
[env]
|
||||
lib_deps =
|
||||
fastled/FastLED @ 3.3.2
|
||||
NeoPixelBus @ 2.6.0
|
||||
ESPAsyncTCP @ 1.2.0
|
||||
ESPAsyncUDP
|
||||
AsyncTCP @ 1.0.3
|
||||
IRremoteESP8266 @ 2.7.3
|
||||
https://github.com/lorol/LITTLEFS.git
|
||||
https://github.com/Aircoookie/ESPAsyncWebServer.git @ ~2.0.0
|
||||
U8g2@~2.27.2
|
||||
Wire
|
||||
33
usermods/usermod_v2_rotary_encoder_ui/readme.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# Rotary Encoder UI Usermod
|
||||
|
||||
First, thanks to the authors of other Rotary Encoder usermods.
|
||||
|
||||
This usermod starts to provide a relatively complete on-device
|
||||
UI when paired with the Four Line Display usermod. I strongly
|
||||
encourage you to try them together.
|
||||
|
||||
[See the pair of usermods in action](https://www.youtube.com/watch?v=tITQY80rIOA)
|
||||
|
||||
## Installation
|
||||
|
||||
Copy and update the example `platformio_override.ini.sample` to the root directory of your particular build.
|
||||
This file should be placed in the same directory as `platformio.ini`.
|
||||
|
||||
### Define Your Options
|
||||
|
||||
* `USERMOD_ROTARY_ENCODER_UI` - define this to have this user mod included wled00\usermods_list.cpp
|
||||
* `USERMOD_FOUR_LINE_DISLAY` - 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)
|
||||
* `ENCODER_DT_PIN` - The encoders DT pin, defaults to 12
|
||||
* `ENCODER_CLK_PIN` - The encoders CLK pin, defaults to 14
|
||||
* `ENCODER_SW_PIN` - The encoders SW pin, defaults to 13
|
||||
|
||||
### PlatformIO requirements
|
||||
|
||||
No special requirements.
|
||||
|
||||
Note: the Four Line Display usermod requires the libraries `U8g2` and `Wire`.
|
||||
|
||||
## Change Log
|
||||
|
||||
2021-02
|
||||
* First public release
|
||||
@@ -0,0 +1,401 @@
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
|
||||
//
|
||||
// Inspired by the v1 usermods
|
||||
// * rotary_encoder_change_brightness
|
||||
// * rotary_encoder_change_effect
|
||||
//
|
||||
// v2 usermod that provides a rotary encoder-based UI.
|
||||
//
|
||||
// This usermod allows you to control:
|
||||
//
|
||||
// * Brightness
|
||||
// * Selected Effect
|
||||
// * Effect Speed
|
||||
// * Effect Intensity
|
||||
// * Palette
|
||||
//
|
||||
// Change between modes by pressing a button.
|
||||
//
|
||||
// Dependencies
|
||||
// * This usermod REQURES the ModeSortUsermod
|
||||
// * This Usermod works best coupled with
|
||||
// FourLineDisplayUsermod.
|
||||
//
|
||||
|
||||
#ifndef ENCODER_DT_PIN
|
||||
#define ENCODER_DT_PIN 12
|
||||
#endif
|
||||
|
||||
#ifndef ENCODER_CLK_PIN
|
||||
#define ENCODER_CLK_PIN 14
|
||||
#endif
|
||||
|
||||
#ifndef ENCODER_SW_PIN
|
||||
#define ENCODER_SW_PIN 13
|
||||
#endif
|
||||
|
||||
#ifndef USERMOD_FOUR_LINE_DISLAY
|
||||
// These constants won't be defined if we aren't using FourLineDisplay.
|
||||
#define FLD_LINE_3_BRIGHTNESS 0
|
||||
#define FLD_LINE_3_EFFECT_SPEED 0
|
||||
#define FLD_LINE_3_EFFECT_INTENSITY 0
|
||||
#define FLD_LINE_3_PALETTE 0
|
||||
#endif
|
||||
|
||||
|
||||
// The last UI state
|
||||
#define LAST_UI_STATE 4
|
||||
|
||||
|
||||
class RotaryEncoderUIUsermod : public Usermod {
|
||||
private:
|
||||
int fadeAmount = 10; // Amount to change every step (brightness)
|
||||
unsigned long currentTime;
|
||||
unsigned long loopTime;
|
||||
const int pinA = ENCODER_DT_PIN; // DT from encoder
|
||||
const int pinB = ENCODER_CLK_PIN; // CLK from encoder
|
||||
const int pinC = ENCODER_SW_PIN; // SW from encoder
|
||||
unsigned char select_state = 0; // 0: brightness, 1: effect, 2: effect speed
|
||||
unsigned char button_state = HIGH;
|
||||
unsigned char prev_button_state = HIGH;
|
||||
|
||||
#ifdef USERMOD_FOUR_LINE_DISLAY
|
||||
FourLineDisplayUsermod *display;
|
||||
#else
|
||||
void* display = nullptr;
|
||||
#endif
|
||||
|
||||
byte *modes_alpha_indexes = nullptr;
|
||||
byte *palettes_alpha_indexes = nullptr;
|
||||
|
||||
unsigned char Enc_A;
|
||||
unsigned char Enc_B;
|
||||
unsigned char Enc_A_prev = 0;
|
||||
|
||||
bool currentEffectAndPaleeteInitialized = false;
|
||||
uint8_t effectCurrentIndex = 0;
|
||||
uint8_t effectPaletteIndex = 0;
|
||||
|
||||
public:
|
||||
/*
|
||||
* setup() is called once at boot. WiFi is not yet connected at this point.
|
||||
* You can use it to initialize variables, sensors or similar.
|
||||
*/
|
||||
void setup()
|
||||
{
|
||||
pinMode(pinA, INPUT_PULLUP);
|
||||
pinMode(pinB, INPUT_PULLUP);
|
||||
pinMode(pinC, INPUT_PULLUP);
|
||||
currentTime = millis();
|
||||
loopTime = currentTime;
|
||||
|
||||
ModeSortUsermod *modeSortUsermod = (ModeSortUsermod*) usermods.lookup(USERMOD_ID_MODE_SORT);
|
||||
modes_alpha_indexes = modeSortUsermod->getModesAlphaIndexes();
|
||||
palettes_alpha_indexes = modeSortUsermod->getPalettesAlphaIndexes();
|
||||
|
||||
#ifdef USERMOD_FOUR_LINE_DISLAY
|
||||
// This Usermod uses FourLineDisplayUsermod for the best experience.
|
||||
// But it's optional. But you want it.
|
||||
display = (FourLineDisplayUsermod*) usermods.lookup(USERMOD_ID_FOUR_LINE_DISP);
|
||||
if (display != nullptr) {
|
||||
display->setLineThreeType(FLD_LINE_3_BRIGHTNESS);
|
||||
display->setMarkLine(3);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* connected() is called every time the WiFi is (re)connected
|
||||
* Use it to initialize network interfaces
|
||||
*/
|
||||
void connected()
|
||||
{
|
||||
//Serial.println("Connected to WiFi!");
|
||||
}
|
||||
|
||||
/*
|
||||
* loop() is called continuously. Here you can check for events, read sensors, etc.
|
||||
*
|
||||
* Tips:
|
||||
* 1. You can use "if (WLED_CONNECTED)" to check for a successful network connection.
|
||||
* Additionally, "if (WLED_MQTT_CONNECTED)" is available to check for a connection to an MQTT broker.
|
||||
*
|
||||
* 2. Try to avoid using the delay() function. NEVER use delays longer than 10 milliseconds.
|
||||
* Instead, use a timer check as shown here.
|
||||
*/
|
||||
void loop()
|
||||
{
|
||||
currentTime = millis(); // get the current elapsed time
|
||||
|
||||
// Initialize effectCurrentIndex and effectPaletteIndex to
|
||||
// current state. We do it here as (at least) effectCurrent
|
||||
// is not yet initialized when setup is called.
|
||||
if (!currentEffectAndPaleeteInitialized) {
|
||||
findCurrentEffectAndPalette();
|
||||
}
|
||||
|
||||
if (currentTime >= (loopTime + 2)) // 2ms since last check of encoder = 500Hz
|
||||
{
|
||||
button_state = digitalRead(pinC);
|
||||
if (prev_button_state != button_state)
|
||||
{
|
||||
if (button_state == LOW)
|
||||
{
|
||||
prev_button_state = button_state;
|
||||
|
||||
char newState = select_state + 1;
|
||||
if (newState > LAST_UI_STATE) newState = 0;
|
||||
|
||||
bool changedState = true;
|
||||
if (display != nullptr) {
|
||||
switch(newState) {
|
||||
case 0:
|
||||
changedState = changeState("Brightness", FLD_LINE_3_BRIGHTNESS, 3);
|
||||
break;
|
||||
case 1:
|
||||
changedState = changeState("Select FX", FLD_LINE_3_EFFECT_SPEED, 2);
|
||||
break;
|
||||
case 2:
|
||||
changedState = changeState("FX Speed", FLD_LINE_3_EFFECT_SPEED, 3);
|
||||
break;
|
||||
case 3:
|
||||
changedState = changeState("FX Intensity", FLD_LINE_3_EFFECT_INTENSITY, 3);
|
||||
break;
|
||||
case 4:
|
||||
changedState = changeState("Palette", FLD_LINE_3_PALETTE, 3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (changedState) {
|
||||
select_state = newState;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
prev_button_state = button_state;
|
||||
}
|
||||
}
|
||||
int Enc_A = digitalRead(pinA); // Read encoder pins
|
||||
int Enc_B = digitalRead(pinB);
|
||||
if ((!Enc_A) && (Enc_A_prev))
|
||||
{ // A has gone from high to low
|
||||
if (Enc_B == HIGH)
|
||||
{ // B is high so clockwise
|
||||
switch(select_state) {
|
||||
case 0:
|
||||
changeBrightness(true);
|
||||
break;
|
||||
case 1:
|
||||
changeEffect(true);
|
||||
break;
|
||||
case 2:
|
||||
changeEffectSpeed(true);
|
||||
break;
|
||||
case 3:
|
||||
changeEffectIntensity(true);
|
||||
break;
|
||||
case 4:
|
||||
changePalette(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (Enc_B == LOW)
|
||||
{ // B is low so counter-clockwise
|
||||
switch(select_state) {
|
||||
case 0:
|
||||
changeBrightness(false);
|
||||
break;
|
||||
case 1:
|
||||
changeEffect(false);
|
||||
break;
|
||||
case 2:
|
||||
changeEffectSpeed(false);
|
||||
break;
|
||||
case 3:
|
||||
changeEffectIntensity(false);
|
||||
break;
|
||||
case 4:
|
||||
changePalette(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Enc_A_prev = Enc_A; // Store value of A for next time
|
||||
loopTime = currentTime; // Updates loopTime
|
||||
}
|
||||
}
|
||||
|
||||
void findCurrentEffectAndPalette() {
|
||||
currentEffectAndPaleeteInitialized = true;
|
||||
for (uint8_t i = 0; i < strip.getModeCount(); i++) {
|
||||
byte value = modes_alpha_indexes[i];
|
||||
if (modes_alpha_indexes[i] == effectCurrent) {
|
||||
effectCurrentIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < strip.getPaletteCount(); i++) {
|
||||
byte value = palettes_alpha_indexes[i];
|
||||
if (palettes_alpha_indexes[i] == strip.getSegment(0).palette) {
|
||||
effectPaletteIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean changeState(const char *stateName, byte lineThreeMode, byte markedLine) {
|
||||
#ifdef USERMOD_FOUR_LINE_DISLAY
|
||||
if (display != nullptr) {
|
||||
if (display->wakeDisplay()) {
|
||||
// Throw away wake up input
|
||||
return false;
|
||||
}
|
||||
display->overlay("Mode change", stateName, 1500);
|
||||
display->setLineThreeType(lineThreeMode);
|
||||
display->setMarkLine(markedLine);
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
void lampUdated() {
|
||||
bool fxChanged = strip.setEffectConfig(effectCurrent, effectSpeed, effectIntensity, effectPalette);
|
||||
|
||||
//call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification)
|
||||
// 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa
|
||||
colorUpdated(NOTIFIER_CALL_MODE_DIRECT_CHANGE);
|
||||
updateInterfaces(NOTIFIER_CALL_MODE_DIRECT_CHANGE);
|
||||
}
|
||||
|
||||
void changeBrightness(bool increase) {
|
||||
#ifdef USERMOD_FOUR_LINE_DISLAY
|
||||
if (display && display->wakeDisplay()) {
|
||||
// Throw away wake up input
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (increase) {
|
||||
bri = (bri + fadeAmount <= 255) ? (bri + fadeAmount) : 255;
|
||||
}
|
||||
else {
|
||||
bri = (bri - fadeAmount >= 0) ? (bri - fadeAmount) : 0;
|
||||
}
|
||||
lampUdated();
|
||||
}
|
||||
|
||||
void changeEffect(bool increase) {
|
||||
#ifdef USERMOD_FOUR_LINE_DISLAY
|
||||
if (display && display->wakeDisplay()) {
|
||||
// Throw away wake up input
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (increase) {
|
||||
effectCurrentIndex = (effectCurrentIndex + 1 >= strip.getModeCount()) ? 0 : (effectCurrentIndex + 1);
|
||||
}
|
||||
else {
|
||||
effectCurrentIndex = (effectCurrentIndex - 1 < 0) ? (strip.getModeCount() - 1) : (effectCurrentIndex - 1);
|
||||
}
|
||||
effectCurrent = modes_alpha_indexes[effectCurrentIndex];
|
||||
lampUdated();
|
||||
}
|
||||
|
||||
void changeEffectSpeed(bool increase) {
|
||||
#ifdef USERMOD_FOUR_LINE_DISLAY
|
||||
if (display && display->wakeDisplay()) {
|
||||
// Throw away wake up input
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (increase) {
|
||||
effectSpeed = (effectSpeed + fadeAmount <= 255) ? (effectSpeed + fadeAmount) : 255;
|
||||
}
|
||||
else {
|
||||
effectSpeed = (effectSpeed - fadeAmount >= 0) ? (effectSpeed - fadeAmount) : 0;
|
||||
}
|
||||
lampUdated();
|
||||
}
|
||||
|
||||
void changeEffectIntensity(bool increase) {
|
||||
#ifdef USERMOD_FOUR_LINE_DISLAY
|
||||
if (display && display->wakeDisplay()) {
|
||||
// Throw away wake up input
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (increase) {
|
||||
effectIntensity = (effectIntensity + fadeAmount <= 255) ? (effectIntensity + fadeAmount) : 255;
|
||||
}
|
||||
else {
|
||||
effectIntensity = (effectIntensity - fadeAmount >= 0) ? (effectIntensity - fadeAmount) : 0;
|
||||
}
|
||||
lampUdated();
|
||||
}
|
||||
|
||||
void changePalette(bool increase) {
|
||||
#ifdef USERMOD_FOUR_LINE_DISLAY
|
||||
if (display && display->wakeDisplay()) {
|
||||
// Throw away wake up input
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (increase) {
|
||||
effectPaletteIndex = (effectPaletteIndex + 1 >= strip.getPaletteCount()) ? 0 : (effectPaletteIndex + 1);
|
||||
}
|
||||
else {
|
||||
effectPaletteIndex = (effectPaletteIndex - 1 < 0) ? (strip.getPaletteCount() - 1) : (effectPaletteIndex - 1);
|
||||
}
|
||||
effectPalette = palettes_alpha_indexes[effectPaletteIndex];
|
||||
lampUdated();
|
||||
}
|
||||
|
||||
/*
|
||||
* addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
|
||||
* Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI.
|
||||
* Below it is shown how this could be used for e.g. a light sensor
|
||||
*/
|
||||
/*
|
||||
void addToJsonInfo(JsonObject& root)
|
||||
{
|
||||
int reading = 20;
|
||||
//this code adds "u":{"Light":[20," lux"]} to the info object
|
||||
JsonObject user = root["u"];
|
||||
if (user.isNull()) user = root.createNestedObject("u");
|
||||
JsonArray lightArr = user.createNestedArray("Light"); //name
|
||||
lightArr.add(reading); //value
|
||||
lightArr.add(" lux"); //unit
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
|
||||
* Values in the state object may be modified by connected clients
|
||||
*/
|
||||
void addToJsonState(JsonObject &root)
|
||||
{
|
||||
//root["user0"] = userVar0;
|
||||
}
|
||||
|
||||
/*
|
||||
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
|
||||
* Values in the state object may be modified by connected clients
|
||||
*/
|
||||
void readFromJsonState(JsonObject &root)
|
||||
{
|
||||
userVar0 = root["user0"] | userVar0; //if "user0" key exists in JSON, update, else keep old value
|
||||
//if (root["bri"] == 255) Serial.println(F("Don't burn down your garage!"));
|
||||
}
|
||||
|
||||
/*
|
||||
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
|
||||
* This could be used in the future for the system to determine whether your usermod is installed.
|
||||
*/
|
||||
uint16_t getId()
|
||||
{
|
||||
return USERMOD_ID_ROTARY_ENC_UI;
|
||||
}
|
||||
};
|
||||
587
wled00/FX.cpp
@@ -25,11 +25,11 @@
|
||||
*/
|
||||
|
||||
#include "FX.h"
|
||||
#include "tv_colors.h"
|
||||
|
||||
#define IBN 5100
|
||||
#define PALETTE_SOLID_WRAP (paletteBlend == 1 || paletteBlend == 3)
|
||||
|
||||
|
||||
/*
|
||||
* No blinking. Just plain old static light.
|
||||
*/
|
||||
@@ -233,9 +233,9 @@ uint16_t WS2812FX::mode_random_color(void) {
|
||||
|
||||
/*
|
||||
* Lights every LED in a random color. Changes all LED at the same time
|
||||
// * to new random colors.
|
||||
* to new random colors.
|
||||
*/
|
||||
uint16_t WS2812FX::mode_dynamic(void) {
|
||||
uint16_t WS2812FX::dynamic(boolean smooth=false) {
|
||||
if (!SEGENV.allocateData(SEGLEN)) return mode_static(); //allocation failed
|
||||
|
||||
if(SEGENV.call == 0) {
|
||||
@@ -252,12 +252,31 @@ uint16_t WS2812FX::mode_dynamic(void) {
|
||||
SEGENV.step = it;
|
||||
}
|
||||
|
||||
for (uint16_t i = 0; i < SEGLEN; i++) {
|
||||
setPixelColor(i, color_wheel(SEGENV.data[i]));
|
||||
}
|
||||
if (smooth) {
|
||||
for (uint16_t i = 0; i < SEGLEN; i++) {
|
||||
blendPixelColor(i, color_wheel(SEGENV.data[i]),16);
|
||||
}
|
||||
} else {
|
||||
for (uint16_t i = 0; i < SEGLEN; i++) {
|
||||
setPixelColor(i, color_wheel(SEGENV.data[i]));
|
||||
}
|
||||
}
|
||||
return FRAMETIME;
|
||||
}
|
||||
|
||||
/*
|
||||
* Original effect "Dynamic"
|
||||
*/
|
||||
uint16_t WS2812FX::mode_dynamic(void) {
|
||||
return dynamic(false);
|
||||
}
|
||||
|
||||
/*
|
||||
* effect "Dynamic" with smoth color-fading
|
||||
*/
|
||||
uint16_t WS2812FX::mode_dynamic_smooth(void) {
|
||||
return dynamic(true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Does the "standby-breathing" of well known i-Devices.
|
||||
@@ -526,7 +545,7 @@ uint16_t WS2812FX::dissolve(uint32_t color) {
|
||||
}
|
||||
}
|
||||
|
||||
if (SEGENV.call > (255 - SEGMENT.speed) + 15)
|
||||
if (SEGENV.call > (255 - SEGMENT.speed) + 15U)
|
||||
{
|
||||
SEGENV.aux0 = !SEGENV.aux0;
|
||||
SEGENV.call = 0;
|
||||
@@ -574,7 +593,7 @@ uint16_t WS2812FX::mode_sparkle(void) {
|
||||
|
||||
|
||||
/*
|
||||
* Lights all LEDs in the color. Flashes single white pixels randomly.
|
||||
* Lights all LEDs in the color. Flashes single col 1 pixels randomly. (List name: Sparkle Dark)
|
||||
* Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
|
||||
*/
|
||||
uint16_t WS2812FX::mode_flash_sparkle(void) {
|
||||
@@ -582,12 +601,14 @@ uint16_t WS2812FX::mode_flash_sparkle(void) {
|
||||
setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
|
||||
}
|
||||
|
||||
if(random8(5) == 0) {
|
||||
SEGENV.aux0 = random16(SEGLEN); // aux0 stores the random led index
|
||||
setPixelColor(SEGENV.aux0, SEGCOLOR(1));
|
||||
return 20;
|
||||
}
|
||||
return 20 + (uint16_t)(255-SEGMENT.speed);
|
||||
if (now - SEGENV.aux0 > SEGENV.step) {
|
||||
if(random8((255-SEGMENT.intensity) >> 4) == 0) {
|
||||
setPixelColor(random16(SEGLEN), SEGCOLOR(1)); //flash
|
||||
}
|
||||
SEGENV.step = now;
|
||||
SEGENV.aux0 = 255-SEGMENT.speed;
|
||||
}
|
||||
return FRAMETIME;
|
||||
}
|
||||
|
||||
|
||||
@@ -600,13 +621,16 @@ uint16_t WS2812FX::mode_hyper_sparkle(void) {
|
||||
setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
|
||||
}
|
||||
|
||||
if(random8(5) < 2) {
|
||||
for(uint16_t i = 0; i < MAX(1, SEGLEN/3); i++) {
|
||||
setPixelColor(random16(SEGLEN), SEGCOLOR(1));
|
||||
if (now - SEGENV.aux0 > SEGENV.step) {
|
||||
if(random8((255-SEGMENT.intensity) >> 4) == 0) {
|
||||
for(uint16_t i = 0; i < MAX(1, SEGLEN/3); i++) {
|
||||
setPixelColor(random16(SEGLEN), SEGCOLOR(1));
|
||||
}
|
||||
}
|
||||
return 20;
|
||||
SEGENV.step = now;
|
||||
SEGENV.aux0 = 255-SEGMENT.speed;
|
||||
}
|
||||
return 20 + (uint16_t)(255-SEGMENT.speed);
|
||||
return FRAMETIME;
|
||||
}
|
||||
|
||||
|
||||
@@ -617,22 +641,25 @@ uint16_t WS2812FX::mode_multi_strobe(void) {
|
||||
for(uint16_t i = 0; i < SEGLEN; i++) {
|
||||
setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 1));
|
||||
}
|
||||
//blink(SEGCOLOR(0), SEGCOLOR(1), true, true);
|
||||
|
||||
uint16_t delay = 50 + 20*(uint16_t)(255-SEGMENT.speed);
|
||||
uint16_t count = 2 * ((SEGMENT.speed / 10) + 1);
|
||||
if(SEGENV.step < count) {
|
||||
if((SEGENV.step & 1) == 0) {
|
||||
for(uint16_t i = 0; i < SEGLEN; i++) {
|
||||
setPixelColor(i, SEGCOLOR(0));
|
||||
}
|
||||
delay = 20;
|
||||
SEGENV.aux0 = 50 + 20*(uint16_t)(255-SEGMENT.speed);
|
||||
uint16_t count = 2 * ((SEGMENT.intensity / 10) + 1);
|
||||
if(SEGENV.aux1 < count) {
|
||||
if((SEGENV.aux1 & 1) == 0) {
|
||||
fill(SEGCOLOR(0));
|
||||
SEGENV.aux0 = 15;
|
||||
} else {
|
||||
delay = 50;
|
||||
SEGENV.aux0 = 50;
|
||||
}
|
||||
}
|
||||
SEGENV.step = (SEGENV.step + 1) % (count + 1);
|
||||
return delay;
|
||||
|
||||
if (now - SEGENV.aux0 > SEGENV.step) {
|
||||
SEGENV.aux1++;
|
||||
if (SEGENV.aux1 > count) SEGENV.aux1 = 0;
|
||||
SEGENV.step = now;
|
||||
}
|
||||
|
||||
return FRAMETIME;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -778,6 +805,7 @@ uint16_t WS2812FX::mode_chase_random(void) {
|
||||
*/
|
||||
uint16_t WS2812FX::mode_chase_rainbow(void) {
|
||||
uint8_t color_sep = 256 / SEGLEN;
|
||||
if (color_sep == 0) color_sep = 1; // correction for segments longer than 256 LEDs
|
||||
uint8_t color_index = SEGENV.call & 0xFF;
|
||||
uint32_t color = color_wheel(((SEGENV.step * color_sep) + color_index) & 0xFF);
|
||||
|
||||
@@ -802,46 +830,40 @@ uint16_t WS2812FX::mode_chase_rainbow_white(void) {
|
||||
* Red - Amber - Green - Blue lights running
|
||||
*/
|
||||
uint16_t WS2812FX::mode_colorful(void) {
|
||||
uint32_t cols[]{0x00FF0000,0x00EEBB00,0x0000EE00,0x000077CC,0x00FF0000,0x00EEBB00,0x0000EE00};
|
||||
if (SEGMENT.intensity < 127) //pastel (easter) colors
|
||||
uint8_t numColors = 4; //3, 4, or 5
|
||||
uint32_t cols[9]{0x00FF0000,0x00EEBB00,0x0000EE00,0x000077CC};
|
||||
if (SEGMENT.intensity > 160 || SEGMENT.palette) { //palette or color
|
||||
if (!SEGMENT.palette) {
|
||||
numColors = 3;
|
||||
for (uint8_t i = 0; i < 3; i++) cols[i] = SEGCOLOR(i);
|
||||
} else {
|
||||
uint16_t fac = 80;
|
||||
if (SEGMENT.palette == 52) {numColors = 5; fac = 61;} //C9 2 has 5 colors
|
||||
for (uint8_t i = 0; i < numColors; i++) {
|
||||
cols[i] = color_from_palette(i*fac, false, true, 255);
|
||||
}
|
||||
}
|
||||
} else if (SEGMENT.intensity < 80) //pastel (easter) colors
|
||||
{
|
||||
cols[0] = 0x00FF8040;
|
||||
cols[1] = 0x00E5D241;
|
||||
cols[2] = 0x0077FF77;
|
||||
cols[3] = 0x0077F0F0;
|
||||
for (uint8_t i = 4; i < 7; i++) cols[i] = cols[i-4];
|
||||
}
|
||||
for (uint8_t i = numColors; i < numColors*2 -1; i++) cols[i] = cols[i-numColors];
|
||||
|
||||
uint32_t cycleTime = 50 + (15 * (uint32_t)(255 - SEGMENT.speed));
|
||||
uint32_t cycleTime = 50 + (8 * (uint32_t)(255 - SEGMENT.speed));
|
||||
uint32_t it = now / cycleTime;
|
||||
if (it != SEGENV.step)
|
||||
{
|
||||
if (SEGMENT.speed > 0) SEGENV.aux0++;
|
||||
if (SEGENV.aux0 > 3) SEGENV.aux0 = 0;
|
||||
if (SEGENV.aux0 >= numColors) SEGENV.aux0 = 0;
|
||||
SEGENV.step = it;
|
||||
}
|
||||
|
||||
uint16_t i = 0;
|
||||
for (i; i < SEGLEN -3; i+=4)
|
||||
for (uint16_t i = 0; i < SEGLEN; i+= numColors)
|
||||
{
|
||||
setPixelColor(i, cols[SEGENV.aux0]);
|
||||
setPixelColor(i+1, cols[SEGENV.aux0+1]);
|
||||
setPixelColor(i+2, cols[SEGENV.aux0+2]);
|
||||
setPixelColor(i+3, cols[SEGENV.aux0+3]);
|
||||
}
|
||||
if(i < SEGLEN)
|
||||
{
|
||||
setPixelColor(i, cols[SEGENV.aux0]);
|
||||
|
||||
if(i+1 < SEGLEN)
|
||||
{
|
||||
setPixelColor(i+1, cols[SEGENV.aux0+1]);
|
||||
|
||||
if(i+2 < SEGLEN)
|
||||
{
|
||||
setPixelColor(i+2, cols[SEGENV.aux0+2]);
|
||||
}
|
||||
}
|
||||
for (uint16_t j = 0; j < numColors; j++) setPixelColor(i + j, cols[SEGENV.aux0 + j]);
|
||||
}
|
||||
|
||||
return FRAMETIME;
|
||||
@@ -979,23 +1001,13 @@ uint16_t WS2812FX::mode_running_color(void) {
|
||||
return running(SEGCOLOR(0), SEGCOLOR(1));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Alternating red/blue pixels running.
|
||||
* Alternating red/white pixels running.
|
||||
*/
|
||||
uint16_t WS2812FX::mode_running_red_blue(void) {
|
||||
return running(RED, BLUE);
|
||||
uint16_t WS2812FX::mode_candy_cane(void) {
|
||||
return running(RED, WHITE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Alternating red/green pixels running.
|
||||
*/
|
||||
uint16_t WS2812FX::mode_merry_christmas(void) {
|
||||
return running(RED, GREEN);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Alternating orange/purple pixels running.
|
||||
*/
|
||||
@@ -1022,7 +1034,7 @@ uint16_t WS2812FX::mode_running_random(void) {
|
||||
}
|
||||
|
||||
SEGENV.step++;
|
||||
if (SEGENV.step > ((255-SEGMENT.intensity) >> 4))
|
||||
if (SEGENV.step > (uint8_t)((255-SEGMENT.intensity) >> 4))
|
||||
{
|
||||
SEGENV.step = 0;
|
||||
}
|
||||
@@ -1134,12 +1146,12 @@ uint16_t WS2812FX::mode_rain()
|
||||
SEGENV.step += FRAMETIME;
|
||||
if (SEGENV.step > SPEED_FORMULA_L) {
|
||||
SEGENV.step = 0;
|
||||
//shift all leds right
|
||||
uint32_t ctemp = getPixelColor(SEGLEN -1);
|
||||
for(uint16_t i = SEGLEN -1; i > 0; i--) {
|
||||
setPixelColor(i, getPixelColor(i-1));
|
||||
//shift all leds left
|
||||
uint32_t ctemp = getPixelColor(0);
|
||||
for(uint16_t i = 0; i < SEGLEN - 1; i++) {
|
||||
setPixelColor(i, getPixelColor(i+1));
|
||||
}
|
||||
setPixelColor(0, ctemp);
|
||||
setPixelColor(SEGLEN -1, ctemp);
|
||||
SEGENV.aux0++;
|
||||
SEGENV.aux1++;
|
||||
if (SEGENV.aux0 == 0) SEGENV.aux0 = UINT16_MAX;
|
||||
@@ -1245,7 +1257,7 @@ uint16_t WS2812FX::police_base(uint32_t color1, uint32_t color2, bool all)
|
||||
for (uint16_t i = idexB; i < idexR; i++) setPixelColor(i, color2);
|
||||
}
|
||||
} else { //regular dot-only mode
|
||||
uint8_t size = 1 + SEGMENT.intensity >> 3;
|
||||
uint8_t size = 1 + (SEGMENT.intensity >> 3);
|
||||
if (size > SEGLEN/2) size = 1+ SEGLEN/2;
|
||||
for (uint8_t i=0; i <= size; i++) {
|
||||
setPixelColor(idexR+i, color1);
|
||||
@@ -1556,9 +1568,9 @@ uint16_t WS2812FX::mode_oscillate(void)
|
||||
|
||||
if (SEGENV.call == 0)
|
||||
{
|
||||
oscillators[0] = {SEGLEN/4, SEGLEN/8, 1, 1};
|
||||
oscillators[1] = {SEGLEN/4*3, SEGLEN/8, 1, 2};
|
||||
oscillators[2] = {SEGLEN/4*2, SEGLEN/8, -1, 1};
|
||||
oscillators[0] = {(int16_t)(SEGLEN/4), (int8_t)(SEGLEN/8), 1, 1};
|
||||
oscillators[1] = {(int16_t)(SEGLEN/4*3), (int8_t)(SEGLEN/8), 1, 2};
|
||||
oscillators[2] = {(int16_t)(SEGLEN/4*2), (int8_t)(SEGLEN/8), -1, 1};
|
||||
}
|
||||
|
||||
uint32_t cycleTime = 20 + (2 * (uint32_t)(255 - SEGMENT.speed));
|
||||
@@ -1599,40 +1611,42 @@ uint16_t WS2812FX::mode_oscillate(void)
|
||||
uint16_t WS2812FX::mode_lightning(void)
|
||||
{
|
||||
uint16_t ledstart = random16(SEGLEN); // Determine starting location of flash
|
||||
uint16_t ledlen = 1 + random16(SEGLEN -ledstart); // Determine length of flash (not to go beyond NUM_LEDS-1)
|
||||
uint16_t ledlen = 1 + random16(SEGLEN -ledstart); // Determine length of flash (not to go beyond NUM_LEDS-1)
|
||||
uint8_t bri = 255/random8(1, 3);
|
||||
|
||||
if (SEGENV.step == 0)
|
||||
if (SEGENV.aux1 == 0) //init, leader flash
|
||||
{
|
||||
SEGENV.aux0 = random8(3, 3 + SEGMENT.intensity/20); //number of flashes
|
||||
bri = 52;
|
||||
SEGENV.aux1 = 1;
|
||||
SEGENV.aux1 = random8(4, 4 + SEGMENT.intensity/20); //number of flashes
|
||||
SEGENV.aux1 *= 2;
|
||||
|
||||
bri = 52; //leader has lower brightness
|
||||
SEGENV.aux0 = 200; //200ms delay after leader
|
||||
}
|
||||
|
||||
fill(SEGCOLOR(1));
|
||||
|
||||
if (SEGENV.aux1) {
|
||||
if (SEGENV.aux1 > 3 && !(SEGENV.aux1 & 0x01)) { //flash on even number >2
|
||||
for (int i = ledstart; i < ledstart + ledlen; i++)
|
||||
{
|
||||
if (SEGMENT.palette == 0)
|
||||
{
|
||||
setPixelColor(i,bri,bri,bri,bri);
|
||||
} else {
|
||||
setPixelColor(i,color_from_palette(i, true, PALETTE_SOLID_WRAP, 0, bri));
|
||||
}
|
||||
setPixelColor(i,color_from_palette(i, true, PALETTE_SOLID_WRAP, 0, bri));
|
||||
}
|
||||
SEGENV.aux1--;
|
||||
|
||||
SEGENV.step = millis();
|
||||
//return random8(4, 10); // each flash only lasts one frame/every 24ms... originally 4-10 milliseconds
|
||||
} else {
|
||||
if (millis() - SEGENV.step > SEGENV.aux0) {
|
||||
SEGENV.aux1--;
|
||||
if (SEGENV.aux1 < 2) SEGENV.aux1 = 0;
|
||||
|
||||
SEGENV.aux0 = (50 + random8(100)); //delay between flashes
|
||||
if (SEGENV.aux1 == 2) {
|
||||
SEGENV.aux0 = (random8(255 - SEGMENT.speed) * 100); // delay between strikes
|
||||
}
|
||||
SEGENV.step = millis();
|
||||
}
|
||||
SEGENV.aux1 = 0;
|
||||
SEGENV.step++;
|
||||
return random8(4, 10); // each flash only lasts 4-10 milliseconds
|
||||
}
|
||||
|
||||
SEGENV.aux1 = 1;
|
||||
if (SEGENV.step == 1) return (200); // longer delay until next flash after the leader
|
||||
|
||||
if (SEGENV.step <= SEGENV.aux0) return (50 + random8(100)); // shorter delay between strokes
|
||||
|
||||
SEGENV.step = 0;
|
||||
return (random8(255 - SEGMENT.speed) * 100); // delay between strikes
|
||||
return FRAMETIME;
|
||||
}
|
||||
|
||||
|
||||
@@ -1759,19 +1773,22 @@ uint16_t WS2812FX::mode_fire_2012()
|
||||
|
||||
if (it != SEGENV.step)
|
||||
{
|
||||
uint8_t ignition = max(7,SEGLEN/10); // ignition area: 10% of segment length or minimum 7 pixels
|
||||
|
||||
// Step 1. Cool down every cell a little
|
||||
for (uint16_t i = 0; i < SEGLEN; i++) {
|
||||
SEGENV.data[i] = qsub8(heat[i], random8(0, (((20 + SEGMENT.speed /3) * 10) / SEGLEN) + 2));
|
||||
uint8_t temp = qsub8(heat[i], random8(0, (((20 + SEGMENT.speed /3) * 10) / SEGLEN) + 2));
|
||||
heat[i] = (temp==0 && i<ignition) ? 2 : temp; // prevent ignition area from becoming black
|
||||
}
|
||||
|
||||
// Step 2. Heat from each cell drifts 'up' and diffuses a little
|
||||
for (uint16_t k= SEGLEN -1; k > 1; k--) {
|
||||
heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2] ) / 3;
|
||||
heat[k] = (heat[k - 1] + (heat[k - 2]<<1) ) / 3; // heat[k-2] multiplied by 2
|
||||
}
|
||||
|
||||
// Step 3. Randomly ignite new 'sparks' of heat near the bottom
|
||||
if (random8() <= SEGMENT.intensity) {
|
||||
uint8_t y = random8(7);
|
||||
uint8_t y = random8(ignition);
|
||||
if (y < SEGLEN) heat[y] = qadd8(heat[y], random8(160,255));
|
||||
}
|
||||
SEGENV.step = it;
|
||||
@@ -1902,7 +1919,6 @@ uint16_t WS2812FX::mode_noise16_2()
|
||||
for (uint16_t i = 0; i < SEGLEN; i++) {
|
||||
|
||||
uint16_t shift_x = SEGENV.step >> 6; // x as a function of time
|
||||
uint16_t shift_y = SEGENV.step/42;
|
||||
|
||||
uint32_t real_x = (i + shift_x) * scale; // calculate the coordinates within the noise field
|
||||
|
||||
@@ -1966,7 +1982,7 @@ uint16_t WS2812FX::mode_colortwinkle()
|
||||
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
||||
|
||||
CRGB fastled_col, prev;
|
||||
fract8 fadeUpAmount = 8 + (SEGMENT.speed/4), fadeDownAmount = 5 + (SEGMENT.speed/7);
|
||||
fract8 fadeUpAmount = _brightness>28 ? 8 + (SEGMENT.speed>>2) : 68-_brightness, fadeDownAmount = _brightness>28 ? 8 + (SEGMENT.speed>>3) : 68-_brightness;
|
||||
for (uint16_t i = 0; i < SEGLEN; i++) {
|
||||
fastled_col = col_to_crgb(getPixelColor(i));
|
||||
prev = fastled_col;
|
||||
@@ -2732,7 +2748,7 @@ uint16_t WS2812FX::candle(bool multi)
|
||||
|
||||
//max. flicker range controlled by intensity
|
||||
uint8_t valrange = SEGMENT.intensity;
|
||||
uint8_t rndval = valrange >> 1;
|
||||
uint8_t rndval = valrange >> 1; //max 127
|
||||
|
||||
//step (how much to move closer to target per frame) coarsely set by speed
|
||||
uint8_t speedFactor = 4;
|
||||
@@ -2769,9 +2785,9 @@ uint16_t WS2812FX::candle(bool multi)
|
||||
}
|
||||
|
||||
if (newTarget) {
|
||||
s_target = random8(rndval) + random8(rndval);
|
||||
s_target = random8(rndval) + random8(rndval); //between 0 and rndval*2 -2 = 252
|
||||
if (s_target < (rndval >> 1)) s_target = (rndval >> 1) + random8(rndval);
|
||||
uint8_t offset = (255 - valrange) >> 1;
|
||||
uint8_t offset = (255 - valrange);
|
||||
s_target += offset;
|
||||
|
||||
uint8_t dif = (s_target > s) ? s_target - s : s - s_target;
|
||||
@@ -3119,6 +3135,59 @@ uint16_t WS2812FX::mode_drip(void)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Tetris or Stacking (falling bricks) Effect
|
||||
* by Blaz Kristan (https://github.com/blazoncek, https://blaz.at/home)
|
||||
*/
|
||||
typedef struct Tetris {
|
||||
float pos;
|
||||
float speed;
|
||||
uint32_t col;
|
||||
} tetris;
|
||||
|
||||
uint16_t WS2812FX::mode_tetrix(void) {
|
||||
|
||||
uint16_t dataSize = sizeof(tetris);
|
||||
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
||||
Tetris* drop = reinterpret_cast<Tetris*>(SEGENV.data);
|
||||
|
||||
// initialize dropping on first call or segment full
|
||||
if (SEGENV.call == 0 || SEGENV.aux1 >= SEGLEN) {
|
||||
SEGENV.aux1 = 0; // reset brick stack size
|
||||
SEGENV.step = 0;
|
||||
fill(SEGCOLOR(1));
|
||||
return 250; // short wait
|
||||
}
|
||||
|
||||
if (SEGENV.step == 0) { //init
|
||||
drop->speed = 0.0238 * (SEGMENT.speed ? (SEGMENT.speed>>3)+1 : random8(6,40)); // set speed
|
||||
drop->pos = SEGLEN-1; // start at end of segment
|
||||
drop->col = color_from_palette(random8(0,15)<<4,false,false,0); // limit color choices so there is enough HUE gap
|
||||
SEGENV.step = 1; // drop state (0 init, 1 forming, 2 falling)
|
||||
SEGENV.aux0 = (SEGMENT.intensity ? (SEGMENT.intensity>>5)+1 : random8(1,5)) * (1+(SEGLEN>>6)); // size of brick
|
||||
}
|
||||
|
||||
if (SEGENV.step == 1) { // forming
|
||||
if (random8()>>6) { // random drop
|
||||
SEGENV.step = 2; // fall
|
||||
}
|
||||
}
|
||||
|
||||
if (SEGENV.step > 1) { // falling
|
||||
if (drop->pos > SEGENV.aux1) { // fall until top of stack
|
||||
drop->pos -= drop->speed; // may add gravity as: speed += gravity
|
||||
if (int(drop->pos) < SEGENV.aux1) drop->pos = SEGENV.aux1;
|
||||
for (uint16_t i=int(drop->pos); i<SEGLEN; i++) setPixelColor(i,i<int(drop->pos)+SEGENV.aux0 ? drop->col : SEGCOLOR(1));
|
||||
} else { // we hit bottom
|
||||
SEGENV.step = 0; // go back to init
|
||||
SEGENV.aux1 += SEGENV.aux0; // increase the stack size
|
||||
if (SEGENV.aux1 >= SEGLEN) return 1000; // wait for a second
|
||||
}
|
||||
}
|
||||
return FRAMETIME;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/ Plasma Effect
|
||||
/ adapted from https://github.com/atuline/FastLED-Demos/blob/master/plasma/plasma.ino
|
||||
@@ -3128,8 +3197,8 @@ uint16_t WS2812FX::mode_plasma(void) {
|
||||
uint8_t thatPhase = beatsin8(7,-64,64);
|
||||
|
||||
for (int i = 0; i < SEGLEN; i++) { // For each of the LED's in the strand, set color & brightness based on a wave as follows:
|
||||
uint8_t colorIndex = cubicwave8((i*(1+ 3*(SEGMENT.speed >> 5)))+(thisPhase) & 0xFF)/2 // factor=23 // Create a wave and add a phase change and add another wave with its own phase change.
|
||||
+ cos8((i*(1+ 2*(SEGMENT.speed >> 5)))+(thatPhase) & 0xFF)/2; // factor=15 // Hey, you can even change the frequencies if you wish.
|
||||
uint8_t colorIndex = cubicwave8(((i*(1+ 3*(SEGMENT.speed >> 5)))+(thisPhase)) & 0xFF)/2 // factor=23 // Create a wave and add a phase change and add another wave with its own phase change.
|
||||
+ cos8(((i*(1+ 2*(SEGMENT.speed >> 5)))+(thatPhase)) & 0xFF)/2; // factor=15 // Hey, you can even change the frequencies if you wish.
|
||||
uint8_t thisBright = qsub8(colorIndex, beatsin8(6,0, (255 - SEGMENT.intensity)|0x01 ));
|
||||
CRGB color = ColorFromPalette(currentPalette, colorIndex, thisBright, LINEARBLEND);
|
||||
setPixelColor(i, color.red, color.green, color.blue);
|
||||
@@ -3420,6 +3489,7 @@ uint16_t WS2812FX::phased_base(uint8_t moder) { // We're making
|
||||
b = (b > cutOff) ? (b - cutOff) : 0; // A ternary operator to cutoff the light.
|
||||
setPixelColor(i, color_blend(SEGCOLOR(1), color_from_palette(index, false, false, 0), b));
|
||||
index += 256 / SEGLEN;
|
||||
if (SEGLEN > 256) index ++; // Correction for segments longer than 256 LEDs
|
||||
}
|
||||
|
||||
return FRAMETIME;
|
||||
@@ -3557,15 +3627,15 @@ uint16_t WS2812FX::mode_chunchun(void)
|
||||
{
|
||||
fill(SEGCOLOR(1));
|
||||
uint16_t counter = now*(6 + (SEGMENT.speed >> 4));
|
||||
uint16_t numBirds = SEGLEN >> 2;
|
||||
uint16_t span = SEGMENT.intensity << 8;
|
||||
uint16_t numBirds = 2 + (SEGLEN >> 3); // 2 + 1/8 of a segment
|
||||
uint16_t span = (SEGMENT.intensity << 8) / numBirds;
|
||||
|
||||
for (uint16_t i = 0; i < numBirds; i++)
|
||||
{
|
||||
counter -= span/numBirds;
|
||||
int megumin = sin16(counter) + 0x8000;
|
||||
counter -= span;
|
||||
uint16_t megumin = sin16(counter) + 0x8000;
|
||||
uint32_t bird = (megumin * SEGLEN) >> 16;
|
||||
uint32_t c = color_from_palette((i * 255)/ numBirds, false, true, 0);
|
||||
uint32_t c = color_from_palette((i * 255)/ numBirds, false, false, 0); // no palette wrapping
|
||||
setPixelColor(bird, c);
|
||||
}
|
||||
return FRAMETIME;
|
||||
@@ -3712,3 +3782,286 @@ uint16_t WS2812FX::mode_dancing_shadows(void)
|
||||
|
||||
return FRAMETIME;
|
||||
}
|
||||
|
||||
/*
|
||||
Imitates a washing machine, rotating same waves forward, then pause, then backward.
|
||||
By Stefan Seegel
|
||||
*/
|
||||
uint16_t WS2812FX::mode_washing_machine(void) {
|
||||
float speed = tristate_square8(now >> 7, 90, 15);
|
||||
float quot = 32.0f - ((float)SEGMENT.speed / 16.0f);
|
||||
speed /= quot;
|
||||
|
||||
SEGENV.step += (speed * 128.0f);
|
||||
|
||||
for (int i=0; i<SEGLEN; i++) {
|
||||
uint8_t col = sin8(((SEGMENT.intensity / 25 + 1) * 255 * i / SEGLEN) + (SEGENV.step >> 7));
|
||||
setPixelColor(i, color_from_palette(col, false, PALETTE_SOLID_WRAP, 3));
|
||||
}
|
||||
|
||||
return FRAMETIME;
|
||||
}
|
||||
|
||||
/*
|
||||
Blends random colors across palette
|
||||
Modified, originally by Mark Kriegsman https://gist.github.com/kriegsman/1f7ccbbfa492a73c015e
|
||||
*/
|
||||
uint16_t WS2812FX::mode_blends(void) {
|
||||
uint16_t dataSize = sizeof(uint32_t) * SEGLEN;
|
||||
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
||||
uint32_t* pixels = reinterpret_cast<uint32_t*>(SEGENV.data);
|
||||
uint8_t blendSpeed = map(SEGMENT.intensity, 0, UINT8_MAX, 10, 128);
|
||||
uint8_t shift = (now * ((SEGMENT.speed >> 3) +1)) >> 8;
|
||||
|
||||
for (int i = 0; i < SEGLEN; i++) {
|
||||
pixels[i] = color_blend(pixels[i], color_from_palette(shift + quadwave8((i + 1) * 16), false, PALETTE_SOLID_WRAP, 255), blendSpeed);
|
||||
setPixelColor(i, pixels[i]);
|
||||
shift += 3;
|
||||
}
|
||||
|
||||
return FRAMETIME;
|
||||
}
|
||||
|
||||
#ifndef WLED_DISABLE_FX_HIGH_FLASH_USE
|
||||
typedef struct TvSim {
|
||||
uint32_t totalTime = 0;
|
||||
uint32_t fadeTime = 0;
|
||||
uint32_t startTime = 0;
|
||||
uint32_t elapsed = 0;
|
||||
uint32_t pixelNum = 0;
|
||||
uint16_t pr = 0; // Prev R, G, B
|
||||
uint16_t pg = 0;
|
||||
uint16_t pb = 0;
|
||||
} tvSim;
|
||||
|
||||
#define numTVPixels (sizeof(tv_colors) / 2) // 2 bytes per Pixel (5/6/5)
|
||||
#endif
|
||||
|
||||
/*
|
||||
TV Simulator
|
||||
Modified and adapted to WLED by Def3nder, based on "Fake TV Light for Engineers" by Phillip Burgess https://learn.adafruit.com/fake-tv-light-for-engineers/arduino-sketch
|
||||
*/
|
||||
uint16_t WS2812FX::mode_tv_simulator(void) {
|
||||
#ifdef WLED_DISABLE_FX_HIGH_FLASH_USE
|
||||
return mode_static();
|
||||
#else
|
||||
uint16_t nr, ng, nb, r, g, b, i;
|
||||
uint8_t hi, lo, r8, g8, b8;
|
||||
|
||||
if (!SEGENV.allocateData(sizeof(tvSim))) return mode_static(); //allocation failed
|
||||
TvSim* tvSimulator = reinterpret_cast<TvSim*>(SEGENV.data);
|
||||
|
||||
// initialize start of the TV-Colors
|
||||
if (SEGENV.call == 0) {
|
||||
tvSimulator->pixelNum = ((uint8_t)random(18)) * numTVPixels / 18; // Begin at random movie (18 in total)
|
||||
}
|
||||
|
||||
// Read next 16-bit (5/6/5) color
|
||||
hi = pgm_read_byte(&tv_colors[tvSimulator->pixelNum * 2 ]);
|
||||
lo = pgm_read_byte(&tv_colors[tvSimulator->pixelNum * 2 + 1]);
|
||||
|
||||
// Expand to 24-bit (8/8/8)
|
||||
r8 = (hi & 0xF8) | (hi >> 5);
|
||||
g8 = ((hi << 5) & 0xff) | ((lo & 0xE0) >> 3) | ((hi & 0x06) >> 1);
|
||||
b8 = ((lo << 3) & 0xff) | ((lo & 0x1F) >> 2);
|
||||
|
||||
// Apply gamma correction, further expand to 16/16/16
|
||||
nr = (uint8_t)gamma8(r8) * 257; // New R/G/B
|
||||
ng = (uint8_t)gamma8(g8) * 257;
|
||||
nb = (uint8_t)gamma8(b8) * 257;
|
||||
|
||||
if (SEGENV.aux0 == 0) { // initialize next iteration
|
||||
SEGENV.aux0 = 1;
|
||||
|
||||
// increase color-index for next loop
|
||||
tvSimulator->pixelNum++;
|
||||
if (tvSimulator->pixelNum >= numTVPixels) tvSimulator->pixelNum = 0;
|
||||
|
||||
// randomize total duration and fade duration for the actual color
|
||||
tvSimulator->totalTime = random(250, 2500); // Semi-random pixel-to-pixel time
|
||||
tvSimulator->fadeTime = random(0, tvSimulator->totalTime); // Pixel-to-pixel transition time
|
||||
if (random(10) < 3) tvSimulator->fadeTime = 0; // Force scene cut 30% of time
|
||||
|
||||
tvSimulator->startTime = millis();
|
||||
} // end of initialization
|
||||
|
||||
// how much time is elapsed ?
|
||||
tvSimulator->elapsed = millis() - tvSimulator->startTime;
|
||||
|
||||
// fade from prev volor to next color
|
||||
if (tvSimulator->elapsed < tvSimulator->fadeTime) {
|
||||
r = map(tvSimulator->elapsed, 0, tvSimulator->fadeTime, tvSimulator->pr, nr);
|
||||
g = map(tvSimulator->elapsed, 0, tvSimulator->fadeTime, tvSimulator->pg, ng);
|
||||
b = map(tvSimulator->elapsed, 0, tvSimulator->fadeTime, tvSimulator->pb, nb);
|
||||
} else { // Avoid divide-by-zero in map()
|
||||
r = nr;
|
||||
g = ng;
|
||||
b = nb;
|
||||
}
|
||||
|
||||
// set strip color
|
||||
for (i = 0; i < SEGLEN; i++) {
|
||||
setPixelColor(i, r >> 8, g >> 8, b >> 8); // Quantize to 8-bit
|
||||
}
|
||||
|
||||
// if total duration has passed, remember last color and restart the loop
|
||||
if ( tvSimulator->elapsed >= tvSimulator->totalTime) {
|
||||
tvSimulator->pr = nr; // Prev RGB = new RGB
|
||||
tvSimulator->pg = ng;
|
||||
tvSimulator->pb = nb;
|
||||
SEGENV.aux0 = 0;
|
||||
}
|
||||
|
||||
return FRAMETIME;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
Aurora effect
|
||||
*/
|
||||
|
||||
//CONFIG
|
||||
#define BACKLIGHT 5
|
||||
#define W_MAX_COUNT 20 //Number of simultaneous waves
|
||||
#define W_MAX_SPEED 6 //Higher number, higher speed
|
||||
#define W_WIDTH_FACTOR 6 //Higher number, smaller waves
|
||||
|
||||
class AuroraWave {
|
||||
private:
|
||||
uint16_t ttl;
|
||||
CRGB basecolor;
|
||||
float basealpha;
|
||||
uint16_t age;
|
||||
uint16_t width;
|
||||
float center;
|
||||
bool goingleft;
|
||||
float speed_factor;
|
||||
bool alive = true;
|
||||
|
||||
public:
|
||||
void init(uint32_t segment_length, CRGB color) {
|
||||
ttl = random(500, 1501);
|
||||
basecolor = color;
|
||||
basealpha = random(60, 101) / (float)100;
|
||||
age = 0;
|
||||
width = random(segment_length / 20, segment_length / W_WIDTH_FACTOR); //half of width to make math easier
|
||||
if (!width) width = 1;
|
||||
center = random(101) / (float)100 * segment_length;
|
||||
goingleft = random(0, 2) == 0;
|
||||
speed_factor = (random(10, 31) / (float)100 * W_MAX_SPEED / 255);
|
||||
alive = true;
|
||||
}
|
||||
|
||||
CRGB getColorForLED(int ledIndex) {
|
||||
if(ledIndex < center - width || ledIndex > center + width) return 0; //Position out of range of this wave
|
||||
|
||||
CRGB rgb;
|
||||
|
||||
//Offset of this led from center of wave
|
||||
//The further away from the center, the dimmer the LED
|
||||
float offset = ledIndex - center;
|
||||
if (offset < 0) offset = -offset;
|
||||
float offsetFactor = offset / width;
|
||||
|
||||
//The age of the wave determines it brightness.
|
||||
//At half its maximum age it will be the brightest.
|
||||
float ageFactor = 0.1;
|
||||
if((float)age / ttl < 0.5) {
|
||||
ageFactor = (float)age / (ttl / 2);
|
||||
} else {
|
||||
ageFactor = (float)(ttl - age) / ((float)ttl * 0.5);
|
||||
}
|
||||
|
||||
//Calculate color based on above factors and basealpha value
|
||||
float factor = (1 - offsetFactor) * ageFactor * basealpha;
|
||||
rgb.r = basecolor.r * factor;
|
||||
rgb.g = basecolor.g * factor;
|
||||
rgb.b = basecolor.b * factor;
|
||||
|
||||
return rgb;
|
||||
};
|
||||
|
||||
//Change position and age of wave
|
||||
//Determine if its sill "alive"
|
||||
void update(uint32_t segment_length, uint32_t speed) {
|
||||
if(goingleft) {
|
||||
center -= speed_factor * speed;
|
||||
} else {
|
||||
center += speed_factor * speed;
|
||||
}
|
||||
|
||||
age++;
|
||||
|
||||
if(age > ttl) {
|
||||
alive = false;
|
||||
} else {
|
||||
if(goingleft) {
|
||||
if(center + width < 0) {
|
||||
alive = false;
|
||||
}
|
||||
} else {
|
||||
if(center - width > segment_length) {
|
||||
alive = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
bool stillAlive() {
|
||||
return alive;
|
||||
};
|
||||
};
|
||||
|
||||
uint16_t WS2812FX::mode_aurora(void) {
|
||||
//aux1 = Wavecount
|
||||
//aux2 = Intensity in last loop
|
||||
|
||||
AuroraWave* waves;
|
||||
|
||||
if(SEGENV.aux0 != SEGMENT.intensity || SEGENV.call == 0) {
|
||||
//Intensity slider changed or first call
|
||||
SEGENV.aux1 = ((float)SEGMENT.intensity / 255) * W_MAX_COUNT;
|
||||
SEGENV.aux0 = SEGMENT.intensity;
|
||||
|
||||
if(!SEGENV.allocateData(sizeof(AuroraWave) * SEGENV.aux1)) {
|
||||
return mode_static(); //allocation failed
|
||||
}
|
||||
|
||||
waves = reinterpret_cast<AuroraWave*>(SEGENV.data);
|
||||
|
||||
for(int i = 0; i < SEGENV.aux1; i++) {
|
||||
waves[i].init(SEGLEN, col_to_crgb(color_from_palette(random8(), false, false, random(0, 3))));
|
||||
}
|
||||
} else {
|
||||
waves = reinterpret_cast<AuroraWave*>(SEGENV.data);
|
||||
}
|
||||
|
||||
for(int i = 0; i < SEGENV.aux1; i++) {
|
||||
//Update values of wave
|
||||
waves[i].update(SEGLEN, SEGMENT.speed);
|
||||
|
||||
if(!(waves[i].stillAlive())) {
|
||||
//If a wave dies, reinitialize it starts over.
|
||||
waves[i].init(SEGLEN, col_to_crgb(color_from_palette(random8(), false, false, random(0, 3))));
|
||||
}
|
||||
}
|
||||
|
||||
//Loop through LEDs to determine color
|
||||
for(int i = 0; i < SEGLEN; i++) {
|
||||
CRGB mixedRgb = CRGB(BACKLIGHT, BACKLIGHT, BACKLIGHT);
|
||||
|
||||
//For each LED we must check each wave if it is "active" at this position.
|
||||
//If there are multiple waves active on a LED we multiply their values.
|
||||
for(int j = 0; j < SEGENV.aux1; j++) {
|
||||
CRGB rgb = waves[j].getColorForLED(i);
|
||||
|
||||
if(rgb != CRGB(0)) {
|
||||
mixedRgb += rgb;
|
||||
}
|
||||
}
|
||||
|
||||
setPixelColor(i, mixedRgb[0], mixedRgb[1], mixedRgb[2], BACKLIGHT);
|
||||
}
|
||||
|
||||
return FRAMETIME;
|
||||
}
|
||||
271
wled00/FX.h
@@ -24,10 +24,11 @@
|
||||
Modified for WLED
|
||||
*/
|
||||
|
||||
#include "wled.h"
|
||||
|
||||
#ifndef WS2812FX_h
|
||||
#define WS2812FX_h
|
||||
|
||||
#include "NpbWrapper.h"
|
||||
#include "const.h"
|
||||
|
||||
#define FASTLED_INTERNAL //remove annoying pragma messages
|
||||
@@ -37,10 +38,18 @@
|
||||
#define DEFAULT_BRIGHTNESS (uint8_t)127
|
||||
#define DEFAULT_MODE (uint8_t)0
|
||||
#define DEFAULT_SPEED (uint8_t)128
|
||||
#define DEFAULT_INTENSITY (uint8_t)128
|
||||
#define DEFAULT_COLOR (uint32_t)0xFFAA00
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) ((a)<(b)?(a):(b))
|
||||
#endif
|
||||
#ifndef MAX
|
||||
#define MAX(a,b) ((a)>(b)?(a):(b))
|
||||
#endif
|
||||
|
||||
/* Disable effects with high flash memory usage (currently TV simulator) - saves 18.5kB */
|
||||
//#define WLED_DISABLE_FX_HIGH_FLASH_USE
|
||||
|
||||
/* Not used in all effects yet */
|
||||
#define WLED_FPS 42
|
||||
@@ -48,13 +57,16 @@
|
||||
|
||||
/* each segment uses 52 bytes of SRAM memory, so if you're application fails because of
|
||||
insufficient memory, decreasing MAX_NUM_SEGMENTS may help */
|
||||
#define MAX_NUM_SEGMENTS 10
|
||||
|
||||
/* How much data bytes all segments combined may allocate */
|
||||
#ifdef ESP8266
|
||||
#define MAX_SEGMENT_DATA 2048
|
||||
#define MAX_NUM_SEGMENTS 12
|
||||
/* How many color transitions can run at once */
|
||||
#define MAX_NUM_TRANSITIONS 8
|
||||
/* How much data bytes all segments combined may allocate */
|
||||
#define MAX_SEGMENT_DATA 2048
|
||||
#else
|
||||
#define MAX_SEGMENT_DATA 8192
|
||||
#define MAX_NUM_SEGMENTS 16
|
||||
#define MAX_NUM_TRANSITIONS 16
|
||||
#define MAX_SEGMENT_DATA 8192
|
||||
#endif
|
||||
|
||||
#define LED_SKIP_AMOUNT 1
|
||||
@@ -62,7 +74,7 @@
|
||||
|
||||
#define NUM_COLORS 3 /* number of colors per segment */
|
||||
#define SEGMENT _segments[_segment_index]
|
||||
#define SEGCOLOR(x) gamma32(_segments[_segment_index].colors[x])
|
||||
#define SEGCOLOR(x) _colors_t[x]
|
||||
#define SEGENV _segment_runtimes[_segment_index]
|
||||
#define SEGLEN _virtualSegmentLength
|
||||
#define SEGACT SEGMENT.stop
|
||||
@@ -102,7 +114,7 @@
|
||||
#define IS_REVERSE ((SEGMENT.options & REVERSE ) == REVERSE )
|
||||
#define IS_SELECTED ((SEGMENT.options & SELECTED ) == SELECTED )
|
||||
|
||||
#define MODE_COUNT 113
|
||||
#define MODE_COUNT 118
|
||||
|
||||
#define FX_MODE_STATIC 0
|
||||
#define FX_MODE_BLINK 1
|
||||
@@ -142,13 +154,13 @@
|
||||
#define FX_MODE_TRAFFIC_LIGHT 35
|
||||
#define FX_MODE_COLOR_SWEEP_RANDOM 36
|
||||
#define FX_MODE_RUNNING_COLOR 37
|
||||
#define FX_MODE_RUNNING_RED_BLUE 38
|
||||
#define FX_MODE_AURORA 38
|
||||
#define FX_MODE_RUNNING_RANDOM 39
|
||||
#define FX_MODE_LARSON_SCANNER 40
|
||||
#define FX_MODE_COMET 41
|
||||
#define FX_MODE_FIREWORKS 42
|
||||
#define FX_MODE_RAIN 43
|
||||
#define FX_MODE_MERRY_CHRISTMAS 44
|
||||
#define FX_MODE_TETRIX 44
|
||||
#define FX_MODE_FIRE_FLICKER 45
|
||||
#define FX_MODE_GRADIENT 46
|
||||
#define FX_MODE_LOADING 47
|
||||
@@ -217,12 +229,20 @@
|
||||
#define FX_MODE_FLOW 110
|
||||
#define FX_MODE_CHUNCHUN 111
|
||||
#define FX_MODE_DANCING_SHADOWS 112
|
||||
#define FX_MODE_WASHING_MACHINE 113
|
||||
#define FX_MODE_CANDY_CANE 114
|
||||
#define FX_MODE_BLENDS 115
|
||||
#define FX_MODE_TV_SIMULATOR 116
|
||||
#define FX_MODE_DYNAMIC_SMOOTH 117
|
||||
|
||||
|
||||
class WS2812FX {
|
||||
typedef uint16_t (WS2812FX::*mode_ptr)(void);
|
||||
|
||||
// pre show callback
|
||||
typedef void (*show_callback) (void);
|
||||
|
||||
static WS2812FX* instance;
|
||||
|
||||
// segment parameters
|
||||
public:
|
||||
@@ -237,14 +257,40 @@ class WS2812FX {
|
||||
uint8_t grouping, spacing;
|
||||
uint8_t opacity;
|
||||
uint32_t colors[NUM_COLORS];
|
||||
void setOption(uint8_t n, bool val)
|
||||
bool setColor(uint8_t slot, uint32_t c, uint8_t segn) { //returns true if changed
|
||||
if (slot >= NUM_COLORS || segn >= MAX_NUM_SEGMENTS) return false;
|
||||
if (c == colors[slot]) return false;
|
||||
ColorTransition::startTransition(opacity, colors[slot], instance->_transitionDur, segn, slot);
|
||||
colors[slot] = c; return true;
|
||||
}
|
||||
void setOpacity(uint8_t o, uint8_t segn) {
|
||||
if (segn >= MAX_NUM_SEGMENTS) return;
|
||||
if (opacity == o) return;
|
||||
ColorTransition::startTransition(opacity, colors[0], instance->_transitionDur, segn, 0);
|
||||
opacity = o;
|
||||
}
|
||||
/*uint8_t actualOpacity() { //respects On/Off state
|
||||
if (!getOption(SEG_OPTION_ON)) return 0;
|
||||
return opacity;
|
||||
}*/
|
||||
void setOption(uint8_t n, bool val, uint8_t segn = 255)
|
||||
{
|
||||
//bool prevOn = false;
|
||||
//if (n == SEG_OPTION_ON) prevOn = getOption(SEG_OPTION_ON);
|
||||
if (val) {
|
||||
options |= 0x01 << n;
|
||||
} else
|
||||
{
|
||||
options &= ~(0x01 << n);
|
||||
}
|
||||
//transitions on segment on/off don't work correctly at this point
|
||||
/*if (n == SEG_OPTION_ON && segn < MAX_NUM_SEGMENTS && getOption(SEG_OPTION_ON) != prevOn) {
|
||||
if (getOption(SEG_OPTION_ON)) {
|
||||
ColorTransition::startTransition(0, colors[0], instance->_transitionDur, segn, 0);
|
||||
} else {
|
||||
ColorTransition::startTransition(opacity, colors[0], instance->_transitionDur, segn, 0);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
bool getOption(uint8_t n)
|
||||
{
|
||||
@@ -287,10 +333,10 @@ class WS2812FX {
|
||||
bool allocateData(uint16_t len){
|
||||
if (data && _dataLen == len) return true; //already allocated
|
||||
deallocateData();
|
||||
if (WS2812FX::_usedSegmentData + len > MAX_SEGMENT_DATA) return false; //not enough memory
|
||||
if (WS2812FX::instance->_usedSegmentData + len > MAX_SEGMENT_DATA) return false; //not enough memory
|
||||
data = new (std::nothrow) byte[len];
|
||||
if (!data) return false; //allocation failed
|
||||
WS2812FX::_usedSegmentData += len;
|
||||
WS2812FX::instance->_usedSegmentData += len;
|
||||
_dataLen = len;
|
||||
memset(data, 0, len);
|
||||
return true;
|
||||
@@ -298,15 +344,116 @@ class WS2812FX {
|
||||
void deallocateData(){
|
||||
delete[] data;
|
||||
data = nullptr;
|
||||
WS2812FX::_usedSegmentData -= _dataLen;
|
||||
WS2812FX::instance->_usedSegmentData -= _dataLen;
|
||||
_dataLen = 0;
|
||||
}
|
||||
void reset(){next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0; deallocateData();}
|
||||
|
||||
/**
|
||||
* If reset of this segment was request, clears runtime
|
||||
* settings of this segment.
|
||||
* Must not be called while an effect mode function is running
|
||||
* because it could access the data buffer and this method
|
||||
* may free that data buffer.
|
||||
*/
|
||||
void resetIfRequired() {
|
||||
if (_requiresReset) {
|
||||
next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0;
|
||||
deallocateData();
|
||||
_requiresReset = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flags that before the next effect is calculated,
|
||||
* the internal segment state should be reset.
|
||||
* Call resetIfRequired before calling the next effect function.
|
||||
*/
|
||||
void reset() { _requiresReset = true; }
|
||||
private:
|
||||
uint16_t _dataLen = 0;
|
||||
bool _requiresReset = false;
|
||||
} segment_runtime;
|
||||
|
||||
typedef struct ColorTransition { // 12 bytes
|
||||
uint32_t colorOld = 0;
|
||||
uint32_t transitionStart;
|
||||
uint16_t transitionDur;
|
||||
uint8_t segment = 0xFF; //lower 6 bits: the segment this transition is for (255 indicates transition not in use/available) upper 2 bits: color channel
|
||||
uint8_t briOld = 0;
|
||||
static void startTransition(uint8_t oldBri, uint32_t oldCol, uint16_t dur, uint8_t segn, uint8_t slot) {
|
||||
if (segn >= MAX_NUM_SEGMENTS || slot >= NUM_COLORS || dur == 0) return;
|
||||
if (instance->_brightness == 0) return; //do not need transitions if master bri is off
|
||||
uint8_t tIndex = 0xFF; //none found
|
||||
uint16_t tProgression = 0;
|
||||
uint8_t s = segn + (slot << 6); //merge slot and segment into one byte
|
||||
|
||||
for (uint8_t i = 0; i < MAX_NUM_TRANSITIONS; i++) {
|
||||
uint8_t tSeg = instance->transitions[i].segment;
|
||||
//see if this segment + color already has a running transition
|
||||
if (tSeg == s) {
|
||||
tIndex = i; break;
|
||||
}
|
||||
if (tSeg == 0xFF) { //free transition
|
||||
tIndex = i; tProgression = 0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
if (tIndex == 0xFF) { //no slot found yet
|
||||
for (uint8_t i = 0; i < MAX_NUM_TRANSITIONS; i++) {
|
||||
//find most progressed transition to overwrite
|
||||
uint16_t prog = instance->transitions[i].progress();
|
||||
if (prog > tProgression) {
|
||||
tIndex = i; tProgression = prog;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColorTransition& t = instance->transitions[tIndex];
|
||||
if (t.segment == s) //this is an active transition on the same segment+color
|
||||
{
|
||||
t.briOld = t.currentBri();
|
||||
t.colorOld = t.currentColor(oldCol);
|
||||
} else {
|
||||
t.briOld = oldBri;
|
||||
t.colorOld = oldCol;
|
||||
uint8_t prevSeg = t.segment & 0x3F;
|
||||
if (prevSeg < MAX_NUM_SEGMENTS) instance->_segments[prevSeg].setOption(SEG_OPTION_TRANSITIONAL, false);
|
||||
}
|
||||
t.transitionDur = dur;
|
||||
t.transitionStart = millis();
|
||||
t.segment = s;
|
||||
instance->_segments[segn].setOption(SEG_OPTION_TRANSITIONAL, true);
|
||||
//refresh immediately, required for Solid mode
|
||||
if (instance->_segment_runtimes[segn].next_time > t.transitionStart + 22) instance->_segment_runtimes[segn].next_time = t.transitionStart;
|
||||
}
|
||||
uint16_t progress(bool allowEnd = false) { //transition progression between 0-65535
|
||||
uint32_t timeNow = millis();
|
||||
if (timeNow - transitionStart > transitionDur) {
|
||||
if (allowEnd) {
|
||||
uint8_t segn = segment & 0x3F;
|
||||
if (segn < MAX_NUM_SEGMENTS) instance->_segments[segn].setOption(SEG_OPTION_TRANSITIONAL, false);
|
||||
segment = 0xFF;
|
||||
}
|
||||
return 0xFFFF;
|
||||
}
|
||||
uint32_t elapsed = timeNow - transitionStart;
|
||||
uint32_t prog = elapsed * 0xFFFF / transitionDur;
|
||||
return (prog > 0xFFFF) ? 0xFFFF : prog;
|
||||
}
|
||||
uint32_t currentColor(uint32_t colorNew) {
|
||||
return instance->color_blend(colorOld, colorNew, progress(true), true);
|
||||
}
|
||||
uint8_t currentBri() {
|
||||
uint8_t segn = segment & 0x3F;
|
||||
if (segn >= MAX_NUM_SEGMENTS) return 0;
|
||||
uint8_t briNew = instance->_segments[segn].opacity;
|
||||
uint32_t prog = progress() + 1;
|
||||
return ((briNew * prog) + (briOld * (0x10000 - prog))) >> 16;
|
||||
}
|
||||
} color_transition;
|
||||
|
||||
WS2812FX() {
|
||||
WS2812FX::instance = this;
|
||||
//assign each member of the _mode[] array to its respective function reference
|
||||
_mode[FX_MODE_STATIC] = &WS2812FX::mode_static;
|
||||
_mode[FX_MODE_BLINK] = &WS2812FX::mode_blink;
|
||||
@@ -344,13 +491,13 @@ class WS2812FX {
|
||||
_mode[FX_MODE_TRAFFIC_LIGHT] = &WS2812FX::mode_traffic_light;
|
||||
_mode[FX_MODE_COLOR_SWEEP_RANDOM] = &WS2812FX::mode_color_sweep_random;
|
||||
_mode[FX_MODE_RUNNING_COLOR] = &WS2812FX::mode_running_color;
|
||||
_mode[FX_MODE_RUNNING_RED_BLUE] = &WS2812FX::mode_running_red_blue;
|
||||
_mode[FX_MODE_AURORA] = &WS2812FX::mode_aurora;
|
||||
_mode[FX_MODE_RUNNING_RANDOM] = &WS2812FX::mode_running_random;
|
||||
_mode[FX_MODE_LARSON_SCANNER] = &WS2812FX::mode_larson_scanner;
|
||||
_mode[FX_MODE_COMET] = &WS2812FX::mode_comet;
|
||||
_mode[FX_MODE_FIREWORKS] = &WS2812FX::mode_fireworks;
|
||||
_mode[FX_MODE_RAIN] = &WS2812FX::mode_rain;
|
||||
_mode[FX_MODE_MERRY_CHRISTMAS] = &WS2812FX::mode_merry_christmas;
|
||||
_mode[FX_MODE_TETRIX] = &WS2812FX::mode_tetrix;
|
||||
_mode[FX_MODE_FIRE_FLICKER] = &WS2812FX::mode_fire_flicker;
|
||||
_mode[FX_MODE_GRADIENT] = &WS2812FX::mode_gradient;
|
||||
_mode[FX_MODE_LOADING] = &WS2812FX::mode_loading;
|
||||
@@ -421,6 +568,11 @@ class WS2812FX {
|
||||
_mode[FX_MODE_FLOW] = &WS2812FX::mode_flow;
|
||||
_mode[FX_MODE_CHUNCHUN] = &WS2812FX::mode_chunchun;
|
||||
_mode[FX_MODE_DANCING_SHADOWS] = &WS2812FX::mode_dancing_shadows;
|
||||
_mode[FX_MODE_WASHING_MACHINE] = &WS2812FX::mode_washing_machine;
|
||||
_mode[FX_MODE_CANDY_CANE] = &WS2812FX::mode_candy_cane;
|
||||
_mode[FX_MODE_BLENDS] = &WS2812FX::mode_blends;
|
||||
_mode[FX_MODE_TV_SIMULATOR] = &WS2812FX::mode_tv_simulator;
|
||||
_mode[FX_MODE_DYNAMIC_SMOOTH] = &WS2812FX::mode_dynamic_smooth;
|
||||
|
||||
_brightness = DEFAULT_BRIGHTNESS;
|
||||
currentPalette = CRGBPalette16(CRGB::Black);
|
||||
@@ -428,12 +580,11 @@ class WS2812FX {
|
||||
ablMilliampsMax = 850;
|
||||
currentMilliamps = 0;
|
||||
timebase = 0;
|
||||
bus = new NeoPixelWrapper();
|
||||
resetSegments();
|
||||
}
|
||||
|
||||
void
|
||||
init(bool supportWhite, uint16_t countPixels, bool skipFirst),
|
||||
finalizeInit(uint16_t countPixels, bool skipFirst),
|
||||
service(void),
|
||||
blur(uint8_t),
|
||||
fill(uint32_t),
|
||||
@@ -444,31 +595,36 @@ class WS2812FX {
|
||||
setBrightness(uint8_t b),
|
||||
setRange(uint16_t i, uint16_t i2, uint32_t col),
|
||||
setShowCallback(show_callback cb),
|
||||
setTransition(uint16_t t),
|
||||
setTransitionMode(bool t),
|
||||
calcGammaTable(float),
|
||||
trigger(void),
|
||||
setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t grouping = 0, uint8_t spacing = 0),
|
||||
resetSegments(),
|
||||
setPixelColor(uint16_t n, uint32_t c),
|
||||
setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0),
|
||||
show(void),
|
||||
setRgbwPwm(void),
|
||||
setColorOrder(uint8_t co),
|
||||
setPixelSegment(uint8_t n);
|
||||
|
||||
bool
|
||||
reverseMode = false, //is the entire LED strip reversed?
|
||||
isRgbw = false,
|
||||
gammaCorrectBri = false,
|
||||
gammaCorrectCol = true,
|
||||
applyToAllSelected = true,
|
||||
segmentsAreIdentical(Segment* a, Segment* b),
|
||||
setEffectConfig(uint8_t m, uint8_t s, uint8_t i, uint8_t p);
|
||||
setEffectConfig(uint8_t m, uint8_t s, uint8_t i, uint8_t p),
|
||||
// return true if the strip is being sent pixel updates
|
||||
isUpdating(void);
|
||||
|
||||
uint8_t
|
||||
mainSegment = 0,
|
||||
rgbwMode = RGBW_MODE_DUAL,
|
||||
paletteFade = 0,
|
||||
paletteBlend = 0,
|
||||
colorOrder = 0,
|
||||
milliampsPerLed = 55,
|
||||
// getStripType(uint8_t strip=0),
|
||||
// setStripType(uint8_t type, uint8_t strip=0),
|
||||
getBrightness(void),
|
||||
getMode(void),
|
||||
getSpeed(void),
|
||||
@@ -477,20 +633,33 @@ class WS2812FX {
|
||||
getMaxSegments(void),
|
||||
//getFirstSelectedSegment(void),
|
||||
getMainSegmentId(void),
|
||||
getColorOrder(void),
|
||||
gamma8(uint8_t),
|
||||
gamma8_cal(uint8_t, float),
|
||||
get_random_wheel_index(uint8_t);
|
||||
|
||||
int8_t
|
||||
// setStripPin(uint8_t strip, int8_t pin),
|
||||
// getStripPin(uint8_t strip=0),
|
||||
// setStripPinClk(uint8_t strip, int8_t pin),
|
||||
// getStripPinClk(uint8_t strip=0),
|
||||
tristate_square8(uint8_t x, uint8_t pulsewidth, uint8_t attdec);
|
||||
|
||||
uint16_t
|
||||
ablMilliampsMax,
|
||||
currentMilliamps,
|
||||
triwave16(uint16_t);
|
||||
// setStripLen(uint8_t strip, uint16_t len),
|
||||
// getStripLen(uint8_t strip=0),
|
||||
triwave16(uint16_t),
|
||||
getFps();
|
||||
|
||||
uint32_t
|
||||
now,
|
||||
timebase,
|
||||
color_wheel(uint8_t),
|
||||
color_from_palette(uint16_t, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri = 255),
|
||||
color_blend(uint32_t,uint32_t,uint8_t),
|
||||
color_blend(uint32_t,uint32_t,uint16_t,bool b16=false),
|
||||
currentColor(uint32_t colorNew, uint8_t tNr),
|
||||
gamma32(uint32_t),
|
||||
getLastShow(void),
|
||||
getPixelColor(uint16_t),
|
||||
@@ -545,13 +714,13 @@ class WS2812FX {
|
||||
mode_colorful(void),
|
||||
mode_traffic_light(void),
|
||||
mode_running_color(void),
|
||||
mode_running_red_blue(void),
|
||||
mode_aurora(void),
|
||||
mode_running_random(void),
|
||||
mode_larson_scanner(void),
|
||||
mode_comet(void),
|
||||
mode_fireworks(void),
|
||||
mode_rain(void),
|
||||
mode_merry_christmas(void),
|
||||
mode_tetrix(void),
|
||||
mode_halloween(void),
|
||||
mode_fire_flicker(void),
|
||||
mode_gradient(void),
|
||||
@@ -620,11 +789,14 @@ class WS2812FX {
|
||||
mode_phased_noise(void),
|
||||
mode_flow(void),
|
||||
mode_chunchun(void),
|
||||
mode_dancing_shadows(void);
|
||||
mode_dancing_shadows(void),
|
||||
mode_washing_machine(void),
|
||||
mode_candy_cane(void),
|
||||
mode_blends(void),
|
||||
mode_tv_simulator(void),
|
||||
mode_dynamic_smooth(void);
|
||||
|
||||
private:
|
||||
NeoPixelWrapper *bus;
|
||||
|
||||
uint32_t crgb_to_col(CRGB fastled);
|
||||
CRGB col_to_crgb(uint32_t);
|
||||
CRGBPalette16 currentPalette;
|
||||
@@ -633,13 +805,15 @@ class WS2812FX {
|
||||
uint16_t _length, _lengthRaw, _virtualSegmentLength;
|
||||
uint16_t _rand16seed;
|
||||
uint8_t _brightness;
|
||||
static uint16_t _usedSegmentData;
|
||||
uint16_t _usedSegmentData = 0;
|
||||
uint16_t _transitionDur = 750;
|
||||
|
||||
uint16_t _cumulativeFps = 2;
|
||||
|
||||
void load_gradient_palette(uint8_t);
|
||||
void handle_palette(void);
|
||||
|
||||
bool
|
||||
_useRgbw = false,
|
||||
_skipFirstMode,
|
||||
_triggered;
|
||||
|
||||
@@ -652,6 +826,7 @@ class WS2812FX {
|
||||
blink(uint32_t, uint32_t, bool strobe, bool),
|
||||
candle(bool),
|
||||
color_wipe(bool, bool),
|
||||
dynamic(bool),
|
||||
scan(bool),
|
||||
theater_chase(uint32_t, uint32_t, bool),
|
||||
running_base(bool),
|
||||
@@ -671,16 +846,19 @@ class WS2812FX {
|
||||
CRGB twinklefox_one_twinkle(uint32_t ms, uint8_t salt, bool cat);
|
||||
CRGB pacifica_one_layer(uint16_t i, CRGBPalette16& p, uint16_t cistart, uint16_t wavescale, uint8_t bri, uint16_t ioff);
|
||||
|
||||
void blendPixelColor(uint16_t n, uint32_t color, uint8_t blend);
|
||||
void
|
||||
blendPixelColor(uint16_t n, uint32_t color, uint8_t blend),
|
||||
startTransition(uint8_t oldBri, uint32_t oldCol, uint16_t dur, uint8_t segn, uint8_t slot),
|
||||
deserializeMap(void);
|
||||
|
||||
uint16_t* customMappingTable = nullptr;
|
||||
uint16_t customMappingSize = 0;
|
||||
|
||||
uint32_t _lastPaletteChange = 0;
|
||||
uint32_t _lastShow = 0;
|
||||
|
||||
#ifdef WLED_USE_ANALOG_LEDS
|
||||
uint32_t _analogLastShow = 0;
|
||||
RgbwColor _analogLastColor = 0;
|
||||
uint8_t _analogLastBri = 0;
|
||||
#endif
|
||||
|
||||
uint32_t _colors_t[3];
|
||||
uint8_t _bri_t;
|
||||
|
||||
uint8_t _segment_index = 0;
|
||||
uint8_t _segment_index_palette_last = 99;
|
||||
@@ -691,7 +869,12 @@ class WS2812FX {
|
||||
segment_runtime _segment_runtimes[MAX_NUM_SEGMENTS]; // SRAM footprint: 28 bytes per element
|
||||
friend class Segment_runtime;
|
||||
|
||||
uint16_t realPixelIndex(uint16_t i);
|
||||
ColorTransition transitions[MAX_NUM_TRANSITIONS]; //12 bytes per element
|
||||
friend class ColorTransition;
|
||||
|
||||
uint16_t
|
||||
realPixelIndex(uint16_t i),
|
||||
transitionProgress(uint8_t tNr);
|
||||
};
|
||||
|
||||
//10 names per line
|
||||
@@ -699,15 +882,15 @@ const char JSON_mode_names[] PROGMEM = R"=====([
|
||||
"Solid","Blink","Breathe","Wipe","Wipe Random","Random Colors","Sweep","Dynamic","Colorloop","Rainbow",
|
||||
"Scan","Scan Dual","Fade","Theater","Theater Rainbow","Running","Saw","Twinkle","Dissolve","Dissolve Rnd",
|
||||
"Sparkle","Sparkle Dark","Sparkle+","Strobe","Strobe Rainbow","Strobe Mega","Blink Rainbow","Android","Chase","Chase Random",
|
||||
"Chase Rainbow","Chase Flash","Chase Flash Rnd","Rainbow Runner","Colorful","Traffic Light","Sweep Random","Running 2","Red & Blue","Stream",
|
||||
"Scanner","Lighthouse","Fireworks","Rain","Merry Christmas","Fire Flicker","Gradient","Loading","Police","Police All",
|
||||
"Chase Rainbow","Chase Flash","Chase Flash Rnd","Rainbow Runner","Colorful","Traffic Light","Sweep Random","Running 2","Aurora","Stream",
|
||||
"Scanner","Lighthouse","Fireworks","Rain","Tetrix","Fire Flicker","Gradient","Loading","Police","Police All",
|
||||
"Two Dots","Two Areas","Circus","Halloween","Tri Chase","Tri Wipe","Tri Fade","Lightning","ICU","Multi Comet",
|
||||
"Scanner Dual","Stream 2","Oscillate","Pride 2015","Juggle","Palette","Fire 2012","Colorwaves","Bpm","Fill Noise",
|
||||
"Noise 1","Noise 2","Noise 3","Noise 4","Colortwinkles","Lake","Meteor","Meteor Smooth","Railway","Ripple",
|
||||
"Twinklefox","Twinklecat","Halloween Eyes","Solid Pattern","Solid Pattern Tri","Spots","Spots Fade","Glitter","Candle","Fireworks Starburst",
|
||||
"Fireworks 1D","Bouncing Balls","Sinelon","Sinelon Dual","Sinelon Rainbow","Popcorn","Drip","Plasma","Percent","Ripple Rainbow",
|
||||
"Heartbeat","Pacifica","Candle Multi", "Solid Glitter","Sunrise","Phased","Twinkleup","Noise Pal", "Sine","Phased Noise",
|
||||
"Flow","Chunchun","Dancing Shadows"
|
||||
"Flow","Chunchun","Dancing Shadows","Washing Machine","Candy Cane","Blends","TV Simulator","Dynamic Smooth"
|
||||
])=====";
|
||||
|
||||
|
||||
@@ -717,7 +900,7 @@ const char JSON_palette_names[] PROGMEM = R"=====([
|
||||
"Pastel","Sunset 2","Beech","Vintage","Departure","Landscape","Beach","Sherbet","Hult","Hult 64",
|
||||
"Drywet","Jul","Grintage","Rewhi","Tertiary","Fire","Icefire","Cyane","Light Pink","Autumn",
|
||||
"Magenta","Magred","Yelmag","Yelblu","Orange & Teal","Tiamat","April Night","Orangery","C9","Sakura",
|
||||
"Aurora","Atlantica"
|
||||
"Aurora","Atlantica","C9 2","C9 New","Temperature","Aurora 2"
|
||||
])=====";
|
||||
|
||||
#endif
|
||||
|
||||
@@ -27,44 +27,59 @@
|
||||
#include "FX.h"
|
||||
#include "palettes.h"
|
||||
|
||||
//enable custom per-LED mapping. This can allow for better effects on matrices or special displays
|
||||
//#define WLED_CUSTOM_LED_MAPPING
|
||||
/*
|
||||
Custom per-LED mapping has moved!
|
||||
|
||||
#ifdef WLED_CUSTOM_LED_MAPPING
|
||||
//this is just an example (30 LEDs). It will first set all even, then all uneven LEDs.
|
||||
const uint16_t customMappingTable[] = {
|
||||
Create a file "ledmap.json" using the edit page.
|
||||
|
||||
this is just an example (30 LEDs). It will first set all even, then all uneven LEDs.
|
||||
{"map":[
|
||||
0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28,
|
||||
1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29};
|
||||
1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29]}
|
||||
|
||||
//another example. Switches direction every 5 LEDs.
|
||||
/*const uint16_t customMappingTable[] = {
|
||||
another example. Switches direction every 5 LEDs.
|
||||
{"map":[
|
||||
0, 1, 2, 3, 4, 9, 8, 7, 6, 5, 10, 11, 12, 13, 14,
|
||||
19, 18, 17, 16, 15, 20, 21, 22, 23, 24, 29, 28, 27, 26, 25};*/
|
||||
19, 18, 17, 16, 15, 20, 21, 22, 23, 24, 29, 28, 27, 26, 25]
|
||||
*/
|
||||
|
||||
const uint16_t customMappingSize = sizeof(customMappingTable)/sizeof(uint16_t); //30 in example
|
||||
#endif
|
||||
|
||||
void WS2812FX::init(bool supportWhite, uint16_t countPixels, bool skipFirst)
|
||||
//do not call this method from system context (network callback)
|
||||
void WS2812FX::finalizeInit(uint16_t countPixels, bool skipFirst)
|
||||
{
|
||||
if (supportWhite == _useRgbw && countPixels == _length && _skipFirstMode == skipFirst) return;
|
||||
RESET_RUNTIME;
|
||||
_useRgbw = supportWhite;
|
||||
_length = countPixels;
|
||||
_skipFirstMode = skipFirst;
|
||||
|
||||
uint8_t ty = 1;
|
||||
if (supportWhite) ty = 2;
|
||||
_lengthRaw = _length;
|
||||
if (_skipFirstMode) {
|
||||
_lengthRaw += LED_SKIP_AMOUNT;
|
||||
}
|
||||
|
||||
bus->Begin((NeoPixelType)ty, _lengthRaw);
|
||||
//if busses failed to load, add default (FS issue...)
|
||||
if (busses.getNumBusses() == 0) {
|
||||
uint8_t defPin[] = {LEDPIN};
|
||||
BusConfig defCfg = BusConfig(TYPE_WS2812_RGB, defPin, 0, _lengthRaw, COL_ORDER_GRB);
|
||||
busses.add(defCfg);
|
||||
}
|
||||
|
||||
deserializeMap();
|
||||
|
||||
//make segment 0 cover the entire strip
|
||||
_segments[0].start = 0;
|
||||
_segments[0].stop = _length;
|
||||
|
||||
setBrightness(_brightness);
|
||||
|
||||
#ifdef ESP8266
|
||||
for (uint8_t i = 0; i < busses.getNumBusses(); i++) {
|
||||
Bus* b = busses.getBus(i);
|
||||
if ((!IS_DIGITAL(b->getType()) || IS_2PIN(b->getType()))) continue;
|
||||
uint8_t pins[5];
|
||||
b->getPins(pins);
|
||||
BusDigital* bd = static_cast<BusDigital*>(b);
|
||||
if (pins[0] == 3) bd->reinit();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void WS2812FX::service() {
|
||||
@@ -76,23 +91,36 @@ void WS2812FX::service() {
|
||||
for(uint8_t i=0; i < MAX_NUM_SEGMENTS; i++)
|
||||
{
|
||||
_segment_index = i;
|
||||
if (SEGMENT.isActive())
|
||||
|
||||
// reset the segment runtime data if needed, called before isActive to ensure deleted
|
||||
// segment's buffers are cleared
|
||||
SEGENV.resetIfRequired();
|
||||
|
||||
if (!SEGMENT.isActive()) continue;
|
||||
|
||||
if(nowUp > SEGENV.next_time || _triggered || (doShow && SEGMENT.mode == 0)) //last is temporary
|
||||
{
|
||||
if(nowUp > SEGENV.next_time || _triggered || (doShow && SEGMENT.mode == 0)) //last is temporary
|
||||
{
|
||||
if (SEGMENT.grouping == 0) SEGMENT.grouping = 1; //sanity check
|
||||
doShow = true;
|
||||
uint16_t delay = FRAMETIME;
|
||||
if (SEGMENT.grouping == 0) SEGMENT.grouping = 1; //sanity check
|
||||
doShow = true;
|
||||
uint16_t delay = FRAMETIME;
|
||||
|
||||
if (!SEGMENT.getOption(SEG_OPTION_FREEZE)) { //only run effect function if not frozen
|
||||
_virtualSegmentLength = SEGMENT.virtualLength();
|
||||
handle_palette();
|
||||
delay = (this->*_mode[SEGMENT.mode])(); //effect function
|
||||
if (SEGMENT.mode != FX_MODE_HALLOWEEN_EYES) SEGENV.call++;
|
||||
if (!SEGMENT.getOption(SEG_OPTION_FREEZE)) { //only run effect function if not frozen
|
||||
_virtualSegmentLength = SEGMENT.virtualLength();
|
||||
_bri_t = SEGMENT.opacity; _colors_t[0] = SEGMENT.colors[0]; _colors_t[1] = SEGMENT.colors[1]; _colors_t[2] = SEGMENT.colors[2];
|
||||
if (!IS_SEGMENT_ON) _bri_t = 0;
|
||||
for (uint8_t t = 0; t < MAX_NUM_TRANSITIONS; t++) {
|
||||
if ((transitions[t].segment & 0x3F) != i) continue;
|
||||
uint8_t slot = transitions[t].segment >> 6;
|
||||
if (slot == 0) _bri_t = transitions[t].currentBri();
|
||||
_colors_t[slot] = transitions[t].currentColor(SEGMENT.colors[slot]);
|
||||
}
|
||||
|
||||
SEGENV.next_time = nowUp + delay;
|
||||
for (uint8_t c = 0; c < 3; c++) _colors_t[c] = gamma32(_colors_t[c]);
|
||||
handle_palette();
|
||||
delay = (this->*_mode[SEGMENT.mode])(); //effect function
|
||||
if (SEGMENT.mode != FX_MODE_HALLOWEEN_EYES) SEGENV.call++;
|
||||
}
|
||||
|
||||
SEGENV.next_time = nowUp + delay;
|
||||
}
|
||||
}
|
||||
_virtualSegmentLength = 0;
|
||||
@@ -111,8 +139,6 @@ void WS2812FX::setPixelColor(uint16_t n, uint32_t c) {
|
||||
setPixelColor(n, r, g, b, w);
|
||||
}
|
||||
|
||||
#define REV(i) (_length - 1 - (i))
|
||||
|
||||
//used to map from segment index to physical pixel, taking into account grouping, offsets, reverse and mirroring
|
||||
uint16_t WS2812FX::realPixelIndex(uint16_t i) {
|
||||
int16_t iGroup = i * SEGMENT.groupLength();
|
||||
@@ -128,8 +154,6 @@ uint16_t WS2812FX::realPixelIndex(uint16_t i) {
|
||||
}
|
||||
|
||||
realIndex += SEGMENT.start;
|
||||
/* Reverse the whole string */
|
||||
if (reverseMode) realIndex = REV(realIndex);
|
||||
|
||||
return realIndex;
|
||||
}
|
||||
@@ -137,7 +161,7 @@ uint16_t WS2812FX::realPixelIndex(uint16_t i) {
|
||||
void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
|
||||
{
|
||||
//auto calculate white channel value if enabled
|
||||
if (_useRgbw) {
|
||||
if (isRgbw) {
|
||||
if (rgbwMode == RGBW_MODE_AUTO_BRIGHTER || (w == 0 && (rgbwMode == RGBW_MODE_DUAL || rgbwMode == RGBW_MODE_LEGACY)))
|
||||
{
|
||||
//white value is set to lowest RGB channel
|
||||
@@ -150,67 +174,43 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
|
||||
}
|
||||
}
|
||||
|
||||
//reorder channels to selected order
|
||||
RgbwColor col;
|
||||
switch (colorOrder)
|
||||
{
|
||||
case 0: col.G = g; col.R = r; col.B = b; break; //0 = GRB, default
|
||||
case 1: col.G = r; col.R = g; col.B = b; break; //1 = RGB, common for WS2811
|
||||
case 2: col.G = b; col.R = r; col.B = g; break; //2 = BRG
|
||||
case 3: col.G = r; col.R = b; col.B = g; break; //3 = RBG
|
||||
case 4: col.G = b; col.R = g; col.B = r; break; //4 = BGR
|
||||
default: col.G = g; col.R = b; col.B = r; break; //5 = GBR
|
||||
}
|
||||
col.W = w;
|
||||
|
||||
uint16_t skip = _skipFirstMode ? LED_SKIP_AMOUNT : 0;
|
||||
if (SEGLEN) {//from segment
|
||||
|
||||
//color_blend(getpixel, col, SEGMENT.opacity); (pseudocode for future blending of segments)
|
||||
if (IS_SEGMENT_ON)
|
||||
{
|
||||
if (SEGMENT.opacity < 255) {
|
||||
col.R = scale8(col.R, SEGMENT.opacity);
|
||||
col.G = scale8(col.G, SEGMENT.opacity);
|
||||
col.B = scale8(col.B, SEGMENT.opacity);
|
||||
col.W = scale8(col.W, SEGMENT.opacity);
|
||||
}
|
||||
} else {
|
||||
col = BLACK;
|
||||
//color_blend(getpixel, col, _bri_t); (pseudocode for future blending of segments)
|
||||
if (_bri_t < 255) {
|
||||
r = scale8(r, _bri_t);
|
||||
g = scale8(g, _bri_t);
|
||||
b = scale8(b, _bri_t);
|
||||
w = scale8(w, _bri_t);
|
||||
}
|
||||
uint32_t col = ((w << 24) | (r << 16) | (g << 8) | (b));
|
||||
|
||||
/* Set all the pixels in the group, ensuring _skipFirstMode is honored */
|
||||
bool reversed = reverseMode ^ IS_REVERSE;
|
||||
bool reversed = IS_REVERSE;
|
||||
uint16_t realIndex = realPixelIndex(i);
|
||||
|
||||
for (uint16_t j = 0; j < SEGMENT.grouping; j++) {
|
||||
int16_t indexSet = realIndex + (reversed ? -j : j);
|
||||
int16_t indexSetRev = indexSet;
|
||||
if (reverseMode) indexSetRev = REV(indexSet);
|
||||
#ifdef WLED_CUSTOM_LED_MAPPING
|
||||
if (indexSet < customMappingSize) indexSet = customMappingTable[indexSet];
|
||||
#endif
|
||||
if (indexSetRev >= SEGMENT.start && indexSetRev < SEGMENT.stop) {
|
||||
bus->SetPixelColor(indexSet + skip, col);
|
||||
if (indexSet >= SEGMENT.start && indexSet < SEGMENT.stop) {
|
||||
busses.setPixelColor(indexSet + skip, col);
|
||||
if (IS_MIRROR) { //set the corresponding mirrored pixel
|
||||
if (reverseMode) {
|
||||
bus->SetPixelColor(REV(SEGMENT.start) - indexSet + skip + REV(SEGMENT.stop) + 1, col);
|
||||
} else {
|
||||
bus->SetPixelColor(SEGMENT.stop - indexSet + skip + SEGMENT.start - 1, col);
|
||||
}
|
||||
uint16_t indexMir = SEGMENT.stop - indexSet + SEGMENT.start - 1;
|
||||
if (indexMir < customMappingSize) indexMir = customMappingTable[indexMir];
|
||||
busses.setPixelColor(indexMir + skip, col);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { //live data, etc.
|
||||
if (reverseMode) i = REV(i);
|
||||
#ifdef WLED_CUSTOM_LED_MAPPING
|
||||
if (i < customMappingSize) i = customMappingTable[i];
|
||||
#endif
|
||||
bus->SetPixelColor(i + skip, col);
|
||||
|
||||
uint32_t col = ((w << 24) | (r << 16) | (g << 8) | (b));
|
||||
busses.setPixelColor(i + skip, col);
|
||||
}
|
||||
if (skip && i == 0) {
|
||||
for (uint16_t j = 0; j < skip; j++) {
|
||||
bus->SetPixelColor(j, RgbwColor(0, 0, 0, 0));
|
||||
busses.setPixelColor(j, BLACK);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -228,8 +228,11 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
|
||||
//you can set it to 0 if the ESP is powered by USB and the LEDs by external
|
||||
|
||||
void WS2812FX::show(void) {
|
||||
if (_callback) _callback();
|
||||
|
||||
|
||||
// avoid race condition, caputre _callback value
|
||||
show_callback callback = _callback;
|
||||
if (callback) callback();
|
||||
|
||||
//power limit calculation
|
||||
//each LED can draw up 195075 "power units" (approx. 53mA)
|
||||
//one PU is the power it takes to have 1 channel 1 step brighter per brightness step
|
||||
@@ -258,21 +261,22 @@ void WS2812FX::show(void) {
|
||||
|
||||
for (uint16_t i = 0; i < _length; i++) //sum up the usage of each LED
|
||||
{
|
||||
RgbwColor c = bus->GetPixelColorRgbw(i);
|
||||
uint32_t c = busses.getPixelColor(i);
|
||||
byte r = c >> 16, g = c >> 8, b = c, w = c >> 24;
|
||||
|
||||
if(useWackyWS2815PowerModel)
|
||||
{
|
||||
// ignore white component on WS2815 power calculation
|
||||
powerSum += (MAX(MAX(c.R,c.G),c.B)) * 3;
|
||||
powerSum += (MAX(MAX(r,g),b)) * 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
powerSum += (c.R + c.G + c.B + c.W);
|
||||
powerSum += (r + g + b + w);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (_useRgbw) //RGBW led total output with white LEDs enabled is still 50mA, so each channel uses less
|
||||
if (isRgbw) //RGBW led total output with white LEDs enabled is still 50mA, so each channel uses less
|
||||
{
|
||||
powerSum *= 3;
|
||||
powerSum = powerSum >> 2; //same as /= 4
|
||||
@@ -287,24 +291,52 @@ void WS2812FX::show(void) {
|
||||
uint16_t scaleI = scale * 255;
|
||||
uint8_t scaleB = (scaleI > 255) ? 255 : scaleI;
|
||||
uint8_t newBri = scale8(_brightness, scaleB);
|
||||
bus->SetBrightness(newBri);
|
||||
busses.setBrightness(newBri);
|
||||
currentMilliamps = (powerSum0 * newBri) / puPerMilliamp;
|
||||
} else
|
||||
{
|
||||
currentMilliamps = powerSum / puPerMilliamp;
|
||||
bus->SetBrightness(_brightness);
|
||||
busses.setBrightness(_brightness);
|
||||
}
|
||||
currentMilliamps += MA_FOR_ESP; //add power of ESP back to estimate
|
||||
currentMilliamps += _length; //add standby power back to estimate
|
||||
} else {
|
||||
currentMilliamps = 0;
|
||||
bus->SetBrightness(_brightness);
|
||||
busses.setBrightness(_brightness);
|
||||
}
|
||||
|
||||
bus->Show();
|
||||
_lastShow = millis();
|
||||
// some buses send asynchronously and this method will return before
|
||||
// all of the data has been sent.
|
||||
// See https://github.com/Makuna/NeoPixelBus/wiki/ESP32-NeoMethods#neoesp32rmt-methods
|
||||
busses.show();
|
||||
unsigned long now = millis();
|
||||
unsigned long diff = now - _lastShow;
|
||||
uint16_t fpsCurr = 200;
|
||||
if (diff > 0) fpsCurr = 1000 / diff;
|
||||
_cumulativeFps = (3 * _cumulativeFps + fpsCurr) >> 2;
|
||||
_lastShow = now;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a true value if any of the strips are still being updated.
|
||||
* On some hardware (ESP32), strip updates are done asynchronously.
|
||||
*/
|
||||
bool WS2812FX::isUpdating() {
|
||||
return !busses.canAllShow();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the refresh rate of the LED strip. Useful for finding out whether a given setup is fast enough.
|
||||
* Only updates on show() or is set to 0 fps if last show is more than 2 secs ago, so accurary varies
|
||||
*/
|
||||
uint16_t WS2812FX::getFps() {
|
||||
if (millis() - _lastShow > 2000) return 0;
|
||||
return _cumulativeFps +1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces the next frame to be computed on all active segments.
|
||||
*/
|
||||
void WS2812FX::trigger() {
|
||||
_triggered = true;
|
||||
}
|
||||
@@ -331,11 +363,10 @@ uint8_t WS2812FX::getPaletteCount()
|
||||
return 13 + GRADIENT_PALETTE_COUNT;
|
||||
}
|
||||
|
||||
//TODO transitions
|
||||
//TODO effect transitions
|
||||
|
||||
|
||||
bool WS2812FX::setEffectConfig(uint8_t m, uint8_t s, uint8_t in, uint8_t p) {
|
||||
uint8_t mainSeg = getMainSegmentId();
|
||||
Segment& seg = _segments[getMainSegmentId()];
|
||||
uint8_t modePrev = seg.mode, speedPrev = seg.speed, intensityPrev = seg.intensity, palettePrev = seg.palette;
|
||||
|
||||
@@ -378,20 +409,25 @@ void WS2812FX::setColor(uint8_t slot, uint32_t c) {
|
||||
if (applyToAllSelected) {
|
||||
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
|
||||
{
|
||||
if (_segments[i].isSelected()) _segments[i].colors[slot] = c;
|
||||
if (_segments[i].isSelected()) {
|
||||
_segments[i].setColor(slot, c, i);
|
||||
applied = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!applyToAllSelected || !applied) {
|
||||
_segments[getMainSegmentId()].colors[slot] = c;
|
||||
uint8_t mainseg = getMainSegmentId();
|
||||
_segments[mainseg].setColor(slot, c, mainseg);
|
||||
}
|
||||
}
|
||||
|
||||
void WS2812FX::setBrightness(uint8_t b) {
|
||||
if (gammaCorrectBri) b = gamma8(b);
|
||||
if (_brightness == b) return;
|
||||
_brightness = (gammaCorrectBri) ? gamma8(b) : b;
|
||||
_brightness = b;
|
||||
_segment_index = 0;
|
||||
if (b == 0) { //unfreeze all segments on power off
|
||||
if (_brightness == 0) { //unfreeze all segments on power off
|
||||
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
|
||||
{
|
||||
_segments[i].setOption(SEG_OPTION_FREEZE, false);
|
||||
@@ -447,26 +483,13 @@ uint32_t WS2812FX::getPixelColor(uint16_t i)
|
||||
{
|
||||
i = realPixelIndex(i);
|
||||
|
||||
#ifdef WLED_CUSTOM_LED_MAPPING
|
||||
if (i < customMappingSize) i = customMappingTable[i];
|
||||
#endif
|
||||
|
||||
if (_skipFirstMode) i += LED_SKIP_AMOUNT;
|
||||
|
||||
if (i >= _lengthRaw) return 0;
|
||||
|
||||
RgbwColor col = bus->GetPixelColorRgbw(i);
|
||||
switch (colorOrder)
|
||||
{
|
||||
// W G R B
|
||||
case 0: return ((col.W << 24) | (col.G << 8) | (col.R << 16) | (col.B)); //0 = GRB, default
|
||||
case 1: return ((col.W << 24) | (col.R << 8) | (col.G << 16) | (col.B)); //1 = RGB, common for WS2811
|
||||
case 2: return ((col.W << 24) | (col.B << 8) | (col.R << 16) | (col.G)); //2 = BRG
|
||||
case 3: return ((col.W << 24) | (col.B << 8) | (col.G << 16) | (col.R)); //3 = RBG
|
||||
case 4: return ((col.W << 24) | (col.R << 8) | (col.B << 16) | (col.G)); //4 = BGR
|
||||
case 5: return ((col.W << 24) | (col.G << 8) | (col.B << 16) | (col.R)); //5 = GBR
|
||||
}
|
||||
return 0;
|
||||
return busses.getPixelColor(i);
|
||||
}
|
||||
|
||||
WS2812FX::Segment& WS2812FX::getSegment(uint8_t id) {
|
||||
@@ -486,6 +509,15 @@ uint32_t WS2812FX::getLastShow(void) {
|
||||
return _lastShow;
|
||||
}
|
||||
|
||||
//TODO these need to be on a per-strip basis
|
||||
uint8_t WS2812FX::getColorOrder(void) {
|
||||
return COL_ORDER_GRB;
|
||||
}
|
||||
|
||||
void WS2812FX::setColorOrder(uint8_t co) {
|
||||
//bus->SetColorOrder(co);
|
||||
}
|
||||
|
||||
void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping, uint8_t spacing) {
|
||||
if (n >= MAX_NUM_SEGMENTS) return;
|
||||
Segment& seg = _segments[n];
|
||||
@@ -529,6 +561,7 @@ void WS2812FX::resetSegments() {
|
||||
_segments[0].colors[0] = DEFAULT_COLOR;
|
||||
_segments[0].start = 0;
|
||||
_segments[0].speed = DEFAULT_SPEED;
|
||||
_segments[0].intensity = DEFAULT_INTENSITY;
|
||||
_segments[0].stop = _length;
|
||||
_segments[0].grouping = 1;
|
||||
_segments[0].setOption(SEG_OPTION_SELECTED, 1);
|
||||
@@ -541,6 +574,8 @@ void WS2812FX::resetSegments() {
|
||||
_segments[i].grouping = 1;
|
||||
_segments[i].setOption(SEG_OPTION_ON, 1);
|
||||
_segments[i].opacity = 255;
|
||||
_segments[i].speed = DEFAULT_SPEED;
|
||||
_segments[i].intensity = DEFAULT_INTENSITY;
|
||||
_segment_runtimes[i].reset();
|
||||
}
|
||||
_segment_runtimes[0].reset();
|
||||
@@ -574,6 +609,11 @@ void WS2812FX::setShowCallback(show_callback cb)
|
||||
_callback = cb;
|
||||
}
|
||||
|
||||
void WS2812FX::setTransition(uint16_t t)
|
||||
{
|
||||
_transitionDur = t;
|
||||
}
|
||||
|
||||
void WS2812FX::setTransitionMode(bool t)
|
||||
{
|
||||
unsigned long waitMax = millis() + 20; //refresh after 20 ms if transition enabled
|
||||
@@ -589,24 +629,26 @@ void WS2812FX::setTransitionMode(bool t)
|
||||
/*
|
||||
* color blend function
|
||||
*/
|
||||
uint32_t WS2812FX::color_blend(uint32_t color1, uint32_t color2, uint8_t blend) {
|
||||
uint32_t WS2812FX::color_blend(uint32_t color1, uint32_t color2, uint16_t blend, bool b16) {
|
||||
if(blend == 0) return color1;
|
||||
if(blend == 255) return color2;
|
||||
uint16_t blendmax = b16 ? 0xFFFF : 0xFF;
|
||||
if(blend == blendmax) return color2;
|
||||
uint8_t shift = b16 ? 16 : 8;
|
||||
|
||||
uint32_t w1 = (color1 >> 24) & 0xff;
|
||||
uint32_t r1 = (color1 >> 16) & 0xff;
|
||||
uint32_t g1 = (color1 >> 8) & 0xff;
|
||||
uint32_t b1 = color1 & 0xff;
|
||||
uint32_t w1 = (color1 >> 24) & 0xFF;
|
||||
uint32_t r1 = (color1 >> 16) & 0xFF;
|
||||
uint32_t g1 = (color1 >> 8) & 0xFF;
|
||||
uint32_t b1 = color1 & 0xFF;
|
||||
|
||||
uint32_t w2 = (color2 >> 24) & 0xff;
|
||||
uint32_t r2 = (color2 >> 16) & 0xff;
|
||||
uint32_t g2 = (color2 >> 8) & 0xff;
|
||||
uint32_t b2 = color2 & 0xff;
|
||||
uint32_t w2 = (color2 >> 24) & 0xFF;
|
||||
uint32_t r2 = (color2 >> 16) & 0xFF;
|
||||
uint32_t g2 = (color2 >> 8) & 0xFF;
|
||||
uint32_t b2 = color2 & 0xFF;
|
||||
|
||||
uint32_t w3 = ((w2 * blend) + (w1 * (255 - blend))) >> 8;
|
||||
uint32_t r3 = ((r2 * blend) + (r1 * (255 - blend))) >> 8;
|
||||
uint32_t g3 = ((g2 * blend) + (g1 * (255 - blend))) >> 8;
|
||||
uint32_t b3 = ((b2 * blend) + (b1 * (255 - blend))) >> 8;
|
||||
uint32_t w3 = ((w2 * blend) + (w1 * (blendmax - blend))) >> shift;
|
||||
uint32_t r3 = ((r2 * blend) + (r1 * (blendmax - blend))) >> shift;
|
||||
uint32_t g3 = ((g2 * blend) + (g1 * (blendmax - blend))) >> shift;
|
||||
uint32_t b3 = ((b2 * blend) + (b1 * (blendmax - blend))) >> shift;
|
||||
|
||||
return ((w3 << 24) | (r3 << 16) | (g3 << 8) | (b3));
|
||||
}
|
||||
@@ -696,6 +738,32 @@ uint16_t WS2812FX::triwave16(uint16_t in)
|
||||
return 0xFFFF - (in - 0x8000)*2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generates a tristate square wave w/ attac & decay
|
||||
* @param x input value 0-255
|
||||
* @param pulsewidth 0-127
|
||||
* @param attdec attac & decay, max. pulsewidth / 2
|
||||
* @returns signed waveform value
|
||||
*/
|
||||
int8_t WS2812FX::tristate_square8(uint8_t x, uint8_t pulsewidth, uint8_t attdec) {
|
||||
int8_t a = 127;
|
||||
if (x > 127) {
|
||||
a = -127;
|
||||
x -= 127;
|
||||
}
|
||||
|
||||
if (x < attdec) { //inc to max
|
||||
return (int16_t) x * a / attdec;
|
||||
}
|
||||
else if (x < pulsewidth - attdec) { //max
|
||||
return a;
|
||||
}
|
||||
else if (x < pulsewidth) { //dec to 0
|
||||
return (int16_t) (pulsewidth - x) * a / attdec;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Put a value 0 to 255 in to get a color value.
|
||||
* The colours are a transition r -> g -> b -> back to r
|
||||
@@ -841,7 +909,7 @@ void WS2812FX::handle_palette(void)
|
||||
load_gradient_palette(paletteIndex -13);
|
||||
}
|
||||
|
||||
if (singleSegmentMode && paletteFade) //only blend if just one segment uses FastLED mode
|
||||
if (singleSegmentMode && paletteFade && SEGENV.call > 0) //only blend if just one segment uses FastLED mode
|
||||
{
|
||||
nblendPaletteTowardPalette(currentPalette, targetPalette, 48);
|
||||
} else
|
||||
@@ -862,13 +930,24 @@ void WS2812FX::handle_palette(void)
|
||||
*/
|
||||
uint32_t WS2812FX::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri)
|
||||
{
|
||||
if (SEGMENT.palette == 0 && mcol < 3) return SEGCOLOR(mcol); //WS2812FX default
|
||||
if (SEGMENT.palette == 0 && mcol < 3) {
|
||||
uint32_t color = SEGCOLOR(mcol);
|
||||
if (pbri != 255) {
|
||||
CRGB crgb_color = col_to_crgb(color);
|
||||
crgb_color.nscale8_video(pbri);
|
||||
return crgb_to_col(crgb_color);
|
||||
} else {
|
||||
return color;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t paletteIndex = i;
|
||||
if (mapping) paletteIndex = (i*255)/(SEGLEN -1);
|
||||
if (!wrap) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end"
|
||||
CRGB fastled_col;
|
||||
fastled_col = ColorFromPalette( currentPalette, paletteIndex, pbri, (paletteBlend == 3)? NOBLEND:LINEARBLEND);
|
||||
return fastled_col.r*65536 + fastled_col.g*256 + fastled_col.b;
|
||||
|
||||
return crgb_to_col(fastled_col);
|
||||
}
|
||||
|
||||
//@returns `true` if color, mode, speed, intensity and palette match
|
||||
@@ -888,44 +967,34 @@ bool WS2812FX::segmentsAreIdentical(Segment* a, Segment* b)
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef WLED_USE_ANALOG_LEDS
|
||||
void WS2812FX::setRgbwPwm(void) {
|
||||
uint32_t nowUp = millis(); // Be aware, millis() rolls over every 49 days
|
||||
if (nowUp - _analogLastShow < MIN_SHOW_DELAY) return;
|
||||
|
||||
_analogLastShow = nowUp;
|
||||
//load custom mapping table from JSON file
|
||||
void WS2812FX::deserializeMap(void) {
|
||||
if (!WLED_FS.exists("/ledmap.json")) return;
|
||||
DynamicJsonDocument doc(JSON_BUFFER_SIZE); // full sized buffer for larger maps
|
||||
|
||||
RgbwColor color = bus->GetPixelColorRgbw(0);
|
||||
byte b = getBrightness();
|
||||
if (color == _analogLastColor && b == _analogLastBri) return;
|
||||
|
||||
// check color values for Warm / Cold white mix (for RGBW) // EsplanexaDevice.cpp
|
||||
#ifdef WLED_USE_5CH_LEDS
|
||||
if (color.R == 255 && color.G == 255 && color.B == 255 && color.W == 255) {
|
||||
bus->SetRgbwPwm(0, 0, 0, 0, color.W * b / 255);
|
||||
} else if (color.R == 127 && color.G == 127 && color.B == 127 && color.W == 255) {
|
||||
bus->SetRgbwPwm(0, 0, 0, color.W * b / 512, color.W * b / 255);
|
||||
} else if (color.R == 0 && color.G == 0 && color.B == 0 && color.W == 255) {
|
||||
bus->SetRgbwPwm(0, 0, 0, color.W * b / 255, 0);
|
||||
} else if (color.R == 130 && color.G == 90 && color.B == 0 && color.W == 255) {
|
||||
bus->SetRgbwPwm(0, 0, 0, color.W * b / 255, color.W * b / 512);
|
||||
} else if (color.R == 255 && color.G == 153 && color.B == 0 && color.W == 255) {
|
||||
bus->SetRgbwPwm(0, 0, 0, color.W * b / 255, 0);
|
||||
} else { // not only white colors
|
||||
bus->SetRgbwPwm(color.R * b / 255, color.G * b / 255, color.B * b / 255, color.W * b / 255);
|
||||
DEBUG_PRINTLN(F("Reading LED map from /ledmap.json..."));
|
||||
|
||||
if (!readObjectFromFile("/ledmap.json", nullptr, &doc)) return; //if file does not exist just exit
|
||||
|
||||
if (customMappingTable != nullptr) {
|
||||
delete[] customMappingTable;
|
||||
customMappingTable = nullptr;
|
||||
customMappingSize = 0;
|
||||
}
|
||||
|
||||
JsonArray map = doc[F("map")];
|
||||
if (!map.isNull() && map.size()) { // not an empty map
|
||||
customMappingSize = map.size();
|
||||
customMappingTable = new uint16_t[customMappingSize];
|
||||
for (uint16_t i=0; i<customMappingSize; i++) {
|
||||
customMappingTable[i] = (uint16_t) map[i];
|
||||
}
|
||||
#else
|
||||
bus->SetRgbwPwm(color.R * b / 255, color.G * b / 255, color.B * b / 255, color.W * b / 255);
|
||||
#endif
|
||||
_analogLastColor = color;
|
||||
_analogLastBri = b;
|
||||
}
|
||||
}
|
||||
#else
|
||||
void WS2812FX::setRgbwPwm() {}
|
||||
#endif
|
||||
|
||||
//gamma 2.4 lookup table used for color correction
|
||||
const byte gammaT[] = {
|
||||
//gamma 2.8 lookup table used for color correction
|
||||
byte gammaT[] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
|
||||
@@ -943,6 +1012,17 @@ const byte gammaT[] = {
|
||||
177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213,
|
||||
215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255 };
|
||||
|
||||
uint8_t WS2812FX::gamma8_cal(uint8_t b, float gamma) {
|
||||
return (int)(pow((float)b / 255.0, gamma) * 255 + 0.5);
|
||||
}
|
||||
|
||||
void WS2812FX::calcGammaTable(float gamma)
|
||||
{
|
||||
for (uint16_t i = 0; i < 256; i++) {
|
||||
gammaT[i] = gamma8_cal(i, gamma);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t WS2812FX::gamma8(uint8_t b)
|
||||
{
|
||||
return gammaT[b];
|
||||
@@ -962,4 +1042,4 @@ uint32_t WS2812FX::gamma32(uint32_t color)
|
||||
return ((w << 24) | (r << 16) | (g << 8) | (b));
|
||||
}
|
||||
|
||||
uint16_t WS2812FX::_usedSegmentData = 0;
|
||||
WS2812FX* WS2812FX::instance = nullptr;
|
||||
34
wled00/NodeStruct.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#ifndef WLED_NODESTRUCT_H
|
||||
#define WLED_NODESTRUCT_H
|
||||
|
||||
/*********************************************************************************************\
|
||||
* NodeStruct from the ESP Easy project (https://github.com/letscontrolit/ESPEasy)
|
||||
\*********************************************************************************************/
|
||||
|
||||
#include <map>
|
||||
#include <IPAddress.h>
|
||||
|
||||
#define NODE_TYPE_ID_UNDEFINED 0
|
||||
#define NODE_TYPE_ID_ESP8266 82
|
||||
#define NODE_TYPE_ID_ESP32 32
|
||||
|
||||
/*********************************************************************************************\
|
||||
* NodeStruct
|
||||
\*********************************************************************************************/
|
||||
struct NodeStruct
|
||||
{
|
||||
String nodeName;
|
||||
IPAddress ip;
|
||||
uint8_t unit;
|
||||
uint8_t age;
|
||||
uint8_t nodeType;
|
||||
uint32_t build;
|
||||
|
||||
NodeStruct() : age(0), nodeType(0), build(0)
|
||||
{
|
||||
for (uint8_t i = 0; i < 4; ++i) { ip[i] = 0; }
|
||||
}
|
||||
};
|
||||
typedef std::map<uint8_t, NodeStruct> NodesMap;
|
||||
|
||||
#endif // WLED_NODESTRUCT_H
|
||||
@@ -1,348 +0,0 @@
|
||||
//this code is a modified version of https://github.com/Makuna/NeoPixelBus/issues/103
|
||||
#ifndef NpbWrapper_h
|
||||
#define NpbWrapper_h
|
||||
|
||||
//PIN CONFIGURATION
|
||||
#ifndef LEDPIN
|
||||
#define LEDPIN 2 //strip pin. Any for ESP32, gpio2 or 3 is recommended for ESP8266 (gpio2/3 are labeled D4/RX on NodeMCU and Wemos)
|
||||
#endif
|
||||
//#define USE_APA102 // Uncomment for using APA102 LEDs.
|
||||
//#define USE_WS2801 // Uncomment for using WS2801 LEDs (make sure you have NeoPixelBus v2.5.6 or newer)
|
||||
//#define USE_LPD8806 // Uncomment for using LPD8806
|
||||
//#define USE_TM1814 // Uncomment for using TM1814 LEDs (make sure you have NeoPixelBus v2.5.7 or newer)
|
||||
//#define USE_P9813 // Uncomment for using P9813 LEDs (make sure you have NeoPixelBus v2.5.8 or newer)
|
||||
//#define WLED_USE_ANALOG_LEDS //Uncomment for using "dumb" PWM controlled LEDs (see pins below, default R: gpio5, G: 12, B: 15, W: 13)
|
||||
//#define WLED_USE_H801 //H801 controller. Please uncomment #define WLED_USE_ANALOG_LEDS as well
|
||||
//#define WLED_USE_5CH_LEDS //5 Channel H801 for cold and warm white
|
||||
//#define WLED_USE_BWLT11
|
||||
//#define WLED_USE_SHOJO_PCB
|
||||
|
||||
#ifndef BTNPIN
|
||||
#define BTNPIN 0 //button pin. Needs to have pullup (gpio0 recommended)
|
||||
#endif
|
||||
|
||||
#ifndef IR_PIN
|
||||
#define IR_PIN 4 //infrared pin (-1 to disable) MagicHome: 4, H801 Wifi: 0
|
||||
#endif
|
||||
|
||||
#ifndef RLYPIN
|
||||
#define RLYPIN 12 //pin for relay, will be set HIGH if LEDs are on (-1 to disable). Also usable for standby leds, triggers,...
|
||||
#endif
|
||||
|
||||
#ifndef AUXPIN
|
||||
#define AUXPIN -1 //debug auxiliary output pin (-1 to disable)
|
||||
#endif
|
||||
|
||||
#ifndef RLYMDE
|
||||
#define RLYMDE 1 //mode for relay, 0: LOW if LEDs are on 1: HIGH if LEDs are on
|
||||
#endif
|
||||
|
||||
//END CONFIGURATION
|
||||
|
||||
#if defined(USE_APA102) || defined(USE_WS2801) || defined(USE_LPD8806) || defined(USE_P9813)
|
||||
#ifndef CLKPIN
|
||||
#define CLKPIN 0
|
||||
#endif
|
||||
#ifndef DATAPIN
|
||||
#define DATAPIN 2
|
||||
#endif
|
||||
#if BTNPIN == CLKPIN || BTNPIN == DATAPIN
|
||||
#undef BTNPIN // Deactivate button pin if it conflicts with one of the APA102 pins.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef WLED_USE_ANALOG_LEDS
|
||||
//PWM pins - PINs 15,13,12,14 (W2 = 04)are used with H801 Wifi LED Controller
|
||||
#ifdef WLED_USE_H801
|
||||
#define RPIN 15 //R pin for analog LED strip
|
||||
#define GPIN 13 //G pin for analog LED strip
|
||||
#define BPIN 12 //B pin for analog LED strip
|
||||
#define WPIN 14 //W pin for analog LED strip
|
||||
#define W2PIN 04 //W2 pin for analog LED strip
|
||||
#undef BTNPIN
|
||||
#undef IR_PIN
|
||||
#define IR_PIN 0 //infrared pin (-1 to disable) MagicHome: 4, H801 Wifi: 0
|
||||
#elif defined(WLED_USE_BWLT11)
|
||||
//PWM pins - to use with BW-LT11
|
||||
#define RPIN 12 //R pin for analog LED strip
|
||||
#define GPIN 4 //G pin for analog LED strip
|
||||
#define BPIN 14 //B pin for analog LED strip
|
||||
#define WPIN 5 //W pin for analog LED strip
|
||||
#elif defined(WLED_USE_SHOJO_PCB)
|
||||
//PWM pins - to use with Shojo PCB (https://www.bastelbunker.de/esp-rgbww-wifi-led-controller-vbs-edition/)
|
||||
#define RPIN 14 //R pin for analog LED strip
|
||||
#define GPIN 4 //G pin for analog LED strip
|
||||
#define BPIN 5 //B pin for analog LED strip
|
||||
#define WPIN 15 //W pin for analog LED strip
|
||||
#define W2PIN 12 //W2 pin for analog LED strip
|
||||
#elif defined(WLED_USE_PLJAKOBS_PCB)
|
||||
// PWM pins - to use with esp_rgbww_controller from patrickjahns/pljakobs (https://github.com/pljakobs/esp_rgbww_controller)
|
||||
#define RPIN 12 //R pin for analog LED strip
|
||||
#define GPIN 13 //G pin for analog LED strip
|
||||
#define BPIN 14 //B pin for analog LED strip
|
||||
#define WPIN 4 //W pin for analog LED strip
|
||||
#define W2PIN 5 //W2 pin for analog LED strip
|
||||
#undef IR_PIN
|
||||
#else
|
||||
//PWM pins - PINs 5,12,13,15 are used with Magic Home LED Controller
|
||||
#define RPIN 5 //R pin for analog LED strip
|
||||
#define GPIN 12 //G pin for analog LED strip
|
||||
#define BPIN 15 //B pin for analog LED strip
|
||||
#define WPIN 13 //W pin for analog LED strip
|
||||
#endif
|
||||
#undef RLYPIN
|
||||
#define RLYPIN -1 //disable as pin 12 is used by analog LEDs
|
||||
#endif
|
||||
|
||||
//automatically uses the right driver method for each platform
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#ifdef USE_APA102
|
||||
#define PIXELMETHOD DotStarMethod
|
||||
#elif defined(USE_WS2801)
|
||||
#define PIXELMETHOD NeoWs2801Method
|
||||
#elif defined(USE_LPD8806)
|
||||
#define PIXELMETHOD Lpd8806Method
|
||||
#elif defined(USE_TM1814)
|
||||
#define PIXELMETHOD NeoTm1814Method
|
||||
#elif defined(USE_P9813)
|
||||
#define PIXELMETHOD P9813Method
|
||||
#else
|
||||
#define PIXELMETHOD NeoEsp32Rmt0Ws2812xMethod
|
||||
#endif
|
||||
#else //esp8266
|
||||
//autoselect the right method depending on strip pin
|
||||
#ifdef USE_APA102
|
||||
#define PIXELMETHOD DotStarMethod
|
||||
#elif defined(USE_WS2801)
|
||||
#define PIXELMETHOD NeoWs2801Method
|
||||
#elif defined(USE_LPD8806)
|
||||
#define PIXELMETHOD Lpd8806Method
|
||||
#elif defined(USE_TM1814)
|
||||
#define PIXELMETHOD NeoTm1814Method
|
||||
#elif defined(USE_P9813)
|
||||
#define PIXELMETHOD P9813Method
|
||||
#elif LEDPIN == 2
|
||||
#define PIXELMETHOD NeoEsp8266Uart1Ws2813Method //if you get an error here, try to change to NeoEsp8266UartWs2813Method or update Neopixelbus
|
||||
#elif LEDPIN == 3
|
||||
#define PIXELMETHOD NeoEsp8266Dma800KbpsMethod
|
||||
#else
|
||||
#define PIXELMETHOD NeoEsp8266BitBang800KbpsMethod
|
||||
#pragma message "Software BitBang will be used because of your selected LED pin. This may cause flicker. Use GPIO 2 or 3 for best results."
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
//you can now change the color order in the web settings
|
||||
#ifdef USE_APA102
|
||||
#define PIXELFEATURE3 DotStarBgrFeature
|
||||
#define PIXELFEATURE4 DotStarLbgrFeature
|
||||
#elif defined(USE_LPD8806)
|
||||
#define PIXELFEATURE3 Lpd8806GrbFeature
|
||||
#elif defined(USE_WS2801)
|
||||
#define PIXELFEATURE3 NeoRbgFeature
|
||||
#define PIXELFEATURE4 NeoRbgFeature
|
||||
#elif defined(USE_TM1814)
|
||||
#define PIXELFEATURE3 NeoWrgbTm1814Feature
|
||||
#define PIXELFEATURE4 NeoWrgbTm1814Feature
|
||||
#elif defined(USE_P9813)
|
||||
#define PIXELFEATURE3 P9813BgrFeature
|
||||
#define PIXELFEATURE4 NeoGrbwFeature
|
||||
#else
|
||||
#define PIXELFEATURE3 NeoGrbFeature
|
||||
#define PIXELFEATURE4 NeoGrbwFeature
|
||||
#endif
|
||||
|
||||
|
||||
#include <NeoPixelBrightnessBus.h>
|
||||
|
||||
enum NeoPixelType
|
||||
{
|
||||
NeoPixelType_None = 0,
|
||||
NeoPixelType_Grb = 1,
|
||||
NeoPixelType_Grbw = 2,
|
||||
NeoPixelType_End = 3
|
||||
};
|
||||
|
||||
class NeoPixelWrapper
|
||||
{
|
||||
public:
|
||||
NeoPixelWrapper() :
|
||||
// initialize each member to null
|
||||
_pGrb(NULL),
|
||||
_pGrbw(NULL),
|
||||
_type(NeoPixelType_None)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
~NeoPixelWrapper()
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
|
||||
void Begin(NeoPixelType type, uint16_t countPixels)
|
||||
{
|
||||
cleanup();
|
||||
_type = type;
|
||||
|
||||
switch (_type)
|
||||
{
|
||||
case NeoPixelType_Grb:
|
||||
#if defined(USE_APA102) || defined(USE_WS2801) || defined(USE_LPD8806) || defined(USE_P9813)
|
||||
_pGrb = new NeoPixelBrightnessBus<PIXELFEATURE3,PIXELMETHOD>(countPixels, CLKPIN, DATAPIN);
|
||||
#else
|
||||
_pGrb = new NeoPixelBrightnessBus<PIXELFEATURE3,PIXELMETHOD>(countPixels, LEDPIN);
|
||||
#endif
|
||||
_pGrb->Begin();
|
||||
break;
|
||||
|
||||
case NeoPixelType_Grbw:
|
||||
#if defined(USE_APA102) || defined(USE_WS2801) || defined(USE_LPD8806) || defined(USE_P9813)
|
||||
_pGrbw = new NeoPixelBrightnessBus<PIXELFEATURE4,PIXELMETHOD>(countPixels, CLKPIN, DATAPIN);
|
||||
#else
|
||||
_pGrbw = new NeoPixelBrightnessBus<PIXELFEATURE4,PIXELMETHOD>(countPixels, LEDPIN);
|
||||
#endif
|
||||
_pGrbw->Begin();
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef WLED_USE_ANALOG_LEDS
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
ledcSetup(0, 5000, 8);
|
||||
ledcAttachPin(RPIN, 0);
|
||||
ledcSetup(1, 5000, 8);
|
||||
ledcAttachPin(GPIN, 1);
|
||||
ledcSetup(2, 5000, 8);
|
||||
ledcAttachPin(BPIN, 2);
|
||||
if(_type == NeoPixelType_Grbw)
|
||||
{
|
||||
ledcSetup(3, 5000, 8);
|
||||
ledcAttachPin(WPIN, 3);
|
||||
#ifdef WLED_USE_5CH_LEDS
|
||||
ledcSetup(4, 5000, 8);
|
||||
ledcAttachPin(W2PIN, 4);
|
||||
#endif
|
||||
}
|
||||
#else // ESP8266
|
||||
//init PWM pins
|
||||
pinMode(RPIN, OUTPUT);
|
||||
pinMode(GPIN, OUTPUT);
|
||||
pinMode(BPIN, OUTPUT);
|
||||
if(_type == NeoPixelType_Grbw)
|
||||
{
|
||||
pinMode(WPIN, OUTPUT);
|
||||
#ifdef WLED_USE_5CH_LEDS
|
||||
pinMode(W2PIN, OUTPUT);
|
||||
#endif
|
||||
}
|
||||
analogWriteRange(255); //same range as one RGB channel
|
||||
analogWriteFreq(880); //PWM frequency proven as good for LEDs
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef WLED_USE_ANALOG_LEDS
|
||||
void SetRgbwPwm(uint8_t r, uint8_t g, uint8_t b, uint8_t w, uint8_t w2=0)
|
||||
{
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
ledcWrite(0, r);
|
||||
ledcWrite(1, g);
|
||||
ledcWrite(2, b);
|
||||
switch (_type) {
|
||||
case NeoPixelType_Grb: break;
|
||||
#ifdef WLED_USE_5CH_LEDS
|
||||
case NeoPixelType_Grbw: ledcWrite(3, w); ledcWrite(4, w2); break;
|
||||
#else
|
||||
case NeoPixelType_Grbw: ledcWrite(3, w); break;
|
||||
#endif
|
||||
}
|
||||
#else // ESP8266
|
||||
analogWrite(RPIN, r);
|
||||
analogWrite(GPIN, g);
|
||||
analogWrite(BPIN, b);
|
||||
switch (_type) {
|
||||
case NeoPixelType_Grb: break;
|
||||
#ifdef WLED_USE_5CH_LEDS
|
||||
case NeoPixelType_Grbw: analogWrite(WPIN, w); analogWrite(W2PIN, w2); break;
|
||||
#else
|
||||
case NeoPixelType_Grbw: analogWrite(WPIN, w); break;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
void Show()
|
||||
{
|
||||
byte b;
|
||||
switch (_type)
|
||||
{
|
||||
case NeoPixelType_Grb: _pGrb->Show(); break;
|
||||
case NeoPixelType_Grbw: _pGrbw->Show(); break;
|
||||
}
|
||||
}
|
||||
|
||||
void SetPixelColor(uint16_t indexPixel, RgbwColor color)
|
||||
{
|
||||
switch (_type) {
|
||||
case NeoPixelType_Grb: {
|
||||
_pGrb->SetPixelColor(indexPixel, RgbColor(color.R,color.G,color.B));
|
||||
}
|
||||
break;
|
||||
case NeoPixelType_Grbw: {
|
||||
#if defined(USE_LPD8806) || defined(USE_WS2801)
|
||||
_pGrbw->SetPixelColor(indexPixel, RgbColor(color.R,color.G,color.B));
|
||||
#else
|
||||
_pGrbw->SetPixelColor(indexPixel, color);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SetBrightness(byte b)
|
||||
{
|
||||
switch (_type) {
|
||||
case NeoPixelType_Grb: _pGrb->SetBrightness(b); break;
|
||||
case NeoPixelType_Grbw:_pGrbw->SetBrightness(b); break;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Due to feature differences, some support RGBW but the method name
|
||||
// here needs to be unique, thus GetPixeColorRgbw
|
||||
RgbwColor GetPixelColorRgbw(uint16_t indexPixel) const
|
||||
{
|
||||
switch (_type) {
|
||||
case NeoPixelType_Grb: return _pGrb->GetPixelColor(indexPixel); break;
|
||||
case NeoPixelType_Grbw: return _pGrbw->GetPixelColor(indexPixel); break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t* GetPixels(void)
|
||||
{
|
||||
switch (_type) {
|
||||
case NeoPixelType_Grb: return _pGrb->Pixels(); break;
|
||||
case NeoPixelType_Grbw: return _pGrbw->Pixels(); break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
NeoPixelType _type;
|
||||
|
||||
// have a member for every possible type
|
||||
NeoPixelBrightnessBus<PIXELFEATURE3,PIXELMETHOD>* _pGrb;
|
||||
NeoPixelBrightnessBus<PIXELFEATURE4,PIXELMETHOD>* _pGrbw;
|
||||
|
||||
void cleanup()
|
||||
{
|
||||
switch (_type) {
|
||||
case NeoPixelType_Grb: delete _pGrb ; _pGrb = NULL; break;
|
||||
case NeoPixelType_Grbw: delete _pGrbw; _pGrbw = NULL; break;
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif
|
||||
@@ -46,7 +46,7 @@ void onAlexaChange(EspalexaDevice* dev)
|
||||
bri = briLast;
|
||||
colorUpdated(NOTIFIER_CALL_MODE_ALEXA);
|
||||
}
|
||||
} else applyMacro(macroAlexaOn);
|
||||
} else applyPreset(macroAlexaOn);
|
||||
} else if (m == EspalexaDeviceProperty::off)
|
||||
{
|
||||
if (!macroAlexaOff)
|
||||
@@ -57,7 +57,7 @@ void onAlexaChange(EspalexaDevice* dev)
|
||||
bri = 0;
|
||||
colorUpdated(NOTIFIER_CALL_MODE_ALEXA);
|
||||
}
|
||||
} else applyMacro(macroAlexaOff);
|
||||
} else applyPreset(macroAlexaOff);
|
||||
} else if (m == EspalexaDeviceProperty::bri)
|
||||
{
|
||||
bri = espalexaDevice->getValue();
|
||||
@@ -67,7 +67,7 @@ void onAlexaChange(EspalexaDevice* dev)
|
||||
if (espalexaDevice->getColorMode() == EspalexaColorMode::ct) //shade of white
|
||||
{
|
||||
uint16_t ct = espalexaDevice->getCt();
|
||||
if (useRGBW)
|
||||
if (strip.isRgbw)
|
||||
{
|
||||
switch (ct) { //these values empirically look good on RGBW
|
||||
case 199: col[0]=255; col[1]=255; col[2]=255; col[3]=255; break;
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
uint16_t blHue = 0;
|
||||
byte blSat = 255;
|
||||
|
||||
void initBlynk(const char* auth)
|
||||
void initBlynk(const char *auth, const char *host, uint16_t port)
|
||||
{
|
||||
#ifndef WLED_DISABLE_BLYNK
|
||||
if (!WLED_CONNECTED) return;
|
||||
blynkEnabled = (auth[0] != 0);
|
||||
if (blynkEnabled) Blynk.config(auth);
|
||||
if (blynkEnabled) Blynk.config(auth, host, port);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
406
wled00/bus_manager.h
Normal file
@@ -0,0 +1,406 @@
|
||||
#ifndef BusManager_h
|
||||
#define BusManager_h
|
||||
|
||||
/*
|
||||
* Class for addressing various light types
|
||||
*/
|
||||
|
||||
#include "const.h"
|
||||
#include "pin_manager.h"
|
||||
#include "bus_wrapper.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
//temporary struct for passing bus configuration to bus
|
||||
struct BusConfig {
|
||||
uint8_t type = TYPE_WS2812_RGB;
|
||||
uint16_t count = 1;
|
||||
uint16_t start = 0;
|
||||
uint8_t colorOrder = COL_ORDER_GRB;
|
||||
bool reversed = false;
|
||||
uint8_t pins[5] = {LEDPIN, 255, 255, 255, 255};
|
||||
BusConfig(uint8_t busType, uint8_t* ppins, uint16_t pstart, uint16_t len = 1, uint8_t pcolorOrder = COL_ORDER_GRB, bool rev = false) {
|
||||
type = busType; count = len; start = pstart; colorOrder = pcolorOrder; reversed = rev;
|
||||
uint8_t nPins = 1;
|
||||
if (type > 47) nPins = 2;
|
||||
else if (type > 41 && type < 46) nPins = NUM_PWM_PINS(type);
|
||||
for (uint8_t i = 0; i < nPins; i++) pins[i] = ppins[i];
|
||||
}
|
||||
};
|
||||
|
||||
//parent class of BusDigital and BusPwm
|
||||
class Bus {
|
||||
public:
|
||||
Bus(uint8_t type, uint16_t start) {
|
||||
_type = type;
|
||||
_start = start;
|
||||
};
|
||||
|
||||
virtual void show() {}
|
||||
virtual bool canShow() { return true; }
|
||||
|
||||
virtual void setPixelColor(uint16_t pix, uint32_t c) {};
|
||||
|
||||
virtual void setBrightness(uint8_t b) {};
|
||||
|
||||
virtual uint32_t getPixelColor(uint16_t pix) { return 0; };
|
||||
|
||||
virtual void cleanup() {};
|
||||
|
||||
virtual ~Bus() { //throw the bus under the bus
|
||||
}
|
||||
|
||||
virtual uint8_t getPins(uint8_t* pinArray) { return 0; }
|
||||
|
||||
uint16_t getStart() {
|
||||
return _start;
|
||||
}
|
||||
|
||||
void setStart(uint16_t start) {
|
||||
_start = start;
|
||||
}
|
||||
|
||||
virtual uint16_t getLength() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
virtual void setColorOrder() {}
|
||||
|
||||
virtual uint8_t getColorOrder() {
|
||||
return COL_ORDER_RGB;
|
||||
}
|
||||
|
||||
uint8_t getType() {
|
||||
return _type;
|
||||
}
|
||||
|
||||
bool isOk() {
|
||||
return _valid;
|
||||
}
|
||||
|
||||
bool reversed = false;
|
||||
|
||||
protected:
|
||||
uint8_t _type = TYPE_NONE;
|
||||
uint8_t _bri = 255;
|
||||
uint16_t _start = 0;
|
||||
bool _valid = false;
|
||||
};
|
||||
|
||||
|
||||
class BusDigital : public Bus {
|
||||
public:
|
||||
BusDigital(BusConfig &bc, uint8_t nr) : Bus(bc.type, bc.start) {
|
||||
if (!IS_DIGITAL(bc.type) || !bc.count) return;
|
||||
_pins[0] = bc.pins[0];
|
||||
if (!pinManager.allocatePin(_pins[0])) return;
|
||||
if (IS_2PIN(bc.type)) {
|
||||
_pins[1] = bc.pins[1];
|
||||
if (!pinManager.allocatePin(_pins[1])) {
|
||||
cleanup(); return;
|
||||
}
|
||||
}
|
||||
_len = bc.count;
|
||||
reversed = bc.reversed;
|
||||
_iType = PolyBus::getI(bc.type, _pins, nr);
|
||||
if (_iType == I_NONE) return;
|
||||
_busPtr = PolyBus::create(_iType, _pins, _len);
|
||||
_valid = (_busPtr != nullptr);
|
||||
_colorOrder = bc.colorOrder;
|
||||
//Serial.printf("Successfully inited strip %u (len %u) with type %u and pins %u,%u (itype %u)\n",nr, len, type, pins[0],pins[1],_iType);
|
||||
};
|
||||
|
||||
void show() {
|
||||
PolyBus::show(_busPtr, _iType);
|
||||
}
|
||||
|
||||
bool canShow() {
|
||||
return PolyBus::canShow(_busPtr, _iType);
|
||||
}
|
||||
|
||||
void setBrightness(uint8_t b) {
|
||||
//Fix for turning off onboard LED breaking bus
|
||||
#ifdef LED_BUILTIN
|
||||
if (_bri == 0 && b > 0) {
|
||||
if (_pins[0] == LED_BUILTIN || _pins[1] == LED_BUILTIN) PolyBus::begin(_busPtr, _iType, _pins);
|
||||
}
|
||||
#endif
|
||||
_bri = b;
|
||||
PolyBus::setBrightness(_busPtr, _iType, b);
|
||||
}
|
||||
|
||||
void setPixelColor(uint16_t pix, uint32_t c) {
|
||||
if (reversed) pix = _len - pix -1;
|
||||
PolyBus::setPixelColor(_busPtr, _iType, pix, c, _colorOrder);
|
||||
}
|
||||
|
||||
uint32_t getPixelColor(uint16_t pix) {
|
||||
if (reversed) pix = _len - pix -1;
|
||||
return PolyBus::getPixelColor(_busPtr, _iType, pix, _colorOrder);
|
||||
}
|
||||
|
||||
uint8_t getColorOrder() {
|
||||
return _colorOrder;
|
||||
}
|
||||
|
||||
uint16_t getLength() {
|
||||
return _len;
|
||||
}
|
||||
|
||||
uint8_t getPins(uint8_t* pinArray) {
|
||||
uint8_t numPins = IS_2PIN(_type) ? 2 : 1;
|
||||
for (uint8_t i = 0; i < numPins; i++) pinArray[i] = _pins[i];
|
||||
return numPins;
|
||||
}
|
||||
|
||||
void setColorOrder(uint8_t colorOrder) {
|
||||
if (colorOrder > 5) return;
|
||||
_colorOrder = colorOrder;
|
||||
}
|
||||
|
||||
void reinit() {
|
||||
PolyBus::begin(_busPtr, _iType, _pins);
|
||||
}
|
||||
|
||||
void cleanup() {
|
||||
//Serial.println("Digital Cleanup");
|
||||
PolyBus::cleanup(_busPtr, _iType);
|
||||
_iType = I_NONE;
|
||||
_valid = false;
|
||||
_busPtr = nullptr;
|
||||
pinManager.deallocatePin(_pins[0]);
|
||||
pinManager.deallocatePin(_pins[1]);
|
||||
}
|
||||
|
||||
~BusDigital() {
|
||||
cleanup();
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t _colorOrder = COL_ORDER_GRB;
|
||||
uint8_t _pins[2] = {255, 255};
|
||||
uint8_t _iType = I_NONE;
|
||||
uint16_t _len = 0;
|
||||
void * _busPtr = nullptr;
|
||||
};
|
||||
|
||||
|
||||
class BusPwm : public Bus {
|
||||
public:
|
||||
BusPwm(BusConfig &bc) : Bus(bc.type, bc.start) {
|
||||
if (!IS_PWM(bc.type)) return;
|
||||
uint8_t numPins = NUM_PWM_PINS(bc.type);
|
||||
|
||||
#ifdef ESP8266
|
||||
analogWriteRange(255); //same range as one RGB channel
|
||||
analogWriteFreq(WLED_PWM_FREQ);
|
||||
#else
|
||||
_ledcStart = pinManager.allocateLedc(numPins);
|
||||
if (_ledcStart == 255) { //no more free LEDC channels
|
||||
deallocatePins(); return;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (uint8_t i = 0; i < numPins; i++) {
|
||||
_pins[i] = bc.pins[i];
|
||||
if (!pinManager.allocatePin(_pins[i])) {
|
||||
deallocatePins(); return;
|
||||
}
|
||||
#ifdef ESP8266
|
||||
pinMode(_pins[i], OUTPUT);
|
||||
#else
|
||||
ledcSetup(_ledcStart + i, WLED_PWM_FREQ, 8);
|
||||
ledcAttachPin(_pins[i], _ledcStart + i);
|
||||
#endif
|
||||
}
|
||||
reversed = bc.reversed;
|
||||
_valid = true;
|
||||
};
|
||||
|
||||
void setPixelColor(uint16_t pix, uint32_t c) {
|
||||
if (pix != 0 || !_valid) return; //only react to first pixel
|
||||
uint8_t r = c >> 16;
|
||||
uint8_t g = c >> 8;
|
||||
uint8_t b = c ;
|
||||
uint8_t w = c >> 24;
|
||||
|
||||
switch (_type) {
|
||||
case TYPE_ANALOG_1CH: //one channel (white), use highest RGBW value
|
||||
_data[0] = max(r, max(g, max(b, w))); break;
|
||||
|
||||
case TYPE_ANALOG_2CH: //warm white + cold white, we'll need some nice handling here, for now just R+G channels
|
||||
case TYPE_ANALOG_3CH: //standard dumb RGB
|
||||
case TYPE_ANALOG_4CH: //RGBW
|
||||
case TYPE_ANALOG_5CH: //we'll want the white handling from 2CH here + RGB
|
||||
_data[0] = r; _data[1] = g; _data[2] = b; _data[3] = w; _data[4] = 0; break;
|
||||
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
//does no index check
|
||||
uint32_t getPixelColor(uint16_t pix) {
|
||||
return ((_data[3] << 24) | (_data[0] << 16) | (_data[1] << 8) | (_data[2]));
|
||||
}
|
||||
|
||||
void show() {
|
||||
uint8_t numPins = NUM_PWM_PINS(_type);
|
||||
for (uint8_t i = 0; i < numPins; i++) {
|
||||
uint8_t scaled = (_data[i] * _bri) / 255;
|
||||
if (reversed) scaled = 255 - scaled;
|
||||
#ifdef ESP8266
|
||||
analogWrite(_pins[i], scaled);
|
||||
#else
|
||||
ledcWrite(_ledcStart + i, scaled);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void setBrightness(uint8_t b) {
|
||||
_bri = b;
|
||||
}
|
||||
|
||||
uint8_t getPins(uint8_t* pinArray) {
|
||||
uint8_t numPins = NUM_PWM_PINS(_type);
|
||||
for (uint8_t i = 0; i < numPins; i++) pinArray[i] = _pins[i];
|
||||
return numPins;
|
||||
}
|
||||
|
||||
void cleanup() {
|
||||
deallocatePins();
|
||||
}
|
||||
|
||||
~BusPwm() {
|
||||
cleanup();
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t _pins[5] = {255, 255, 255, 255, 255};
|
||||
uint8_t _data[5] = {255, 255, 255, 255, 255};
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
uint8_t _ledcStart = 255;
|
||||
#endif
|
||||
|
||||
void deallocatePins() {
|
||||
uint8_t numPins = NUM_PWM_PINS(_type);
|
||||
for (uint8_t i = 0; i < numPins; i++) {
|
||||
if (!pinManager.isPinOk(_pins[i])) continue;
|
||||
#ifdef ESP8266
|
||||
digitalWrite(_pins[i], LOW); //turn off PWM interrupt
|
||||
#else
|
||||
if (_ledcStart < 16) ledcDetachPin(_pins[i]);
|
||||
#endif
|
||||
pinManager.deallocatePin(_pins[i]);
|
||||
}
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
pinManager.deallocateLedc(_ledcStart, numPins);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
class BusManager {
|
||||
public:
|
||||
BusManager() {
|
||||
|
||||
};
|
||||
|
||||
//utility to get the approx. memory usage of a given BusConfig
|
||||
uint32_t memUsage(BusConfig &bc) {
|
||||
uint8_t type = bc.type;
|
||||
uint16_t len = bc.count;
|
||||
if (type < 32) {
|
||||
#ifdef ESP8266
|
||||
if (bc.pins[0] == 3) { //8266 DMA uses 5x the mem
|
||||
if (type > 29) return len*20; //RGBW
|
||||
return len*15;
|
||||
}
|
||||
if (type > 29) return len*4; //RGBW
|
||||
return len*3;
|
||||
#else //ESP32 RMT uses double buffer?
|
||||
if (type > 29) return len*8; //RGBW
|
||||
return len*6;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (type > 31 && type < 48) return 5;
|
||||
if (type == 44 || type == 45) return len*4; //RGBW
|
||||
return len*3;
|
||||
}
|
||||
|
||||
int add(BusConfig &bc) {
|
||||
if (numBusses >= WLED_MAX_BUSSES) return -1;
|
||||
if (IS_DIGITAL(bc.type)) {
|
||||
busses[numBusses] = new BusDigital(bc, numBusses);
|
||||
} else {
|
||||
busses[numBusses] = new BusPwm(bc);
|
||||
}
|
||||
numBusses++;
|
||||
return numBusses -1;
|
||||
}
|
||||
|
||||
//do not call this method from system context (network callback)
|
||||
void removeAll() {
|
||||
//Serial.println("Removing all.");
|
||||
//prevents crashes due to deleting busses while in use.
|
||||
while (!canAllShow()) yield();
|
||||
for (uint8_t i = 0; i < numBusses; i++) delete busses[i];
|
||||
numBusses = 0;
|
||||
}
|
||||
|
||||
void show() {
|
||||
for (uint8_t i = 0; i < numBusses; i++) {
|
||||
busses[i]->show();
|
||||
}
|
||||
}
|
||||
|
||||
void setPixelColor(uint16_t pix, uint32_t c) {
|
||||
for (uint8_t i = 0; i < numBusses; i++) {
|
||||
Bus* b = busses[i];
|
||||
uint16_t bstart = b->getStart();
|
||||
if (pix < bstart || pix >= bstart + b->getLength()) continue;
|
||||
busses[i]->setPixelColor(pix - bstart, c);
|
||||
}
|
||||
}
|
||||
|
||||
void setBrightness(uint8_t b) {
|
||||
for (uint8_t i = 0; i < numBusses; i++) {
|
||||
busses[i]->setBrightness(b);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t getPixelColor(uint16_t pix) {
|
||||
for (uint8_t i = 0; i < numBusses; i++) {
|
||||
Bus* b = busses[i];
|
||||
uint16_t bstart = b->getStart();
|
||||
if (pix < bstart || pix >= bstart + b->getLength()) continue;
|
||||
return b->getPixelColor(pix - bstart);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool canAllShow() {
|
||||
for (uint8_t i = 0; i < numBusses; i++) {
|
||||
if (!busses[i]->canShow()) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bus* getBus(uint8_t busNr) {
|
||||
if (busNr >= numBusses) return nullptr;
|
||||
return busses[busNr];
|
||||
}
|
||||
|
||||
uint8_t getNumBusses() {
|
||||
return numBusses;
|
||||
}
|
||||
|
||||
static bool isRgbw(uint8_t type) {
|
||||
if (type == TYPE_SK6812_RGBW || type == TYPE_TM1814) return true;
|
||||
if (type > TYPE_ONOFF && type <= TYPE_ANALOG_5CH && type != TYPE_ANALOG_3CH) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t numBusses = 0;
|
||||
Bus* busses[WLED_MAX_BUSSES];
|
||||
};
|
||||
#endif
|
||||
882
wled00/bus_wrapper.h
Normal file
@@ -0,0 +1,882 @@
|
||||
#ifndef BusWrapper_h
|
||||
#define BusWrapper_h
|
||||
|
||||
#include "NeoPixelBrightnessBus.h"
|
||||
|
||||
//Hardware SPI Pins
|
||||
#define P_8266_HS_MOSI 13
|
||||
#define P_8266_HS_CLK 14
|
||||
#define P_32_HS_MOSI 13
|
||||
#define P_32_HS_CLK 14
|
||||
#define P_32_VS_MOSI 23
|
||||
#define P_32_VS_CLK 18
|
||||
|
||||
//The dirty list of possible bus types. Quite a lot...
|
||||
#define I_NONE 0
|
||||
//ESP8266 RGB
|
||||
#define I_8266_U0_NEO_3 1
|
||||
#define I_8266_U1_NEO_3 2
|
||||
#define I_8266_DM_NEO_3 3
|
||||
#define I_8266_BB_NEO_3 4
|
||||
//RGBW
|
||||
#define I_8266_U0_NEO_4 5
|
||||
#define I_8266_U1_NEO_4 6
|
||||
#define I_8266_DM_NEO_4 7
|
||||
#define I_8266_BB_NEO_4 8
|
||||
//400Kbps
|
||||
#define I_8266_U0_400_3 9
|
||||
#define I_8266_U1_400_3 10
|
||||
#define I_8266_DM_400_3 11
|
||||
#define I_8266_BB_400_3 12
|
||||
//TM1418 (RGBW)
|
||||
#define I_8266_U0_TM1_4 13
|
||||
#define I_8266_U1_TM1_4 14
|
||||
#define I_8266_DM_TM1_4 15
|
||||
#define I_8266_BB_TM1_4 16
|
||||
|
||||
/*** ESP32 Neopixel methods ***/
|
||||
//RGB
|
||||
#define I_32_R0_NEO_3 17
|
||||
#define I_32_R1_NEO_3 18
|
||||
#define I_32_R2_NEO_3 19
|
||||
#define I_32_R3_NEO_3 20
|
||||
#define I_32_R4_NEO_3 21
|
||||
#define I_32_R5_NEO_3 22
|
||||
#define I_32_R6_NEO_3 23
|
||||
#define I_32_R7_NEO_3 24
|
||||
#define I_32_I0_NEO_3 25
|
||||
#define I_32_I1_NEO_3 26
|
||||
//RGBW
|
||||
#define I_32_R0_NEO_4 27
|
||||
#define I_32_R1_NEO_4 28
|
||||
#define I_32_R2_NEO_4 29
|
||||
#define I_32_R3_NEO_4 30
|
||||
#define I_32_R4_NEO_4 31
|
||||
#define I_32_R5_NEO_4 32
|
||||
#define I_32_R6_NEO_4 33
|
||||
#define I_32_R7_NEO_4 34
|
||||
#define I_32_I0_NEO_4 35
|
||||
#define I_32_I1_NEO_4 36
|
||||
//400Kbps
|
||||
#define I_32_R0_400_3 37
|
||||
#define I_32_R1_400_3 38
|
||||
#define I_32_R2_400_3 39
|
||||
#define I_32_R3_400_3 40
|
||||
#define I_32_R4_400_3 41
|
||||
#define I_32_R5_400_3 42
|
||||
#define I_32_R6_400_3 43
|
||||
#define I_32_R7_400_3 44
|
||||
#define I_32_I0_400_3 45
|
||||
#define I_32_I1_400_3 46
|
||||
//TM1418 (RGBW)
|
||||
#define I_32_R0_TM1_4 47
|
||||
#define I_32_R1_TM1_4 48
|
||||
#define I_32_R2_TM1_4 49
|
||||
#define I_32_R3_TM1_4 50
|
||||
#define I_32_R4_TM1_4 51
|
||||
#define I_32_R5_TM1_4 52
|
||||
#define I_32_R6_TM1_4 53
|
||||
#define I_32_R7_TM1_4 54
|
||||
#define I_32_I0_TM1_4 55
|
||||
#define I_32_I1_TM1_4 56
|
||||
//Bit Bang theoratically possible, but very undesirable and not needed (no pin restrictions on RMT and I2S)
|
||||
|
||||
//APA102
|
||||
#define I_HS_DOT_3 57 //hardware SPI
|
||||
#define I_SS_DOT_3 58 //soft SPI
|
||||
|
||||
//LPD8806
|
||||
#define I_HS_LPD_3 59
|
||||
#define I_SS_LPD_3 60
|
||||
|
||||
//WS2801
|
||||
#define I_HS_WS1_3 61
|
||||
#define I_SS_WS1_3 62
|
||||
|
||||
//P9813
|
||||
#define I_HS_P98_3 63
|
||||
#define I_SS_P98_3 64
|
||||
|
||||
|
||||
/*** ESP8266 Neopixel methods ***/
|
||||
#ifdef ESP8266
|
||||
//RGB
|
||||
#define B_8266_U0_NEO_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp8266Uart0Ws2813Method> //3 chan, esp8266, gpio1
|
||||
#define B_8266_U1_NEO_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp8266Uart1Ws2813Method> //3 chan, esp8266, gpio2
|
||||
#define B_8266_DM_NEO_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp8266Dma800KbpsMethod> //3 chan, esp8266, gpio3
|
||||
#define B_8266_BB_NEO_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp8266BitBang800KbpsMethod> //3 chan, esp8266, bb (any pin but 16)
|
||||
//RGBW
|
||||
#define B_8266_U0_NEO_4 NeoPixelBrightnessBus<NeoGrbwFeature, NeoEsp8266Uart0Ws2813Method> //4 chan, esp8266, gpio1
|
||||
#define B_8266_U1_NEO_4 NeoPixelBrightnessBus<NeoGrbwFeature, NeoEsp8266Uart1Ws2813Method> //4 chan, esp8266, gpio2
|
||||
#define B_8266_DM_NEO_4 NeoPixelBrightnessBus<NeoGrbwFeature, NeoEsp8266Dma800KbpsMethod> //4 chan, esp8266, gpio3
|
||||
#define B_8266_BB_NEO_4 NeoPixelBrightnessBus<NeoGrbwFeature, NeoEsp8266BitBang800KbpsMethod> //4 chan, esp8266, bb (any pin)
|
||||
//400Kbps
|
||||
#define B_8266_U0_400_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp8266Uart0400KbpsMethod> //3 chan, esp8266, gpio1
|
||||
#define B_8266_U1_400_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp8266Uart1400KbpsMethod> //3 chan, esp8266, gpio2
|
||||
#define B_8266_DM_400_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp8266Dma400KbpsMethod> //3 chan, esp8266, gpio3
|
||||
#define B_8266_BB_400_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp8266BitBang400KbpsMethod> //3 chan, esp8266, bb (any pin)
|
||||
//TM1418 (RGBW)
|
||||
#define B_8266_U0_TM1_4 NeoPixelBrightnessBus<NeoWrgbTm1814Feature, NeoEsp8266Uart0Tm1814Method>
|
||||
#define B_8266_U1_TM1_4 NeoPixelBrightnessBus<NeoWrgbTm1814Feature, NeoEsp8266Uart1Tm1814Method>
|
||||
#define B_8266_DM_TM1_4 NeoPixelBrightnessBus<NeoWrgbTm1814Feature, NeoEsp8266DmaTm1814Method>
|
||||
#define B_8266_BB_TM1_4 NeoPixelBrightnessBus<NeoWrgbTm1814Feature, NeoEsp8266BitBangTm1814Method>
|
||||
#endif
|
||||
|
||||
/*** ESP32 Neopixel methods ***/
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
//RGB
|
||||
#define B_32_R0_NEO_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32Rmt0Ws2812xMethod>
|
||||
#define B_32_R1_NEO_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32Rmt1Ws2812xMethod>
|
||||
#define B_32_R2_NEO_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32Rmt2Ws2812xMethod>
|
||||
#define B_32_R3_NEO_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32Rmt3Ws2812xMethod>
|
||||
#define B_32_R4_NEO_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32Rmt4Ws2812xMethod>
|
||||
#define B_32_R5_NEO_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32Rmt5Ws2812xMethod>
|
||||
#define B_32_R6_NEO_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32Rmt6Ws2812xMethod>
|
||||
#define B_32_R7_NEO_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32Rmt7Ws2812xMethod>
|
||||
#define B_32_I0_NEO_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32I2s0800KbpsMethod>
|
||||
#define B_32_I1_NEO_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32I2s1800KbpsMethod>
|
||||
//RGBW
|
||||
#define B_32_R0_NEO_4 NeoPixelBrightnessBus<NeoGrbwFeature, NeoEsp32Rmt0Ws2812xMethod>
|
||||
#define B_32_R1_NEO_4 NeoPixelBrightnessBus<NeoGrbwFeature, NeoEsp32Rmt1Ws2812xMethod>
|
||||
#define B_32_R2_NEO_4 NeoPixelBrightnessBus<NeoGrbwFeature, NeoEsp32Rmt2Ws2812xMethod>
|
||||
#define B_32_R3_NEO_4 NeoPixelBrightnessBus<NeoGrbwFeature, NeoEsp32Rmt3Ws2812xMethod>
|
||||
#define B_32_R4_NEO_4 NeoPixelBrightnessBus<NeoGrbwFeature, NeoEsp32Rmt4Ws2812xMethod>
|
||||
#define B_32_R5_NEO_4 NeoPixelBrightnessBus<NeoGrbwFeature, NeoEsp32Rmt5Ws2812xMethod>
|
||||
#define B_32_R6_NEO_4 NeoPixelBrightnessBus<NeoGrbwFeature, NeoEsp32Rmt6Ws2812xMethod>
|
||||
#define B_32_R7_NEO_4 NeoPixelBrightnessBus<NeoGrbwFeature, NeoEsp32Rmt7Ws2812xMethod>
|
||||
#define B_32_I0_NEO_4 NeoPixelBrightnessBus<NeoGrbwFeature, NeoEsp32I2s0800KbpsMethod>
|
||||
#define B_32_I1_NEO_4 NeoPixelBrightnessBus<NeoGrbwFeature, NeoEsp32I2s1800KbpsMethod>
|
||||
//400Kbps
|
||||
#define B_32_R0_400_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32Rmt0400KbpsMethod>
|
||||
#define B_32_R1_400_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32Rmt1400KbpsMethod>
|
||||
#define B_32_R2_400_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32Rmt2400KbpsMethod>
|
||||
#define B_32_R3_400_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32Rmt3400KbpsMethod>
|
||||
#define B_32_R4_400_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32Rmt4400KbpsMethod>
|
||||
#define B_32_R5_400_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32Rmt5400KbpsMethod>
|
||||
#define B_32_R6_400_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32Rmt6400KbpsMethod>
|
||||
#define B_32_R7_400_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32Rmt7400KbpsMethod>
|
||||
#define B_32_I0_400_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32I2s0400KbpsMethod>
|
||||
#define B_32_I1_400_3 NeoPixelBrightnessBus<NeoGrbFeature, NeoEsp32I2s1400KbpsMethod>
|
||||
//TM1418 (RGBW)
|
||||
#define B_32_R0_TM1_4 NeoPixelBrightnessBus<NeoWrgbTm1814Feature, NeoEsp32Rmt0Tm1814Method>
|
||||
#define B_32_R1_TM1_4 NeoPixelBrightnessBus<NeoWrgbTm1814Feature, NeoEsp32Rmt1Tm1814Method>
|
||||
#define B_32_R2_TM1_4 NeoPixelBrightnessBus<NeoWrgbTm1814Feature, NeoEsp32Rmt2Tm1814Method>
|
||||
#define B_32_R3_TM1_4 NeoPixelBrightnessBus<NeoWrgbTm1814Feature, NeoEsp32Rmt3Tm1814Method>
|
||||
#define B_32_R4_TM1_4 NeoPixelBrightnessBus<NeoWrgbTm1814Feature, NeoEsp32Rmt4Tm1814Method>
|
||||
#define B_32_R5_TM1_4 NeoPixelBrightnessBus<NeoWrgbTm1814Feature, NeoEsp32Rmt5Tm1814Method>
|
||||
#define B_32_R6_TM1_4 NeoPixelBrightnessBus<NeoWrgbTm1814Feature, NeoEsp32Rmt6Tm1814Method>
|
||||
#define B_32_R7_TM1_4 NeoPixelBrightnessBus<NeoWrgbTm1814Feature, NeoEsp32Rmt7Tm1814Method>
|
||||
#define B_32_I0_TM1_4 NeoPixelBrightnessBus<NeoWrgbTm1814Feature, NeoEsp32I2s0Tm1814Method>
|
||||
#define B_32_I1_TM1_4 NeoPixelBrightnessBus<NeoWrgbTm1814Feature, NeoEsp32I2s1Tm1814Method>
|
||||
//Bit Bang theoratically possible, but very undesirable and not needed (no pin restrictions on RMT and I2S)
|
||||
|
||||
#endif
|
||||
|
||||
//APA102
|
||||
#define B_HS_DOT_3 NeoPixelBrightnessBus<DotStarBgrFeature, DotStarSpiMethod> //hardware SPI
|
||||
#define B_SS_DOT_3 NeoPixelBrightnessBus<DotStarBgrFeature, DotStarMethod> //soft SPI
|
||||
|
||||
//LPD8806
|
||||
#define B_HS_LPD_3 NeoPixelBrightnessBus<Lpd8806GrbFeature, Lpd8806SpiMethod>
|
||||
#define B_SS_LPD_3 NeoPixelBrightnessBus<Lpd8806GrbFeature, Lpd8806Method>
|
||||
|
||||
//WS2801
|
||||
#define B_HS_WS1_3 NeoPixelBrightnessBus<NeoRbgFeature, NeoWs2801SpiMethod>
|
||||
#define B_SS_WS1_3 NeoPixelBrightnessBus<NeoRbgFeature, NeoWs2801Method>
|
||||
|
||||
//P9813
|
||||
#define B_HS_P98_3 NeoPixelBrightnessBus<P9813BgrFeature, P9813SpiMethod>
|
||||
#define B_SS_P98_3 NeoPixelBrightnessBus<P9813BgrFeature, P9813Method>
|
||||
|
||||
//handles pointer type conversion for all possible bus types
|
||||
class PolyBus {
|
||||
public:
|
||||
static void begin(void* busPtr, uint8_t busType, uint8_t* pins) {
|
||||
switch (busType) {
|
||||
case I_NONE: break;
|
||||
#ifdef ESP8266
|
||||
case I_8266_U0_NEO_3: (static_cast<B_8266_U0_NEO_3*>(busPtr))->Begin(); break;
|
||||
case I_8266_U1_NEO_3: (static_cast<B_8266_U1_NEO_3*>(busPtr))->Begin(); break;
|
||||
case I_8266_DM_NEO_3: (static_cast<B_8266_DM_NEO_3*>(busPtr))->Begin(); break;
|
||||
case I_8266_BB_NEO_3: (static_cast<B_8266_BB_NEO_3*>(busPtr))->Begin(); break;
|
||||
case I_8266_U0_NEO_4: (static_cast<B_8266_U0_NEO_4*>(busPtr))->Begin(); break;
|
||||
case I_8266_U1_NEO_4: (static_cast<B_8266_U1_NEO_4*>(busPtr))->Begin(); break;
|
||||
case I_8266_DM_NEO_4: (static_cast<B_8266_DM_NEO_4*>(busPtr))->Begin(); break;
|
||||
case I_8266_BB_NEO_4: (static_cast<B_8266_BB_NEO_4*>(busPtr))->Begin(); break;
|
||||
case I_8266_U0_400_3: (static_cast<B_8266_U0_400_3*>(busPtr))->Begin(); break;
|
||||
case I_8266_U1_400_3: (static_cast<B_8266_U1_400_3*>(busPtr))->Begin(); break;
|
||||
case I_8266_DM_400_3: (static_cast<B_8266_DM_400_3*>(busPtr))->Begin(); break;
|
||||
case I_8266_BB_400_3: (static_cast<B_8266_BB_400_3*>(busPtr))->Begin(); break;
|
||||
case I_8266_U0_TM1_4: (static_cast<B_8266_U0_TM1_4*>(busPtr))->Begin(); break;
|
||||
case I_8266_U1_TM1_4: (static_cast<B_8266_U1_TM1_4*>(busPtr))->Begin(); break;
|
||||
case I_8266_DM_TM1_4: (static_cast<B_8266_DM_TM1_4*>(busPtr))->Begin(); break;
|
||||
case I_8266_BB_TM1_4: (static_cast<B_8266_BB_TM1_4*>(busPtr))->Begin(); break;
|
||||
case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->Begin(); break;
|
||||
case I_HS_LPD_3: (static_cast<B_HS_LPD_3*>(busPtr))->Begin(); break;
|
||||
case I_HS_WS1_3: (static_cast<B_HS_WS1_3*>(busPtr))->Begin(); break;
|
||||
case I_HS_P98_3: (static_cast<B_HS_P98_3*>(busPtr))->Begin(); break;
|
||||
#endif
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
case I_32_R0_NEO_3: (static_cast<B_32_R0_NEO_3*>(busPtr))->Begin(); break;
|
||||
case I_32_R1_NEO_3: (static_cast<B_32_R1_NEO_3*>(busPtr))->Begin(); break;
|
||||
case I_32_R2_NEO_3: (static_cast<B_32_R2_NEO_3*>(busPtr))->Begin(); break;
|
||||
case I_32_R3_NEO_3: (static_cast<B_32_R3_NEO_3*>(busPtr))->Begin(); break;
|
||||
case I_32_R4_NEO_3: (static_cast<B_32_R4_NEO_3*>(busPtr))->Begin(); break;
|
||||
case I_32_R5_NEO_3: (static_cast<B_32_R5_NEO_3*>(busPtr))->Begin(); break;
|
||||
case I_32_R6_NEO_3: (static_cast<B_32_R6_NEO_3*>(busPtr))->Begin(); break;
|
||||
case I_32_R7_NEO_3: (static_cast<B_32_R7_NEO_3*>(busPtr))->Begin(); break;
|
||||
case I_32_I0_NEO_3: (static_cast<B_32_I0_NEO_3*>(busPtr))->Begin(); break;
|
||||
case I_32_I1_NEO_3: (static_cast<B_32_I1_NEO_3*>(busPtr))->Begin(); break;
|
||||
case I_32_R0_NEO_4: (static_cast<B_32_R0_NEO_4*>(busPtr))->Begin(); break;
|
||||
case I_32_R1_NEO_4: (static_cast<B_32_R1_NEO_4*>(busPtr))->Begin(); break;
|
||||
case I_32_R2_NEO_4: (static_cast<B_32_R2_NEO_4*>(busPtr))->Begin(); break;
|
||||
case I_32_R3_NEO_4: (static_cast<B_32_R3_NEO_4*>(busPtr))->Begin(); break;
|
||||
case I_32_R4_NEO_4: (static_cast<B_32_R4_NEO_4*>(busPtr))->Begin(); break;
|
||||
case I_32_R5_NEO_4: (static_cast<B_32_R5_NEO_4*>(busPtr))->Begin(); break;
|
||||
case I_32_R6_NEO_4: (static_cast<B_32_R6_NEO_4*>(busPtr))->Begin(); break;
|
||||
case I_32_R7_NEO_4: (static_cast<B_32_R7_NEO_4*>(busPtr))->Begin(); break;
|
||||
case I_32_I0_NEO_4: (static_cast<B_32_I0_NEO_4*>(busPtr))->Begin(); break;
|
||||
case I_32_I1_NEO_4: (static_cast<B_32_I1_NEO_4*>(busPtr))->Begin(); break;
|
||||
case I_32_R0_400_3: (static_cast<B_32_R0_400_3*>(busPtr))->Begin(); break;
|
||||
case I_32_R1_400_3: (static_cast<B_32_R1_400_3*>(busPtr))->Begin(); break;
|
||||
case I_32_R2_400_3: (static_cast<B_32_R2_400_3*>(busPtr))->Begin(); break;
|
||||
case I_32_R3_400_3: (static_cast<B_32_R3_400_3*>(busPtr))->Begin(); break;
|
||||
case I_32_R4_400_3: (static_cast<B_32_R4_400_3*>(busPtr))->Begin(); break;
|
||||
case I_32_R5_400_3: (static_cast<B_32_R5_400_3*>(busPtr))->Begin(); break;
|
||||
case I_32_R6_400_3: (static_cast<B_32_R6_400_3*>(busPtr))->Begin(); break;
|
||||
case I_32_R7_400_3: (static_cast<B_32_R7_400_3*>(busPtr))->Begin(); break;
|
||||
case I_32_I0_400_3: (static_cast<B_32_I0_400_3*>(busPtr))->Begin(); break;
|
||||
case I_32_I1_400_3: (static_cast<B_32_I1_400_3*>(busPtr))->Begin(); break;
|
||||
case I_32_R0_TM1_4: (static_cast<B_32_R0_TM1_4*>(busPtr))->Begin(); break;
|
||||
case I_32_R1_TM1_4: (static_cast<B_32_R1_TM1_4*>(busPtr))->Begin(); break;
|
||||
case I_32_R2_TM1_4: (static_cast<B_32_R2_TM1_4*>(busPtr))->Begin(); break;
|
||||
case I_32_R3_TM1_4: (static_cast<B_32_R3_TM1_4*>(busPtr))->Begin(); break;
|
||||
case I_32_R4_TM1_4: (static_cast<B_32_R4_TM1_4*>(busPtr))->Begin(); break;
|
||||
case I_32_R5_TM1_4: (static_cast<B_32_R5_TM1_4*>(busPtr))->Begin(); break;
|
||||
case I_32_R6_TM1_4: (static_cast<B_32_R6_TM1_4*>(busPtr))->Begin(); break;
|
||||
case I_32_R7_TM1_4: (static_cast<B_32_R7_TM1_4*>(busPtr))->Begin(); break;
|
||||
case I_32_I0_TM1_4: (static_cast<B_32_I0_TM1_4*>(busPtr))->Begin(); break;
|
||||
case I_32_I1_TM1_4: (static_cast<B_32_I1_TM1_4*>(busPtr))->Begin(); break;
|
||||
// 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: (static_cast<B_HS_DOT_3*>(busPtr))->Begin(pins[1], -1, pins[0], -1); break;
|
||||
case I_HS_LPD_3: (static_cast<B_HS_LPD_3*>(busPtr))->Begin(pins[1], -1, pins[0], -1); break;
|
||||
case I_HS_WS1_3: (static_cast<B_HS_WS1_3*>(busPtr))->Begin(pins[1], -1, pins[0], -1); break;
|
||||
case I_HS_P98_3: (static_cast<B_HS_P98_3*>(busPtr))->Begin(pins[1], -1, pins[0], -1); break;
|
||||
#endif
|
||||
case I_SS_DOT_3: (static_cast<B_SS_DOT_3*>(busPtr))->Begin(); break;
|
||||
case I_SS_LPD_3: (static_cast<B_SS_LPD_3*>(busPtr))->Begin(); break;
|
||||
case I_SS_WS1_3: (static_cast<B_SS_WS1_3*>(busPtr))->Begin(); break;
|
||||
case I_SS_P98_3: (static_cast<B_SS_P98_3*>(busPtr))->Begin(); break;
|
||||
}
|
||||
};
|
||||
static void* create(uint8_t busType, uint8_t* pins, uint16_t len) {
|
||||
void* busPtr = nullptr;
|
||||
switch (busType) {
|
||||
case I_NONE: break;
|
||||
#ifdef ESP8266
|
||||
case I_8266_U0_NEO_3: busPtr = new B_8266_U0_NEO_3(len, pins[0]); break;
|
||||
case I_8266_U1_NEO_3: busPtr = new B_8266_U1_NEO_3(len, pins[0]); break;
|
||||
case I_8266_DM_NEO_3: busPtr = new B_8266_DM_NEO_3(len, pins[0]); break;
|
||||
case I_8266_BB_NEO_3: busPtr = new B_8266_BB_NEO_3(len, pins[0]); break;
|
||||
case I_8266_U0_NEO_4: busPtr = new B_8266_U0_NEO_4(len, pins[0]); break;
|
||||
case I_8266_U1_NEO_4: busPtr = new B_8266_U1_NEO_4(len, pins[0]); break;
|
||||
case I_8266_DM_NEO_4: busPtr = new B_8266_DM_NEO_4(len, pins[0]); break;
|
||||
case I_8266_BB_NEO_4: busPtr = new B_8266_BB_NEO_4(len, pins[0]); break;
|
||||
case I_8266_U0_400_3: busPtr = new B_8266_U0_400_3(len, pins[0]); break;
|
||||
case I_8266_U1_400_3: busPtr = new B_8266_U1_400_3(len, pins[0]); break;
|
||||
case I_8266_DM_400_3: busPtr = new B_8266_DM_400_3(len, pins[0]); break;
|
||||
case I_8266_BB_400_3: busPtr = new B_8266_BB_400_3(len, pins[0]); break;
|
||||
case I_8266_U0_TM1_4: busPtr = new B_8266_U0_TM1_4(len, pins[0]); break;
|
||||
case I_8266_U1_TM1_4: busPtr = new B_8266_U1_TM1_4(len, pins[0]); break;
|
||||
case I_8266_DM_TM1_4: busPtr = new B_8266_DM_TM1_4(len, pins[0]); break;
|
||||
case I_8266_BB_TM1_4: busPtr = new B_8266_BB_TM1_4(len, pins[0]); break;
|
||||
#endif
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
case I_32_R0_NEO_3: busPtr = new B_32_R0_NEO_3(len, pins[0]); break;
|
||||
case I_32_R1_NEO_3: busPtr = new B_32_R1_NEO_3(len, pins[0]); break;
|
||||
case I_32_R2_NEO_3: busPtr = new B_32_R2_NEO_3(len, pins[0]); break;
|
||||
case I_32_R3_NEO_3: busPtr = new B_32_R3_NEO_3(len, pins[0]); break;
|
||||
case I_32_R4_NEO_3: busPtr = new B_32_R4_NEO_3(len, pins[0]); break;
|
||||
case I_32_R5_NEO_3: busPtr = new B_32_R5_NEO_3(len, pins[0]); break;
|
||||
case I_32_R6_NEO_3: busPtr = new B_32_R6_NEO_3(len, pins[0]); break;
|
||||
case I_32_R7_NEO_3: busPtr = new B_32_R7_NEO_3(len, pins[0]); break;
|
||||
case I_32_I0_NEO_3: busPtr = new B_32_I0_NEO_3(len, pins[0]); break;
|
||||
case I_32_I1_NEO_3: busPtr = new B_32_I1_NEO_3(len, pins[0]); break;
|
||||
case I_32_R0_NEO_4: busPtr = new B_32_R0_NEO_4(len, pins[0]); break;
|
||||
case I_32_R1_NEO_4: busPtr = new B_32_R1_NEO_4(len, pins[0]); break;
|
||||
case I_32_R2_NEO_4: busPtr = new B_32_R2_NEO_4(len, pins[0]); break;
|
||||
case I_32_R3_NEO_4: busPtr = new B_32_R3_NEO_4(len, pins[0]); break;
|
||||
case I_32_R4_NEO_4: busPtr = new B_32_R4_NEO_4(len, pins[0]); break;
|
||||
case I_32_R5_NEO_4: busPtr = new B_32_R5_NEO_4(len, pins[0]); break;
|
||||
case I_32_R6_NEO_4: busPtr = new B_32_R6_NEO_4(len, pins[0]); break;
|
||||
case I_32_R7_NEO_4: busPtr = new B_32_R7_NEO_4(len, pins[0]); break;
|
||||
case I_32_I0_NEO_4: busPtr = new B_32_I0_NEO_4(len, pins[0]); break;
|
||||
case I_32_I1_NEO_4: busPtr = new B_32_I1_NEO_4(len, pins[0]); break;
|
||||
case I_32_R0_400_3: busPtr = new B_32_R0_400_3(len, pins[0]); break;
|
||||
case I_32_R1_400_3: busPtr = new B_32_R1_400_3(len, pins[0]); break;
|
||||
case I_32_R2_400_3: busPtr = new B_32_R2_400_3(len, pins[0]); break;
|
||||
case I_32_R3_400_3: busPtr = new B_32_R3_400_3(len, pins[0]); break;
|
||||
case I_32_R4_400_3: busPtr = new B_32_R4_400_3(len, pins[0]); break;
|
||||
case I_32_R5_400_3: busPtr = new B_32_R5_400_3(len, pins[0]); break;
|
||||
case I_32_R6_400_3: busPtr = new B_32_R6_400_3(len, pins[0]); break;
|
||||
case I_32_R7_400_3: busPtr = new B_32_R7_400_3(len, pins[0]); break;
|
||||
case I_32_I0_400_3: busPtr = new B_32_I0_400_3(len, pins[0]); break;
|
||||
case I_32_I1_400_3: busPtr = new B_32_I1_400_3(len, pins[0]); break;
|
||||
case I_32_R0_TM1_4: busPtr = new B_32_R0_TM1_4(len, pins[0]); break;
|
||||
case I_32_R1_TM1_4: busPtr = new B_32_R1_TM1_4(len, pins[0]); break;
|
||||
case I_32_R2_TM1_4: busPtr = new B_32_R2_TM1_4(len, pins[0]); break;
|
||||
case I_32_R3_TM1_4: busPtr = new B_32_R3_TM1_4(len, pins[0]); break;
|
||||
case I_32_R4_TM1_4: busPtr = new B_32_R4_TM1_4(len, pins[0]); break;
|
||||
case I_32_R5_TM1_4: busPtr = new B_32_R5_TM1_4(len, pins[0]); break;
|
||||
case I_32_R6_TM1_4: busPtr = new B_32_R6_TM1_4(len, pins[0]); break;
|
||||
case I_32_R7_TM1_4: busPtr = new B_32_R7_TM1_4(len, pins[0]); break;
|
||||
case I_32_I0_TM1_4: busPtr = new B_32_I0_TM1_4(len, pins[0]); break;
|
||||
case I_32_I1_TM1_4: busPtr = new B_32_I1_TM1_4(len, pins[0]); break;
|
||||
#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;
|
||||
case I_SS_DOT_3: busPtr = new B_SS_DOT_3(len, pins[1], pins[0]); break;
|
||||
case I_HS_LPD_3: busPtr = new B_HS_LPD_3(len, pins[1], pins[0]); break;
|
||||
case I_SS_LPD_3: busPtr = new B_SS_LPD_3(len, pins[1], pins[0]); break;
|
||||
case I_HS_WS1_3: busPtr = new B_HS_WS1_3(len, pins[1], pins[0]); break;
|
||||
case I_SS_WS1_3: busPtr = new B_SS_WS1_3(len, pins[1], pins[0]); break;
|
||||
case I_HS_P98_3: busPtr = new B_HS_P98_3(len, pins[1], pins[0]); break;
|
||||
case I_SS_P98_3: busPtr = new B_SS_P98_3(len, pins[1], pins[0]); break;
|
||||
}
|
||||
begin(busPtr, busType, pins);
|
||||
return busPtr;
|
||||
};
|
||||
static void show(void* busPtr, uint8_t busType) {
|
||||
switch (busType) {
|
||||
case I_NONE: break;
|
||||
#ifdef ESP8266
|
||||
case I_8266_U0_NEO_3: (static_cast<B_8266_U0_NEO_3*>(busPtr))->Show(); break;
|
||||
case I_8266_U1_NEO_3: (static_cast<B_8266_U1_NEO_3*>(busPtr))->Show(); break;
|
||||
case I_8266_DM_NEO_3: (static_cast<B_8266_DM_NEO_3*>(busPtr))->Show(); break;
|
||||
case I_8266_BB_NEO_3: (static_cast<B_8266_BB_NEO_3*>(busPtr))->Show(); break;
|
||||
case I_8266_U0_NEO_4: (static_cast<B_8266_U0_NEO_4*>(busPtr))->Show(); break;
|
||||
case I_8266_U1_NEO_4: (static_cast<B_8266_U1_NEO_4*>(busPtr))->Show(); break;
|
||||
case I_8266_DM_NEO_4: (static_cast<B_8266_DM_NEO_4*>(busPtr))->Show(); break;
|
||||
case I_8266_BB_NEO_4: (static_cast<B_8266_BB_NEO_4*>(busPtr))->Show(); break;
|
||||
case I_8266_U0_400_3: (static_cast<B_8266_U0_400_3*>(busPtr))->Show(); break;
|
||||
case I_8266_U1_400_3: (static_cast<B_8266_U1_400_3*>(busPtr))->Show(); break;
|
||||
case I_8266_DM_400_3: (static_cast<B_8266_DM_400_3*>(busPtr))->Show(); break;
|
||||
case I_8266_BB_400_3: (static_cast<B_8266_BB_400_3*>(busPtr))->Show(); break;
|
||||
case I_8266_U0_TM1_4: (static_cast<B_8266_U0_TM1_4*>(busPtr))->Show(); break;
|
||||
case I_8266_U1_TM1_4: (static_cast<B_8266_U1_TM1_4*>(busPtr))->Show(); break;
|
||||
case I_8266_DM_TM1_4: (static_cast<B_8266_DM_TM1_4*>(busPtr))->Show(); break;
|
||||
case I_8266_BB_TM1_4: (static_cast<B_8266_BB_TM1_4*>(busPtr))->Show(); break;
|
||||
#endif
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
case I_32_R0_NEO_3: (static_cast<B_32_R0_NEO_3*>(busPtr))->Show(); break;
|
||||
case I_32_R1_NEO_3: (static_cast<B_32_R1_NEO_3*>(busPtr))->Show(); break;
|
||||
case I_32_R2_NEO_3: (static_cast<B_32_R2_NEO_3*>(busPtr))->Show(); break;
|
||||
case I_32_R3_NEO_3: (static_cast<B_32_R3_NEO_3*>(busPtr))->Show(); break;
|
||||
case I_32_R4_NEO_3: (static_cast<B_32_R4_NEO_3*>(busPtr))->Show(); break;
|
||||
case I_32_R5_NEO_3: (static_cast<B_32_R5_NEO_3*>(busPtr))->Show(); break;
|
||||
case I_32_R6_NEO_3: (static_cast<B_32_R6_NEO_3*>(busPtr))->Show(); break;
|
||||
case I_32_R7_NEO_3: (static_cast<B_32_R7_NEO_3*>(busPtr))->Show(); break;
|
||||
case I_32_I0_NEO_3: (static_cast<B_32_I0_NEO_3*>(busPtr))->Show(); break;
|
||||
case I_32_I1_NEO_3: (static_cast<B_32_I1_NEO_3*>(busPtr))->Show(); break;
|
||||
case I_32_R0_NEO_4: (static_cast<B_32_R0_NEO_4*>(busPtr))->Show(); break;
|
||||
case I_32_R1_NEO_4: (static_cast<B_32_R1_NEO_4*>(busPtr))->Show(); break;
|
||||
case I_32_R2_NEO_4: (static_cast<B_32_R2_NEO_4*>(busPtr))->Show(); break;
|
||||
case I_32_R3_NEO_4: (static_cast<B_32_R3_NEO_4*>(busPtr))->Show(); break;
|
||||
case I_32_R4_NEO_4: (static_cast<B_32_R4_NEO_4*>(busPtr))->Show(); break;
|
||||
case I_32_R5_NEO_4: (static_cast<B_32_R5_NEO_4*>(busPtr))->Show(); break;
|
||||
case I_32_R6_NEO_4: (static_cast<B_32_R6_NEO_4*>(busPtr))->Show(); break;
|
||||
case I_32_R7_NEO_4: (static_cast<B_32_R7_NEO_4*>(busPtr))->Show(); break;
|
||||
case I_32_I0_NEO_4: (static_cast<B_32_I0_NEO_4*>(busPtr))->Show(); break;
|
||||
case I_32_I1_NEO_4: (static_cast<B_32_I1_NEO_4*>(busPtr))->Show(); break;
|
||||
case I_32_R0_400_3: (static_cast<B_32_R0_400_3*>(busPtr))->Show(); break;
|
||||
case I_32_R1_400_3: (static_cast<B_32_R1_400_3*>(busPtr))->Show(); break;
|
||||
case I_32_R2_400_3: (static_cast<B_32_R2_400_3*>(busPtr))->Show(); break;
|
||||
case I_32_R3_400_3: (static_cast<B_32_R3_400_3*>(busPtr))->Show(); break;
|
||||
case I_32_R4_400_3: (static_cast<B_32_R4_400_3*>(busPtr))->Show(); break;
|
||||
case I_32_R5_400_3: (static_cast<B_32_R5_400_3*>(busPtr))->Show(); break;
|
||||
case I_32_R6_400_3: (static_cast<B_32_R6_400_3*>(busPtr))->Show(); break;
|
||||
case I_32_R7_400_3: (static_cast<B_32_R7_400_3*>(busPtr))->Show(); break;
|
||||
case I_32_I0_400_3: (static_cast<B_32_I0_400_3*>(busPtr))->Show(); break;
|
||||
case I_32_I1_400_3: (static_cast<B_32_I1_400_3*>(busPtr))->Show(); break;
|
||||
case I_32_R0_TM1_4: (static_cast<B_32_R0_TM1_4*>(busPtr))->Show(); break;
|
||||
case I_32_R1_TM1_4: (static_cast<B_32_R1_TM1_4*>(busPtr))->Show(); break;
|
||||
case I_32_R2_TM1_4: (static_cast<B_32_R2_TM1_4*>(busPtr))->Show(); break;
|
||||
case I_32_R3_TM1_4: (static_cast<B_32_R3_TM1_4*>(busPtr))->Show(); break;
|
||||
case I_32_R4_TM1_4: (static_cast<B_32_R4_TM1_4*>(busPtr))->Show(); break;
|
||||
case I_32_R5_TM1_4: (static_cast<B_32_R5_TM1_4*>(busPtr))->Show(); break;
|
||||
case I_32_R6_TM1_4: (static_cast<B_32_R6_TM1_4*>(busPtr))->Show(); break;
|
||||
case I_32_R7_TM1_4: (static_cast<B_32_R7_TM1_4*>(busPtr))->Show(); break;
|
||||
case I_32_I0_TM1_4: (static_cast<B_32_I0_TM1_4*>(busPtr))->Show(); break;
|
||||
case I_32_I1_TM1_4: (static_cast<B_32_I1_TM1_4*>(busPtr))->Show(); break;
|
||||
#endif
|
||||
case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->Show(); break;
|
||||
case I_SS_DOT_3: (static_cast<B_SS_DOT_3*>(busPtr))->Show(); break;
|
||||
case I_HS_LPD_3: (static_cast<B_HS_LPD_3*>(busPtr))->Show(); break;
|
||||
case I_SS_LPD_3: (static_cast<B_SS_LPD_3*>(busPtr))->Show(); break;
|
||||
case I_HS_WS1_3: (static_cast<B_HS_WS1_3*>(busPtr))->Show(); break;
|
||||
case I_SS_WS1_3: (static_cast<B_SS_WS1_3*>(busPtr))->Show(); break;
|
||||
case I_HS_P98_3: (static_cast<B_HS_P98_3*>(busPtr))->Show(); break;
|
||||
case I_SS_P98_3: (static_cast<B_SS_P98_3*>(busPtr))->Show(); break;
|
||||
}
|
||||
};
|
||||
static bool canShow(void* busPtr, uint8_t busType) {
|
||||
switch (busType) {
|
||||
case I_NONE: return true;
|
||||
#ifdef ESP8266
|
||||
case I_8266_U0_NEO_3: return (static_cast<B_8266_U0_NEO_3*>(busPtr))->CanShow(); break;
|
||||
case I_8266_U1_NEO_3: return (static_cast<B_8266_U1_NEO_3*>(busPtr))->CanShow(); break;
|
||||
case I_8266_DM_NEO_3: return (static_cast<B_8266_DM_NEO_3*>(busPtr))->CanShow(); break;
|
||||
case I_8266_BB_NEO_3: return (static_cast<B_8266_BB_NEO_3*>(busPtr))->CanShow(); break;
|
||||
case I_8266_U0_NEO_4: return (static_cast<B_8266_U0_NEO_4*>(busPtr))->CanShow(); break;
|
||||
case I_8266_U1_NEO_4: return (static_cast<B_8266_U1_NEO_4*>(busPtr))->CanShow(); break;
|
||||
case I_8266_DM_NEO_4: return (static_cast<B_8266_DM_NEO_4*>(busPtr))->CanShow(); break;
|
||||
case I_8266_BB_NEO_4: return (static_cast<B_8266_BB_NEO_4*>(busPtr))->CanShow(); break;
|
||||
case I_8266_U0_400_3: return (static_cast<B_8266_U0_400_3*>(busPtr))->CanShow(); break;
|
||||
case I_8266_U1_400_3: return (static_cast<B_8266_U1_400_3*>(busPtr))->CanShow(); break;
|
||||
case I_8266_DM_400_3: return (static_cast<B_8266_DM_400_3*>(busPtr))->CanShow(); break;
|
||||
case I_8266_BB_400_3: return (static_cast<B_8266_BB_400_3*>(busPtr))->CanShow(); break;
|
||||
case I_8266_U0_TM1_4: return (static_cast<B_8266_U0_TM1_4*>(busPtr))->CanShow(); break;
|
||||
case I_8266_U1_TM1_4: return (static_cast<B_8266_U1_TM1_4*>(busPtr))->CanShow(); break;
|
||||
case I_8266_DM_TM1_4: return (static_cast<B_8266_DM_TM1_4*>(busPtr))->CanShow(); break;
|
||||
case I_8266_BB_TM1_4: return (static_cast<B_8266_BB_TM1_4*>(busPtr))->CanShow(); break;
|
||||
#endif
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
case I_32_R0_NEO_3: return (static_cast<B_32_R0_NEO_3*>(busPtr))->CanShow(); break;
|
||||
case I_32_R1_NEO_3: return (static_cast<B_32_R1_NEO_3*>(busPtr))->CanShow(); break;
|
||||
case I_32_R2_NEO_3: return (static_cast<B_32_R2_NEO_3*>(busPtr))->CanShow(); break;
|
||||
case I_32_R3_NEO_3: return (static_cast<B_32_R3_NEO_3*>(busPtr))->CanShow(); break;
|
||||
case I_32_R4_NEO_3: return (static_cast<B_32_R4_NEO_3*>(busPtr))->CanShow(); break;
|
||||
case I_32_R5_NEO_3: return (static_cast<B_32_R5_NEO_3*>(busPtr))->CanShow(); break;
|
||||
case I_32_R6_NEO_3: return (static_cast<B_32_R6_NEO_3*>(busPtr))->CanShow(); break;
|
||||
case I_32_R7_NEO_3: return (static_cast<B_32_R7_NEO_3*>(busPtr))->CanShow(); break;
|
||||
case I_32_I0_NEO_3: return (static_cast<B_32_I0_NEO_3*>(busPtr))->CanShow(); break;
|
||||
case I_32_I1_NEO_3: return (static_cast<B_32_I1_NEO_3*>(busPtr))->CanShow(); break;
|
||||
case I_32_R0_NEO_4: return (static_cast<B_32_R0_NEO_4*>(busPtr))->CanShow(); break;
|
||||
case I_32_R1_NEO_4: return (static_cast<B_32_R1_NEO_4*>(busPtr))->CanShow(); break;
|
||||
case I_32_R2_NEO_4: return (static_cast<B_32_R2_NEO_4*>(busPtr))->CanShow(); break;
|
||||
case I_32_R3_NEO_4: return (static_cast<B_32_R3_NEO_4*>(busPtr))->CanShow(); break;
|
||||
case I_32_R4_NEO_4: return (static_cast<B_32_R4_NEO_4*>(busPtr))->CanShow(); break;
|
||||
case I_32_R5_NEO_4: return (static_cast<B_32_R5_NEO_4*>(busPtr))->CanShow(); break;
|
||||
case I_32_R6_NEO_4: return (static_cast<B_32_R6_NEO_4*>(busPtr))->CanShow(); break;
|
||||
case I_32_R7_NEO_4: return (static_cast<B_32_R7_NEO_4*>(busPtr))->CanShow(); break;
|
||||
case I_32_I0_NEO_4: return (static_cast<B_32_I0_NEO_4*>(busPtr))->CanShow(); break;
|
||||
case I_32_I1_NEO_4: return (static_cast<B_32_I1_NEO_4*>(busPtr))->CanShow(); break;
|
||||
case I_32_R0_400_3: return (static_cast<B_32_R0_400_3*>(busPtr))->CanShow(); break;
|
||||
case I_32_R1_400_3: return (static_cast<B_32_R1_400_3*>(busPtr))->CanShow(); break;
|
||||
case I_32_R2_400_3: return (static_cast<B_32_R2_400_3*>(busPtr))->CanShow(); break;
|
||||
case I_32_R3_400_3: return (static_cast<B_32_R3_400_3*>(busPtr))->CanShow(); break;
|
||||
case I_32_R4_400_3: return (static_cast<B_32_R4_400_3*>(busPtr))->CanShow(); break;
|
||||
case I_32_R5_400_3: return (static_cast<B_32_R5_400_3*>(busPtr))->CanShow(); break;
|
||||
case I_32_R6_400_3: return (static_cast<B_32_R6_400_3*>(busPtr))->CanShow(); break;
|
||||
case I_32_R7_400_3: return (static_cast<B_32_R7_400_3*>(busPtr))->CanShow(); break;
|
||||
case I_32_I0_400_3: return (static_cast<B_32_I0_400_3*>(busPtr))->CanShow(); break;
|
||||
case I_32_I1_400_3: return (static_cast<B_32_I1_400_3*>(busPtr))->CanShow(); break;
|
||||
case I_32_R0_TM1_4: return (static_cast<B_32_R0_TM1_4*>(busPtr))->CanShow(); break;
|
||||
case I_32_R1_TM1_4: return (static_cast<B_32_R1_TM1_4*>(busPtr))->CanShow(); break;
|
||||
case I_32_R2_TM1_4: return (static_cast<B_32_R2_TM1_4*>(busPtr))->CanShow(); break;
|
||||
case I_32_R3_TM1_4: return (static_cast<B_32_R3_TM1_4*>(busPtr))->CanShow(); break;
|
||||
case I_32_R4_TM1_4: return (static_cast<B_32_R4_TM1_4*>(busPtr))->CanShow(); break;
|
||||
case I_32_R5_TM1_4: return (static_cast<B_32_R5_TM1_4*>(busPtr))->CanShow(); break;
|
||||
case I_32_R6_TM1_4: return (static_cast<B_32_R6_TM1_4*>(busPtr))->CanShow(); break;
|
||||
case I_32_R7_TM1_4: return (static_cast<B_32_R7_TM1_4*>(busPtr))->CanShow(); break;
|
||||
case I_32_I0_TM1_4: return (static_cast<B_32_I0_TM1_4*>(busPtr))->CanShow(); break;
|
||||
case I_32_I1_TM1_4: return (static_cast<B_32_I1_TM1_4*>(busPtr))->CanShow(); break;
|
||||
#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;
|
||||
case I_HS_LPD_3: return (static_cast<B_HS_LPD_3*>(busPtr))->CanShow(); break;
|
||||
case I_SS_LPD_3: return (static_cast<B_SS_LPD_3*>(busPtr))->CanShow(); break;
|
||||
case I_HS_WS1_3: return (static_cast<B_HS_WS1_3*>(busPtr))->CanShow(); break;
|
||||
case I_SS_WS1_3: return (static_cast<B_SS_WS1_3*>(busPtr))->CanShow(); break;
|
||||
case I_HS_P98_3: return (static_cast<B_HS_P98_3*>(busPtr))->CanShow(); break;
|
||||
case I_SS_P98_3: return (static_cast<B_SS_P98_3*>(busPtr))->CanShow(); break;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
static void setPixelColor(void* busPtr, uint8_t busType, uint16_t pix, uint32_t c, uint8_t co) {
|
||||
uint8_t r = c >> 16;
|
||||
uint8_t g = c >> 8;
|
||||
uint8_t b = c >> 0;
|
||||
uint8_t w = c >> 24;
|
||||
RgbwColor col;
|
||||
|
||||
//TODO make color order override possible on a per-strip basis
|
||||
#ifdef COLOR_ORDER_OVERRIDE
|
||||
if (pix >= COO_MIN && pix < COO_MAX) co = COO_ORDER;
|
||||
#endif
|
||||
|
||||
//reorder channels to selected order
|
||||
switch (co)
|
||||
{
|
||||
case 0: col.G = g; col.R = r; col.B = b; break; //0 = GRB, default
|
||||
case 1: col.G = r; col.R = g; col.B = b; break; //1 = RGB, common for WS2811
|
||||
case 2: col.G = b; col.R = r; col.B = g; break; //2 = BRG
|
||||
case 3: col.G = r; col.R = b; col.B = g; break; //3 = RBG
|
||||
case 4: col.G = b; col.R = g; col.B = r; break; //4 = BGR
|
||||
default: col.G = g; col.R = b; col.B = r; break; //5 = GBR
|
||||
}
|
||||
col.W = w;
|
||||
|
||||
switch (busType) {
|
||||
case I_NONE: break;
|
||||
#ifdef ESP8266
|
||||
case I_8266_U0_NEO_3: (static_cast<B_8266_U0_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_8266_U1_NEO_3: (static_cast<B_8266_U1_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_8266_DM_NEO_3: (static_cast<B_8266_DM_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_8266_BB_NEO_3: (static_cast<B_8266_BB_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_8266_U0_NEO_4: (static_cast<B_8266_U0_NEO_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
case I_8266_U1_NEO_4: (static_cast<B_8266_U1_NEO_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
case I_8266_DM_NEO_4: (static_cast<B_8266_DM_NEO_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
case I_8266_BB_NEO_4: (static_cast<B_8266_BB_NEO_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
case I_8266_U0_400_3: (static_cast<B_8266_U0_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_8266_U1_400_3: (static_cast<B_8266_U1_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_8266_DM_400_3: (static_cast<B_8266_DM_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_8266_BB_400_3: (static_cast<B_8266_BB_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_8266_U0_TM1_4: (static_cast<B_8266_U0_TM1_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
case I_8266_U1_TM1_4: (static_cast<B_8266_U1_TM1_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
case I_8266_DM_TM1_4: (static_cast<B_8266_DM_TM1_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
case I_8266_BB_TM1_4: (static_cast<B_8266_BB_TM1_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
#endif
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
case I_32_R0_NEO_3: (static_cast<B_32_R0_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_32_R1_NEO_3: (static_cast<B_32_R1_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_32_R2_NEO_3: (static_cast<B_32_R2_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_32_R3_NEO_3: (static_cast<B_32_R3_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_32_R4_NEO_3: (static_cast<B_32_R4_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_32_R5_NEO_3: (static_cast<B_32_R5_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_32_R6_NEO_3: (static_cast<B_32_R6_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_32_R7_NEO_3: (static_cast<B_32_R7_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_32_I0_NEO_3: (static_cast<B_32_I0_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_32_I1_NEO_3: (static_cast<B_32_I1_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_32_R0_NEO_4: (static_cast<B_32_R0_NEO_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
case I_32_R1_NEO_4: (static_cast<B_32_R1_NEO_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
case I_32_R2_NEO_4: (static_cast<B_32_R2_NEO_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
case I_32_R3_NEO_4: (static_cast<B_32_R3_NEO_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
case I_32_R4_NEO_4: (static_cast<B_32_R4_NEO_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
case I_32_R5_NEO_4: (static_cast<B_32_R5_NEO_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
case I_32_R6_NEO_4: (static_cast<B_32_R6_NEO_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
case I_32_R7_NEO_4: (static_cast<B_32_R7_NEO_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
case I_32_I0_NEO_4: (static_cast<B_32_I0_NEO_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
case I_32_I1_NEO_4: (static_cast<B_32_I1_NEO_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
case I_32_R0_400_3: (static_cast<B_32_R0_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_32_R1_400_3: (static_cast<B_32_R1_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_32_R2_400_3: (static_cast<B_32_R2_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_32_R3_400_3: (static_cast<B_32_R3_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_32_R4_400_3: (static_cast<B_32_R4_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_32_R5_400_3: (static_cast<B_32_R5_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_32_R6_400_3: (static_cast<B_32_R6_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_32_R7_400_3: (static_cast<B_32_R7_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_32_I0_400_3: (static_cast<B_32_I0_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_32_I1_400_3: (static_cast<B_32_I1_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_32_R0_TM1_4: (static_cast<B_32_R0_TM1_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
case I_32_R1_TM1_4: (static_cast<B_32_R1_TM1_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
case I_32_R2_TM1_4: (static_cast<B_32_R2_TM1_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
case I_32_R3_TM1_4: (static_cast<B_32_R3_TM1_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
case I_32_R4_TM1_4: (static_cast<B_32_R4_TM1_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
case I_32_R5_TM1_4: (static_cast<B_32_R5_TM1_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
case I_32_R6_TM1_4: (static_cast<B_32_R6_TM1_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
case I_32_R7_TM1_4: (static_cast<B_32_R7_TM1_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
case I_32_I0_TM1_4: (static_cast<B_32_I0_TM1_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
case I_32_I1_TM1_4: (static_cast<B_32_I1_TM1_4*>(busPtr))->SetPixelColor(pix, col); break;
|
||||
#endif
|
||||
case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_SS_DOT_3: (static_cast<B_SS_DOT_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_HS_LPD_3: (static_cast<B_HS_LPD_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_SS_LPD_3: (static_cast<B_SS_LPD_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_HS_WS1_3: (static_cast<B_HS_WS1_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_SS_WS1_3: (static_cast<B_SS_WS1_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_HS_P98_3: (static_cast<B_HS_P98_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_SS_P98_3: (static_cast<B_SS_P98_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
}
|
||||
};
|
||||
static void setBrightness(void* busPtr, uint8_t busType, uint8_t b) {
|
||||
switch (busType) {
|
||||
case I_NONE: break;
|
||||
#ifdef ESP8266
|
||||
case I_8266_U0_NEO_3: (static_cast<B_8266_U0_NEO_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_8266_U1_NEO_3: (static_cast<B_8266_U1_NEO_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_8266_DM_NEO_3: (static_cast<B_8266_DM_NEO_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_8266_BB_NEO_3: (static_cast<B_8266_BB_NEO_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_8266_U0_NEO_4: (static_cast<B_8266_U0_NEO_4*>(busPtr))->SetBrightness(b); break;
|
||||
case I_8266_U1_NEO_4: (static_cast<B_8266_U1_NEO_4*>(busPtr))->SetBrightness(b); break;
|
||||
case I_8266_DM_NEO_4: (static_cast<B_8266_DM_NEO_4*>(busPtr))->SetBrightness(b); break;
|
||||
case I_8266_BB_NEO_4: (static_cast<B_8266_BB_NEO_4*>(busPtr))->SetBrightness(b); break;
|
||||
case I_8266_U0_400_3: (static_cast<B_8266_U0_400_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_8266_U1_400_3: (static_cast<B_8266_U1_400_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_8266_DM_400_3: (static_cast<B_8266_DM_400_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_8266_BB_400_3: (static_cast<B_8266_BB_400_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_8266_U0_TM1_4: (static_cast<B_8266_U0_TM1_4*>(busPtr))->SetBrightness(b); break;
|
||||
case I_8266_U1_TM1_4: (static_cast<B_8266_U1_TM1_4*>(busPtr))->SetBrightness(b); break;
|
||||
case I_8266_DM_TM1_4: (static_cast<B_8266_DM_TM1_4*>(busPtr))->SetBrightness(b); break;
|
||||
case I_8266_BB_TM1_4: (static_cast<B_8266_BB_TM1_4*>(busPtr))->SetBrightness(b); break;
|
||||
#endif
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
case I_32_R0_NEO_3: (static_cast<B_32_R0_NEO_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_R1_NEO_3: (static_cast<B_32_R1_NEO_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_R2_NEO_3: (static_cast<B_32_R2_NEO_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_R3_NEO_3: (static_cast<B_32_R3_NEO_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_R4_NEO_3: (static_cast<B_32_R4_NEO_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_R5_NEO_3: (static_cast<B_32_R5_NEO_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_R6_NEO_3: (static_cast<B_32_R6_NEO_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_R7_NEO_3: (static_cast<B_32_R7_NEO_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_I0_NEO_3: (static_cast<B_32_I0_NEO_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_I1_NEO_3: (static_cast<B_32_I1_NEO_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_R0_NEO_4: (static_cast<B_32_R0_NEO_4*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_R1_NEO_4: (static_cast<B_32_R1_NEO_4*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_R2_NEO_4: (static_cast<B_32_R2_NEO_4*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_R3_NEO_4: (static_cast<B_32_R3_NEO_4*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_R4_NEO_4: (static_cast<B_32_R4_NEO_4*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_R5_NEO_4: (static_cast<B_32_R5_NEO_4*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_R6_NEO_4: (static_cast<B_32_R6_NEO_4*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_R7_NEO_4: (static_cast<B_32_R7_NEO_4*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_I0_NEO_4: (static_cast<B_32_I0_NEO_4*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_I1_NEO_4: (static_cast<B_32_I1_NEO_4*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_R0_400_3: (static_cast<B_32_R0_400_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_R1_400_3: (static_cast<B_32_R1_400_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_R2_400_3: (static_cast<B_32_R2_400_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_R3_400_3: (static_cast<B_32_R3_400_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_R4_400_3: (static_cast<B_32_R4_400_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_R5_400_3: (static_cast<B_32_R5_400_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_R6_400_3: (static_cast<B_32_R6_400_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_R7_400_3: (static_cast<B_32_R7_400_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_I0_400_3: (static_cast<B_32_I0_400_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_I1_400_3: (static_cast<B_32_I1_400_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_R0_TM1_4: (static_cast<B_32_R0_TM1_4*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_R1_TM1_4: (static_cast<B_32_R1_TM1_4*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_R2_TM1_4: (static_cast<B_32_R2_TM1_4*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_R3_TM1_4: (static_cast<B_32_R3_TM1_4*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_R4_TM1_4: (static_cast<B_32_R4_TM1_4*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_R5_TM1_4: (static_cast<B_32_R5_TM1_4*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_R6_TM1_4: (static_cast<B_32_R6_TM1_4*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_R7_TM1_4: (static_cast<B_32_R7_TM1_4*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_I0_TM1_4: (static_cast<B_32_I0_TM1_4*>(busPtr))->SetBrightness(b); break;
|
||||
case I_32_I1_TM1_4: (static_cast<B_32_I1_TM1_4*>(busPtr))->SetBrightness(b); break;
|
||||
#endif
|
||||
case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_SS_DOT_3: (static_cast<B_SS_DOT_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_HS_LPD_3: (static_cast<B_HS_LPD_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_SS_LPD_3: (static_cast<B_SS_LPD_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_HS_WS1_3: (static_cast<B_HS_WS1_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_SS_WS1_3: (static_cast<B_SS_WS1_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_HS_P98_3: (static_cast<B_HS_P98_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_SS_P98_3: (static_cast<B_SS_P98_3*>(busPtr))->SetBrightness(b); break;
|
||||
}
|
||||
};
|
||||
static uint32_t getPixelColor(void* busPtr, uint8_t busType, uint16_t pix, uint8_t co) {
|
||||
RgbwColor col(0,0,0,0);
|
||||
switch (busType) {
|
||||
case I_NONE: break;
|
||||
#ifdef ESP8266
|
||||
case I_8266_U0_NEO_3: col = (static_cast<B_8266_U0_NEO_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_8266_U1_NEO_3: col = (static_cast<B_8266_U1_NEO_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_8266_DM_NEO_3: col = (static_cast<B_8266_DM_NEO_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_8266_BB_NEO_3: col = (static_cast<B_8266_BB_NEO_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_8266_U0_NEO_4: col = (static_cast<B_8266_U0_NEO_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_8266_U1_NEO_4: col = (static_cast<B_8266_U1_NEO_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_8266_DM_NEO_4: col = (static_cast<B_8266_DM_NEO_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_8266_BB_NEO_4: col = (static_cast<B_8266_BB_NEO_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_8266_U0_400_3: col = (static_cast<B_8266_U0_400_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_8266_U1_400_3: col = (static_cast<B_8266_U1_400_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_8266_DM_400_3: col = (static_cast<B_8266_DM_400_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_8266_BB_400_3: col = (static_cast<B_8266_BB_400_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_8266_U0_TM1_4: col = (static_cast<B_8266_U0_TM1_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_8266_U1_TM1_4: col = (static_cast<B_8266_U1_TM1_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_8266_DM_TM1_4: col = (static_cast<B_8266_DM_TM1_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_8266_BB_TM1_4: col = (static_cast<B_8266_BB_TM1_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
#endif
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
case I_32_R0_NEO_3: col = (static_cast<B_32_R0_NEO_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_R1_NEO_3: col = (static_cast<B_32_R1_NEO_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_R2_NEO_3: col = (static_cast<B_32_R2_NEO_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_R3_NEO_3: col = (static_cast<B_32_R3_NEO_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_R4_NEO_3: col = (static_cast<B_32_R4_NEO_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_R5_NEO_3: col = (static_cast<B_32_R5_NEO_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_R6_NEO_3: col = (static_cast<B_32_R6_NEO_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_R7_NEO_3: col = (static_cast<B_32_R7_NEO_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_I0_NEO_3: col = (static_cast<B_32_I0_NEO_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_I1_NEO_3: col = (static_cast<B_32_I1_NEO_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_R0_NEO_4: col = (static_cast<B_32_R0_NEO_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_R1_NEO_4: col = (static_cast<B_32_R1_NEO_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_R2_NEO_4: col = (static_cast<B_32_R2_NEO_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_R3_NEO_4: col = (static_cast<B_32_R3_NEO_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_R4_NEO_4: col = (static_cast<B_32_R4_NEO_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_R5_NEO_4: col = (static_cast<B_32_R5_NEO_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_R6_NEO_4: col = (static_cast<B_32_R6_NEO_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_R7_NEO_4: col = (static_cast<B_32_R7_NEO_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_I0_NEO_4: col = (static_cast<B_32_I0_NEO_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_I1_NEO_4: col = (static_cast<B_32_I1_NEO_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_R0_400_3: col = (static_cast<B_32_R0_400_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_R1_400_3: col = (static_cast<B_32_R1_400_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_R2_400_3: col = (static_cast<B_32_R2_400_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_R3_400_3: col = (static_cast<B_32_R3_400_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_R4_400_3: col = (static_cast<B_32_R4_400_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_R5_400_3: col = (static_cast<B_32_R5_400_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_R6_400_3: col = (static_cast<B_32_R6_400_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_R7_400_3: col = (static_cast<B_32_R7_400_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_I0_400_3: col = (static_cast<B_32_I0_400_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_I1_400_3: col = (static_cast<B_32_I1_400_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_R0_TM1_4: col = (static_cast<B_32_R0_TM1_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_R1_TM1_4: col = (static_cast<B_32_R1_TM1_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_R2_TM1_4: col = (static_cast<B_32_R2_TM1_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_R3_TM1_4: col = (static_cast<B_32_R3_TM1_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_R4_TM1_4: col = (static_cast<B_32_R4_TM1_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_R5_TM1_4: col = (static_cast<B_32_R5_TM1_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_R6_TM1_4: col = (static_cast<B_32_R6_TM1_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_R7_TM1_4: col = (static_cast<B_32_R7_TM1_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_I0_TM1_4: col = (static_cast<B_32_I0_TM1_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_32_I1_TM1_4: col = (static_cast<B_32_I1_TM1_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
#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;
|
||||
case I_HS_LPD_3: col = (static_cast<B_HS_LPD_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_SS_LPD_3: col = (static_cast<B_SS_LPD_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_HS_WS1_3: col = (static_cast<B_HS_WS1_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_SS_WS1_3: col = (static_cast<B_SS_WS1_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_HS_P98_3: col = (static_cast<B_HS_P98_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_SS_P98_3: col = (static_cast<B_SS_P98_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
}
|
||||
|
||||
#ifdef COLOR_ORDER_OVERRIDE
|
||||
if (pix >= COO_MIN && pix < COO_MAX) co = COO_ORDER;
|
||||
#endif
|
||||
|
||||
switch (co)
|
||||
{
|
||||
// W G R B
|
||||
case 0: return ((col.W << 24) | (col.G << 8) | (col.R << 16) | (col.B)); //0 = GRB, default
|
||||
case 1: return ((col.W << 24) | (col.R << 8) | (col.G << 16) | (col.B)); //1 = RGB, common for WS2811
|
||||
case 2: return ((col.W << 24) | (col.B << 8) | (col.R << 16) | (col.G)); //2 = BRG
|
||||
case 3: return ((col.W << 24) | (col.B << 8) | (col.G << 16) | (col.R)); //3 = RBG
|
||||
case 4: return ((col.W << 24) | (col.R << 8) | (col.B << 16) | (col.G)); //4 = BGR
|
||||
case 5: return ((col.W << 24) | (col.G << 8) | (col.B << 16) | (col.R)); //5 = GBR
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cleanup(void* busPtr, uint8_t busType) {
|
||||
if (busPtr == nullptr) return;
|
||||
switch (busType) {
|
||||
case I_NONE: break;
|
||||
#ifdef ESP8266
|
||||
case I_8266_U0_NEO_3: delete (static_cast<B_8266_U0_NEO_3*>(busPtr)); break;
|
||||
case I_8266_U1_NEO_3: delete (static_cast<B_8266_U1_NEO_3*>(busPtr)); break;
|
||||
case I_8266_DM_NEO_3: delete (static_cast<B_8266_DM_NEO_3*>(busPtr)); break;
|
||||
case I_8266_BB_NEO_3: delete (static_cast<B_8266_BB_NEO_3*>(busPtr)); break;
|
||||
case I_8266_U0_NEO_4: delete (static_cast<B_8266_U0_NEO_4*>(busPtr)); break;
|
||||
case I_8266_U1_NEO_4: delete (static_cast<B_8266_U1_NEO_4*>(busPtr)); break;
|
||||
case I_8266_DM_NEO_4: delete (static_cast<B_8266_DM_NEO_4*>(busPtr)); break;
|
||||
case I_8266_BB_NEO_4: delete (static_cast<B_8266_BB_NEO_4*>(busPtr)); break;
|
||||
case I_8266_U0_400_3: delete (static_cast<B_8266_U0_400_3*>(busPtr)); break;
|
||||
case I_8266_U1_400_3: delete (static_cast<B_8266_U1_400_3*>(busPtr)); break;
|
||||
case I_8266_DM_400_3: delete (static_cast<B_8266_DM_400_3*>(busPtr)); break;
|
||||
case I_8266_BB_400_3: delete (static_cast<B_8266_BB_400_3*>(busPtr)); break;
|
||||
case I_8266_U0_TM1_4: delete (static_cast<B_8266_U0_TM1_4*>(busPtr)); break;
|
||||
case I_8266_U1_TM1_4: delete (static_cast<B_8266_U1_TM1_4*>(busPtr)); break;
|
||||
case I_8266_DM_TM1_4: delete (static_cast<B_8266_DM_TM1_4*>(busPtr)); break;
|
||||
case I_8266_BB_TM1_4: delete (static_cast<B_8266_BB_TM1_4*>(busPtr)); break;
|
||||
#endif
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
case I_32_R0_NEO_3: delete (static_cast<B_32_R0_NEO_3*>(busPtr)); break;
|
||||
case I_32_R1_NEO_3: delete (static_cast<B_32_R1_NEO_3*>(busPtr)); break;
|
||||
case I_32_R2_NEO_3: delete (static_cast<B_32_R2_NEO_3*>(busPtr)); break;
|
||||
case I_32_R3_NEO_3: delete (static_cast<B_32_R3_NEO_3*>(busPtr)); break;
|
||||
case I_32_R4_NEO_3: delete (static_cast<B_32_R4_NEO_3*>(busPtr)); break;
|
||||
case I_32_R5_NEO_3: delete (static_cast<B_32_R5_NEO_3*>(busPtr)); break;
|
||||
case I_32_R6_NEO_3: delete (static_cast<B_32_R6_NEO_3*>(busPtr)); break;
|
||||
case I_32_R7_NEO_3: delete (static_cast<B_32_R7_NEO_3*>(busPtr)); break;
|
||||
case I_32_I0_NEO_3: delete (static_cast<B_32_I0_NEO_3*>(busPtr)); break;
|
||||
case I_32_I1_NEO_3: delete (static_cast<B_32_I1_NEO_3*>(busPtr)); break;
|
||||
case I_32_R0_NEO_4: delete (static_cast<B_32_R0_NEO_4*>(busPtr)); break;
|
||||
case I_32_R1_NEO_4: delete (static_cast<B_32_R1_NEO_4*>(busPtr)); break;
|
||||
case I_32_R2_NEO_4: delete (static_cast<B_32_R2_NEO_4*>(busPtr)); break;
|
||||
case I_32_R3_NEO_4: delete (static_cast<B_32_R3_NEO_4*>(busPtr)); break;
|
||||
case I_32_R4_NEO_4: delete (static_cast<B_32_R4_NEO_4*>(busPtr)); break;
|
||||
case I_32_R5_NEO_4: delete (static_cast<B_32_R5_NEO_4*>(busPtr)); break;
|
||||
case I_32_R6_NEO_4: delete (static_cast<B_32_R6_NEO_4*>(busPtr)); break;
|
||||
case I_32_R7_NEO_4: delete (static_cast<B_32_R7_NEO_4*>(busPtr)); break;
|
||||
case I_32_I0_NEO_4: delete (static_cast<B_32_I0_NEO_4*>(busPtr)); break;
|
||||
case I_32_I1_NEO_4: delete (static_cast<B_32_I1_NEO_4*>(busPtr)); break;
|
||||
case I_32_R0_400_3: delete (static_cast<B_32_R0_400_3*>(busPtr)); break;
|
||||
case I_32_R1_400_3: delete (static_cast<B_32_R1_400_3*>(busPtr)); break;
|
||||
case I_32_R2_400_3: delete (static_cast<B_32_R2_400_3*>(busPtr)); break;
|
||||
case I_32_R3_400_3: delete (static_cast<B_32_R3_400_3*>(busPtr)); break;
|
||||
case I_32_R4_400_3: delete (static_cast<B_32_R4_400_3*>(busPtr)); break;
|
||||
case I_32_R5_400_3: delete (static_cast<B_32_R5_400_3*>(busPtr)); break;
|
||||
case I_32_R6_400_3: delete (static_cast<B_32_R6_400_3*>(busPtr)); break;
|
||||
case I_32_R7_400_3: delete (static_cast<B_32_R7_400_3*>(busPtr)); break;
|
||||
case I_32_I0_400_3: delete (static_cast<B_32_I0_400_3*>(busPtr)); break;
|
||||
case I_32_I1_400_3: delete (static_cast<B_32_I1_400_3*>(busPtr)); break;
|
||||
case I_32_R0_TM1_4: delete (static_cast<B_32_R0_TM1_4*>(busPtr)); break;
|
||||
case I_32_R1_TM1_4: delete (static_cast<B_32_R1_TM1_4*>(busPtr)); break;
|
||||
case I_32_R2_TM1_4: delete (static_cast<B_32_R2_TM1_4*>(busPtr)); break;
|
||||
case I_32_R3_TM1_4: delete (static_cast<B_32_R3_TM1_4*>(busPtr)); break;
|
||||
case I_32_R4_TM1_4: delete (static_cast<B_32_R4_TM1_4*>(busPtr)); break;
|
||||
case I_32_R5_TM1_4: delete (static_cast<B_32_R5_TM1_4*>(busPtr)); break;
|
||||
case I_32_R6_TM1_4: delete (static_cast<B_32_R6_TM1_4*>(busPtr)); break;
|
||||
case I_32_R7_TM1_4: delete (static_cast<B_32_R7_TM1_4*>(busPtr)); break;
|
||||
case I_32_I0_TM1_4: delete (static_cast<B_32_I0_TM1_4*>(busPtr)); break;
|
||||
case I_32_I1_TM1_4: delete (static_cast<B_32_I1_TM1_4*>(busPtr)); break;
|
||||
#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;
|
||||
case I_HS_LPD_3: delete (static_cast<B_HS_LPD_3*>(busPtr)); break;
|
||||
case I_SS_LPD_3: delete (static_cast<B_SS_LPD_3*>(busPtr)); break;
|
||||
case I_HS_WS1_3: delete (static_cast<B_HS_WS1_3*>(busPtr)); break;
|
||||
case I_SS_WS1_3: delete (static_cast<B_SS_WS1_3*>(busPtr)); break;
|
||||
case I_HS_P98_3: delete (static_cast<B_HS_P98_3*>(busPtr)); break;
|
||||
case I_SS_P98_3: delete (static_cast<B_SS_P98_3*>(busPtr)); break;
|
||||
}
|
||||
}
|
||||
|
||||
//gives back the internal type index (I_XX_XXX_X above) for the input
|
||||
static uint8_t getI(uint8_t busType, uint8_t* pins, uint8_t num = 0) {
|
||||
if (!IS_DIGITAL(busType)) return I_NONE;
|
||||
if (IS_2PIN(busType)) { //SPI LED chips
|
||||
bool isHSPI = false;
|
||||
#ifdef ESP8266
|
||||
if (pins[0] == P_8266_HS_MOSI && pins[1] == P_8266_HS_CLK) isHSPI = true;
|
||||
#else
|
||||
if(!num) isHSPI = true; // temporary hack to limit use of hardware SPI to a single SPI peripheral: only allow ESP32 hardware serial on segment 0
|
||||
#endif
|
||||
uint8_t t = I_NONE;
|
||||
switch (busType) {
|
||||
case TYPE_APA102: t = I_SS_DOT_3; break;
|
||||
case TYPE_LPD8806: t = I_SS_LPD_3; break;
|
||||
case TYPE_WS2801: t = I_SS_WS1_3; break;
|
||||
case TYPE_P9813: t = I_SS_P98_3; break;
|
||||
default: t=I_NONE;
|
||||
}
|
||||
if (t > I_NONE && isHSPI) t--; //hardware SPI has one smaller ID than software
|
||||
return t;
|
||||
} else {
|
||||
#ifdef ESP8266
|
||||
uint8_t offset = pins[0] -1; //for driver: 0 = uart0, 1 = uart1, 2 = dma, 3 = bitbang
|
||||
if (offset > 3) offset = 3;
|
||||
switch (busType) {
|
||||
case TYPE_WS2812_RGB:
|
||||
case TYPE_WS2812_WWA:
|
||||
return I_8266_U0_NEO_3 + offset;
|
||||
case TYPE_SK6812_RGBW:
|
||||
return I_8266_U0_NEO_4 + offset;
|
||||
case TYPE_WS2811_400KHZ:
|
||||
return I_8266_U0_400_3 + offset;
|
||||
}
|
||||
#else //ESP32
|
||||
uint8_t offset = num; //RMT bus # == bus index in BusManager
|
||||
if (offset > 9) return I_NONE;
|
||||
switch (busType) {
|
||||
case TYPE_WS2812_RGB:
|
||||
case TYPE_WS2812_WWA:
|
||||
return I_32_R0_NEO_3 + offset;
|
||||
case TYPE_SK6812_RGBW:
|
||||
return I_32_R0_NEO_4 + offset;
|
||||
case TYPE_WS2811_400KHZ:
|
||||
return I_32_R0_400_3 + offset;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return I_NONE;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -11,17 +11,25 @@ void shortPressAction()
|
||||
toggleOnOff();
|
||||
colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
|
||||
} else {
|
||||
applyMacro(macroButton);
|
||||
applyPreset(macroButton);
|
||||
}
|
||||
}
|
||||
|
||||
bool isButtonPressed()
|
||||
{
|
||||
if (btnPin>=0 && digitalRead(btnPin) == LOW) return true;
|
||||
#ifdef TOUCHPIN
|
||||
if (touchRead(TOUCHPIN) <= TOUCH_THRESHOLD) return true;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void handleButton()
|
||||
{
|
||||
#ifdef BTNPIN
|
||||
if (!buttonEnabled) return;
|
||||
|
||||
if (digitalRead(BTNPIN) == LOW) //pressed
|
||||
if (btnPin<0 || !buttonEnabled) return;
|
||||
|
||||
if (isButtonPressed()) //pressed
|
||||
{
|
||||
if (!buttonPressedBefore) buttonPressedTime = millis();
|
||||
buttonPressedBefore = true;
|
||||
@@ -30,14 +38,14 @@ void handleButton()
|
||||
{
|
||||
if (!buttonLongPressed)
|
||||
{
|
||||
if (macroLongPress) {applyMacro(macroLongPress);}
|
||||
if (macroLongPress) {applyPreset(macroLongPress);}
|
||||
else _setRandomColor(false,true);
|
||||
|
||||
buttonLongPressed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (digitalRead(BTNPIN) == HIGH && buttonPressedBefore) //released
|
||||
else if (!isButtonPressed() && buttonPressedBefore) //released
|
||||
{
|
||||
long dur = millis() - buttonPressedTime;
|
||||
if (dur < 50) {buttonPressedBefore = false; return;} //too short "press", debounce
|
||||
@@ -51,7 +59,7 @@ void handleButton()
|
||||
else if (!buttonLongPressed) { //short press
|
||||
if (macroDoublePress)
|
||||
{
|
||||
if (doublePress) applyMacro(macroDoublePress);
|
||||
if (doublePress) applyPreset(macroDoublePress);
|
||||
else buttonWaitTime = millis();
|
||||
} else shortPressAction();
|
||||
}
|
||||
@@ -64,7 +72,6 @@ void handleButton()
|
||||
buttonWaitTime = 0;
|
||||
shortPressAction();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void handleIO()
|
||||
@@ -76,46 +83,26 @@ void handleIO()
|
||||
{
|
||||
lastOnTime = millis();
|
||||
if (offMode)
|
||||
{
|
||||
#if RLYPIN >= 0
|
||||
digitalWrite(RLYPIN, RLYMDE);
|
||||
#endif
|
||||
{
|
||||
if (rlyPin>=0) {
|
||||
pinMode(rlyPin, OUTPUT);
|
||||
digitalWrite(rlyPin, rlyMde);
|
||||
}
|
||||
offMode = false;
|
||||
}
|
||||
} else if (millis() - lastOnTime > 600)
|
||||
{
|
||||
#if RLYPIN >= 0
|
||||
if (!offMode) digitalWrite(RLYPIN, !RLYMDE);
|
||||
#endif
|
||||
if (!offMode) {
|
||||
#ifdef ESP8266
|
||||
//turn off built-in LED if strip is turned off
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
#endif
|
||||
if (rlyPin>=0) {
|
||||
pinMode(rlyPin, OUTPUT);
|
||||
digitalWrite(rlyPin, !rlyMde);
|
||||
}
|
||||
}
|
||||
offMode = true;
|
||||
}
|
||||
|
||||
#if AUXPIN >= 0
|
||||
//output
|
||||
if (auxActive || auxActiveBefore)
|
||||
{
|
||||
if (!auxActiveBefore)
|
||||
{
|
||||
auxActiveBefore = true;
|
||||
switch (auxTriggeredState)
|
||||
{
|
||||
case 0: pinMode(AUXPIN, INPUT); break;
|
||||
case 1: pinMode(AUXPIN, OUTPUT); digitalWrite(AUXPIN, HIGH); break;
|
||||
case 2: pinMode(AUXPIN, OUTPUT); digitalWrite(AUXPIN, LOW); break;
|
||||
}
|
||||
auxStartTime = millis();
|
||||
}
|
||||
if ((millis() - auxStartTime > auxTime*1000 && auxTime != 255) || !auxActive)
|
||||
{
|
||||
auxActive = false;
|
||||
auxActiveBefore = false;
|
||||
switch (auxDefaultState)
|
||||
{
|
||||
case 0: pinMode(AUXPIN, INPUT); break;
|
||||
case 1: pinMode(AUXPIN, OUTPUT); digitalWrite(AUXPIN, HIGH); break;
|
||||
case 2: pinMode(AUXPIN, OUTPUT); digitalWrite(AUXPIN, LOW); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
746
wled00/cfg.cpp
Normal file
@@ -0,0 +1,746 @@
|
||||
#include "wled.h"
|
||||
|
||||
/*
|
||||
* Serializes and parses the cfg.json and wsec.json settings files, stored in internal FS.
|
||||
* The structure of the JSON is not to be considered an official API and may change without notice.
|
||||
*/
|
||||
|
||||
//simple macro for ArduinoJSON's or syntax
|
||||
#define CJSON(a,b) a = b | a
|
||||
|
||||
void getStringFromJson(char* dest, const char* src, size_t len) {
|
||||
if (src != nullptr) strlcpy(dest, src, len);
|
||||
}
|
||||
|
||||
void deserializeConfig() {
|
||||
bool fromeep = false;
|
||||
bool success = deserializeConfigSec();
|
||||
if (!success) { //if file does not exist, try reading from EEPROM
|
||||
deEEPSettings();
|
||||
fromeep = true;
|
||||
}
|
||||
|
||||
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
|
||||
|
||||
DEBUG_PRINTLN(F("Reading settings from /cfg.json..."));
|
||||
|
||||
success = readObjectFromFile("/cfg.json", nullptr, &doc);
|
||||
if (!success) { //if file does not exist, try reading from EEPROM
|
||||
if (!fromeep) deEEPSettings();
|
||||
return;
|
||||
}
|
||||
|
||||
//int rev_major = doc["rev"][0]; // 1
|
||||
//int rev_minor = doc["rev"][1]; // 0
|
||||
|
||||
//long vid = doc[F("vid")]; // 2010020
|
||||
|
||||
JsonObject id = doc["id"];
|
||||
getStringFromJson(cmDNS, id[F("mdns")], 33);
|
||||
getStringFromJson(serverDescription, id[F("name")], 33);
|
||||
getStringFromJson(alexaInvocationName, id[F("inv")], 33);
|
||||
|
||||
JsonObject nw_ins_0 = doc["nw"][F("ins")][0];
|
||||
getStringFromJson(clientSSID, nw_ins_0[F("ssid")], 33);
|
||||
//int nw_ins_0_pskl = nw_ins_0[F("pskl")];
|
||||
//The WiFi PSK is normally not contained in the regular file for security reasons.
|
||||
//If it is present however, we will use it
|
||||
getStringFromJson(clientPass, nw_ins_0["psk"], 65);
|
||||
|
||||
JsonArray nw_ins_0_ip = nw_ins_0["ip"];
|
||||
JsonArray nw_ins_0_gw = nw_ins_0["gw"];
|
||||
JsonArray nw_ins_0_sn = nw_ins_0["sn"];
|
||||
|
||||
for (byte i = 0; i < 4; i++) {
|
||||
CJSON(staticIP[i], nw_ins_0_ip[i]);
|
||||
CJSON(staticGateway[i], nw_ins_0_gw[i]);
|
||||
CJSON(staticSubnet[i], nw_ins_0_sn[i]);
|
||||
}
|
||||
|
||||
JsonObject ap = doc["ap"];
|
||||
getStringFromJson(apSSID, ap[F("ssid")], 33);
|
||||
getStringFromJson(apPass, ap["psk"] , 65); //normally not present due to security
|
||||
//int ap_pskl = ap[F("pskl")];
|
||||
|
||||
CJSON(apChannel, ap[F("chan")]);
|
||||
if (apChannel > 13 || apChannel < 1) apChannel = 1;
|
||||
|
||||
CJSON(apHide, ap[F("hide")]);
|
||||
if (apHide > 1) apHide = 1;
|
||||
|
||||
CJSON(apBehavior, ap[F("behav")]);
|
||||
|
||||
#ifdef WLED_USE_ETHERNET
|
||||
JsonObject ethernet = doc[F("eth")];
|
||||
CJSON(ethernetType, ethernet["type"]);
|
||||
#endif
|
||||
|
||||
/*
|
||||
JsonArray ap_ip = ap["ip"];
|
||||
for (byte i = 0; i < 4; i++) {
|
||||
apIP[i] = ap_ip;
|
||||
}*/
|
||||
|
||||
noWifiSleep = doc[F("wifi")][F("sleep")] | !noWifiSleep; // inverted
|
||||
noWifiSleep = !noWifiSleep;
|
||||
//int wifi_phy = doc[F("wifi")][F("phy")]; //force phy mode n?
|
||||
|
||||
JsonObject hw = doc[F("hw")];
|
||||
|
||||
// initialize LED pins and lengths prior to other HW
|
||||
JsonObject hw_led = hw[F("led")];
|
||||
|
||||
CJSON(ledCount, hw_led[F("total")]);
|
||||
if (ledCount > MAX_LEDS) ledCount = MAX_LEDS;
|
||||
|
||||
CJSON(strip.ablMilliampsMax, hw_led[F("maxpwr")]);
|
||||
CJSON(strip.milliampsPerLed, hw_led[F("ledma")]);
|
||||
CJSON(strip.rgbwMode, hw_led[F("rgbwm")]);
|
||||
|
||||
JsonArray ins = hw_led["ins"];
|
||||
uint8_t s = 0; //bus iterator
|
||||
strip.isRgbw = false;
|
||||
busses.removeAll();
|
||||
uint32_t mem = 0;
|
||||
for (JsonObject elm : ins) {
|
||||
if (s >= WLED_MAX_BUSSES) break;
|
||||
uint8_t pins[5] = {255, 255, 255, 255, 255};
|
||||
JsonArray pinArr = elm[F("pin")];
|
||||
if (pinArr.size() == 0) continue;
|
||||
pins[0] = pinArr[0];
|
||||
uint8_t i = 0;
|
||||
for (int p : pinArr) {
|
||||
pins[i] = p;
|
||||
i++;
|
||||
if (i>4) break;
|
||||
}
|
||||
|
||||
uint16_t length = elm[F("len")];
|
||||
if (length==0) continue;
|
||||
uint8_t colorOrder = (int)elm[F("order")];
|
||||
//only use skip from the first strip (this shouldn't have been in ins obj. but remains here for compatibility)
|
||||
if (s==0) skipFirstLed = elm[F("skip")];
|
||||
uint16_t start = elm[F("start")] | 0;
|
||||
if (start >= ledCount) continue;
|
||||
//limit length of strip if it would exceed total configured LEDs
|
||||
if (start + length > ledCount) length = ledCount - start;
|
||||
uint8_t ledType = elm["type"] | TYPE_WS2812_RGB;
|
||||
bool reversed = elm["rev"];
|
||||
//RGBW mode is enabled if at least one of the strips is RGBW
|
||||
strip.isRgbw = (strip.isRgbw || BusManager::isRgbw(ledType));
|
||||
s++;
|
||||
BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed);
|
||||
mem += busses.memUsage(bc);
|
||||
if (mem <= MAX_LED_MEMORY) busses.add(bc);
|
||||
}
|
||||
strip.finalizeInit(ledCount, skipFirstLed);
|
||||
if (hw_led["rev"]) busses.getBus(0)->reversed = true; //set 0.11 global reversed setting for first bus
|
||||
|
||||
JsonObject hw_btn_ins_0 = hw[F("btn")][F("ins")][0];
|
||||
CJSON(buttonEnabled, hw_btn_ins_0["type"]);
|
||||
int hw_btn_pin = hw_btn_ins_0[F("pin")][0];
|
||||
if (pinManager.allocatePin(hw_btn_pin,false)) {
|
||||
btnPin = hw_btn_pin;
|
||||
pinMode(btnPin, INPUT_PULLUP);
|
||||
} else {
|
||||
btnPin = -1;
|
||||
}
|
||||
|
||||
JsonArray hw_btn_ins_0_macros = hw_btn_ins_0[F("macros")];
|
||||
CJSON(macroButton, hw_btn_ins_0_macros[0]);
|
||||
CJSON(macroLongPress,hw_btn_ins_0_macros[1]);
|
||||
CJSON(macroDoublePress, hw_btn_ins_0_macros[2]);
|
||||
|
||||
//int hw_btn_ins_0_type = hw_btn_ins_0["type"]; // 0
|
||||
|
||||
#ifndef WLED_DISABLE_INFRARED
|
||||
int hw_ir_pin = hw["ir"]["pin"] | -1; // 4
|
||||
if (pinManager.allocatePin(hw_ir_pin,false)) {
|
||||
irPin = hw_ir_pin;
|
||||
} else {
|
||||
irPin = -1;
|
||||
}
|
||||
#endif
|
||||
CJSON(irEnabled, hw["ir"]["type"]);
|
||||
|
||||
JsonObject relay = hw[F("relay")];
|
||||
|
||||
int hw_relay_pin = relay["pin"];
|
||||
if (pinManager.allocatePin(hw_relay_pin,true)) {
|
||||
rlyPin = hw_relay_pin;
|
||||
pinMode(rlyPin, OUTPUT);
|
||||
} else {
|
||||
rlyPin = -1;
|
||||
}
|
||||
if (relay.containsKey("rev")) {
|
||||
rlyMde = !relay["rev"];
|
||||
}
|
||||
|
||||
//int hw_status_pin = hw[F("status")][F("pin")]; // -1
|
||||
|
||||
JsonObject light = doc[F("light")];
|
||||
CJSON(briMultiplier, light[F("scale-bri")]);
|
||||
CJSON(strip.paletteBlend, light[F("pal-mode")]);
|
||||
|
||||
float light_gc_bri = light[F("gc")]["bri"];
|
||||
float light_gc_col = light[F("gc")]["col"]; // 2.8
|
||||
if (light_gc_bri > 1.5) strip.gammaCorrectBri = true;
|
||||
else if (light_gc_bri > 0.5) strip.gammaCorrectBri = false;
|
||||
if (light_gc_col > 1.5) strip.gammaCorrectCol = true;
|
||||
else if (light_gc_col > 0.5) strip.gammaCorrectCol = false;
|
||||
|
||||
JsonObject light_tr = light[F("tr")];
|
||||
CJSON(fadeTransition, light_tr[F("mode")]);
|
||||
int tdd = light_tr[F("dur")] | -1;
|
||||
if (tdd >= 0) transitionDelayDefault = tdd * 100;
|
||||
CJSON(strip.paletteFade, light_tr[F("pal")]);
|
||||
|
||||
JsonObject light_nl = light["nl"];
|
||||
CJSON(nightlightMode, light_nl[F("mode")]);
|
||||
CJSON(nightlightDelayMinsDefault, light_nl[F("dur")]);
|
||||
nightlightDelayMins = nightlightDelayMinsDefault;
|
||||
|
||||
CJSON(nightlightTargetBri, light_nl[F("tbri")]);
|
||||
CJSON(macroNl, light_nl[F("macro")]);
|
||||
|
||||
JsonObject def = doc[F("def")];
|
||||
CJSON(bootPreset, def[F("ps")]);
|
||||
CJSON(turnOnAtBoot, def["on"]); // true
|
||||
CJSON(briS, def["bri"]); // 128
|
||||
|
||||
JsonObject def_cy = def[F("cy")];
|
||||
CJSON(presetCyclingEnabled, def_cy["on"]);
|
||||
|
||||
CJSON(presetCycleMin, def_cy[F("range")][0]);
|
||||
CJSON(presetCycleMax, def_cy[F("range")][1]);
|
||||
|
||||
tdd = def_cy[F("dur")] | -1;
|
||||
if (tdd > 0) presetCycleTime = tdd;
|
||||
|
||||
JsonObject interfaces = doc["if"];
|
||||
|
||||
JsonObject if_sync = interfaces[F("sync")];
|
||||
CJSON(udpPort, if_sync[F("port0")]); // 21324
|
||||
CJSON(udpPort2, if_sync[F("port1")]); // 65506
|
||||
|
||||
JsonObject if_sync_recv = if_sync["recv"];
|
||||
CJSON(receiveNotificationBrightness, if_sync_recv["bri"]);
|
||||
CJSON(receiveNotificationColor, if_sync_recv["col"]);
|
||||
CJSON(receiveNotificationEffects, if_sync_recv[F("fx")]);
|
||||
receiveNotifications = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects);
|
||||
|
||||
JsonObject if_sync_send = if_sync["send"];
|
||||
CJSON(notifyDirectDefault, if_sync_send[F("dir")]);
|
||||
notifyDirect = notifyDirectDefault;
|
||||
CJSON(notifyButton, if_sync_send[F("btn")]);
|
||||
CJSON(notifyAlexa, if_sync_send[F("va")]);
|
||||
CJSON(notifyHue, if_sync_send[F("hue")]);
|
||||
CJSON(notifyMacro, if_sync_send[F("macro")]);
|
||||
CJSON(notifyTwice, if_sync_send[F("twice")]);
|
||||
|
||||
JsonObject if_nodes = interfaces["nodes"];
|
||||
CJSON(nodeListEnabled, if_nodes[F("list")]);
|
||||
CJSON(nodeBroadcastEnabled, if_nodes[F("bcast")]);
|
||||
|
||||
JsonObject if_live = interfaces["live"];
|
||||
CJSON(receiveDirect, if_live["en"]);
|
||||
CJSON(e131Port, if_live["port"]); // 5568
|
||||
CJSON(e131Multicast, if_live[F("mc")]);
|
||||
|
||||
JsonObject if_live_dmx = if_live[F("dmx")];
|
||||
CJSON(e131Universe, if_live_dmx[F("uni")]);
|
||||
CJSON(e131SkipOutOfSequence, if_live_dmx[F("seqskip")]);
|
||||
CJSON(DMXAddress, if_live_dmx[F("addr")]);
|
||||
CJSON(DMXMode, if_live_dmx[F("mode")]);
|
||||
|
||||
tdd = if_live[F("timeout")] | -1;
|
||||
if (tdd >= 0) realtimeTimeoutMs = tdd * 100;
|
||||
CJSON(arlsForceMaxBri, if_live[F("maxbri")]);
|
||||
CJSON(arlsDisableGammaCorrection, if_live[F("no-gc")]); // false
|
||||
CJSON(arlsOffset, if_live[F("offset")]); // 0
|
||||
|
||||
CJSON(alexaEnabled, interfaces[F("va")][F("alexa")]); // false
|
||||
|
||||
CJSON(macroAlexaOn, interfaces[F("va")][F("macros")][0]);
|
||||
CJSON(macroAlexaOff, interfaces[F("va")][F("macros")][1]);
|
||||
|
||||
const char* apikey = interfaces["blynk"][F("token")] | "Hidden";
|
||||
tdd = strnlen(apikey, 36);
|
||||
if (tdd > 20 || tdd == 0)
|
||||
getStringFromJson(blynkApiKey, apikey, 36); //normally not present due to security
|
||||
|
||||
JsonObject if_blynk = interfaces["blynk"];
|
||||
getStringFromJson(blynkHost, if_blynk[F("host")], 33);
|
||||
CJSON(blynkPort, if_blynk["port"]);
|
||||
|
||||
JsonObject if_mqtt = interfaces["mqtt"];
|
||||
CJSON(mqttEnabled, if_mqtt["en"]);
|
||||
getStringFromJson(mqttServer, if_mqtt[F("broker")], 33);
|
||||
CJSON(mqttPort, if_mqtt["port"]); // 1883
|
||||
getStringFromJson(mqttUser, if_mqtt[F("user")], 41);
|
||||
getStringFromJson(mqttPass, if_mqtt["psk"], 41); //normally not present due to security
|
||||
getStringFromJson(mqttClientID, if_mqtt[F("cid")], 41);
|
||||
|
||||
getStringFromJson(mqttDeviceTopic, if_mqtt[F("topics")][F("device")], 33); // "wled/test"
|
||||
getStringFromJson(mqttGroupTopic, if_mqtt[F("topics")][F("group")], 33); // ""
|
||||
|
||||
JsonObject if_hue = interfaces[F("hue")];
|
||||
CJSON(huePollingEnabled, if_hue["en"]);
|
||||
CJSON(huePollLightId, if_hue["id"]);
|
||||
tdd = if_hue[F("iv")] | -1;
|
||||
if (tdd >= 2) huePollIntervalMs = tdd * 100;
|
||||
|
||||
JsonObject if_hue_recv = if_hue["recv"];
|
||||
CJSON(hueApplyOnOff, if_hue_recv["on"]);
|
||||
CJSON(hueApplyBri, if_hue_recv["bri"]);
|
||||
CJSON(hueApplyColor, if_hue_recv["col"]);
|
||||
|
||||
JsonArray if_hue_ip = if_hue["ip"];
|
||||
|
||||
for (byte i = 0; i < 4; i++)
|
||||
CJSON(hueIP[i], if_hue_ip[i]);
|
||||
|
||||
JsonObject if_ntp = interfaces[F("ntp")];
|
||||
CJSON(ntpEnabled, if_ntp["en"]);
|
||||
getStringFromJson(ntpServerName, if_ntp[F("host")], 33); // "1.wled.pool.ntp.org"
|
||||
CJSON(currentTimezone, if_ntp[F("tz")]);
|
||||
CJSON(utcOffsetSecs, if_ntp[F("offset")]);
|
||||
CJSON(useAMPM, if_ntp[F("ampm")]);
|
||||
|
||||
JsonObject ol = doc[F("ol")];
|
||||
CJSON(overlayDefault ,ol[F("clock")]); // 0
|
||||
CJSON(countdownMode, ol[F("cntdwn")]);
|
||||
overlayCurrent = overlayDefault;
|
||||
|
||||
CJSON(overlayMin, ol[F("min")]);
|
||||
CJSON(overlayMax, ol[F("max")]);
|
||||
CJSON(analogClock12pixel, ol[F("o12pix")]);
|
||||
CJSON(analogClock5MinuteMarks, ol[F("o5m")]);
|
||||
CJSON(analogClockSecondsTrail, ol[F("osec")]);
|
||||
|
||||
//timed macro rules
|
||||
JsonObject tm = doc[F("timers")];
|
||||
JsonObject cntdwn = tm[F("cntdwn")];
|
||||
JsonArray cntdwn_goal = cntdwn[F("goal")];
|
||||
CJSON(countdownYear, cntdwn_goal[0]);
|
||||
CJSON(countdownMonth, cntdwn_goal[1]);
|
||||
CJSON(countdownDay, cntdwn_goal[2]);
|
||||
CJSON(countdownHour, cntdwn_goal[3]);
|
||||
CJSON(countdownMin, cntdwn_goal[4]);
|
||||
CJSON(countdownSec, cntdwn_goal[5]);
|
||||
CJSON(macroCountdown, cntdwn[F("macro")]);
|
||||
setCountdown();
|
||||
|
||||
JsonArray timers = tm[F("ins")];
|
||||
uint8_t it = 0;
|
||||
for (JsonObject timer : timers) {
|
||||
if (it > 7) break;
|
||||
CJSON(timerHours[it], timer[F("hour")]);
|
||||
CJSON(timerMinutes[it], timer[F("min")]);
|
||||
CJSON(timerMacro[it], timer[F("macro")]);
|
||||
|
||||
byte dowPrev = timerWeekday[it];
|
||||
//note: act is currently only 0 or 1.
|
||||
//the reason we are not using bool is that the on-disk type in 0.11.0 was already int
|
||||
int actPrev = timerWeekday[it] & 0x01;
|
||||
CJSON(timerWeekday[it], timer[F("dow")]);
|
||||
if (timerWeekday[it] != dowPrev) { //present in JSON
|
||||
timerWeekday[it] <<= 1; //add active bit
|
||||
int act = timer["en"] | actPrev;
|
||||
if (act) timerWeekday[it]++;
|
||||
}
|
||||
|
||||
it++;
|
||||
}
|
||||
|
||||
JsonObject ota = doc["ota"];
|
||||
const char* pwd = ota["psk"]; //normally not present due to security
|
||||
|
||||
bool pwdCorrect = !otaLock; //always allow access if ota not locked
|
||||
if (pwd != nullptr && strncmp(otaPass, pwd, 33) == 0) pwdCorrect = true;
|
||||
|
||||
if (pwdCorrect) { //only accept these values from cfg.json if ota is unlocked (else from wsec.json)
|
||||
CJSON(otaLock, ota[F("lock")]);
|
||||
CJSON(wifiLock, ota[F("lock-wifi")]);
|
||||
CJSON(aOtaEnabled, ota[F("aota")]);
|
||||
getStringFromJson(otaPass, pwd, 33); //normally not present due to security
|
||||
}
|
||||
|
||||
#ifdef WLED_ENABLE_DMX
|
||||
JsonObject dmx = doc["dmx"];
|
||||
CJSON(DMXChannels, dmx[F("chan")]);
|
||||
CJSON(DMXGap,dmx[F("gap")]);
|
||||
CJSON(DMXStart, dmx[F("start")]);
|
||||
CJSON(DMXStartLED,dmx[F("start-led")]);
|
||||
|
||||
JsonArray dmx_fixmap = dmx[F("fixmap")];
|
||||
it = 0;
|
||||
for (int i : dmx_fixmap) {
|
||||
if (it > 14) break;
|
||||
CJSON(DMXFixtureMap[i],dmx_fixmap[i]);
|
||||
it++;
|
||||
}
|
||||
#endif
|
||||
|
||||
JsonObject usermods_settings = doc["um"];
|
||||
usermods.readFromConfig(usermods_settings);
|
||||
}
|
||||
|
||||
void serializeConfig() {
|
||||
serializeConfigSec();
|
||||
|
||||
DEBUG_PRINTLN(F("Writing settings to /cfg.json..."));
|
||||
|
||||
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
|
||||
|
||||
JsonArray rev = doc.createNestedArray("rev");
|
||||
rev.add(1); //major settings revision
|
||||
rev.add(0); //minor settings revision
|
||||
|
||||
doc[F("vid")] = VERSION;
|
||||
|
||||
JsonObject id = doc.createNestedObject("id");
|
||||
id[F("mdns")] = cmDNS;
|
||||
id[F("name")] = serverDescription;
|
||||
id[F("inv")] = alexaInvocationName;
|
||||
|
||||
JsonObject nw = doc.createNestedObject("nw");
|
||||
|
||||
JsonArray nw_ins = nw.createNestedArray("ins");
|
||||
|
||||
JsonObject nw_ins_0 = nw_ins.createNestedObject();
|
||||
nw_ins_0[F("ssid")] = clientSSID;
|
||||
nw_ins_0[F("pskl")] = strlen(clientPass);
|
||||
|
||||
JsonArray nw_ins_0_ip = nw_ins_0.createNestedArray("ip");
|
||||
JsonArray nw_ins_0_gw = nw_ins_0.createNestedArray("gw");
|
||||
JsonArray nw_ins_0_sn = nw_ins_0.createNestedArray("sn");
|
||||
|
||||
for (byte i = 0; i < 4; i++) {
|
||||
nw_ins_0_ip.add(staticIP[i]);
|
||||
nw_ins_0_gw.add(staticGateway[i]);
|
||||
nw_ins_0_sn.add(staticSubnet[i]);
|
||||
}
|
||||
|
||||
JsonObject ap = doc.createNestedObject("ap");
|
||||
ap[F("ssid")] = apSSID;
|
||||
ap[F("pskl")] = strlen(apPass);
|
||||
ap[F("chan")] = apChannel;
|
||||
ap[F("hide")] = apHide;
|
||||
ap[F("behav")] = apBehavior;
|
||||
|
||||
JsonArray ap_ip = ap.createNestedArray("ip");
|
||||
ap_ip.add(4);
|
||||
ap_ip.add(3);
|
||||
ap_ip.add(2);
|
||||
ap_ip.add(1);
|
||||
|
||||
JsonObject wifi = doc.createNestedObject("wifi");
|
||||
wifi[F("sleep")] = !noWifiSleep;
|
||||
wifi[F("phy")] = 1;
|
||||
|
||||
#ifdef WLED_USE_ETHERNET
|
||||
JsonObject ethernet = doc.createNestedObject("eth");
|
||||
ethernet["type"] = ethernetType;
|
||||
#endif
|
||||
|
||||
JsonObject hw = doc.createNestedObject("hw");
|
||||
|
||||
JsonObject hw_led = hw.createNestedObject("led");
|
||||
hw_led[F("total")] = ledCount;
|
||||
hw_led[F("maxpwr")] = strip.ablMilliampsMax;
|
||||
hw_led[F("ledma")] = strip.milliampsPerLed;
|
||||
hw_led[F("rgbwm")] = strip.rgbwMode;
|
||||
|
||||
JsonArray hw_led_ins = hw_led.createNestedArray("ins");
|
||||
|
||||
for (uint8_t s = 0; s < busses.getNumBusses(); s++) {
|
||||
Bus *bus = busses.getBus(s);
|
||||
if (!bus || bus->getLength()==0) break;
|
||||
JsonObject ins = hw_led_ins.createNestedObject();
|
||||
ins["en"] = true;
|
||||
ins[F("start")] = bus->getStart();
|
||||
ins[F("len")] = bus->getLength();
|
||||
JsonArray ins_pin = ins.createNestedArray("pin");
|
||||
uint8_t pins[5];
|
||||
uint8_t nPins = bus->getPins(pins);
|
||||
for (uint8_t i = 0; i < nPins; i++) ins_pin.add(pins[i]);
|
||||
ins[F("order")] = bus->getColorOrder();
|
||||
ins["rev"] = bus->reversed;
|
||||
ins[F("skip")] = (skipFirstLed && s == 0) ? 1 : 0;
|
||||
ins["type"] = bus->getType();
|
||||
}
|
||||
|
||||
JsonObject hw_btn = hw.createNestedObject("btn");
|
||||
|
||||
JsonArray hw_btn_ins = hw_btn.createNestedArray("ins");
|
||||
|
||||
// button BTNPIN
|
||||
JsonObject hw_btn_ins_0 = hw_btn_ins.createNestedObject();
|
||||
hw_btn_ins_0["type"] = (buttonEnabled) ? BTN_TYPE_PUSH : BTN_TYPE_NONE;
|
||||
|
||||
JsonArray hw_btn_ins_0_pin = hw_btn_ins_0.createNestedArray("pin");
|
||||
hw_btn_ins_0_pin.add(btnPin);
|
||||
|
||||
JsonArray hw_btn_ins_0_macros = hw_btn_ins_0.createNestedArray("macros");
|
||||
hw_btn_ins_0_macros.add(macroButton);
|
||||
hw_btn_ins_0_macros.add(macroLongPress);
|
||||
hw_btn_ins_0_macros.add(macroDoublePress);
|
||||
|
||||
#ifndef WLED_DISABLE_INFRARED
|
||||
JsonObject hw_ir = hw.createNestedObject("ir");
|
||||
hw_ir["pin"] = irPin;
|
||||
hw_ir[F("type")] = irEnabled; // the byte 'irEnabled' does contain the IR-Remote Type ( 0=disabled )
|
||||
#endif
|
||||
|
||||
JsonObject hw_relay = hw.createNestedObject(F("relay"));
|
||||
hw_relay["pin"] = rlyPin;
|
||||
hw_relay["rev"] = !rlyMde;
|
||||
|
||||
//JsonObject hw_status = hw.createNestedObject("status");
|
||||
//hw_status["pin"] = -1;
|
||||
|
||||
JsonObject light = doc.createNestedObject(F("light"));
|
||||
light[F("scale-bri")] = briMultiplier;
|
||||
light[F("pal-mode")] = strip.paletteBlend;
|
||||
|
||||
JsonObject light_gc = light.createNestedObject("gc");
|
||||
light_gc["bri"] = (strip.gammaCorrectBri) ? 2.8 : 1.0;
|
||||
light_gc["col"] = (strip.gammaCorrectCol) ? 2.8 : 1.0;
|
||||
|
||||
JsonObject light_tr = light.createNestedObject("tr");
|
||||
light_tr[F("mode")] = fadeTransition;
|
||||
light_tr[F("dur")] = transitionDelayDefault / 100;
|
||||
light_tr[F("pal")] = strip.paletteFade;
|
||||
|
||||
JsonObject light_nl = light.createNestedObject("nl");
|
||||
light_nl[F("mode")] = nightlightMode;
|
||||
light_nl[F("dur")] = nightlightDelayMinsDefault;
|
||||
light_nl[F("tbri")] = nightlightTargetBri;
|
||||
light_nl[F("macro")] = macroNl;
|
||||
|
||||
JsonObject def = doc.createNestedObject("def");
|
||||
def[F("ps")] = bootPreset;
|
||||
def["on"] = turnOnAtBoot;
|
||||
def["bri"] = briS;
|
||||
|
||||
//to be removed once preset cycles are presets
|
||||
if (saveCurrPresetCycConf) {
|
||||
JsonObject def_cy = def.createNestedObject("cy");
|
||||
def_cy["on"] = presetCyclingEnabled;
|
||||
|
||||
JsonArray def_cy_range = def_cy.createNestedArray(F("range"));
|
||||
def_cy_range.add(presetCycleMin);
|
||||
def_cy_range.add(presetCycleMax);
|
||||
def_cy[F("dur")] = presetCycleTime;
|
||||
}
|
||||
|
||||
JsonObject interfaces = doc.createNestedObject("if");
|
||||
|
||||
JsonObject if_sync = interfaces.createNestedObject("sync");
|
||||
if_sync[F("port0")] = udpPort;
|
||||
if_sync[F("port1")] = udpPort2;
|
||||
|
||||
JsonObject if_sync_recv = if_sync.createNestedObject("recv");
|
||||
if_sync_recv["bri"] = receiveNotificationBrightness;
|
||||
if_sync_recv["col"] = receiveNotificationColor;
|
||||
if_sync_recv[F("fx")] = receiveNotificationEffects;
|
||||
|
||||
JsonObject if_sync_send = if_sync.createNestedObject("send");
|
||||
if_sync_send[F("dir")] = notifyDirect;
|
||||
if_sync_send[F("btn")] = notifyButton;
|
||||
if_sync_send[F("va")] = notifyAlexa;
|
||||
if_sync_send[F("hue")] = notifyHue;
|
||||
if_sync_send[F("macro")] = notifyMacro;
|
||||
if_sync_send[F("twice")] = notifyTwice;
|
||||
|
||||
JsonObject if_nodes = interfaces.createNestedObject("nodes");
|
||||
if_nodes[F("list")] = nodeListEnabled;
|
||||
if_nodes[F("bcast")] = nodeBroadcastEnabled;
|
||||
|
||||
JsonObject if_live = interfaces.createNestedObject("live");
|
||||
if_live["en"] = receiveDirect;
|
||||
if_live["port"] = e131Port;
|
||||
if_live[F("mc")] = e131Multicast;
|
||||
|
||||
JsonObject if_live_dmx = if_live.createNestedObject("dmx");
|
||||
if_live_dmx[F("uni")] = e131Universe;
|
||||
if_live_dmx[F("seqskip")] = e131SkipOutOfSequence;
|
||||
if_live_dmx[F("addr")] = DMXAddress;
|
||||
if_live_dmx[F("mode")] = DMXMode;
|
||||
if_live[F("timeout")] = realtimeTimeoutMs / 100;
|
||||
if_live[F("maxbri")] = arlsForceMaxBri;
|
||||
if_live[F("no-gc")] = arlsDisableGammaCorrection;
|
||||
if_live[F("offset")] = arlsOffset;
|
||||
|
||||
JsonObject if_va = interfaces.createNestedObject("va");
|
||||
if_va[F("alexa")] = alexaEnabled;
|
||||
|
||||
JsonArray if_va_macros = if_va.createNestedArray("macros");
|
||||
if_va_macros.add(macroAlexaOn);
|
||||
if_va_macros.add(macroAlexaOff);
|
||||
JsonObject if_blynk = interfaces.createNestedObject("blynk");
|
||||
if_blynk[F("token")] = strlen(blynkApiKey) ? "Hidden":"";
|
||||
if_blynk[F("host")] = blynkHost;
|
||||
if_blynk["port"] = blynkPort;
|
||||
|
||||
JsonObject if_mqtt = interfaces.createNestedObject("mqtt");
|
||||
if_mqtt["en"] = mqttEnabled;
|
||||
if_mqtt[F("broker")] = mqttServer;
|
||||
if_mqtt["port"] = mqttPort;
|
||||
if_mqtt[F("user")] = mqttUser;
|
||||
if_mqtt[F("pskl")] = strlen(mqttPass);
|
||||
if_mqtt[F("cid")] = mqttClientID;
|
||||
|
||||
JsonObject if_mqtt_topics = if_mqtt.createNestedObject(F("topics"));
|
||||
if_mqtt_topics[F("device")] = mqttDeviceTopic;
|
||||
if_mqtt_topics[F("group")] = mqttGroupTopic;
|
||||
|
||||
JsonObject if_hue = interfaces.createNestedObject("hue");
|
||||
if_hue["en"] = huePollingEnabled;
|
||||
if_hue["id"] = huePollLightId;
|
||||
if_hue[F("iv")] = huePollIntervalMs / 100;
|
||||
|
||||
JsonObject if_hue_recv = if_hue.createNestedObject("recv");
|
||||
if_hue_recv["on"] = hueApplyOnOff;
|
||||
if_hue_recv["bri"] = hueApplyBri;
|
||||
if_hue_recv["col"] = hueApplyColor;
|
||||
|
||||
JsonArray if_hue_ip = if_hue.createNestedArray("ip");
|
||||
for (byte i = 0; i < 4; i++) {
|
||||
if_hue_ip.add(hueIP[i]);
|
||||
}
|
||||
|
||||
JsonObject if_ntp = interfaces.createNestedObject("ntp");
|
||||
if_ntp["en"] = ntpEnabled;
|
||||
if_ntp[F("host")] = ntpServerName;
|
||||
if_ntp[F("tz")] = currentTimezone;
|
||||
if_ntp[F("offset")] = utcOffsetSecs;
|
||||
if_ntp[F("ampm")] = useAMPM;
|
||||
|
||||
JsonObject ol = doc.createNestedObject("ol");
|
||||
ol[F("clock")] = overlayDefault;
|
||||
ol[F("cntdwn")] = countdownMode;
|
||||
|
||||
ol[F("min")] = overlayMin;
|
||||
ol[F("max")] = overlayMax;
|
||||
ol[F("o12pix")] = analogClock12pixel;
|
||||
ol[F("o5m")] = analogClock5MinuteMarks;
|
||||
ol[F("osec")] = analogClockSecondsTrail;
|
||||
|
||||
JsonObject timers = doc.createNestedObject(F("timers"));
|
||||
|
||||
JsonObject cntdwn = timers.createNestedObject(F("cntdwn"));
|
||||
JsonArray goal = cntdwn.createNestedArray(F("goal"));
|
||||
goal.add(countdownYear); goal.add(countdownMonth); goal.add(countdownDay);
|
||||
goal.add(countdownHour); goal.add(countdownMin); goal.add(countdownSec);
|
||||
cntdwn[F("macro")] = macroCountdown;
|
||||
|
||||
JsonArray timers_ins = timers.createNestedArray("ins");
|
||||
|
||||
for (byte i = 0; i < 8; i++) {
|
||||
if (timerMacro[i] == 0 && timerHours[i] == 0 && timerMinutes[i] == 0) continue;
|
||||
JsonObject timers_ins0 = timers_ins.createNestedObject();
|
||||
timers_ins0["en"] = (timerWeekday[i] & 0x01);
|
||||
timers_ins0[F("hour")] = timerHours[i];
|
||||
timers_ins0[F("min")] = timerMinutes[i];
|
||||
timers_ins0[F("macro")] = timerMacro[i];
|
||||
timers_ins0[F("dow")] = timerWeekday[i] >> 1;
|
||||
}
|
||||
|
||||
JsonObject ota = doc.createNestedObject("ota");
|
||||
ota[F("lock")] = otaLock;
|
||||
ota[F("lock-wifi")] = wifiLock;
|
||||
ota[F("pskl")] = strlen(otaPass);
|
||||
ota[F("aota")] = aOtaEnabled;
|
||||
|
||||
#ifdef WLED_ENABLE_DMX
|
||||
JsonObject dmx = doc.createNestedObject("dmx");
|
||||
dmx[F("chan")] = DMXChannels;
|
||||
dmx[F("gap")] = DMXGap;
|
||||
dmx[F("start")] = DMXStart;
|
||||
dmx[F("start-led")] = DMXStartLED;
|
||||
|
||||
JsonArray dmx_fixmap = dmx.createNestedArray(F("fixmap"));
|
||||
for (byte i = 0; i < 15; i++)
|
||||
dmx_fixmap.add(DMXFixtureMap[i]);
|
||||
#endif
|
||||
//}
|
||||
|
||||
JsonObject usermods_settings = doc.createNestedObject("um");
|
||||
usermods.addToConfig(usermods_settings);
|
||||
|
||||
File f = WLED_FS.open("/cfg.json", "w");
|
||||
if (f) serializeJson(doc, f);
|
||||
f.close();
|
||||
}
|
||||
|
||||
//settings in /wsec.json, not accessible via webserver, for passwords and tokens
|
||||
bool deserializeConfigSec() {
|
||||
DEBUG_PRINTLN(F("Reading settings from /wsec.json..."));
|
||||
|
||||
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
|
||||
|
||||
bool success = readObjectFromFile("/wsec.json", nullptr, &doc);
|
||||
if (!success) return false;
|
||||
|
||||
JsonObject nw_ins_0 = doc["nw"][F("ins")][0];
|
||||
getStringFromJson(clientPass, nw_ins_0["psk"], 65);
|
||||
|
||||
JsonObject ap = doc["ap"];
|
||||
getStringFromJson(apPass, ap["psk"] , 65);
|
||||
|
||||
JsonObject interfaces = doc["if"];
|
||||
|
||||
const char* apikey = interfaces["blynk"][F("token")] | "Hidden";
|
||||
int tdd = strnlen(apikey, 36);
|
||||
if (tdd > 20 || tdd == 0)
|
||||
getStringFromJson(blynkApiKey, apikey, 36);
|
||||
|
||||
JsonObject if_mqtt = interfaces["mqtt"];
|
||||
getStringFromJson(mqttPass, if_mqtt["psk"], 41);
|
||||
|
||||
getStringFromJson(hueApiKey, interfaces[F("hue")][F("key")], 47);
|
||||
|
||||
JsonObject ota = doc["ota"];
|
||||
getStringFromJson(otaPass, ota[F("pwd")], 33);
|
||||
CJSON(otaLock, ota[F("lock")]);
|
||||
CJSON(wifiLock, ota[F("lock-wifi")]);
|
||||
CJSON(aOtaEnabled, ota[F("aota")]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void serializeConfigSec() {
|
||||
DEBUG_PRINTLN(F("Writing settings to /wsec.json..."));
|
||||
|
||||
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
|
||||
|
||||
JsonObject nw = doc.createNestedObject("nw");
|
||||
|
||||
JsonArray nw_ins = nw.createNestedArray("ins");
|
||||
|
||||
JsonObject nw_ins_0 = nw_ins.createNestedObject();
|
||||
nw_ins_0["psk"] = clientPass;
|
||||
|
||||
JsonObject ap = doc.createNestedObject("ap");
|
||||
ap["psk"] = apPass;
|
||||
|
||||
JsonObject interfaces = doc.createNestedObject("if");
|
||||
JsonObject if_blynk = interfaces.createNestedObject("blynk");
|
||||
if_blynk[F("token")] = blynkApiKey;
|
||||
JsonObject if_mqtt = interfaces.createNestedObject("mqtt");
|
||||
if_mqtt["psk"] = mqttPass;
|
||||
JsonObject if_hue = interfaces.createNestedObject("hue");
|
||||
if_hue[F("key")] = hueApiKey;
|
||||
|
||||
JsonObject ota = doc.createNestedObject("ota");
|
||||
ota[F("pwd")] = otaPass;
|
||||
ota[F("lock")] = otaLock;
|
||||
ota[F("lock-wifi")] = wifiLock;
|
||||
ota[F("aota")] = aOtaEnabled;
|
||||
|
||||
File f = WLED_FS.open("/wsec.json", "w");
|
||||
if (f) serializeJson(doc, f);
|
||||
f.close();
|
||||
}
|
||||
@@ -33,6 +33,11 @@ void colorFromUint24(uint32_t in, bool secondary)
|
||||
}
|
||||
}
|
||||
|
||||
//store color components in uint32_t
|
||||
uint32_t colorFromRgbw(byte* rgbw) {
|
||||
return (rgbw[0] << 16) + (rgbw[1] << 8) + rgbw[2] + (rgbw[3] << 24);
|
||||
}
|
||||
|
||||
//relatively change white brightness, minumum A=5
|
||||
void relativeChangeWhite(int8_t amount, byte lowerBoundary)
|
||||
{
|
||||
@@ -59,10 +64,34 @@ void colorHStoRGB(uint16_t hue, byte sat, byte* rgb) //hue, sat to rgb
|
||||
case 4: rgb[0]=t,rgb[1]=p,rgb[2]=255;break;
|
||||
case 5: rgb[0]=255,rgb[1]=p,rgb[2]=q;
|
||||
}
|
||||
if (useRGBW && strip.rgbwMode == RGBW_MODE_LEGACY) colorRGBtoRGBW(col);
|
||||
if (strip.isRgbw && strip.rgbwMode == RGBW_MODE_LEGACY) colorRGBtoRGBW(col);
|
||||
}
|
||||
|
||||
void colorCTtoRGB(uint16_t mired, byte* rgb) //white spectrum to rgb
|
||||
void colorKtoRGB(uint16_t kelvin, byte* rgb) //white spectrum to rgb, calc
|
||||
{
|
||||
float r = 0, g = 0, b = 0;
|
||||
float temp = kelvin / 100;
|
||||
if (temp <= 66) {
|
||||
r = 255;
|
||||
g = round(99.4708025861 * log(temp) - 161.1195681661);
|
||||
if (temp <= 19) {
|
||||
b = 0;
|
||||
} else {
|
||||
b = round(138.5177312231 * log((temp - 10)) - 305.0447927307);
|
||||
}
|
||||
} else {
|
||||
r = round(329.698727446 * pow((temp - 60), -0.1332047592));
|
||||
g = round(288.1221695283 * pow((temp - 60), -0.0755148492));
|
||||
b = 255;
|
||||
}
|
||||
g += 15; //mod by Aircoookie, a bit less accurate but visibly less pinkish
|
||||
rgb[0] = (uint8_t) constrain(r, 0, 255);
|
||||
rgb[1] = (uint8_t) constrain(g, 0, 255);
|
||||
rgb[2] = (uint8_t) constrain(b, 0, 255);
|
||||
rgb[3] = 0;
|
||||
}
|
||||
|
||||
void colorCTtoRGB(uint16_t mired, byte* rgb) //white spectrum to rgb, bins
|
||||
{
|
||||
//this is only an approximation using WS2812B with gamma correction enabled
|
||||
if (mired > 475) {
|
||||
@@ -82,7 +111,7 @@ void colorCTtoRGB(uint16_t mired, byte* rgb) //white spectrum to rgb
|
||||
} else {
|
||||
rgb[0]=237;rgb[1]=255;rgb[2]=239;//150
|
||||
}
|
||||
if (useRGBW && strip.rgbwMode == RGBW_MODE_LEGACY) colorRGBtoRGBW(col);
|
||||
if (strip.isRgbw && strip.rgbwMode == RGBW_MODE_LEGACY) colorRGBtoRGBW(col);
|
||||
}
|
||||
|
||||
#ifndef WLED_DISABLE_HUESYNC
|
||||
@@ -140,7 +169,7 @@ void colorXYtoRGB(float x, float y, byte* rgb) //coordinates to rgb (https://www
|
||||
rgb[0] = 255.0*r;
|
||||
rgb[1] = 255.0*g;
|
||||
rgb[2] = 255.0*b;
|
||||
if (useRGBW) colorRGBtoRGBW(col);
|
||||
if (strip.isRgbw && strip.rgbwMode == RGBW_MODE_LEGACY) colorRGBtoRGBW(col);
|
||||
}
|
||||
|
||||
void colorRGBtoXY(byte* rgb, float* xy) //rgb to coordinates (https://www.developers.meethue.com/documentation/color-conversions-rgb-xy)
|
||||
@@ -153,7 +182,7 @@ void colorRGBtoXY(byte* rgb, float* xy) //rgb to coordinates (https://www.develo
|
||||
}
|
||||
#endif // WLED_DISABLE_HUESYNC
|
||||
|
||||
|
||||
//RRGGBB / WWRRGGBB order for hex
|
||||
void colorFromDecOrHexString(byte* rgb, char* in)
|
||||
{
|
||||
if (in[0] == 0) return;
|
||||
@@ -174,6 +203,27 @@ void colorFromDecOrHexString(byte* rgb, char* in)
|
||||
rgb[2] = c & 0xFF;
|
||||
}
|
||||
|
||||
//contrary to the colorFromDecOrHexString() function, this uses the more standard RRGGBB / RRGGBBWW order
|
||||
bool colorFromHexString(byte* rgb, const char* in) {
|
||||
if (in == nullptr) return false;
|
||||
size_t inputSize = strnlen(in, 9);
|
||||
if (inputSize != 6 && inputSize != 8) return false;
|
||||
|
||||
uint32_t c = strtoul(in, NULL, 16);
|
||||
|
||||
if (inputSize == 6) {
|
||||
rgb[0] = (c >> 16) & 0xFF;
|
||||
rgb[1] = (c >> 8) & 0xFF;
|
||||
rgb[2] = c & 0xFF;
|
||||
} else {
|
||||
rgb[0] = (c >> 24) & 0xFF;
|
||||
rgb[1] = (c >> 16) & 0xFF;
|
||||
rgb[2] = (c >> 8) & 0xFF;
|
||||
rgb[3] = c & 0xFF;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
float minf (float v, float w)
|
||||
{
|
||||
if (w > v) return v;
|
||||
|
||||
161
wled00/const.h
@@ -13,6 +13,12 @@
|
||||
//increase if you need more
|
||||
#define WLED_MAX_USERMODS 4
|
||||
|
||||
#ifdef ESP8266
|
||||
#define WLED_MAX_BUSSES 3
|
||||
#else
|
||||
#define WLED_MAX_BUSSES 10
|
||||
#endif
|
||||
|
||||
//Usermod IDs
|
||||
#define USERMOD_ID_RESERVED 0 //Unused. Might indicate no usermod present
|
||||
#define USERMOD_ID_UNSPECIFIED 1 //Default value for a general user mod that does not specify a custom ID
|
||||
@@ -21,6 +27,11 @@
|
||||
#define USERMOD_ID_FIXNETSERVICES 4 //Usermod "usermod_Fix_unreachable_netservices.h"
|
||||
#define USERMOD_ID_PIRSWITCH 5 //Usermod "usermod_PIR_sensor_switch.h"
|
||||
#define USERMOD_ID_IMU 6 //Usermod "usermod_mpu6050_imu.h"
|
||||
#define USERMOD_ID_FOUR_LINE_DISP 7 //Usermod "usermod_v2_four_line_display.h
|
||||
#define USERMOD_ID_ROTARY_ENC_UI 8 //Usermod "usermod_v2_rotary_encoder_ui.h"
|
||||
#define USERMOD_ID_AUTO_SAVE 9 //Usermod "usermod_v2_auto_save.h"
|
||||
#define USERMOD_ID_DHT 10 //Usermod "usermod_dht.h"
|
||||
#define USERMOD_ID_MODE_SORT 11 //Usermod "usermod_v2_mode_sort.h"
|
||||
|
||||
//Access point behavior
|
||||
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot
|
||||
@@ -57,6 +68,7 @@
|
||||
#define REALTIME_MODE_ADALIGHT 5
|
||||
#define REALTIME_MODE_ARTNET 6
|
||||
#define REALTIME_MODE_TPM2NET 7
|
||||
#define REALTIME_MODE_DDP 8
|
||||
|
||||
//realtime override modes
|
||||
#define REALTIME_OVERRIDE_NONE 0
|
||||
@@ -70,21 +82,69 @@
|
||||
#define DMX_MODE_EFFECT 3 //trigger standalone effects of WLED (11 channels)
|
||||
#define DMX_MODE_MULTIPLE_RGB 4 //every LED is addressed with its own RGB (ledCount * 3 channels)
|
||||
#define DMX_MODE_MULTIPLE_DRGB 5 //every LED is addressed with its own RGB and share a master dimmer (ledCount * 3 + 1 channels)
|
||||
#define DMX_MODE_MULTIPLE_RGBW 6 //every LED is addressed with its own RGBW (ledCount * 4 channels)
|
||||
|
||||
//Light capability byte (unused) 0bRRCCTTTT
|
||||
//bits 0/1/2/3: specifies a type of LED driver. A single "driver" may have different chip models but must have the same protocol/behavior
|
||||
//bits 4/5: specifies the class of LED driver - 0b00 (dec. 0-15) unconfigured/reserved
|
||||
// - 0b01 (dec. 16-31) digital (data pin only)
|
||||
// - 0b10 (dec. 32-47) analog (PWM)
|
||||
// - 0b11 (dec. 48-63) digital (data + clock / SPI)
|
||||
//bits 6/7 are reserved and set to 0b00
|
||||
|
||||
//Light capability byte (unused)
|
||||
#define TYPE_NONE 0 //light is not configured
|
||||
#define TYPE_RESERVED 1 //unused. Might indicate a "virtual" light
|
||||
#define TYPE_WS2812_RGB 2
|
||||
#define TYPE_SK6812_RGBW 3
|
||||
#define TYPE_WS2812_WWA 4 //amber + warm + cold white
|
||||
#define TYPE_WS2801 5
|
||||
#define TYPE_ANALOG_1CH 6 //single channel PWM. Uses value of brightest RGBW channel
|
||||
#define TYPE_ANALOG_2CH 7 //analog WW + CW
|
||||
#define TYPE_ANALOG_3CH 8 //analog RGB
|
||||
#define TYPE_ANALOG_4CH 9 //analog RGBW
|
||||
#define TYPE_ANALOG_5CH 10 //analog RGB + WW + CW
|
||||
#define TYPE_APA102 11
|
||||
#define TYPE_LPD8806 12
|
||||
//Digital types (data pin only) (16-31)
|
||||
#define TYPE_WS2812_1CH 20 //white-only chips
|
||||
#define TYPE_WS2812_WWA 21 //amber + warm + cold white
|
||||
#define TYPE_WS2812_RGB 22
|
||||
#define TYPE_GS8608 23 //same driver as WS2812, but will require signal 2x per second (else displays test pattern)
|
||||
#define TYPE_WS2811_400KHZ 24 //half-speed WS2812 protocol, used by very old WS2811 units
|
||||
#define TYPE_SK6812_RGBW 30
|
||||
#define TYPE_TM1814 31
|
||||
//"Analog" types (PWM) (32-47)
|
||||
#define TYPE_ONOFF 40 //binary output (relays etc.)
|
||||
#define TYPE_ANALOG_1CH 41 //single channel PWM. Uses value of brightest RGBW channel
|
||||
#define TYPE_ANALOG_2CH 42 //analog WW + CW
|
||||
#define TYPE_ANALOG_3CH 43 //analog RGB
|
||||
#define TYPE_ANALOG_4CH 44 //analog RGBW
|
||||
#define TYPE_ANALOG_5CH 45 //analog RGB + WW + CW
|
||||
//Digital types (data + clock / SPI) (48-63)
|
||||
#define TYPE_WS2801 50
|
||||
#define TYPE_APA102 51
|
||||
#define TYPE_LPD8806 52
|
||||
#define TYPE_P9813 53
|
||||
|
||||
#define IS_DIGITAL(t) (t & 0x10) //digital are 16-31 and 48-63
|
||||
#define IS_PWM(t) (t > 40 && t < 46)
|
||||
#define NUM_PWM_PINS(t) (t - 40) //for analog PWM 41-45 only
|
||||
#define IS_2PIN(t) (t > 47)
|
||||
|
||||
//Color orders
|
||||
#define COL_ORDER_GRB 0 //GRB(w),defaut
|
||||
#define COL_ORDER_RGB 1 //common for WS2811
|
||||
#define COL_ORDER_BRG 2
|
||||
#define COL_ORDER_RBG 3
|
||||
#define COL_ORDER_BGR 4
|
||||
#define COL_ORDER_GBR 5
|
||||
|
||||
|
||||
//Button type
|
||||
#define BTN_TYPE_NONE 0
|
||||
#define BTN_TYPE_RESERVED 1
|
||||
#define BTN_TYPE_PUSH 2
|
||||
#define BTN_TYPE_PUSH_ACT_HIGH 3 //not implemented
|
||||
#define BTN_TYPE_SWITCH 4 //not implemented
|
||||
#define BTN_TYPE_SWITCH_ACT_HIGH 5 //not implemented
|
||||
|
||||
//Ethernet board types
|
||||
#define WLED_NUM_ETH_TYPES 5
|
||||
|
||||
#define WLED_ETH_NONE 0
|
||||
#define WLED_ETH_WT32_ETH01 1
|
||||
#define WLED_ETH_ESP32_POE 2
|
||||
#define WLED_ETH_WESP32 3
|
||||
#define WLED_ETH_QUINLED 4
|
||||
|
||||
//Hue error codes
|
||||
#define HUE_ERROR_INACTIVE 0
|
||||
@@ -104,26 +164,91 @@
|
||||
#define SEG_OPTION_FREEZE 5 //Segment contents will not be refreshed
|
||||
#define SEG_OPTION_TRANSITIONAL 7
|
||||
|
||||
// WLED Error modes
|
||||
#define ERR_NONE 0 // All good :)
|
||||
#define ERR_EEP_COMMIT 2 // Could not commit to EEPROM (wrong flash layout?)
|
||||
#define ERR_JSON 9 // JSON parsing failed (input too large?)
|
||||
#define ERR_FS_BEGIN 10 // Could not init filesystem (no partition?)
|
||||
#define ERR_FS_QUOTA 11 // The FS is full or the maximum file size is reached
|
||||
#define ERR_FS_PLOAD 12 // It was attempted to load a preset that does not exist
|
||||
#define ERR_FS_GENERAL 19 // A general unspecified filesystem error occured
|
||||
#define ERR_OVERTEMP 30 // An attached temperature sensor has measured above threshold temperature (not implemented)
|
||||
#define ERR_OVERCURRENT 31 // An attached current sensor has measured a current above the threshold (not implemented)
|
||||
#define ERR_UNDERVOLT 32 // An attached voltmeter has measured a voltage below the threshold (not implemented)
|
||||
|
||||
//Timer mode types
|
||||
#define NL_MODE_SET 0 //After nightlight time elapsed, set to target brightness
|
||||
#define NL_MODE_FADE 1 //Fade to target brightness gradually
|
||||
#define NL_MODE_COLORFADE 2 //Fade to target brightness and secondary color gradually
|
||||
#define NL_MODE_SUN 3 //Sunrise/sunset. Target brightness is set immediately, then Sunrise effect is started. Max 60 min.
|
||||
|
||||
//EEPROM size
|
||||
#define EEPSIZE 2560 //Maximum is 4096
|
||||
|
||||
#define NTP_PACKET_SIZE 48
|
||||
|
||||
// maximum number of LEDs - MAX_LEDS is coming from the JSON response getting too big, MAX_LEDS_DMA will become a timing issue
|
||||
#define MAX_LEDS 1500
|
||||
#define MAX_LEDS_DMA 500
|
||||
// maximum number of LEDs - more than 1500 LEDs (or 500 DMA "LEDPIN 3" driven ones) will cause a low memory condition on ESP8266
|
||||
#ifndef MAX_LEDS
|
||||
#ifdef ESP8266
|
||||
#define MAX_LEDS 8192 //rely on memory limit to limit this to 1600 LEDs
|
||||
#else
|
||||
#define MAX_LEDS 8192
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef MAX_LED_MEMORY
|
||||
#ifdef ESP8266
|
||||
#define MAX_LED_MEMORY 5000
|
||||
#else
|
||||
#define MAX_LED_MEMORY 64000
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef MAX_LEDS_PER_BUS
|
||||
#define MAX_LEDS_PER_BUS 4096
|
||||
#endif
|
||||
|
||||
// string temp buffer (now stored in stack locally)
|
||||
#define OMAX 2048
|
||||
|
||||
#define E131_MAX_UNIVERSE_COUNT 9
|
||||
|
||||
#define ABL_MILLIAMPS_DEFAULT 850; // auto lower brightness to stay close to milliampere limit
|
||||
#define ABL_MILLIAMPS_DEFAULT 850 // auto lower brightness to stay close to milliampere limit
|
||||
|
||||
// PWM settings
|
||||
#ifndef WLED_PWM_FREQ
|
||||
#ifdef ESP8266
|
||||
#define WLED_PWM_FREQ 880 //PWM frequency proven as good for LEDs
|
||||
#else
|
||||
#define WLED_PWM_FREQ 19531
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define TOUCH_THRESHOLD 32 // limit to recognize a touch, higher value means more sensitive
|
||||
|
||||
// Size of buffer for API JSON object (increase for more segments)
|
||||
#ifdef ESP8266
|
||||
#define JSON_BUFFER_SIZE 9216
|
||||
#else
|
||||
#define JSON_BUFFER_SIZE 16384
|
||||
#endif
|
||||
|
||||
// Maximum size of node map (list of other WLED instances)
|
||||
#ifdef ESP8266
|
||||
#define WLED_MAX_NODES 15
|
||||
#else
|
||||
#define WLED_MAX_NODES 150
|
||||
#endif
|
||||
|
||||
//this is merely a default now and can be changed at runtime
|
||||
#ifndef LEDPIN
|
||||
#define LEDPIN 2
|
||||
#endif
|
||||
|
||||
#ifdef WLED_ENABLE_DMX
|
||||
#if (LEDPIN == 2)
|
||||
#undef LEDPIN
|
||||
#define LEDPIN 3
|
||||
#warning "Pin conflict compiling with DMX and LEDs on pin 2. The default LED pin has been changed to pin 3."
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
47
wled00/data/404.htm
Normal file
@@ -0,0 +1,47 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta content='width=device-width' name='viewport'>
|
||||
<meta name="theme-color" content="#222222">
|
||||
<title>Not found</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Verdana, Helvetica, sans-serif;
|
||||
text-align: center;
|
||||
background-color: #222;
|
||||
margin: 0;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 400px;
|
||||
max-width: 50%;
|
||||
image-rendering: pixelated;
|
||||
image-rendering: crisp-edges;
|
||||
margin: 25px 0 -10px 0;
|
||||
}
|
||||
|
||||
button {
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
padding: 8px;
|
||||
margin: 10px;
|
||||
width: 230px;
|
||||
text-transform: uppercase;
|
||||
font-family: helvetica;
|
||||
font-size: 19px;
|
||||
background-color: #333;
|
||||
color: white;
|
||||
border: 0px solid white;
|
||||
border-radius: 25px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<img alt="" src=" data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsEAAA7BAbiRa+0AAAFMSURBVFhH7ZTfbYNADMaPKDNUrJA85CEjdIjOgNQV+sASlZgmI/AIK6AuQfngnDrmjtpHItQ/P+l0juHsz2cH9+fJ/G7nreldfnDnp+ln/ZIlxbIfQmIwJOekCrEJ8FUvASEWEXoBiuSERcTO75uhuwFWff86bi57n3ZC+rW3YLqB5rn11ldCEPNr2LwFJgHHy8G1bTsu3oKYX4N5BrQ8ZAYewSoBGDjr0ElWCUC/rT2X7MqynL7tG4Dc45BwEYM9H5w7DqHMdfNCURR9nue3Iobk55MtOYeLoOQ8vmoG6o+0FaLrOm9FwC3wayLgx5I2WHpGIGYorulfgPYQ3AZLz4hQ9TMBVVVleJGrRUWz2YgQOg8bPjzzrit7vwcRQb5NTiARRPPzMYItoCpoWZITMkao+mRkddpqQ6z6FN+DfwFJrOm55GfewC/CuU/E4tQYg7BPYQAAAABJRU5ErkJggg==">
|
||||
<h1>404 Not Found</h1>
|
||||
<b>Akemi does not know where you are headed...</b><br><br>
|
||||
<button onclick="window.location.href='/sliders'">Back to controls</button>
|
||||
</body>
|
||||
</html>
|
||||