mirror of
https://github.com/wled/WLED.git
synced 2025-04-20 21:07:19 +00:00
Compare commits
No commits in common. "main" and "v0.15.0-b7" have entirely different histories.
main
...
v0.15.0-b7
@ -2,7 +2,12 @@
|
||||
|
||||
# [Choice] Python version: 3, 3.9, 3.8, 3.7, 3.6
|
||||
ARG VARIANT="3"
|
||||
FROM mcr.microsoft.com/devcontainers/python:0-${VARIANT}
|
||||
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/
|
||||
|
@ -5,7 +5,10 @@
|
||||
"context": "..",
|
||||
"args": {
|
||||
// Update 'VARIANT' to pick a Python version: 3, 3.6, 3.7, 3.8, 3.9
|
||||
"VARIANT": "3"
|
||||
"VARIANT": "3",
|
||||
// Options
|
||||
"INSTALL_NODE": "true",
|
||||
"NODE_VERSION": "lts/*"
|
||||
}
|
||||
},
|
||||
|
||||
@ -24,35 +27,34 @@
|
||||
// risk to running the build directly on the host.
|
||||
// "runArgs": ["--privileged", "-v", "/dev/bus/usb:/dev/bus/usb", "--group-add", "dialout"],
|
||||
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"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"
|
||||
},
|
||||
"extensions": [
|
||||
"ms-python.python",
|
||||
"platformio.platformio-ide"
|
||||
]
|
||||
}
|
||||
// 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": "bash -i -c 'nvm install && npm ci'",
|
||||
"postCreateCommand": "npm install",
|
||||
|
||||
// Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
|
||||
"remoteUser": "vscode"
|
||||
|
2
.github/ISSUE_TEMPLATE/bug.yml
vendored
2
.github/ISSUE_TEMPLATE/bug.yml
vendored
@ -80,7 +80,7 @@ body:
|
||||
id: terms
|
||||
attributes:
|
||||
label: Code of Conduct
|
||||
description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/wled-dev/WLED/blob/main/CODE_OF_CONDUCT.md)
|
||||
description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/Aircoookie/WLED/blob/master/CODE_OF_CONDUCT.md)
|
||||
options:
|
||||
- label: I agree to follow this project's Code of Conduct
|
||||
required: true
|
||||
|
82
.github/workflows/build.yml
vendored
82
.github/workflows/build.yml
vendored
@ -1,82 +0,0 @@
|
||||
name: WLED Build
|
||||
|
||||
# Only included into other workflows
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
|
||||
get_default_envs:
|
||||
name: Gather Environments
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
cache: 'pip'
|
||||
- name: Install PlatformIO
|
||||
run: pip install -r requirements.txt
|
||||
- name: Get default environments
|
||||
id: envs
|
||||
run: |
|
||||
echo "environments=$(pio project config --json-output | jq -cr '.[0][1][0][1]')" >> $GITHUB_OUTPUT
|
||||
outputs:
|
||||
environments: ${{ steps.envs.outputs.environments }}
|
||||
|
||||
|
||||
build:
|
||||
name: Build Environments
|
||||
runs-on: ubuntu-latest
|
||||
needs: get_default_envs
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
environment: ${{ fromJSON(needs.get_default_envs.outputs.environments) }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'npm'
|
||||
- run: npm ci
|
||||
- name: Cache PlatformIO
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.platformio/.cache
|
||||
~/.buildcache
|
||||
build_output
|
||||
key: pio-${{ runner.os }}-${{ matrix.environment }}-${{ hashFiles('platformio.ini', 'pio-scripts/output_bins.py') }}-${{ hashFiles('wled00/**', 'usermods/**') }}
|
||||
restore-keys: pio-${{ runner.os }}-${{ matrix.environment }}-${{ hashFiles('platformio.ini', 'pio-scripts/output_bins.py') }}-
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
cache: 'pip'
|
||||
- name: Install PlatformIO
|
||||
run: pip install -r requirements.txt
|
||||
|
||||
- name: Build firmware
|
||||
run: pio run -e ${{ matrix.environment }}
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: firmware-${{ matrix.environment }}
|
||||
path: |
|
||||
build_output/release/*.bin
|
||||
build_output/release/*_ESP02*.bin.gz
|
||||
|
||||
|
||||
testCdata:
|
||||
name: Test cdata.js
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Use Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'npm'
|
||||
- run: npm ci
|
||||
- run: npm test
|
47
.github/workflows/nightly.yml
vendored
47
.github/workflows/nightly.yml
vendored
@ -1,47 +0,0 @@
|
||||
|
||||
name: Deploy Nightly
|
||||
on:
|
||||
# This can be used to automatically publish nightlies at UTC nighttime
|
||||
schedule:
|
||||
- cron: '0 2 * * *' # run at 2 AM UTC
|
||||
# This can be used to allow manually triggering nightlies from the web interface
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
wled_build:
|
||||
uses: ./.github/workflows/build.yml
|
||||
nightly:
|
||||
name: Deploy nightly
|
||||
runs-on: ubuntu-latest
|
||||
needs: wled_build
|
||||
steps:
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
merge-multiple: true
|
||||
- name: Show Files
|
||||
run: ls -la
|
||||
- name: "✏️ Generate release changelog"
|
||||
id: changelog
|
||||
uses: janheinrichmerker/action-github-changelog-generator@v2.3
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
sinceTag: v0.15.0
|
||||
- name: Update Nightly Release
|
||||
uses: andelf/nightly-release@main
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: nightly
|
||||
name: 'Nightly Release $$'
|
||||
prerelease: true
|
||||
body: ${{ steps.changelog.outputs.changelog }}
|
||||
files: |
|
||||
*.bin
|
||||
*.bin.gz
|
||||
- name: Repository Dispatch
|
||||
uses: peter-evans/repository-dispatch@v3
|
||||
with:
|
||||
repository: wled/WLED-WebInstaller
|
||||
event-type: release-nightly
|
||||
token: ${{ secrets.PAT_PUBLIC }}
|
16
.github/workflows/pr-merge.yaml
vendored
16
.github/workflows/pr-merge.yaml
vendored
@ -1,16 +0,0 @@
|
||||
name: Notify Discord on PR Merge
|
||||
on:
|
||||
pull_request:
|
||||
types: [closed]
|
||||
|
||||
jobs:
|
||||
notify:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Send Discord notification
|
||||
shell: bash
|
||||
env:
|
||||
DISCORD_WEBHOOK_BETA_TESTERS: ${{ secrets.DISCORD_WEBHOOK_BETA_TESTERS }}
|
||||
if: github.event.pull_request.merged == true
|
||||
run: |
|
||||
curl -H "Content-Type: application/json" -d '{"content": "Pull Request #{{ github.event.pull_request.number }} merged by {{ github.actor }}"}' $DISCORD_WEBHOOK_BETA_TESTERS
|
35
.github/workflows/release.yml
vendored
35
.github/workflows/release.yml
vendored
@ -1,35 +0,0 @@
|
||||
name: WLED Release CI
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
|
||||
wled_build:
|
||||
uses: ./.github/workflows/build.yml
|
||||
|
||||
release:
|
||||
name: Create Release
|
||||
runs-on: ubuntu-latest
|
||||
needs: wled_build
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
merge-multiple: true
|
||||
- name: "✏️ Generate release changelog"
|
||||
id: changelog
|
||||
uses: janheinrichmerker/action-github-changelog-generator@v2.3
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
sinceTag: v0.15.0
|
||||
- name: Create draft release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
body: ${{ steps.changelog.outputs.changelog }}
|
||||
draft: True
|
||||
files: |
|
||||
*.bin
|
||||
*.bin.gz
|
||||
|
13
.github/workflows/test.yaml
vendored
13
.github/workflows/test.yaml
vendored
@ -1,13 +0,0 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
dispatch:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Repository Dispatch
|
||||
uses: peter-evans/repository-dispatch@v3
|
||||
with:
|
||||
repository: wled/WLED-WebInstaller
|
||||
event-type: release-nightly
|
||||
token: ${{ secrets.PAT_PUBLIC }}
|
97
.github/workflows/wled-ci.yml
vendored
97
.github/workflows/wled-ci.yml
vendored
@ -1,11 +1,94 @@
|
||||
name: WLED CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
pull_request:
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
wled_build:
|
||||
uses: ./.github/workflows/build.yml
|
||||
|
||||
get_default_envs:
|
||||
name: Gather Environments
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
cache: 'pip'
|
||||
- name: Install PlatformIO
|
||||
run: pip install -r requirements.txt
|
||||
- name: Get default environments
|
||||
id: envs
|
||||
run: |
|
||||
echo "environments=$(pio project config --json-output | jq -cr '.[0][1][0][1]')" >> $GITHUB_OUTPUT
|
||||
outputs:
|
||||
environments: ${{ steps.envs.outputs.environments }}
|
||||
|
||||
|
||||
build:
|
||||
name: Build Enviornments
|
||||
runs-on: ubuntu-latest
|
||||
needs: get_default_envs
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
environment: ${{ fromJSON(needs.get_default_envs.outputs.environments) }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
cache: 'npm'
|
||||
- run: npm ci
|
||||
- name: Cache PlatformIO
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.platformio/.cache
|
||||
~/.buildcache
|
||||
build_output
|
||||
key: pio-${{ runner.os }}-${{ matrix.environment }}-${{ hashFiles('platformio.ini', 'pio-scripts/output_bins.py') }}-${{ hashFiles('wled00/**', 'usermods/**') }}
|
||||
restore-keys: pio-${{ runner.os }}-${{ matrix.environment }}-${{ hashFiles('platformio.ini', 'pio-scripts/output_bins.py') }}-
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
cache: 'pip'
|
||||
- name: Install PlatformIO
|
||||
run: pip install -r requirements.txt
|
||||
- name: Build firmware
|
||||
run: pio run -e ${{ matrix.environment }}
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: firmware-${{ matrix.environment }}
|
||||
path: |
|
||||
build_output/release/*.bin
|
||||
build_output/release/*_ESP02*.bin.gz
|
||||
release:
|
||||
name: Create Release
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
merge-multiple: true
|
||||
- name: Create draft release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
draft: True
|
||||
files: |
|
||||
*.bin
|
||||
*.bin.gz
|
||||
|
||||
|
||||
testCdata:
|
||||
name: Test cdata.js
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Use Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20.x'
|
||||
cache: 'npm'
|
||||
- run: npm ci
|
||||
- run: npm test
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -15,7 +15,6 @@ wled-update.sh
|
||||
|
||||
/build_output/
|
||||
/node_modules/
|
||||
/logs/
|
||||
|
||||
/wled00/extLibs
|
||||
/wled00/LittleFS
|
||||
|
@ -173,7 +173,7 @@
|
||||
- v0.15.0-b2
|
||||
- WS2805 support (RGB + WW + CW, 600kbps)
|
||||
- Unified PSRAM use
|
||||
- NeoPixelBus v2.7.9 (for future WS2805 support)
|
||||
- NeoPixelBus v2.7.9
|
||||
- Ubiquitous PSRAM mode for all variants of ESP32
|
||||
- SSD1309_64 I2C Support for FLD Usermod (#3836 by @THATDONFC)
|
||||
- Palette cycling fix (add support for `{"seg":[{"pal":"X~Y~"}]}` or `{"seg":[{"pal":"X~Yr"}]}`)
|
||||
|
@ -14,7 +14,7 @@ A good description helps us to review and understand your proposed changes. For
|
||||
|
||||
### Target branch for pull requests
|
||||
|
||||
Please make all PRs against the `main` branch.
|
||||
Please make all PRs against the `0_15` branch.
|
||||
|
||||
### Updating your code
|
||||
While the PR is open - and under review by maintainers - you may be asked to modify your PR source code.
|
||||
@ -27,7 +27,7 @@ Github will pick up the changes so your PR stays up-to-date.
|
||||
> For example, we regularly lost review comments when the PR author force-pushes code changes. So, pretty please, do not force-push.
|
||||
|
||||
|
||||
You can find a collection of very useful tips and tricks here: https://github.com/wled-dev/WLED/wiki/How-to-properly-submit-a-PR
|
||||
You can find a collection of very useful tips and tricks here: https://github.com/Aircoookie/WLED/wiki/How-to-properly-submit-a-PR
|
||||
|
||||
|
||||
### Code style
|
||||
@ -105,4 +105,4 @@ Good:
|
||||
|
||||
There is no hard character limit for a comment within a line,
|
||||
though as a rule of thumb consider wrapping after 120 characters.
|
||||
Inline comments are OK if they describe that line only and are not exceedingly wide.
|
||||
Inline comments are OK if they describe that line only and are not exceedingly wide.
|
@ -1,47 +0,0 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "esp32s3_out.ld",
|
||||
"memory_type": "qio_qspi"
|
||||
},
|
||||
"core": "esp32",
|
||||
"extra_flags": [
|
||||
"-DBOARD_HAS_PSRAM",
|
||||
"-DARDUINO_LOLIN_S3_MINI",
|
||||
"-DARDUINO_USB_MODE=1"
|
||||
],
|
||||
"f_cpu": "240000000L",
|
||||
"f_flash": "80000000L",
|
||||
"flash_mode": "qio",
|
||||
"hwids": [
|
||||
[
|
||||
"0x303A",
|
||||
"0x8167"
|
||||
]
|
||||
],
|
||||
"mcu": "esp32s3",
|
||||
"variant": "lolin_s3_mini"
|
||||
},
|
||||
"connectivity": [
|
||||
"bluetooth",
|
||||
"wifi"
|
||||
],
|
||||
"debug": {
|
||||
"openocd_target": "esp32s3.cfg"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino",
|
||||
"espidf"
|
||||
],
|
||||
"name": "WEMOS LOLIN S3 Mini",
|
||||
"upload": {
|
||||
"flash_size": "4MB",
|
||||
"maximum_ram_size": 327680,
|
||||
"maximum_size": 4194304,
|
||||
"require_upload_port": true,
|
||||
"speed": 460800
|
||||
},
|
||||
"url": "https://www.wemos.cc/en/latest/s3/index.html",
|
||||
"vendor": "WEMOS"
|
||||
}
|
||||
|
@ -1,504 +0,0 @@
|
||||
/* esp8266_waveform imported from platform source code
|
||||
Modified for WLED to work around a fault in the NMI handling,
|
||||
which can result in the system locking up and hard WDT crashes.
|
||||
|
||||
Imported from https://github.com/esp8266/Arduino/blob/7e0d20e2b9034994f573a236364e0aef17fd66de/cores/esp8266/core_esp8266_waveform_phase.cpp
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
esp8266_waveform - General purpose waveform generation and control,
|
||||
supporting outputs on all pins in parallel.
|
||||
|
||||
Copyright (c) 2018 Earle F. Philhower, III. All rights reserved.
|
||||
Copyright (c) 2020 Dirk O. Kaar.
|
||||
|
||||
The core idea is to have a programmable waveform generator with a unique
|
||||
high and low period (defined in microseconds or CPU clock cycles). TIMER1 is
|
||||
set to 1-shot mode and is always loaded with the time until the next edge
|
||||
of any live waveforms.
|
||||
|
||||
Up to one waveform generator per pin supported.
|
||||
|
||||
Each waveform generator is synchronized to the ESP clock cycle counter, not the
|
||||
timer. This allows for removing interrupt jitter and delay as the counter
|
||||
always increments once per 80MHz clock. Changes to a waveform are
|
||||
contiguous and only take effect on the next waveform transition,
|
||||
allowing for smooth transitions.
|
||||
|
||||
This replaces older tone(), analogWrite(), and the Servo classes.
|
||||
|
||||
Everywhere in the code where "ccy" or "ccys" is used, it means ESP.getCycleCount()
|
||||
clock cycle time, or an interval measured in clock cycles, but not TIMER1
|
||||
cycles (which may be 2 CPU clock cycles @ 160MHz).
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "core_esp8266_waveform.h"
|
||||
#include <Arduino.h>
|
||||
#include "debug.h"
|
||||
#include "ets_sys.h"
|
||||
#include <atomic>
|
||||
|
||||
|
||||
// ----- @willmmiles begin patch -----
|
||||
// Linker magic
|
||||
extern "C" void usePWMFixedNMI(void) {};
|
||||
|
||||
// NMI crash workaround
|
||||
// Sometimes the NMI fails to return, stalling the CPU. When this happens,
|
||||
// the next NMI gets a return address /inside the NMI handler function/.
|
||||
// We work around this by caching the last NMI return address, and restoring
|
||||
// the epc3 and eps3 registers to the previous values if the observed epc3
|
||||
// happens to be pointing to the _NMILevelVector function.
|
||||
extern "C" void _NMILevelVector();
|
||||
extern "C" void _UserExceptionVector_1(); // the next function after _NMILevelVector
|
||||
static inline IRAM_ATTR void nmiCrashWorkaround() {
|
||||
static uintptr_t epc3_backup, eps3_backup;
|
||||
|
||||
uintptr_t epc3, eps3;
|
||||
__asm__ __volatile__("rsr %0,epc3; rsr %1,eps3":"=a"(epc3),"=a" (eps3));
|
||||
if ((epc3 < (uintptr_t) &_NMILevelVector) || (epc3 >= (uintptr_t) &_UserExceptionVector_1)) {
|
||||
// Address is good; save backup
|
||||
epc3_backup = epc3;
|
||||
eps3_backup = eps3;
|
||||
} else {
|
||||
// Address is inside the NMI handler -- restore from backup
|
||||
__asm__ __volatile__("wsr %0,epc3; wsr %1,eps3"::"a"(epc3_backup),"a"(eps3_backup));
|
||||
}
|
||||
}
|
||||
// ----- @willmmiles end patch -----
|
||||
|
||||
|
||||
// No-op calls to override the PWM implementation
|
||||
extern "C" void _setPWMFreq_weak(uint32_t freq) { (void) freq; }
|
||||
extern "C" IRAM_ATTR bool _stopPWM_weak(int pin) { (void) pin; return false; }
|
||||
extern "C" bool _setPWM_weak(int pin, uint32_t val, uint32_t range) { (void) pin; (void) val; (void) range; return false; }
|
||||
|
||||
|
||||
// Timer is 80MHz fixed. 160MHz CPU frequency need scaling.
|
||||
constexpr bool ISCPUFREQ160MHZ = clockCyclesPerMicrosecond() == 160;
|
||||
// Maximum delay between IRQs, Timer1, <= 2^23 / 80MHz
|
||||
constexpr int32_t MAXIRQTICKSCCYS = microsecondsToClockCycles(10000);
|
||||
// Maximum servicing time for any single IRQ
|
||||
constexpr uint32_t ISRTIMEOUTCCYS = microsecondsToClockCycles(18);
|
||||
// The latency between in-ISR rearming of the timer and the earliest firing
|
||||
constexpr int32_t IRQLATENCYCCYS = microsecondsToClockCycles(2);
|
||||
// The SDK and hardware take some time to actually get to our NMI code
|
||||
constexpr int32_t DELTAIRQCCYS = ISCPUFREQ160MHZ ?
|
||||
microsecondsToClockCycles(2) >> 1 : microsecondsToClockCycles(2);
|
||||
|
||||
// for INFINITE, the NMI proceeds on the waveform without expiry deadline.
|
||||
// for EXPIRES, the NMI expires the waveform automatically on the expiry ccy.
|
||||
// for UPDATEEXPIRY, the NMI recomputes the exact expiry ccy and transitions to EXPIRES.
|
||||
// for UPDATEPHASE, the NMI recomputes the target timings
|
||||
// for INIT, the NMI initializes nextPeriodCcy, and if expiryCcy != 0 includes UPDATEEXPIRY.
|
||||
enum class WaveformMode : uint8_t {INFINITE = 0, EXPIRES = 1, UPDATEEXPIRY = 2, UPDATEPHASE = 3, INIT = 4};
|
||||
|
||||
// Waveform generator can create tones, PWM, and servos
|
||||
typedef struct {
|
||||
uint32_t nextPeriodCcy; // ESP clock cycle when a period begins.
|
||||
uint32_t endDutyCcy; // ESP clock cycle when going from duty to off
|
||||
int32_t dutyCcys; // Set next off cycle at low->high to maintain phase
|
||||
int32_t adjDutyCcys; // Temporary correction for next period
|
||||
int32_t periodCcys; // Set next phase cycle at low->high to maintain phase
|
||||
uint32_t expiryCcy; // For time-limited waveform, the CPU clock cycle when this waveform must stop. If WaveformMode::UPDATE, temporarily holds relative ccy count
|
||||
WaveformMode mode;
|
||||
bool autoPwm; // perform PWM duty to idle cycle ratio correction under high load at the expense of precise timings
|
||||
} Waveform;
|
||||
|
||||
namespace {
|
||||
|
||||
static struct {
|
||||
Waveform pins[17]; // State of all possible pins
|
||||
uint32_t states = 0; // Is the pin high or low, updated in NMI so no access outside the NMI code
|
||||
uint32_t enabled = 0; // Is it actively running, updated in NMI so no access outside the NMI code
|
||||
|
||||
// Enable lock-free by only allowing updates to waveform.states and waveform.enabled from IRQ service routine
|
||||
int32_t toSetBits = 0; // Message to the NMI handler to start/modify exactly one waveform
|
||||
int32_t toDisableBits = 0; // Message to the NMI handler to disable exactly one pin from waveform generation
|
||||
|
||||
// toSetBits temporaries
|
||||
// cheaper than packing them in every Waveform, since we permit only one use at a time
|
||||
uint32_t phaseCcy; // positive phase offset ccy count
|
||||
int8_t alignPhase; // < 0 no phase alignment, otherwise starts waveform in relative phase offset to given pin
|
||||
|
||||
uint32_t(*timer1CB)() = nullptr;
|
||||
|
||||
bool timer1Running = false;
|
||||
|
||||
uint32_t nextEventCcy;
|
||||
} waveform;
|
||||
|
||||
}
|
||||
|
||||
// Interrupt on/off control
|
||||
static IRAM_ATTR void timer1Interrupt();
|
||||
|
||||
// Non-speed critical bits
|
||||
#pragma GCC optimize ("Os")
|
||||
|
||||
static void initTimer() {
|
||||
timer1_disable();
|
||||
ETS_FRC_TIMER1_INTR_ATTACH(NULL, NULL);
|
||||
ETS_FRC_TIMER1_NMI_INTR_ATTACH(timer1Interrupt);
|
||||
timer1_enable(TIM_DIV1, TIM_EDGE, TIM_SINGLE);
|
||||
waveform.timer1Running = true;
|
||||
timer1_write(IRQLATENCYCCYS); // Cause an interrupt post-haste
|
||||
}
|
||||
|
||||
static void IRAM_ATTR deinitTimer() {
|
||||
ETS_FRC_TIMER1_NMI_INTR_ATTACH(NULL);
|
||||
timer1_disable();
|
||||
timer1_isr_init();
|
||||
waveform.timer1Running = false;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
// Set a callback. Pass in NULL to stop it
|
||||
void setTimer1Callback_weak(uint32_t (*fn)()) {
|
||||
waveform.timer1CB = fn;
|
||||
std::atomic_thread_fence(std::memory_order_acq_rel);
|
||||
if (!waveform.timer1Running && fn) {
|
||||
initTimer();
|
||||
} else if (waveform.timer1Running && !fn && !waveform.enabled) {
|
||||
deinitTimer();
|
||||
}
|
||||
}
|
||||
|
||||
// Start up a waveform on a pin, or change the current one. Will change to the new
|
||||
// waveform smoothly on next low->high transition. For immediate change, stopWaveform()
|
||||
// first, then it will immediately begin.
|
||||
int startWaveformClockCycles_weak(uint8_t pin, uint32_t highCcys, uint32_t lowCcys,
|
||||
uint32_t runTimeCcys, int8_t alignPhase, uint32_t phaseOffsetCcys, bool autoPwm) {
|
||||
uint32_t periodCcys = highCcys + lowCcys;
|
||||
if (periodCcys < MAXIRQTICKSCCYS) {
|
||||
if (!highCcys) {
|
||||
periodCcys = (MAXIRQTICKSCCYS / periodCcys) * periodCcys;
|
||||
}
|
||||
else if (!lowCcys) {
|
||||
highCcys = periodCcys = (MAXIRQTICKSCCYS / periodCcys) * periodCcys;
|
||||
}
|
||||
}
|
||||
// sanity checks, including mixed signed/unsigned arithmetic safety
|
||||
if ((pin > 16) || isFlashInterfacePin(pin) || (alignPhase > 16) ||
|
||||
static_cast<int32_t>(periodCcys) <= 0 ||
|
||||
static_cast<int32_t>(highCcys) < 0 || static_cast<int32_t>(lowCcys) < 0) {
|
||||
return false;
|
||||
}
|
||||
Waveform& wave = waveform.pins[pin];
|
||||
wave.dutyCcys = highCcys;
|
||||
wave.adjDutyCcys = 0;
|
||||
wave.periodCcys = periodCcys;
|
||||
wave.autoPwm = autoPwm;
|
||||
waveform.alignPhase = (alignPhase < 0) ? -1 : alignPhase;
|
||||
waveform.phaseCcy = phaseOffsetCcys;
|
||||
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
const uint32_t pinBit = 1UL << pin;
|
||||
if (!(waveform.enabled & pinBit)) {
|
||||
// wave.nextPeriodCcy and wave.endDutyCcy are initialized by the ISR
|
||||
wave.expiryCcy = runTimeCcys; // in WaveformMode::INIT, temporarily hold relative cycle count
|
||||
wave.mode = WaveformMode::INIT;
|
||||
if (!wave.dutyCcys) {
|
||||
// If initially at zero duty cycle, force GPIO off
|
||||
if (pin == 16) {
|
||||
GP16O = 0;
|
||||
}
|
||||
else {
|
||||
GPOC = pinBit;
|
||||
}
|
||||
}
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
waveform.toSetBits = 1UL << pin;
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
if (!waveform.timer1Running) {
|
||||
initTimer();
|
||||
}
|
||||
else if (T1V > IRQLATENCYCCYS) {
|
||||
// Must not interfere if Timer is due shortly
|
||||
timer1_write(IRQLATENCYCCYS);
|
||||
}
|
||||
}
|
||||
else {
|
||||
wave.mode = WaveformMode::INFINITE; // turn off possible expiry to make update atomic from NMI
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
if (runTimeCcys) {
|
||||
wave.expiryCcy = runTimeCcys; // in WaveformMode::UPDATEEXPIRY, temporarily hold relative cycle count
|
||||
wave.mode = WaveformMode::UPDATEEXPIRY;
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
waveform.toSetBits = 1UL << pin;
|
||||
} else if (alignPhase >= 0) {
|
||||
// @willmmiles new feature
|
||||
wave.mode = WaveformMode::UPDATEPHASE; // recalculate start
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
waveform.toSetBits = 1UL << pin;
|
||||
}
|
||||
}
|
||||
std::atomic_thread_fence(std::memory_order_acq_rel);
|
||||
while (waveform.toSetBits) {
|
||||
esp_yield(); // Wait for waveform to update
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Stops a waveform on a pin
|
||||
IRAM_ATTR int stopWaveform_weak(uint8_t pin) {
|
||||
// Can't possibly need to stop anything if there is no timer active
|
||||
if (!waveform.timer1Running) {
|
||||
return false;
|
||||
}
|
||||
// If user sends in a pin >16 but <32, this will always point to a 0 bit
|
||||
// If they send >=32, then the shift will result in 0 and it will also return false
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
const uint32_t pinBit = 1UL << pin;
|
||||
if (waveform.enabled & pinBit) {
|
||||
waveform.toDisableBits = 1UL << pin;
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
// Must not interfere if Timer is due shortly
|
||||
if (T1V > IRQLATENCYCCYS) {
|
||||
timer1_write(IRQLATENCYCCYS);
|
||||
}
|
||||
while (waveform.toDisableBits) {
|
||||
/* no-op */ // Can't delay() since stopWaveform may be called from an IRQ
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
}
|
||||
}
|
||||
if (!waveform.enabled && !waveform.timer1CB) {
|
||||
deinitTimer();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Speed critical bits
|
||||
#pragma GCC optimize ("O2")
|
||||
|
||||
// For dynamic CPU clock frequency switch in loop the scaling logic would have to be adapted.
|
||||
// Using constexpr makes sure that the CPU clock frequency is compile-time fixed.
|
||||
static inline IRAM_ATTR int32_t scaleCcys(const int32_t ccys, const bool isCPU2X) {
|
||||
if (ISCPUFREQ160MHZ) {
|
||||
return isCPU2X ? ccys : (ccys >> 1);
|
||||
}
|
||||
else {
|
||||
return isCPU2X ? (ccys << 1) : ccys;
|
||||
}
|
||||
}
|
||||
|
||||
static IRAM_ATTR void timer1Interrupt() {
|
||||
const uint32_t isrStartCcy = ESP.getCycleCount();
|
||||
//int32_t clockDrift = isrStartCcy - waveform.nextEventCcy;
|
||||
|
||||
// ----- @willmmiles begin patch -----
|
||||
nmiCrashWorkaround();
|
||||
// ----- @willmmiles end patch -----
|
||||
|
||||
const bool isCPU2X = CPU2X & 1;
|
||||
if ((waveform.toSetBits && !(waveform.enabled & waveform.toSetBits)) || waveform.toDisableBits) {
|
||||
// Handle enable/disable requests from main app.
|
||||
waveform.enabled = (waveform.enabled & ~waveform.toDisableBits) | waveform.toSetBits; // Set the requested waveforms on/off
|
||||
// Find the first GPIO being generated by checking GCC's find-first-set (returns 1 + the bit of the first 1 in an int32_t)
|
||||
waveform.toDisableBits = 0;
|
||||
}
|
||||
|
||||
if (waveform.toSetBits) {
|
||||
const int toSetPin = __builtin_ffs(waveform.toSetBits) - 1;
|
||||
Waveform& wave = waveform.pins[toSetPin];
|
||||
switch (wave.mode) {
|
||||
case WaveformMode::INIT:
|
||||
waveform.states &= ~waveform.toSetBits; // Clear the state of any just started
|
||||
if (waveform.alignPhase >= 0 && waveform.enabled & (1UL << waveform.alignPhase)) {
|
||||
wave.nextPeriodCcy = waveform.pins[waveform.alignPhase].nextPeriodCcy + scaleCcys(waveform.phaseCcy, isCPU2X);
|
||||
}
|
||||
else {
|
||||
wave.nextPeriodCcy = waveform.nextEventCcy;
|
||||
}
|
||||
if (!wave.expiryCcy) {
|
||||
wave.mode = WaveformMode::INFINITE;
|
||||
break;
|
||||
}
|
||||
// fall through
|
||||
case WaveformMode::UPDATEEXPIRY:
|
||||
// in WaveformMode::UPDATEEXPIRY, expiryCcy temporarily holds relative CPU cycle count
|
||||
wave.expiryCcy = wave.nextPeriodCcy + scaleCcys(wave.expiryCcy, isCPU2X);
|
||||
wave.mode = WaveformMode::EXPIRES;
|
||||
break;
|
||||
// @willmmiles new feature
|
||||
case WaveformMode::UPDATEPHASE:
|
||||
// in WaveformMode::UPDATEPHASE, we recalculate the targets
|
||||
if ((waveform.alignPhase >= 0) && (waveform.enabled & (1UL << waveform.alignPhase))) {
|
||||
// Compute phase shift to realign with target
|
||||
auto const newPeriodCcy = waveform.pins[waveform.alignPhase].nextPeriodCcy + scaleCcys(waveform.phaseCcy, isCPU2X);
|
||||
auto const period = scaleCcys(wave.periodCcys, isCPU2X);
|
||||
auto shift = ((static_cast<int32_t> (newPeriodCcy - wave.nextPeriodCcy) + period/2) % period) - (period/2);
|
||||
wave.nextPeriodCcy += static_cast<uint32_t>(shift);
|
||||
if (static_cast<int32_t>(wave.endDutyCcy - wave.nextPeriodCcy) > 0) {
|
||||
wave.endDutyCcy = wave.nextPeriodCcy;
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
waveform.toSetBits = 0;
|
||||
}
|
||||
|
||||
// Exit the loop if the next event, if any, is sufficiently distant.
|
||||
const uint32_t isrTimeoutCcy = isrStartCcy + ISRTIMEOUTCCYS;
|
||||
uint32_t busyPins = waveform.enabled;
|
||||
waveform.nextEventCcy = isrStartCcy + MAXIRQTICKSCCYS;
|
||||
|
||||
uint32_t now = ESP.getCycleCount();
|
||||
uint32_t isrNextEventCcy = now;
|
||||
while (busyPins) {
|
||||
if (static_cast<int32_t>(isrNextEventCcy - now) > IRQLATENCYCCYS) {
|
||||
waveform.nextEventCcy = isrNextEventCcy;
|
||||
break;
|
||||
}
|
||||
isrNextEventCcy = waveform.nextEventCcy;
|
||||
uint32_t loopPins = busyPins;
|
||||
while (loopPins) {
|
||||
const int pin = __builtin_ffsl(loopPins) - 1;
|
||||
const uint32_t pinBit = 1UL << pin;
|
||||
loopPins ^= pinBit;
|
||||
|
||||
Waveform& wave = waveform.pins[pin];
|
||||
|
||||
/* @willmmiles - wtf? We don't want to accumulate drift
|
||||
if (clockDrift) {
|
||||
wave.endDutyCcy += clockDrift;
|
||||
wave.nextPeriodCcy += clockDrift;
|
||||
wave.expiryCcy += clockDrift;
|
||||
}
|
||||
*/
|
||||
|
||||
uint32_t waveNextEventCcy = (waveform.states & pinBit) ? wave.endDutyCcy : wave.nextPeriodCcy;
|
||||
if (WaveformMode::EXPIRES == wave.mode &&
|
||||
static_cast<int32_t>(waveNextEventCcy - wave.expiryCcy) >= 0 &&
|
||||
static_cast<int32_t>(now - wave.expiryCcy) >= 0) {
|
||||
// Disable any waveforms that are done
|
||||
waveform.enabled ^= pinBit;
|
||||
busyPins ^= pinBit;
|
||||
}
|
||||
else {
|
||||
const int32_t overshootCcys = now - waveNextEventCcy;
|
||||
if (overshootCcys >= 0) {
|
||||
const int32_t periodCcys = scaleCcys(wave.periodCcys, isCPU2X);
|
||||
if (waveform.states & pinBit) {
|
||||
// active configuration and forward are 100% duty
|
||||
if (wave.periodCcys == wave.dutyCcys) {
|
||||
wave.nextPeriodCcy += periodCcys;
|
||||
wave.endDutyCcy = wave.nextPeriodCcy;
|
||||
}
|
||||
else {
|
||||
if (wave.autoPwm) {
|
||||
wave.adjDutyCcys += overshootCcys;
|
||||
}
|
||||
waveform.states ^= pinBit;
|
||||
if (16 == pin) {
|
||||
GP16O = 0;
|
||||
}
|
||||
else {
|
||||
GPOC = pinBit;
|
||||
}
|
||||
}
|
||||
waveNextEventCcy = wave.nextPeriodCcy;
|
||||
}
|
||||
else {
|
||||
wave.nextPeriodCcy += periodCcys;
|
||||
if (!wave.dutyCcys) {
|
||||
wave.endDutyCcy = wave.nextPeriodCcy;
|
||||
}
|
||||
else {
|
||||
int32_t dutyCcys = scaleCcys(wave.dutyCcys, isCPU2X);
|
||||
if (dutyCcys <= wave.adjDutyCcys) {
|
||||
dutyCcys >>= 1;
|
||||
wave.adjDutyCcys -= dutyCcys;
|
||||
}
|
||||
else if (wave.adjDutyCcys) {
|
||||
dutyCcys -= wave.adjDutyCcys;
|
||||
wave.adjDutyCcys = 0;
|
||||
}
|
||||
wave.endDutyCcy = now + dutyCcys;
|
||||
if (static_cast<int32_t>(wave.endDutyCcy - wave.nextPeriodCcy) > 0) {
|
||||
wave.endDutyCcy = wave.nextPeriodCcy;
|
||||
}
|
||||
waveform.states |= pinBit;
|
||||
if (16 == pin) {
|
||||
GP16O = 1;
|
||||
}
|
||||
else {
|
||||
GPOS = pinBit;
|
||||
}
|
||||
}
|
||||
waveNextEventCcy = wave.endDutyCcy;
|
||||
}
|
||||
|
||||
if (WaveformMode::EXPIRES == wave.mode && static_cast<int32_t>(waveNextEventCcy - wave.expiryCcy) > 0) {
|
||||
waveNextEventCcy = wave.expiryCcy;
|
||||
}
|
||||
}
|
||||
|
||||
if (static_cast<int32_t>(waveNextEventCcy - isrTimeoutCcy) >= 0) {
|
||||
busyPins ^= pinBit;
|
||||
if (static_cast<int32_t>(waveform.nextEventCcy - waveNextEventCcy) > 0) {
|
||||
waveform.nextEventCcy = waveNextEventCcy;
|
||||
}
|
||||
}
|
||||
else if (static_cast<int32_t>(isrNextEventCcy - waveNextEventCcy) > 0) {
|
||||
isrNextEventCcy = waveNextEventCcy;
|
||||
}
|
||||
}
|
||||
now = ESP.getCycleCount();
|
||||
}
|
||||
//clockDrift = 0;
|
||||
}
|
||||
|
||||
int32_t callbackCcys = 0;
|
||||
if (waveform.timer1CB) {
|
||||
callbackCcys = scaleCcys(waveform.timer1CB(), isCPU2X);
|
||||
}
|
||||
now = ESP.getCycleCount();
|
||||
int32_t nextEventCcys = waveform.nextEventCcy - now;
|
||||
// Account for unknown duration of timer1CB().
|
||||
if (waveform.timer1CB && nextEventCcys > callbackCcys) {
|
||||
waveform.nextEventCcy = now + callbackCcys;
|
||||
nextEventCcys = callbackCcys;
|
||||
}
|
||||
|
||||
// Timer is 80MHz fixed. 160MHz CPU frequency need scaling.
|
||||
int32_t deltaIrqCcys = DELTAIRQCCYS;
|
||||
int32_t irqLatencyCcys = IRQLATENCYCCYS;
|
||||
if (isCPU2X) {
|
||||
nextEventCcys >>= 1;
|
||||
deltaIrqCcys >>= 1;
|
||||
irqLatencyCcys >>= 1;
|
||||
}
|
||||
|
||||
// Firing timer too soon, the NMI occurs before ISR has returned.
|
||||
if (nextEventCcys < irqLatencyCcys + deltaIrqCcys) {
|
||||
waveform.nextEventCcy = now + IRQLATENCYCCYS + DELTAIRQCCYS;
|
||||
nextEventCcys = irqLatencyCcys;
|
||||
}
|
||||
else {
|
||||
nextEventCcys -= deltaIrqCcys;
|
||||
}
|
||||
|
||||
// Register access is fast and edge IRQ was configured before.
|
||||
T1L = nextEventCcys;
|
||||
}
|
717
lib/ESP8266PWM/src/core_esp8266_waveform_pwm.cpp
Normal file
717
lib/ESP8266PWM/src/core_esp8266_waveform_pwm.cpp
Normal file
@ -0,0 +1,717 @@
|
||||
/* esp8266_waveform imported from platform source code
|
||||
Modified for WLED to work around a fault in the NMI handling,
|
||||
which can result in the system locking up and hard WDT crashes.
|
||||
|
||||
Imported from https://github.com/esp8266/Arduino/blob/7e0d20e2b9034994f573a236364e0aef17fd66de/cores/esp8266/core_esp8266_waveform_pwm.cpp
|
||||
*/
|
||||
|
||||
/*
|
||||
esp8266_waveform - General purpose waveform generation and control,
|
||||
supporting outputs on all pins in parallel.
|
||||
|
||||
Copyright (c) 2018 Earle F. Philhower, III. All rights reserved.
|
||||
|
||||
The core idea is to have a programmable waveform generator with a unique
|
||||
high and low period (defined in microseconds or CPU clock cycles). TIMER1
|
||||
is set to 1-shot mode and is always loaded with the time until the next
|
||||
edge of any live waveforms.
|
||||
|
||||
Up to one waveform generator per pin supported.
|
||||
|
||||
Each waveform generator is synchronized to the ESP clock cycle counter, not
|
||||
the timer. This allows for removing interrupt jitter and delay as the
|
||||
counter always increments once per 80MHz clock. Changes to a waveform are
|
||||
contiguous and only take effect on the next waveform transition,
|
||||
allowing for smooth transitions.
|
||||
|
||||
This replaces older tone(), analogWrite(), and the Servo classes.
|
||||
|
||||
Everywhere in the code where "cycles" is used, it means ESP.getCycleCount()
|
||||
clock cycle count, or an interval measured in CPU clock cycles, but not
|
||||
TIMER1 cycles (which may be 2 CPU clock cycles @ 160MHz).
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <coredecls.h>
|
||||
#include "ets_sys.h"
|
||||
#include "core_esp8266_waveform.h"
|
||||
#include "user_interface.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
// Linker magic
|
||||
void usePWMFixedNMI() {};
|
||||
|
||||
// Maximum delay between IRQs
|
||||
#define MAXIRQUS (10000)
|
||||
|
||||
// Waveform generator can create tones, PWM, and servos
|
||||
typedef struct {
|
||||
uint32_t nextServiceCycle; // ESP cycle timer when a transition required
|
||||
uint32_t expiryCycle; // For time-limited waveform, the cycle when this waveform must stop
|
||||
uint32_t timeHighCycles; // Actual running waveform period (adjusted using desiredCycles)
|
||||
uint32_t timeLowCycles; //
|
||||
uint32_t desiredHighCycles; // Ideal waveform period to drive the error signal
|
||||
uint32_t desiredLowCycles; //
|
||||
uint32_t lastEdge; // Cycle when this generator last changed
|
||||
} Waveform;
|
||||
|
||||
class WVFState {
|
||||
public:
|
||||
Waveform waveform[17]; // State of all possible pins
|
||||
uint32_t waveformState = 0; // Is the pin high or low, updated in NMI so no access outside the NMI code
|
||||
uint32_t waveformEnabled = 0; // Is it actively running, updated in NMI so no access outside the NMI code
|
||||
|
||||
// Enable lock-free by only allowing updates to waveformState and waveformEnabled from IRQ service routine
|
||||
uint32_t waveformToEnable = 0; // Message to the NMI handler to start a waveform on a inactive pin
|
||||
uint32_t waveformToDisable = 0; // Message to the NMI handler to disable a pin from waveform generation
|
||||
|
||||
uint32_t waveformToChange = 0; // Mask of pin to change. One bit set in main app, cleared when effected in the NMI
|
||||
uint32_t waveformNewHigh = 0;
|
||||
uint32_t waveformNewLow = 0;
|
||||
|
||||
uint32_t (*timer1CB)() = NULL;
|
||||
|
||||
// Optimize the NMI inner loop by keeping track of the min and max GPIO that we
|
||||
// are generating. In the common case (1 PWM) these may be the same pin and
|
||||
// we can avoid looking at the other pins.
|
||||
uint16_t startPin = 0;
|
||||
uint16_t endPin = 0;
|
||||
};
|
||||
static WVFState wvfState;
|
||||
|
||||
|
||||
// Ensure everything is read/written to RAM
|
||||
#define MEMBARRIER() { __asm__ volatile("" ::: "memory"); }
|
||||
|
||||
// Non-speed critical bits
|
||||
#pragma GCC optimize ("Os")
|
||||
|
||||
// Interrupt on/off control
|
||||
static IRAM_ATTR void timer1Interrupt();
|
||||
static bool timerRunning = false;
|
||||
|
||||
static __attribute__((noinline)) void initTimer() {
|
||||
if (!timerRunning) {
|
||||
timer1_disable();
|
||||
ETS_FRC_TIMER1_INTR_ATTACH(NULL, NULL);
|
||||
ETS_FRC_TIMER1_NMI_INTR_ATTACH(timer1Interrupt);
|
||||
timer1_enable(TIM_DIV1, TIM_EDGE, TIM_SINGLE);
|
||||
timerRunning = true;
|
||||
timer1_write(microsecondsToClockCycles(10));
|
||||
}
|
||||
}
|
||||
|
||||
static IRAM_ATTR void forceTimerInterrupt() {
|
||||
if (T1L > microsecondsToClockCycles(10)) {
|
||||
T1L = microsecondsToClockCycles(10);
|
||||
}
|
||||
}
|
||||
|
||||
// PWM implementation using special purpose state machine
|
||||
//
|
||||
// Keep an ordered list of pins with the delta in cycles between each
|
||||
// element, with a terminal entry making up the remainder of the PWM
|
||||
// period. With this method sum(all deltas) == PWM period clock cycles.
|
||||
//
|
||||
// At t=0 set all pins high and set the timeout for the 1st edge.
|
||||
// On interrupt, if we're at the last element reset to t=0 state
|
||||
// Otherwise, clear that pin down and set delay for next element
|
||||
// and so forth.
|
||||
|
||||
constexpr int maxPWMs = 8;
|
||||
|
||||
// PWM machine state
|
||||
typedef struct PWMState {
|
||||
uint32_t mask; // Bitmask of active pins
|
||||
uint32_t cnt; // How many entries
|
||||
uint32_t idx; // Where the state machine is along the list
|
||||
uint8_t pin[maxPWMs + 1];
|
||||
uint32_t delta[maxPWMs + 1];
|
||||
uint32_t nextServiceCycle; // Clock cycle for next step
|
||||
struct PWMState *pwmUpdate; // Set by main code, cleared by ISR
|
||||
} PWMState;
|
||||
|
||||
static PWMState pwmState;
|
||||
static uint32_t _pwmFreq = 1000;
|
||||
static uint32_t _pwmPeriod = microsecondsToClockCycles(1000000UL) / _pwmFreq;
|
||||
|
||||
|
||||
// If there are no more scheduled activities, shut down Timer 1.
|
||||
// Otherwise, do nothing.
|
||||
static IRAM_ATTR void disableIdleTimer() {
|
||||
if (timerRunning && !wvfState.waveformEnabled && !pwmState.cnt && !wvfState.timer1CB) {
|
||||
ETS_FRC_TIMER1_NMI_INTR_ATTACH(NULL);
|
||||
timer1_disable();
|
||||
timer1_isr_init();
|
||||
timerRunning = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Notify the NMI that a new PWM state is available through the mailbox.
|
||||
// Wait for mailbox to be emptied (either busy or delay() as needed)
|
||||
static IRAM_ATTR void _notifyPWM(PWMState *p, bool idle) {
|
||||
p->pwmUpdate = nullptr;
|
||||
pwmState.pwmUpdate = p;
|
||||
MEMBARRIER();
|
||||
forceTimerInterrupt();
|
||||
while (pwmState.pwmUpdate) {
|
||||
if (idle) {
|
||||
esp_yield();
|
||||
}
|
||||
MEMBARRIER();
|
||||
}
|
||||
}
|
||||
|
||||
static void _addPWMtoList(PWMState &p, int pin, uint32_t val, uint32_t range);
|
||||
|
||||
|
||||
// Called when analogWriteFreq() changed to update the PWM total period
|
||||
//extern void _setPWMFreq_weak(uint32_t freq) __attribute__((weak));
|
||||
void _setPWMFreq_weak(uint32_t freq) {
|
||||
_pwmFreq = freq;
|
||||
|
||||
// Convert frequency into clock cycles
|
||||
uint32_t cc = microsecondsToClockCycles(1000000UL) / freq;
|
||||
|
||||
// Simple static adjustment to bring period closer to requested due to overhead
|
||||
// Empirically determined as a constant PWM delay and a function of the number of PWMs
|
||||
#if F_CPU == 80000000
|
||||
cc -= ((microsecondsToClockCycles(pwmState.cnt) * 13) >> 4) + 110;
|
||||
#else
|
||||
cc -= ((microsecondsToClockCycles(pwmState.cnt) * 10) >> 4) + 75;
|
||||
#endif
|
||||
|
||||
if (cc == _pwmPeriod) {
|
||||
return; // No change
|
||||
}
|
||||
|
||||
_pwmPeriod = cc;
|
||||
|
||||
if (pwmState.cnt) {
|
||||
PWMState p; // The working copy since we can't edit the one in use
|
||||
p.mask = 0;
|
||||
p.cnt = 0;
|
||||
for (uint32_t i = 0; i < pwmState.cnt; i++) {
|
||||
auto pin = pwmState.pin[i];
|
||||
_addPWMtoList(p, pin, wvfState.waveform[pin].desiredHighCycles, wvfState.waveform[pin].desiredLowCycles);
|
||||
}
|
||||
// Update and wait for mailbox to be emptied
|
||||
initTimer();
|
||||
_notifyPWM(&p, true);
|
||||
disableIdleTimer();
|
||||
}
|
||||
}
|
||||
/*
|
||||
static void _setPWMFreq_bound(uint32_t freq) __attribute__((weakref("_setPWMFreq_weak")));
|
||||
void _setPWMFreq(uint32_t freq) {
|
||||
_setPWMFreq_bound(freq);
|
||||
}
|
||||
*/
|
||||
|
||||
// Helper routine to remove an entry from the state machine
|
||||
// and clean up any marked-off entries
|
||||
static void _cleanAndRemovePWM(PWMState *p, int pin) {
|
||||
uint32_t leftover = 0;
|
||||
uint32_t in, out;
|
||||
for (in = 0, out = 0; in < p->cnt; in++) {
|
||||
if ((p->pin[in] != pin) && (p->mask & (1<<p->pin[in]))) {
|
||||
p->pin[out] = p->pin[in];
|
||||
p->delta[out] = p->delta[in] + leftover;
|
||||
leftover = 0;
|
||||
out++;
|
||||
} else {
|
||||
leftover += p->delta[in];
|
||||
p->mask &= ~(1<<p->pin[in]);
|
||||
}
|
||||
}
|
||||
p->cnt = out;
|
||||
// Final pin is never used: p->pin[out] = 0xff;
|
||||
p->delta[out] = p->delta[in] + leftover;
|
||||
}
|
||||
|
||||
|
||||
// Disable PWM on a specific pin (i.e. when a digitalWrite or analogWrite(0%/100%))
|
||||
//extern bool _stopPWM_weak(uint8_t pin) __attribute__((weak));
|
||||
IRAM_ATTR bool _stopPWM_weak(uint8_t pin) {
|
||||
if (!((1<<pin) & pwmState.mask)) {
|
||||
return false; // Pin not actually active
|
||||
}
|
||||
|
||||
PWMState p; // The working copy since we can't edit the one in use
|
||||
p = pwmState;
|
||||
|
||||
// In _stopPWM we just clear the mask but keep everything else
|
||||
// untouched to save IRAM. The main startPWM will handle cleanup.
|
||||
p.mask &= ~(1<<pin);
|
||||
if (!p.mask) {
|
||||
// If all have been stopped, then turn PWM off completely
|
||||
p.cnt = 0;
|
||||
}
|
||||
|
||||
// Update and wait for mailbox to be emptied, no delay (could be in ISR)
|
||||
_notifyPWM(&p, false);
|
||||
// Possibly shut down the timer completely if we're done
|
||||
disableIdleTimer();
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
static bool _stopPWM_bound(uint8_t pin) __attribute__((weakref("_stopPWM_weak")));
|
||||
IRAM_ATTR bool _stopPWM(uint8_t pin) {
|
||||
return _stopPWM_bound(pin);
|
||||
}
|
||||
*/
|
||||
|
||||
static void _addPWMtoList(PWMState &p, int pin, uint32_t val, uint32_t range) {
|
||||
// Stash the val and range so we can re-evaluate the fraction
|
||||
// should the user change PWM frequency. This allows us to
|
||||
// give as great a precision as possible. We know by construction
|
||||
// that the waveform for this pin will be inactive so we can borrow
|
||||
// memory from that structure.
|
||||
wvfState.waveform[pin].desiredHighCycles = val; // Numerator == high
|
||||
wvfState.waveform[pin].desiredLowCycles = range; // Denominator == low
|
||||
|
||||
uint32_t cc = (_pwmPeriod * val) / range;
|
||||
|
||||
// Clip to sane values in the case we go from OK to not-OK when adjusting frequencies
|
||||
if (cc == 0) {
|
||||
cc = 1;
|
||||
} else if (cc >= _pwmPeriod) {
|
||||
cc = _pwmPeriod - 1;
|
||||
}
|
||||
|
||||
if (p.cnt == 0) {
|
||||
// Starting up from scratch, special case 1st element and PWM period
|
||||
p.pin[0] = pin;
|
||||
p.delta[0] = cc;
|
||||
// Final pin is never used: p.pin[1] = 0xff;
|
||||
p.delta[1] = _pwmPeriod - cc;
|
||||
} else {
|
||||
uint32_t ttl = 0;
|
||||
uint32_t i;
|
||||
// Skip along until we're at the spot to insert
|
||||
for (i=0; (i <= p.cnt) && (ttl + p.delta[i] < cc); i++) {
|
||||
ttl += p.delta[i];
|
||||
}
|
||||
// Shift everything out by one to make space for new edge
|
||||
for (int32_t j = p.cnt; j >= (int)i; j--) {
|
||||
p.pin[j + 1] = p.pin[j];
|
||||
p.delta[j + 1] = p.delta[j];
|
||||
}
|
||||
int off = cc - ttl; // The delta from the last edge to the one we're inserting
|
||||
p.pin[i] = pin;
|
||||
p.delta[i] = off; // Add the delta to this new pin
|
||||
p.delta[i + 1] -= off; // And subtract it from the follower to keep sum(deltas) constant
|
||||
}
|
||||
p.cnt++;
|
||||
p.mask |= 1<<pin;
|
||||
}
|
||||
|
||||
// Called by analogWrite(1...99%) to set the PWM duty in clock cycles
|
||||
//extern bool _setPWM_weak(int pin, uint32_t val, uint32_t range) __attribute__((weak));
|
||||
bool _setPWM_weak(int pin, uint32_t val, uint32_t range) {
|
||||
stopWaveform(pin);
|
||||
PWMState p; // Working copy
|
||||
p = pwmState;
|
||||
// Get rid of any entries for this pin
|
||||
_cleanAndRemovePWM(&p, pin);
|
||||
// And add it to the list, in order
|
||||
if (p.cnt >= maxPWMs) {
|
||||
return false; // No space left
|
||||
}
|
||||
|
||||
// Sanity check for all-on/off
|
||||
uint32_t cc = (_pwmPeriod * val) / range;
|
||||
if ((cc == 0) || (cc >= _pwmPeriod)) {
|
||||
digitalWrite(pin, cc ? HIGH : LOW);
|
||||
return true;
|
||||
}
|
||||
|
||||
_addPWMtoList(p, pin, val, range);
|
||||
|
||||
// Set mailbox and wait for ISR to copy it over
|
||||
initTimer();
|
||||
_notifyPWM(&p, true);
|
||||
disableIdleTimer();
|
||||
|
||||
// Potentially recalculate the PWM period if we've added another pin
|
||||
_setPWMFreq(_pwmFreq);
|
||||
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
static bool _setPWM_bound(int pin, uint32_t val, uint32_t range) __attribute__((weakref("_setPWM_weak")));
|
||||
bool _setPWM(int pin, uint32_t val, uint32_t range) {
|
||||
return _setPWM_bound(pin, val, range);
|
||||
}
|
||||
*/
|
||||
|
||||
// Start up a waveform on a pin, or change the current one. Will change to the new
|
||||
// waveform smoothly on next low->high transition. For immediate change, stopWaveform()
|
||||
// first, then it will immediately begin.
|
||||
//extern int startWaveformClockCycles_weak(uint8_t pin, uint32_t timeHighCycles, uint32_t timeLowCycles, uint32_t runTimeCycles, int8_t alignPhase, uint32_t phaseOffsetUS, bool autoPwm) __attribute__((weak));
|
||||
int startWaveformClockCycles_weak(uint8_t pin, uint32_t timeHighCycles, uint32_t timeLowCycles, uint32_t runTimeCycles,
|
||||
int8_t alignPhase, uint32_t phaseOffsetUS, bool autoPwm) {
|
||||
(void) alignPhase;
|
||||
(void) phaseOffsetUS;
|
||||
(void) autoPwm;
|
||||
|
||||
if ((pin > 16) || isFlashInterfacePin(pin) || (timeHighCycles == 0)) {
|
||||
return false;
|
||||
}
|
||||
Waveform *wave = &wvfState.waveform[pin];
|
||||
wave->expiryCycle = runTimeCycles ? ESP.getCycleCount() + runTimeCycles : 0;
|
||||
if (runTimeCycles && !wave->expiryCycle) {
|
||||
wave->expiryCycle = 1; // expiryCycle==0 means no timeout, so avoid setting it
|
||||
}
|
||||
|
||||
_stopPWM(pin); // Make sure there's no PWM live here
|
||||
|
||||
uint32_t mask = 1<<pin;
|
||||
MEMBARRIER();
|
||||
if (wvfState.waveformEnabled & mask) {
|
||||
// Make sure no waveform changes are waiting to be applied
|
||||
while (wvfState.waveformToChange) {
|
||||
esp_yield(); // Wait for waveform to update
|
||||
MEMBARRIER();
|
||||
}
|
||||
wvfState.waveformNewHigh = timeHighCycles;
|
||||
wvfState.waveformNewLow = timeLowCycles;
|
||||
MEMBARRIER();
|
||||
wvfState.waveformToChange = mask;
|
||||
// The waveform will be updated some time in the future on the next period for the signal
|
||||
} else { // if (!(wvfState.waveformEnabled & mask)) {
|
||||
wave->timeHighCycles = timeHighCycles;
|
||||
wave->desiredHighCycles = timeHighCycles;
|
||||
wave->timeLowCycles = timeLowCycles;
|
||||
wave->desiredLowCycles = timeLowCycles;
|
||||
wave->lastEdge = 0;
|
||||
wave->nextServiceCycle = ESP.getCycleCount() + microsecondsToClockCycles(1);
|
||||
wvfState.waveformToEnable |= mask;
|
||||
MEMBARRIER();
|
||||
initTimer();
|
||||
forceTimerInterrupt();
|
||||
while (wvfState.waveformToEnable) {
|
||||
esp_yield(); // Wait for waveform to update
|
||||
MEMBARRIER();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
static int startWaveformClockCycles_bound(uint8_t pin, uint32_t timeHighCycles, uint32_t timeLowCycles, uint32_t runTimeCycles, int8_t alignPhase, uint32_t phaseOffsetUS, bool autoPwm) __attribute__((weakref("startWaveformClockCycles_weak")));
|
||||
int startWaveformClockCycles(uint8_t pin, uint32_t timeHighCycles, uint32_t timeLowCycles, uint32_t runTimeCycles, int8_t alignPhase, uint32_t phaseOffsetUS, bool autoPwm) {
|
||||
return startWaveformClockCycles_bound(pin, timeHighCycles, timeLowCycles, runTimeCycles, alignPhase, phaseOffsetUS, autoPwm);
|
||||
}
|
||||
|
||||
|
||||
// This version falls-thru to the proper startWaveformClockCycles call and is invariant across waveform generators
|
||||
int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS, uint32_t runTimeUS,
|
||||
int8_t alignPhase, uint32_t phaseOffsetUS, bool autoPwm) {
|
||||
return startWaveformClockCycles_bound(pin,
|
||||
microsecondsToClockCycles(timeHighUS), microsecondsToClockCycles(timeLowUS),
|
||||
microsecondsToClockCycles(runTimeUS), alignPhase, microsecondsToClockCycles(phaseOffsetUS), autoPwm);
|
||||
}
|
||||
*/
|
||||
|
||||
// Set a callback. Pass in NULL to stop it
|
||||
//extern void setTimer1Callback_weak(uint32_t (*fn)()) __attribute__((weak));
|
||||
void setTimer1Callback_weak(uint32_t (*fn)()) {
|
||||
wvfState.timer1CB = fn;
|
||||
if (fn) {
|
||||
initTimer();
|
||||
forceTimerInterrupt();
|
||||
}
|
||||
disableIdleTimer();
|
||||
}
|
||||
/*
|
||||
static void setTimer1Callback_bound(uint32_t (*fn)()) __attribute__((weakref("setTimer1Callback_weak")));
|
||||
void setTimer1Callback(uint32_t (*fn)()) {
|
||||
setTimer1Callback_bound(fn);
|
||||
}
|
||||
*/
|
||||
|
||||
// Stops a waveform on a pin
|
||||
//extern int stopWaveform_weak(uint8_t pin) __attribute__((weak));
|
||||
IRAM_ATTR int stopWaveform_weak(uint8_t pin) {
|
||||
// Can't possibly need to stop anything if there is no timer active
|
||||
if (!timerRunning) {
|
||||
return false;
|
||||
}
|
||||
// If user sends in a pin >16 but <32, this will always point to a 0 bit
|
||||
// If they send >=32, then the shift will result in 0 and it will also return false
|
||||
uint32_t mask = 1<<pin;
|
||||
if (wvfState.waveformEnabled & mask) {
|
||||
wvfState.waveformToDisable = mask;
|
||||
// Cancel any pending updates for this waveform, too.
|
||||
if (wvfState.waveformToChange & mask) {
|
||||
wvfState.waveformToChange = 0;
|
||||
}
|
||||
forceTimerInterrupt();
|
||||
while (wvfState.waveformToDisable) {
|
||||
MEMBARRIER(); // If it wasn't written yet, it has to be by now
|
||||
/* no-op */ // Can't delay() since stopWaveform may be called from an IRQ
|
||||
}
|
||||
}
|
||||
disableIdleTimer();
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
static int stopWaveform_bound(uint8_t pin) __attribute__((weakref("stopWaveform_weak")));
|
||||
IRAM_ATTR int stopWaveform(uint8_t pin) {
|
||||
return stopWaveform_bound(pin);
|
||||
}
|
||||
*/
|
||||
|
||||
// Speed critical bits
|
||||
#pragma GCC optimize ("O2")
|
||||
|
||||
// Normally would not want two copies like this, but due to different
|
||||
// optimization levels the inline attribute gets lost if we try the
|
||||
// other version.
|
||||
static inline IRAM_ATTR uint32_t GetCycleCountIRQ() {
|
||||
uint32_t ccount;
|
||||
__asm__ __volatile__("rsr %0,ccount":"=a"(ccount));
|
||||
return ccount;
|
||||
}
|
||||
|
||||
// Find the earliest cycle as compared to right now
|
||||
static inline IRAM_ATTR uint32_t earliest(uint32_t a, uint32_t b) {
|
||||
uint32_t now = GetCycleCountIRQ();
|
||||
int32_t da = a - now;
|
||||
int32_t db = b - now;
|
||||
return (da < db) ? a : b;
|
||||
}
|
||||
|
||||
// ----- @willmmiles begin patch -----
|
||||
// NMI crash workaround
|
||||
// Sometimes the NMI fails to return, stalling the CPU. When this happens,
|
||||
// the next NMI gets a return address /inside the NMI handler function/.
|
||||
// We work around this by caching the last NMI return address, and restoring
|
||||
// the epc3 and eps3 registers to the previous values if the observed epc3
|
||||
// happens to be pointing to the _NMILevelVector function.
|
||||
extern void _NMILevelVector();
|
||||
extern void _UserExceptionVector_1(); // the next function after _NMILevelVector
|
||||
static inline IRAM_ATTR void nmiCrashWorkaround() {
|
||||
static uintptr_t epc3_backup, eps3_backup;
|
||||
|
||||
uintptr_t epc3, eps3;
|
||||
__asm__ __volatile__("rsr %0,epc3; rsr %1,eps3":"=a"(epc3),"=a" (eps3));
|
||||
if ((epc3 < (uintptr_t) &_NMILevelVector) || (epc3 >= (uintptr_t) &_UserExceptionVector_1)) {
|
||||
// Address is good; save backup
|
||||
epc3_backup = epc3;
|
||||
eps3_backup = eps3;
|
||||
} else {
|
||||
// Address is inside the NMI handler -- restore from backup
|
||||
__asm__ __volatile__("wsr %0,epc3; wsr %1,eps3"::"a"(epc3_backup),"a"(eps3_backup));
|
||||
}
|
||||
}
|
||||
// ----- @willmmiles end patch -----
|
||||
|
||||
|
||||
// The SDK and hardware take some time to actually get to our NMI code, so
|
||||
// decrement the next IRQ's timer value by a bit so we can actually catch the
|
||||
// real CPU cycle counter we want for the waveforms.
|
||||
|
||||
// The SDK also sometimes is running at a different speed the the Arduino core
|
||||
// so the ESP cycle counter is actually running at a variable speed.
|
||||
// adjust(x) takes care of adjusting a delta clock cycle amount accordingly.
|
||||
#if F_CPU == 80000000
|
||||
#define DELTAIRQ (microsecondsToClockCycles(9)/4)
|
||||
#define adjust(x) ((x) << (turbo ? 1 : 0))
|
||||
#else
|
||||
#define DELTAIRQ (microsecondsToClockCycles(9)/8)
|
||||
#define adjust(x) ((x) >> 0)
|
||||
#endif
|
||||
|
||||
// When the time to the next edge is greater than this, RTI and set another IRQ to minimize CPU usage
|
||||
#define MINIRQTIME microsecondsToClockCycles(6)
|
||||
|
||||
static IRAM_ATTR void timer1Interrupt() {
|
||||
// ----- @willmmiles begin patch -----
|
||||
nmiCrashWorkaround();
|
||||
// ----- @willmmiles end patch -----
|
||||
|
||||
// Flag if the core is at 160 MHz, for use by adjust()
|
||||
bool turbo = (*(uint32_t*)0x3FF00014) & 1 ? true : false;
|
||||
|
||||
uint32_t nextEventCycle = GetCycleCountIRQ() + microsecondsToClockCycles(MAXIRQUS);
|
||||
uint32_t timeoutCycle = GetCycleCountIRQ() + microsecondsToClockCycles(14);
|
||||
|
||||
if (wvfState.waveformToEnable || wvfState.waveformToDisable) {
|
||||
// Handle enable/disable requests from main app
|
||||
wvfState.waveformEnabled = (wvfState.waveformEnabled & ~wvfState.waveformToDisable) | wvfState.waveformToEnable; // Set the requested waveforms on/off
|
||||
wvfState.waveformState &= ~wvfState.waveformToEnable; // And clear the state of any just started
|
||||
wvfState.waveformToEnable = 0;
|
||||
wvfState.waveformToDisable = 0;
|
||||
// No mem barrier. Globals must be written to RAM on ISR exit.
|
||||
// Find the first GPIO being generated by checking GCC's find-first-set (returns 1 + the bit of the first 1 in an int32_t)
|
||||
wvfState.startPin = __builtin_ffs(wvfState.waveformEnabled) - 1;
|
||||
// Find the last bit by subtracting off GCC's count-leading-zeros (no offset in this one)
|
||||
wvfState.endPin = 32 - __builtin_clz(wvfState.waveformEnabled);
|
||||
} else if (!pwmState.cnt && pwmState.pwmUpdate) {
|
||||
// Start up the PWM generator by copying from the mailbox
|
||||
pwmState.cnt = 1;
|
||||
pwmState.idx = 1; // Ensure copy this cycle, cause it to start at t=0
|
||||
pwmState.nextServiceCycle = GetCycleCountIRQ(); // Do it this loop!
|
||||
// No need for mem barrier here. Global must be written by IRQ exit
|
||||
}
|
||||
|
||||
bool done = false;
|
||||
if (wvfState.waveformEnabled || pwmState.cnt) {
|
||||
do {
|
||||
nextEventCycle = GetCycleCountIRQ() + microsecondsToClockCycles(MAXIRQUS);
|
||||
|
||||
// PWM state machine implementation
|
||||
if (pwmState.cnt) {
|
||||
int32_t cyclesToGo;
|
||||
do {
|
||||
cyclesToGo = pwmState.nextServiceCycle - GetCycleCountIRQ();
|
||||
if (cyclesToGo < 0) {
|
||||
if (pwmState.idx == pwmState.cnt) { // Start of pulses, possibly copy new
|
||||
if (pwmState.pwmUpdate) {
|
||||
// Do the memory copy from temp to global and clear mailbox
|
||||
pwmState = *(PWMState*)pwmState.pwmUpdate;
|
||||
}
|
||||
GPOS = pwmState.mask; // Set all active pins high
|
||||
if (pwmState.mask & (1<<16)) {
|
||||
GP16O = 1;
|
||||
}
|
||||
pwmState.idx = 0;
|
||||
} else {
|
||||
do {
|
||||
// Drop the pin at this edge
|
||||
if (pwmState.mask & (1<<pwmState.pin[pwmState.idx])) {
|
||||
GPOC = 1<<pwmState.pin[pwmState.idx];
|
||||
if (pwmState.pin[pwmState.idx] == 16) {
|
||||
GP16O = 0;
|
||||
}
|
||||
}
|
||||
pwmState.idx++;
|
||||
// Any other pins at this same PWM value will have delta==0, drop them too.
|
||||
} while (pwmState.delta[pwmState.idx] == 0);
|
||||
}
|
||||
// Preserve duty cycle over PWM period by using now+xxx instead of += delta
|
||||
cyclesToGo = adjust(pwmState.delta[pwmState.idx]);
|
||||
pwmState.nextServiceCycle = GetCycleCountIRQ() + cyclesToGo;
|
||||
}
|
||||
nextEventCycle = earliest(nextEventCycle, pwmState.nextServiceCycle);
|
||||
} while (pwmState.cnt && (cyclesToGo < 100));
|
||||
}
|
||||
|
||||
for (auto i = wvfState.startPin; i <= wvfState.endPin; i++) {
|
||||
uint32_t mask = 1<<i;
|
||||
|
||||
// If it's not on, ignore!
|
||||
if (!(wvfState.waveformEnabled & mask)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Waveform *wave = &wvfState.waveform[i];
|
||||
uint32_t now = GetCycleCountIRQ();
|
||||
|
||||
// Disable any waveforms that are done
|
||||
if (wave->expiryCycle) {
|
||||
int32_t expiryToGo = wave->expiryCycle - now;
|
||||
if (expiryToGo < 0) {
|
||||
// Done, remove!
|
||||
if (i == 16) {
|
||||
GP16O = 0;
|
||||
}
|
||||
GPOC = mask;
|
||||
wvfState.waveformEnabled &= ~mask;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for toggles
|
||||
int32_t cyclesToGo = wave->nextServiceCycle - now;
|
||||
if (cyclesToGo < 0) {
|
||||
uint32_t nextEdgeCycles;
|
||||
uint32_t desired = 0;
|
||||
uint32_t *timeToUpdate;
|
||||
wvfState.waveformState ^= mask;
|
||||
if (wvfState.waveformState & mask) {
|
||||
if (i == 16) {
|
||||
GP16O = 1;
|
||||
}
|
||||
GPOS = mask;
|
||||
|
||||
if (wvfState.waveformToChange & mask) {
|
||||
// Copy over next full-cycle timings
|
||||
wave->timeHighCycles = wvfState.waveformNewHigh;
|
||||
wave->desiredHighCycles = wvfState.waveformNewHigh;
|
||||
wave->timeLowCycles = wvfState.waveformNewLow;
|
||||
wave->desiredLowCycles = wvfState.waveformNewLow;
|
||||
wave->lastEdge = 0;
|
||||
wvfState.waveformToChange = 0;
|
||||
}
|
||||
if (wave->lastEdge) {
|
||||
desired = wave->desiredLowCycles;
|
||||
timeToUpdate = &wave->timeLowCycles;
|
||||
}
|
||||
nextEdgeCycles = wave->timeHighCycles;
|
||||
} else {
|
||||
if (i == 16) {
|
||||
GP16O = 0;
|
||||
}
|
||||
GPOC = mask;
|
||||
desired = wave->desiredHighCycles;
|
||||
timeToUpdate = &wave->timeHighCycles;
|
||||
nextEdgeCycles = wave->timeLowCycles;
|
||||
}
|
||||
if (desired) {
|
||||
desired = adjust(desired);
|
||||
int32_t err = desired - (now - wave->lastEdge);
|
||||
if (abs(err) < desired) { // If we've lost > the entire phase, ignore this error signal
|
||||
err /= 2;
|
||||
*timeToUpdate += err;
|
||||
}
|
||||
}
|
||||
nextEdgeCycles = adjust(nextEdgeCycles);
|
||||
wave->nextServiceCycle = now + nextEdgeCycles;
|
||||
wave->lastEdge = now;
|
||||
}
|
||||
nextEventCycle = earliest(nextEventCycle, wave->nextServiceCycle);
|
||||
}
|
||||
|
||||
// Exit the loop if we've hit the fixed runtime limit or the next event is known to be after that timeout would occur
|
||||
uint32_t now = GetCycleCountIRQ();
|
||||
int32_t cycleDeltaNextEvent = nextEventCycle - now;
|
||||
int32_t cyclesLeftTimeout = timeoutCycle - now;
|
||||
done = (cycleDeltaNextEvent > MINIRQTIME) || (cyclesLeftTimeout < 0);
|
||||
} while (!done);
|
||||
} // if (wvfState.waveformEnabled)
|
||||
|
||||
if (wvfState.timer1CB) {
|
||||
nextEventCycle = earliest(nextEventCycle, GetCycleCountIRQ() + wvfState.timer1CB());
|
||||
}
|
||||
|
||||
int32_t nextEventCycles = nextEventCycle - GetCycleCountIRQ();
|
||||
|
||||
if (nextEventCycles < MINIRQTIME) {
|
||||
nextEventCycles = MINIRQTIME;
|
||||
}
|
||||
nextEventCycles -= DELTAIRQ;
|
||||
|
||||
// Do it here instead of global function to save time and because we know it's edge-IRQ
|
||||
T1L = nextEventCycles >> (turbo ? 1 : 0);
|
||||
}
|
||||
|
||||
};
|
1904
package-lock.json
generated
1904
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
17
package.json
17
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wled",
|
||||
"version": "0.16.0-alpha",
|
||||
"version": "0.15.0-b7",
|
||||
"description": "Tools for WLED project",
|
||||
"main": "tools/cdata.js",
|
||||
"directories": {
|
||||
@ -14,21 +14,18 @@
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/wled-dev/WLED.git"
|
||||
"url": "git+https://github.com/Aircoookie/WLED.git"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"bugs": {
|
||||
"url": "https://github.com/wled-dev/WLED/issues"
|
||||
"url": "https://github.com/Aircoookie/WLED/issues"
|
||||
},
|
||||
"homepage": "https://github.com/wled-dev/WLED#readme",
|
||||
"homepage": "https://github.com/Aircoookie/WLED#readme",
|
||||
"dependencies": {
|
||||
"clean-css": "^5.3.3",
|
||||
"html-minifier-terser": "^7.2.0",
|
||||
"web-resource-inliner": "^7.0.0",
|
||||
"nodemon": "^3.1.9"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
"inliner": "^1.13.1",
|
||||
"nodemon": "^3.1.7"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,21 +1,3 @@
|
||||
Import("env")
|
||||
import shutil
|
||||
Import('env')
|
||||
|
||||
node_ex = shutil.which("node")
|
||||
# Check if Node.js is installed and present in PATH if it failed, abort the build
|
||||
if node_ex is None:
|
||||
print('\x1b[0;31;43m' + 'Node.js is not installed or missing from PATH html css js will not be processed check https://kno.wled.ge/advanced/compiling-wled/' + '\x1b[0m')
|
||||
exitCode = env.Execute("null")
|
||||
exit(exitCode)
|
||||
else:
|
||||
# Install the necessary node packages for the pre-build asset bundling script
|
||||
print('\x1b[6;33;42m' + 'Installing node packages' + '\x1b[0m')
|
||||
env.Execute("npm ci")
|
||||
|
||||
# Call the bundling script
|
||||
exitCode = env.Execute("npm run build")
|
||||
|
||||
# If it failed, abort the build
|
||||
if (exitCode):
|
||||
print('\x1b[0;31;43m' + 'npm run build fails check https://kno.wled.ge/advanced/compiling-wled/' + '\x1b[0m')
|
||||
exit(exitCode)
|
||||
env.Execute("npm run build")
|
@ -1,115 +0,0 @@
|
||||
Import('env')
|
||||
import os.path
|
||||
from collections import deque
|
||||
from pathlib import Path # For OS-agnostic path manipulation
|
||||
from platformio.package.manager.library import LibraryPackageManager
|
||||
|
||||
usermod_dir = Path(env["PROJECT_DIR"]) / "usermods"
|
||||
all_usermods = [f for f in usermod_dir.iterdir() if f.is_dir() and f.joinpath('library.json').exists()]
|
||||
|
||||
if env['PIOENV'] == "usermods":
|
||||
# Add all usermods
|
||||
env.GetProjectConfig().set(f"env:usermods", 'custom_usermods', " ".join([f.name for f in all_usermods]))
|
||||
|
||||
def find_usermod(mod: str):
|
||||
"""Locate this library in the usermods folder.
|
||||
We do this to avoid needing to rename a bunch of folders;
|
||||
this could be removed later
|
||||
"""
|
||||
# Check name match
|
||||
mp = usermod_dir / mod
|
||||
if mp.exists():
|
||||
return mp
|
||||
mp = usermod_dir / f"{mod}_v2"
|
||||
if mp.exists():
|
||||
return mp
|
||||
mp = usermod_dir / f"usermod_v2_{mod}"
|
||||
if mp.exists():
|
||||
return mp
|
||||
raise RuntimeError(f"Couldn't locate module {mod} in usermods directory!")
|
||||
|
||||
usermods = env.GetProjectOption("custom_usermods","")
|
||||
if usermods:
|
||||
# Inject usermods in to project lib_deps
|
||||
proj = env.GetProjectConfig()
|
||||
deps = env.GetProjectOption('lib_deps')
|
||||
src_dir = proj.get("platformio", "src_dir")
|
||||
src_dir = src_dir.replace('\\','/')
|
||||
mod_paths = {mod: find_usermod(mod) for mod in usermods.split()}
|
||||
usermods = [f"{mod} = symlink://{path}" for mod, path in mod_paths.items()]
|
||||
proj.set("env:" + env['PIOENV'], 'lib_deps', deps + usermods)
|
||||
# Force usermods to be installed in to the environment build state before the LDF runs
|
||||
# Otherwise we won't be able to see them until it's too late to change their paths for LDF
|
||||
# Logic is largely borrowed from PlaformIO internals
|
||||
not_found_specs = []
|
||||
for spec in usermods:
|
||||
found = False
|
||||
for storage_dir in env.GetLibSourceDirs():
|
||||
#print(f"Checking {storage_dir} for {spec}")
|
||||
lm = LibraryPackageManager(storage_dir)
|
||||
if lm.get_package(spec):
|
||||
#print("Found!")
|
||||
found = True
|
||||
break
|
||||
if not found:
|
||||
#print("Missing!")
|
||||
not_found_specs.append(spec)
|
||||
if not_found_specs:
|
||||
lm = LibraryPackageManager(
|
||||
env.subst(os.path.join("$PROJECT_LIBDEPS_DIR", "$PIOENV"))
|
||||
)
|
||||
for spec in not_found_specs:
|
||||
#print(f"LU: forcing install of {spec}")
|
||||
lm.install(spec)
|
||||
|
||||
|
||||
# Utility function for assembling usermod include paths
|
||||
def cached_add_includes(dep, dep_cache: set, includes: deque):
|
||||
""" Add dep's include paths to includes if it's not in the cache """
|
||||
if dep not in dep_cache:
|
||||
dep_cache.add(dep)
|
||||
for include in dep.get_include_dirs():
|
||||
if include not in includes:
|
||||
includes.appendleft(include)
|
||||
if usermod_dir not in Path(dep.src_dir).parents:
|
||||
# Recurse, but only for NON-usermods
|
||||
for subdep in dep.depbuilders:
|
||||
cached_add_includes(subdep, dep_cache, includes)
|
||||
|
||||
# Monkey-patch ConfigureProjectLibBuilder to mark up the dependencies
|
||||
# Save the old value
|
||||
old_ConfigureProjectLibBuilder = env.ConfigureProjectLibBuilder
|
||||
|
||||
# Our new wrapper
|
||||
def wrapped_ConfigureProjectLibBuilder(xenv):
|
||||
# Update usermod properties
|
||||
# Set libArchive before build actions are added
|
||||
for um in (um for um in xenv.GetLibBuilders() if usermod_dir in Path(um.src_dir).parents):
|
||||
build = um._manifest.get("build", {})
|
||||
build["libArchive"] = False
|
||||
um._manifest["build"] = build
|
||||
|
||||
# Call the wrapped function
|
||||
result = old_ConfigureProjectLibBuilder.clone(xenv)()
|
||||
|
||||
# Fix up include paths
|
||||
# In PlatformIO >=6.1.17, this could be done prior to ConfigureProjectLibBuilder
|
||||
wled_dir = xenv["PROJECT_SRC_DIR"]
|
||||
# Build a list of dependency include dirs
|
||||
# TODO: Find out if this is the order that PlatformIO/SCons puts them in??
|
||||
processed_deps = set()
|
||||
extra_include_dirs = deque() # Deque used for fast prepend
|
||||
for dep in result.depbuilders:
|
||||
cached_add_includes(dep, processed_deps, extra_include_dirs)
|
||||
|
||||
for um in [dep for dep in result.depbuilders if usermod_dir in Path(dep.src_dir).parents]:
|
||||
# Add the wled folder to the include path
|
||||
um.env.PrependUnique(CPPPATH=wled_dir)
|
||||
# Add WLED's own dependencies
|
||||
for dir in extra_include_dirs:
|
||||
um.env.PrependUnique(CPPPATH=dir)
|
||||
|
||||
return result
|
||||
|
||||
# Apply the wrapper
|
||||
env.AddMethod(wrapped_ConfigureProjectLibBuilder, "ConfigureProjectLibBuilder")
|
@ -19,9 +19,8 @@ def _create_dirs(dirs=["map", "release", "firmware"]):
|
||||
os.makedirs(os.path.join(OUTPUT_DIR, d), exist_ok=True)
|
||||
|
||||
def create_release(source):
|
||||
release_name_def = _get_cpp_define_value(env, "WLED_RELEASE_NAME")
|
||||
if release_name_def:
|
||||
release_name = release_name_def.replace("\\\"", "")
|
||||
release_name = _get_cpp_define_value(env, "WLED_RELEASE_NAME")
|
||||
if release_name:
|
||||
version = _get_cpp_define_value(env, "WLED_VERSION")
|
||||
release_file = os.path.join(OUTPUT_DIR, "release", f"WLED_{version}_{release_name}.bin")
|
||||
release_gz_file = release_file + ".gz"
|
||||
|
233
platformio.ini
233
platformio.ini
@ -10,7 +10,7 @@
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# CI/release binaries
|
||||
default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, nodemcuv2_160, esp8266_2m_160, esp01_1m_full_160, nodemcuv2_compat, esp8266_2m_compat, esp01_1m_full_compat, esp32dev, esp32dev_V4, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_16MB_opi, esp32s3dev_8MB_opi, esp32s3_4M_qspi, esp32_wrover, usermods
|
||||
default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, nodemcuv2_160, esp8266_2m_160, esp01_1m_full_160, nodemcuv2_compat, esp8266_2m_compat, esp01_1m_full_compat, esp32dev, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_16MB_opi, esp32s3dev_8MB_opi, esp32s3_4M_qspi, esp32_wrover
|
||||
|
||||
src_dir = ./wled00
|
||||
data_dir = ./wled00/data
|
||||
@ -114,7 +114,6 @@ extra_scripts =
|
||||
post:pio-scripts/output_bins.py
|
||||
post:pio-scripts/strip-floats.py
|
||||
pre:pio-scripts/user_config_copy.py
|
||||
pre:pio-scripts/load_usermods.py
|
||||
pre:pio-scripts/build_ui.py
|
||||
; post:pio-scripts/obj-dump.py ;; convenience script to create a disassembly dump of the firmware (hardcore debugging)
|
||||
|
||||
@ -139,9 +138,9 @@ lib_compat_mode = strict
|
||||
lib_deps =
|
||||
fastled/FastLED @ 3.6.0
|
||||
IRremoteESP8266 @ 2.8.2
|
||||
makuna/NeoPixelBus @ 2.8.3
|
||||
makuna/NeoPixelBus @ 2.8.0
|
||||
#https://github.com/makuna/NeoPixelBus.git#CoreShaderBeta
|
||||
https://github.com/Aircoookie/ESPAsyncWebServer.git#v2.4.0
|
||||
https://github.com/Aircoookie/ESPAsyncWebServer.git#v2.2.1
|
||||
# for I2C interface
|
||||
;Wire
|
||||
# ESP-NOW library
|
||||
@ -158,18 +157,25 @@ lib_deps =
|
||||
;adafruit/Adafruit BMP280 Library @ 2.1.0
|
||||
;adafruit/Adafruit CCS811 Library @ 1.0.4
|
||||
;adafruit/Adafruit Si7021 Library @ 1.4.0
|
||||
#For ADS1115 sensor uncomment following
|
||||
;adafruit/Adafruit BusIO @ 1.13.2
|
||||
;adafruit/Adafruit ADS1X15 @ 2.4.0
|
||||
#For MAX1704x Lipo Monitor / Fuel Gauge uncomment following
|
||||
; https://github.com/adafruit/Adafruit_BusIO @ 1.14.5
|
||||
; https://github.com/adafruit/Adafruit_MAX1704X @ 1.0.2
|
||||
#For MPU6050 IMU uncomment follwoing
|
||||
;electroniccats/MPU6050 @1.0.1
|
||||
# For -D USERMOD_ANIMARTRIX
|
||||
# CC BY-NC 3.0 licensed effects by Stefan Petrick, include this usermod only if you accept the terms!
|
||||
;https://github.com/netmindz/animartrix.git#18bf17389e57c69f11bc8d04ebe1d215422c7fb7
|
||||
# SHT85
|
||||
;robtillaart/SHT85@~0.3.3
|
||||
# Audioreactive usermod
|
||||
;kosme/arduinoFFT @ 2.0.1
|
||||
|
||||
extra_scripts = ${scripts_defaults.extra_scripts}
|
||||
|
||||
[esp8266]
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags =
|
||||
-DESP8266
|
||||
-DFP_IN_IROM
|
||||
@ -229,30 +235,20 @@ lib_deps_compat =
|
||||
IRremoteESP8266 @ 2.8.2
|
||||
makuna/NeoPixelBus @ 2.7.9
|
||||
https://github.com/blazoncek/QuickESPNow.git#optional-debug
|
||||
https://github.com/Aircoookie/ESPAsyncWebServer.git#v2.4.0
|
||||
https://github.com/Aircoookie/ESPAsyncWebServer.git#v2.2.1
|
||||
|
||||
[esp32_all_variants]
|
||||
lib_deps =
|
||||
willmmiles/AsyncTCP @ 1.3.1
|
||||
bitbank2/AnimatedGIF@^1.4.7
|
||||
https://github.com/Aircoookie/GifDecoder#bc3af18
|
||||
build_flags =
|
||||
-D CONFIG_ASYNC_TCP_USE_WDT=0
|
||||
-D WLED_ENABLE_GIF
|
||||
|
||||
[esp32]
|
||||
#platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.2.3/platform-espressif32-2.0.2.3.zip
|
||||
platform = espressif32@3.5.0
|
||||
platform_packages = framework-arduinoespressif32 @ https://github.com/Aircoookie/arduino-esp32.git#1.0.6.4
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = -g
|
||||
-DARDUINO_ARCH_ESP32
|
||||
#-DCONFIG_LITTLEFS_FOR_IDF_3_2
|
||||
-D CONFIG_ASYNC_TCP_USE_WDT=0
|
||||
#use LITTLEFS library by lorol in ESP32 core 1.x.x instead of built-in in 2.x.x
|
||||
-D LOROL_LITTLEFS
|
||||
; -DARDUINO_USB_CDC_ON_BOOT=0 ;; this flag is mandatory for "classic ESP32" when building with arduino-esp32 >=2.0.3
|
||||
${esp32_all_variants.build_flags}
|
||||
|
||||
tiny_partitions = tools/WLED_ESP32_2MB_noOTA.csv
|
||||
default_partitions = tools/WLED_ESP32_4MB_1MB_FS.csv
|
||||
extended_partitions = tools/WLED_ESP32_4MB_700k_FS.csv
|
||||
@ -261,13 +257,12 @@ large_partitions = tools/WLED_ESP32_8MB.csv
|
||||
extreme_partitions = tools/WLED_ESP32_16MB_9MB_FS.csv
|
||||
lib_deps =
|
||||
https://github.com/lorol/LITTLEFS.git
|
||||
${esp32_all_variants.lib_deps}
|
||||
https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
|
||||
${env.lib_deps}
|
||||
board_build.partitions = ${esp32.default_partitions} ;; default partioning for 4MB Flash - can be overridden in build envs
|
||||
# additional build flags for audioreactive - must be applied globally
|
||||
AR_build_flags = ;; -fsingle-precision-constant ;; forces ArduinoFFT to use float math (2x faster)
|
||||
AR_lib_deps = ;; for pre-usermod-library platformio_override compatibility
|
||||
|
||||
# additional build flags for audioreactive
|
||||
AR_build_flags = -D USERMOD_AUDIOREACTIVE
|
||||
-D sqrt_internal=sqrtf ;; -fsingle-precision-constant ;; forces ArduinoFFT to use float math (2x faster)
|
||||
AR_lib_deps = kosme/arduinoFFT @ 2.0.1
|
||||
|
||||
[esp32_idf_V4]
|
||||
;; experimental build environment for ESP32 using ESP-IDF 4.4.x / arduino-esp32 v2.0.5
|
||||
@ -275,78 +270,69 @@ AR_lib_deps = ;; for pre-usermod-library platformio_override compatibility
|
||||
;;
|
||||
;; please note that you can NOT update existing ESP32 installs with a "V4" build. Also updating by OTA will not work properly.
|
||||
;; You need to completely erase your device (esptool erase_flash) first, then install the "V4" build from VSCode+platformio.
|
||||
|
||||
;; select arduino-esp32 v2.0.9 (arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them)
|
||||
platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.06.02/platform-espressif32.zip ;; Tasmota Arduino Core 2.0.9 with IPv6 support, based on IDF 4.4.4
|
||||
build_unflags = ${common.build_unflags}
|
||||
platform = espressif32@ ~6.3.2
|
||||
platform_packages = platformio/framework-arduinoespressif32 @ 3.20009.0 ;; select arduino-esp32 v2.0.9 (arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them)
|
||||
build_flags = -g
|
||||
-Wshadow=compatible-local ;; emit warning in case a local variable "shadows" another local one
|
||||
-DARDUINO_ARCH_ESP32 -DESP32
|
||||
-D CONFIG_ASYNC_TCP_USE_WDT=0
|
||||
-DARDUINO_USB_CDC_ON_BOOT=0 ;; this flag is mandatory for "classic ESP32" when building with arduino-esp32 >=2.0.3
|
||||
${esp32_all_variants.build_flags}
|
||||
-D WLED_ENABLE_DMX_INPUT
|
||||
lib_deps =
|
||||
${esp32_all_variants.lib_deps}
|
||||
https://github.com/someweisguy/esp_dmx.git#47db25d
|
||||
https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
|
||||
${env.lib_deps}
|
||||
board_build.partitions = ${esp32.default_partitions} ;; default partioning for 4MB Flash - can be overridden in build envs
|
||||
|
||||
[esp32s2]
|
||||
;; generic definitions for all ESP32-S2 boards
|
||||
platform = ${esp32_idf_V4.platform}
|
||||
build_unflags = ${common.build_unflags}
|
||||
platform = espressif32@ ~6.3.2
|
||||
platform_packages = platformio/framework-arduinoespressif32 @ 3.20009.0 ;; select arduino-esp32 v2.0.9 (arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them)
|
||||
build_flags = -g
|
||||
-DARDUINO_ARCH_ESP32
|
||||
-DARDUINO_ARCH_ESP32S2
|
||||
-DCONFIG_IDF_TARGET_ESP32S2=1
|
||||
-D CONFIG_ASYNC_TCP_USE_WDT=0
|
||||
-DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_USB_DFU_ON_BOOT=0
|
||||
-DCO
|
||||
-DARDUINO_USB_MODE=0 ;; this flag is mandatory for ESP32-S2 !
|
||||
;; please make sure that the following flags are properly set (to 0 or 1) by your board.json, or included in your custom platformio_override.ini entry:
|
||||
;; ARDUINO_USB_CDC_ON_BOOT
|
||||
${esp32_all_variants.build_flags}
|
||||
lib_deps =
|
||||
${esp32_all_variants.lib_deps}
|
||||
https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
|
||||
${env.lib_deps}
|
||||
board_build.partitions = ${esp32.default_partitions} ;; default partioning for 4MB Flash - can be overridden in build envs
|
||||
|
||||
[esp32c3]
|
||||
;; generic definitions for all ESP32-C3 boards
|
||||
platform = ${esp32_idf_V4.platform}
|
||||
build_unflags = ${common.build_unflags}
|
||||
platform = espressif32@ ~6.3.2
|
||||
platform_packages = platformio/framework-arduinoespressif32 @ 3.20009.0 ;; select arduino-esp32 v2.0.9 (arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them)
|
||||
build_flags = -g
|
||||
-DARDUINO_ARCH_ESP32
|
||||
-DARDUINO_ARCH_ESP32C3
|
||||
-DCONFIG_IDF_TARGET_ESP32C3=1
|
||||
-D CONFIG_ASYNC_TCP_USE_WDT=0
|
||||
-DCO
|
||||
-DARDUINO_USB_MODE=1 ;; this flag is mandatory for ESP32-C3
|
||||
;; please make sure that the following flags are properly set (to 0 or 1) by your board.json, or included in your custom platformio_override.ini entry:
|
||||
;; ARDUINO_USB_CDC_ON_BOOT
|
||||
${esp32_all_variants.build_flags}
|
||||
lib_deps =
|
||||
${esp32_all_variants.lib_deps}
|
||||
https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
|
||||
${env.lib_deps}
|
||||
board_build.partitions = ${esp32.default_partitions} ;; default partioning for 4MB Flash - can be overridden in build envs
|
||||
board_build.flash_mode = qio
|
||||
|
||||
[esp32s3]
|
||||
;; generic definitions for all ESP32-S3 boards
|
||||
platform = ${esp32_idf_V4.platform}
|
||||
build_unflags = ${common.build_unflags}
|
||||
platform = espressif32@ ~6.3.2
|
||||
platform_packages = platformio/framework-arduinoespressif32 @ 3.20009.0 ;; select arduino-esp32 v2.0.9 (arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them)
|
||||
build_flags = -g
|
||||
-DESP32
|
||||
-DARDUINO_ARCH_ESP32
|
||||
-DARDUINO_ARCH_ESP32S3
|
||||
-DCONFIG_IDF_TARGET_ESP32S3=1
|
||||
-D CONFIG_ASYNC_TCP_USE_WDT=0
|
||||
-DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_DFU_ON_BOOT=0
|
||||
-DCO
|
||||
;; please make sure that the following flags are properly set (to 0 or 1) by your board.json, or included in your custom platformio_override.ini entry:
|
||||
;; ARDUINO_USB_MODE, ARDUINO_USB_CDC_ON_BOOT
|
||||
${esp32_all_variants.build_flags}
|
||||
lib_deps =
|
||||
${esp32_all_variants.lib_deps}
|
||||
https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
|
||||
${env.lib_deps}
|
||||
board_build.partitions = ${esp32.large_partitions} ;; default partioning for 8MB flash - can be overridden in build envs
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
@ -359,8 +345,7 @@ platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP8266\" #-DWLED_DISABLE_2D
|
||||
-D WLED_DISABLE_PARTICLESYSTEM2D
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=ESP8266 #-DWLED_DISABLE_2D
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
monitor_filters = esp8266_exception_decoder
|
||||
|
||||
@ -369,16 +354,14 @@ extends = env:nodemcuv2
|
||||
;; using platform version and build options from WLED 0.14.0
|
||||
platform = ${esp8266.platform_compat}
|
||||
platform_packages = ${esp8266.platform_packages_compat}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=\"ESP8266_compat\" #-DWLED_DISABLE_2D
|
||||
-D WLED_DISABLE_PARTICLESYSTEM2D
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=ESP8266_compat #-DWLED_DISABLE_2D
|
||||
;; lib_deps = ${esp8266.lib_deps_compat} ;; experimental - use older NeoPixelBus 2.7.9
|
||||
|
||||
[env:nodemcuv2_160]
|
||||
extends = env:nodemcuv2
|
||||
board_build.f_cpu = 160000000L
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP8266_160\" #-DWLED_DISABLE_2D
|
||||
-D WLED_DISABLE_PARTICLESYSTEM2D
|
||||
custom_usermods = audioreactive
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=ESP8266_160 #-DWLED_DISABLE_2D
|
||||
-D USERMOD_AUDIOREACTIVE
|
||||
|
||||
[env:esp8266_2m]
|
||||
board = esp_wroom_02
|
||||
@ -386,9 +369,7 @@ platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_2m512k}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP02\"
|
||||
-D WLED_DISABLE_PARTICLESYSTEM2D
|
||||
-D WLED_DISABLE_PARTICLESYSTEM1D
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=ESP02
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
|
||||
[env:esp8266_2m_compat]
|
||||
@ -396,17 +377,13 @@ extends = env:esp8266_2m
|
||||
;; using platform version and build options from WLED 0.14.0
|
||||
platform = ${esp8266.platform_compat}
|
||||
platform_packages = ${esp8266.platform_packages_compat}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=\"ESP02_compat\" #-DWLED_DISABLE_2D
|
||||
-D WLED_DISABLE_PARTICLESYSTEM1D
|
||||
-D WLED_DISABLE_PARTICLESYSTEM2D
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=ESP02_compat #-DWLED_DISABLE_2D
|
||||
|
||||
[env:esp8266_2m_160]
|
||||
extends = env:esp8266_2m
|
||||
board_build.f_cpu = 160000000L
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP02_160\"
|
||||
-D WLED_DISABLE_PARTICLESYSTEM1D
|
||||
-D WLED_DISABLE_PARTICLESYSTEM2D
|
||||
custom_usermods = audioreactive
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=ESP02_160
|
||||
-D USERMOD_AUDIOREACTIVE
|
||||
|
||||
[env:esp01_1m_full]
|
||||
board = esp01_1m
|
||||
@ -414,10 +391,8 @@ platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_1m128k}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP01\" -D WLED_DISABLE_OTA
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=ESP01 -D WLED_DISABLE_OTA
|
||||
; -D WLED_USE_REAL_MATH ;; may fix wrong sunset/sunrise times, at the cost of 7064 bytes FLASH and 975 bytes RAM
|
||||
-D WLED_DISABLE_PARTICLESYSTEM1D
|
||||
-D WLED_DISABLE_PARTICLESYSTEM2D
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
|
||||
[env:esp01_1m_full_compat]
|
||||
@ -425,48 +400,36 @@ extends = env:esp01_1m_full
|
||||
;; using platform version and build options from WLED 0.14.0
|
||||
platform = ${esp8266.platform_compat}
|
||||
platform_packages = ${esp8266.platform_packages_compat}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=\"ESP01_compat\" -D WLED_DISABLE_OTA #-DWLED_DISABLE_2D
|
||||
-D WLED_DISABLE_PARTICLESYSTEM1D
|
||||
-D WLED_DISABLE_PARTICLESYSTEM2D
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=ESP01_compat -D WLED_DISABLE_OTA #-DWLED_DISABLE_2D
|
||||
|
||||
[env:esp01_1m_full_160]
|
||||
extends = env:esp01_1m_full
|
||||
board_build.f_cpu = 160000000L
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP01_160\" -D WLED_DISABLE_OTA
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=ESP01_160 -D WLED_DISABLE_OTA
|
||||
-D USERMOD_AUDIOREACTIVE
|
||||
; -D WLED_USE_REAL_MATH ;; may fix wrong sunset/sunrise times, at the cost of 7064 bytes FLASH and 975 bytes RAM
|
||||
-D WLED_DISABLE_PARTICLESYSTEM1D
|
||||
-D WLED_DISABLE_PARTICLESYSTEM2D
|
||||
custom_usermods = audioreactive
|
||||
|
||||
[env:esp32dev]
|
||||
board = esp32dev
|
||||
platform = ${esp32.platform}
|
||||
platform_packages = ${esp32.platform_packages}
|
||||
custom_usermods = audioreactive
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"ESP32\" #-D WLED_DISABLE_BROWNOUT_DET
|
||||
build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=ESP32 #-D WLED_DISABLE_BROWNOUT_DET
|
||||
${esp32.AR_build_flags}
|
||||
lib_deps = ${esp32.lib_deps}
|
||||
${esp32.AR_lib_deps}
|
||||
monitor_filters = esp32_exception_decoder
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
|
||||
[env:esp32dev_V4]
|
||||
board = esp32dev
|
||||
platform = ${esp32_idf_V4.platform}
|
||||
build_unflags = ${common.build_unflags}
|
||||
custom_usermods = audioreactive
|
||||
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_V4\" #-D WLED_DISABLE_BROWNOUT_DET
|
||||
lib_deps = ${esp32_idf_V4.lib_deps}
|
||||
monitor_filters = esp32_exception_decoder
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
board_build.flash_mode = dio
|
||||
|
||||
[env:esp32dev_8M]
|
||||
board = esp32dev
|
||||
platform = ${esp32_idf_V4.platform}
|
||||
custom_usermods = audioreactive
|
||||
platform_packages = ${esp32_idf_V4.platform_packages}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_8M\" #-D WLED_DISABLE_BROWNOUT_DET
|
||||
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=ESP32_8M #-D WLED_DISABLE_BROWNOUT_DET
|
||||
${esp32.AR_build_flags}
|
||||
lib_deps = ${esp32_idf_V4.lib_deps}
|
||||
${esp32.AR_lib_deps}
|
||||
monitor_filters = esp32_exception_decoder
|
||||
board_build.partitions = ${esp32.large_partitions}
|
||||
board_upload.flash_size = 8MB
|
||||
@ -477,10 +440,12 @@ board_upload.maximum_size = 8388608
|
||||
[env:esp32dev_16M]
|
||||
board = esp32dev
|
||||
platform = ${esp32_idf_V4.platform}
|
||||
custom_usermods = audioreactive
|
||||
platform_packages = ${esp32_idf_V4.platform_packages}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_16M\" #-D WLED_DISABLE_BROWNOUT_DET
|
||||
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=ESP32_16M #-D WLED_DISABLE_BROWNOUT_DET
|
||||
${esp32.AR_build_flags}
|
||||
lib_deps = ${esp32_idf_V4.lib_deps}
|
||||
${esp32.AR_lib_deps}
|
||||
monitor_filters = esp32_exception_decoder
|
||||
board_build.partitions = ${esp32.extreme_partitions}
|
||||
board_upload.flash_size = 16MB
|
||||
@ -492,10 +457,11 @@ board_build.flash_mode = dio
|
||||
;board = esp32dev
|
||||
;platform = ${esp32.platform}
|
||||
;platform_packages = ${esp32.platform_packages}
|
||||
;custom_usermods = audioreactive
|
||||
;build_unflags = ${common.build_unflags}
|
||||
;build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"ESP32_audioreactive\" #-D WLED_DISABLE_BROWNOUT_DET
|
||||
;build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=ESP32_audioreactive #-D WLED_DISABLE_BROWNOUT_DET
|
||||
; ${esp32.AR_build_flags}
|
||||
;lib_deps = ${esp32.lib_deps}
|
||||
; ${esp32.AR_lib_deps}
|
||||
;monitor_filters = esp32_exception_decoder
|
||||
;board_build.partitions = ${esp32.default_partitions}
|
||||
;; board_build.f_flash = 80000000L
|
||||
@ -506,34 +472,38 @@ board = esp32-poe
|
||||
platform = ${esp32.platform}
|
||||
platform_packages = ${esp32.platform_packages}
|
||||
upload_speed = 921600
|
||||
custom_usermods = audioreactive
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"ESP32_Ethernet\" -D RLYPIN=-1 -D WLED_USE_ETHERNET -D BTNPIN=-1
|
||||
build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=ESP32_Ethernet -D RLYPIN=-1 -D WLED_USE_ETHERNET -D BTNPIN=-1
|
||||
; -D WLED_DISABLE_ESPNOW ;; ESP-NOW requires wifi, may crash with ethernet only
|
||||
${esp32.AR_build_flags}
|
||||
lib_deps = ${esp32.lib_deps}
|
||||
${esp32.AR_lib_deps}
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
|
||||
[env:esp32_wrover]
|
||||
extends = esp32_idf_V4
|
||||
platform = ${esp32_idf_V4.platform}
|
||||
platform_packages = ${esp32_idf_V4.platform_packages}
|
||||
board = ttgo-t7-v14-mini32
|
||||
board_build.f_flash = 80000000L
|
||||
board_build.flash_mode = qio
|
||||
board_build.partitions = ${esp32.extended_partitions}
|
||||
custom_usermods = audioreactive
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_WROVER\"
|
||||
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=ESP32_WROVER
|
||||
-DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue ;; Older ESP32 (rev.<3) need a PSRAM fix (increases static RAM used) https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/external-ram.html
|
||||
-D DATA_PINS=25
|
||||
${esp32.AR_build_flags}
|
||||
lib_deps = ${esp32_idf_V4.lib_deps}
|
||||
|
||||
${esp32.AR_lib_deps}
|
||||
|
||||
[env:esp32c3dev]
|
||||
extends = esp32c3
|
||||
platform = ${esp32c3.platform}
|
||||
platform_packages = ${esp32c3.platform_packages}
|
||||
framework = arduino
|
||||
board = esp32-c3-devkitm-1
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
build_flags = ${common.build_flags} ${esp32c3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-C3\"
|
||||
build_flags = ${common.build_flags} ${esp32c3.build_flags} -D WLED_RELEASE_NAME=ESP32-C3
|
||||
-D WLED_WATCHDOG_TIMEOUT=0
|
||||
-DLOLIN_WIFI_FIX ; seems to work much better with this
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1 ;; for virtual CDC USB
|
||||
@ -547,15 +517,17 @@ lib_deps = ${esp32c3.lib_deps}
|
||||
board = esp32-s3-devkitc-1 ;; generic dev board; the next line adds PSRAM support
|
||||
board_build.arduino.memory_type = qio_opi ;; use with PSRAM: 8MB or 16MB
|
||||
platform = ${esp32s3.platform}
|
||||
platform_packages = ${esp32s3.platform_packages}
|
||||
upload_speed = 921600
|
||||
custom_usermods = audioreactive
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_16MB_opi\"
|
||||
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=ESP32-S3_16MB_opi
|
||||
-D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0
|
||||
;-D ARDUINO_USB_CDC_ON_BOOT=0 ;; -D ARDUINO_USB_MODE=1 ;; for boards with serial-to-USB chip
|
||||
-D ARDUINO_USB_CDC_ON_BOOT=1 -D ARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB")
|
||||
-DBOARD_HAS_PSRAM
|
||||
${esp32.AR_build_flags}
|
||||
lib_deps = ${esp32s3.lib_deps}
|
||||
${esp32.AR_lib_deps}
|
||||
board_build.partitions = ${esp32.extreme_partitions}
|
||||
board_upload.flash_size = 16MB
|
||||
board_upload.maximum_size = 16777216
|
||||
@ -568,58 +540,37 @@ monitor_filters = esp32_exception_decoder
|
||||
board = esp32-s3-devkitc-1 ;; generic dev board; the next line adds PSRAM support
|
||||
board_build.arduino.memory_type = qio_opi ;; use with PSRAM: 8MB or 16MB
|
||||
platform = ${esp32s3.platform}
|
||||
platform_packages = ${esp32s3.platform_packages}
|
||||
upload_speed = 921600
|
||||
custom_usermods = audioreactive
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_8MB_opi\"
|
||||
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=ESP32-S3_8MB_opi
|
||||
-D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0
|
||||
;-D ARDUINO_USB_CDC_ON_BOOT=0 ;; -D ARDUINO_USB_MODE=1 ;; for boards with serial-to-USB chip
|
||||
-D ARDUINO_USB_CDC_ON_BOOT=1 -D ARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB")
|
||||
-DBOARD_HAS_PSRAM
|
||||
${esp32.AR_build_flags}
|
||||
lib_deps = ${esp32s3.lib_deps}
|
||||
${esp32.AR_lib_deps}
|
||||
board_build.partitions = ${esp32.large_partitions}
|
||||
board_build.f_flash = 80000000L
|
||||
board_build.flash_mode = qio
|
||||
monitor_filters = esp32_exception_decoder
|
||||
|
||||
[env:esp32S3_wroom2]
|
||||
;; For ESP32-S3 WROOM-2, a.k.a. ESP32-S3 DevKitC-1 v1.1
|
||||
;; with >= 16MB FLASH and >= 8MB PSRAM (memory_type: opi_opi)
|
||||
platform = ${esp32s3.platform}
|
||||
board = esp32s3camlcd ;; this is the only standard board with "opi_opi"
|
||||
board_build.arduino.memory_type = opi_opi
|
||||
upload_speed = 921600
|
||||
custom_usermods = audioreactive
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_WROOM-2\"
|
||||
-D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0
|
||||
-D ARDUINO_USB_CDC_ON_BOOT=0 ;; -D ARDUINO_USB_MODE=1 ;; for boards with serial-to-USB chip
|
||||
;; -D ARDUINO_USB_CDC_ON_BOOT=1 -D ARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB")
|
||||
-DBOARD_HAS_PSRAM
|
||||
-D LEDPIN=38 -D DATA_PINS=38 ;; buildin WS2812b LED
|
||||
-D BTNPIN=0 -D RLYPIN=16 -D IRPIN=17 -D AUDIOPIN=-1
|
||||
-D WLED_DEBUG
|
||||
-D SR_DMTYPE=1 -D I2S_SDPIN=13 -D I2S_CKPIN=14 -D I2S_WSPIN=15 -D MCLK_PIN=4 ;; I2S mic
|
||||
lib_deps = ${esp32s3.lib_deps}
|
||||
|
||||
board_build.partitions = ${esp32.extreme_partitions}
|
||||
board_upload.flash_size = 16MB
|
||||
board_upload.maximum_size = 16777216
|
||||
monitor_filters = esp32_exception_decoder
|
||||
|
||||
[env:esp32s3_4M_qspi]
|
||||
;; ESP32-S3, with 4MB FLASH and <= 4MB PSRAM (memory_type: qio_qspi)
|
||||
board = lolin_s3_mini ;; -S3 mini, 4MB flash 2MB PSRAM
|
||||
platform = ${esp32s3.platform}
|
||||
platform_packages = ${esp32s3.platform_packages}
|
||||
upload_speed = 921600
|
||||
custom_usermods = audioreactive
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_4M_qspi\"
|
||||
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=ESP32-S3_4M_qspi
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1 -DARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB")
|
||||
-DBOARD_HAS_PSRAM
|
||||
-DLOLIN_WIFI_FIX ; seems to work much better with this
|
||||
-D WLED_WATCHDOG_TIMEOUT=0
|
||||
${esp32.AR_build_flags}
|
||||
lib_deps = ${esp32s3.lib_deps}
|
||||
${esp32.AR_lib_deps}
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
board_build.f_flash = 80000000L
|
||||
board_build.flash_mode = qio
|
||||
@ -627,19 +578,20 @@ monitor_filters = esp32_exception_decoder
|
||||
|
||||
[env:lolin_s2_mini]
|
||||
platform = ${esp32s2.platform}
|
||||
platform_packages = ${esp32s2.platform_packages}
|
||||
board = lolin_s2_mini
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
board_build.flash_mode = qio
|
||||
board_build.f_flash = 80000000L
|
||||
custom_usermods = audioreactive
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32s2.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S2\"
|
||||
build_flags = ${common.build_flags} ${esp32s2.build_flags} -D WLED_RELEASE_NAME=ESP32-S2
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1
|
||||
-DARDUINO_USB_MSC_ON_BOOT=0
|
||||
-DARDUINO_USB_DFU_ON_BOOT=0
|
||||
-DBOARD_HAS_PSRAM
|
||||
-DLOLIN_WIFI_FIX ; seems to work much better with this
|
||||
-D WLED_WATCHDOG_TIMEOUT=0
|
||||
-D CONFIG_ASYNC_TCP_USE_WDT=0
|
||||
-D DATA_PINS=16
|
||||
-D HW_PIN_SCL=35
|
||||
-D HW_PIN_SDA=33
|
||||
@ -647,17 +599,6 @@ build_flags = ${common.build_flags} ${esp32s2.build_flags} -D WLED_RELEASE_NAME=
|
||||
-D HW_PIN_DATASPI=11
|
||||
-D HW_PIN_MISOSPI=9
|
||||
; -D STATUSLED=15
|
||||
${esp32.AR_build_flags}
|
||||
lib_deps = ${esp32s2.lib_deps}
|
||||
|
||||
|
||||
[env:usermods]
|
||||
board = esp32dev
|
||||
platform = ${esp32_idf_V4.platform}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_USERMODS\"
|
||||
-DTOUCH_CS=9
|
||||
lib_deps = ${esp32_idf_V4.lib_deps}
|
||||
monitor_filters = esp32_exception_decoder
|
||||
board_build.flash_mode = dio
|
||||
; custom_usermods = *every folder with library.json* -- injected by pio-scripts/load_usermods.py
|
||||
board_build.partitions = ${esp32.extreme_partitions} ; We're gonna need a bigger boat
|
||||
${esp32.AR_lib_deps}
|
||||
|
@ -5,7 +5,7 @@
|
||||
# Please visit documentation: https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[platformio]
|
||||
default_envs = WLED_generic8266_1M, esp32dev_V4_dio80 # put the name(s) of your own build environment here. You can define as many as you need
|
||||
default_envs = WLED_tasmota_1M # define as many as you need
|
||||
|
||||
#----------
|
||||
# SAMPLE
|
||||
@ -28,16 +28,16 @@ lib_deps = ${esp8266.lib_deps}
|
||||
; robtillaart/SHT85@~0.3.3
|
||||
; ;gmag11/QuickESPNow @ ~0.7.0 # will also load QuickDebug
|
||||
; https://github.com/blazoncek/QuickESPNow.git#optional-debug ;; exludes debug library
|
||||
; ${esp32.AR_lib_deps} ;; used for USERMOD_AUDIOREACTIVE
|
||||
; bitbank2/PNGdec@^1.0.1 ;; used for POV display uncomment following
|
||||
; ${esp32.AR_lib_deps} ;; needed for USERMOD_AUDIOREACTIVE
|
||||
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags}
|
||||
;
|
||||
; *** To use the below defines/overrides, copy and paste each onto its own line just below build_flags in the section above.
|
||||
; *** To use the below defines/overrides, copy and paste each onto it's own line just below build_flags in the section above.
|
||||
;
|
||||
; Set a release name that may be used to distinguish required binary for flashing
|
||||
; -D WLED_RELEASE_NAME=\"ESP32_MULTI_USREMODS\"
|
||||
; -D WLED_RELEASE_NAME=ESP32_MULTI_USREMODS
|
||||
;
|
||||
; disable specific features
|
||||
; -D WLED_DISABLE_OTA
|
||||
@ -111,6 +111,7 @@ build_flags = ${common.build_flags} ${esp8266.build_flags}
|
||||
;
|
||||
; Use 4 Line Display usermod with SPI display
|
||||
; -D USERMOD_FOUR_LINE_DISPLAY
|
||||
; -D USE_ALT_DISPlAY # mandatory
|
||||
; -DFLD_SPI_DEFAULT
|
||||
; -D FLD_TYPE=SSD1306_SPI64
|
||||
; -D FLD_PIN_CLOCKSPI=14
|
||||
@ -141,8 +142,7 @@ build_flags = ${common.build_flags} ${esp8266.build_flags}
|
||||
; -D PIR_SENSOR_MAX_SENSORS=2 # max allowable sensors (uses OR logic for triggering)
|
||||
;
|
||||
; Use Audioreactive usermod and configure I2S microphone
|
||||
; ${esp32.AR_build_flags} ;; default flags required to properly configure ArduinoFFT
|
||||
; ;; don't forget to add ArduinoFFT to your libs_deps: ${esp32.AR_lib_deps}
|
||||
; -D USERMOD_AUDIOREACTIVE
|
||||
; -D AUDIOPIN=-1
|
||||
; -D DMTYPE=1 # 0-analog/disabled, 1-I2S generic, 2-ES7243, 3-SPH0645, 4-I2S+mclk, 5-I2S PDM
|
||||
; -D I2S_SDPIN=36
|
||||
@ -158,22 +158,17 @@ build_flags = ${common.build_flags} ${esp8266.build_flags}
|
||||
; -D USERMOD_POV_DISPLAY
|
||||
; Use built-in or custom LED as a status indicator (assumes LED is connected to GPIO16)
|
||||
; -D STATUSLED=16
|
||||
;
|
||||
;
|
||||
; set the name of the module - make sure there is a quote-backslash-quote before the name and a backslash-quote-quote after the name
|
||||
; -D SERVERNAME="\"WLED\""
|
||||
;
|
||||
;
|
||||
; set the number of LEDs
|
||||
; -D PIXEL_COUNTS=30
|
||||
; -D DEFAULT_LED_COUNT=30
|
||||
; or this for multiple outputs
|
||||
; -D PIXEL_COUNTS=30,30
|
||||
;
|
||||
; set the default LED type
|
||||
; -D LED_TYPES=22 # see const.h (TYPE_xxxx)
|
||||
; or this for multiple outputs
|
||||
; -D LED_TYPES=TYPE_SK6812_RGBW,TYPE_WS2812_RGB
|
||||
;
|
||||
; set default color order of your led strip
|
||||
; -D DEFAULT_LED_COLOR_ORDER=COL_ORDER_GRB
|
||||
; -D DEFAULT_LED_TYPE=22 # see const.h (TYPE_xxxx)
|
||||
;
|
||||
; set milliampere limit when using ESP power pin (or inadequate PSU) to power LEDs
|
||||
; -D ABL_MILLIAMPS_DEFAULT=850
|
||||
@ -182,6 +177,9 @@ build_flags = ${common.build_flags} ${esp8266.build_flags}
|
||||
; enable IR by setting remote type
|
||||
; -D IRTYPE=0 # 0 Remote disabled | 1 24-key RGB | 2 24-key with CT | 3 40-key blue | 4 40-key RGB | 5 21-key RGB | 6 6-key black | 7 9-key red | 8 JSON remote
|
||||
;
|
||||
; set default color order of your led strip
|
||||
; -D DEFAULT_LED_COLOR_ORDER=COL_ORDER_GRB
|
||||
;
|
||||
; use PSRAM on classic ESP32 rev.1 (rev.3 or above has no issues)
|
||||
; -DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue # needed only for classic ESP32 rev.1
|
||||
;
|
||||
@ -239,13 +237,14 @@ build_flags = ${common.build_flags} ${esp8266.build_flags} -D DATA_PINS=1 -D WLE
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
|
||||
[env:esp32dev_qio80]
|
||||
extends = env:esp32dev # we want to extend the existing esp32dev environment (and define only updated options)
|
||||
board = esp32dev
|
||||
platform = ${esp32.platform}
|
||||
platform_packages = ${esp32.platform_packages}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32.build_flags} #-D WLED_DISABLE_BROWNOUT_DET
|
||||
${esp32.AR_build_flags} ;; optional - includes USERMOD_AUDIOREACTIVE
|
||||
lib_deps = ${esp32.lib_deps}
|
||||
${esp32.AR_lib_deps} ;; needed for USERMOD_AUDIOREACTIVE
|
||||
monitor_filters = esp32_exception_decoder
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
board_build.f_flash = 80000000L
|
||||
board_build.flash_mode = qio
|
||||
|
||||
@ -253,25 +252,26 @@ board_build.flash_mode = qio
|
||||
;; experimental ESP32 env using ESP-IDF V4.4.x
|
||||
;; Warning: this build environment is not stable!!
|
||||
;; please erase your device before installing.
|
||||
extends = esp32_idf_V4 # based on newer "esp-idf V4" platform environment
|
||||
board = esp32dev
|
||||
platform = ${esp32_idf_V4.platform}
|
||||
platform_packages = ${esp32_idf_V4.platform_packages}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} #-D WLED_DISABLE_BROWNOUT_DET
|
||||
${esp32.AR_build_flags} ;; includes USERMOD_AUDIOREACTIVE
|
||||
lib_deps = ${esp32_idf_V4.lib_deps}
|
||||
${esp32.AR_lib_deps} ;; needed for USERMOD_AUDIOREACTIVE
|
||||
monitor_filters = esp32_exception_decoder
|
||||
board_build.partitions = ${esp32.default_partitions} ;; if you get errors about "out of program space", change this to ${esp32.extended_partitions} or even ${esp32.big_partitions}
|
||||
board_build.partitions = ${esp32_idf_V4.default_partitions}
|
||||
board_build.f_flash = 80000000L
|
||||
board_build.flash_mode = dio
|
||||
|
||||
[env:esp32s2_saola]
|
||||
extends = esp32s2
|
||||
board = esp32-s2-saola-1
|
||||
platform = ${esp32s2.platform}
|
||||
platform_packages = ${esp32s2.platform_packages}
|
||||
framework = arduino
|
||||
board_build.partitions = tools/WLED_ESP32_4MB_1MB_FS.csv
|
||||
board_build.flash_mode = qio
|
||||
upload_speed = 460800
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32s2.build_flags}
|
||||
;-DLOLIN_WIFI_FIX ;; try this in case Wifi does not work
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1
|
||||
@ -280,7 +280,7 @@ lib_deps = ${esp32s2.lib_deps}
|
||||
[env:esp32s3dev_8MB_PSRAM_qspi]
|
||||
;; ESP32-TinyS3 development board, with 8MB FLASH and PSRAM (memory_type: qio_qspi)
|
||||
extends = env:esp32s3dev_8MB_PSRAM_opi
|
||||
;board = um_tinys3 ; -> needs workaround from https://github.com/wled-dev/WLED/pull/2905#issuecomment-1328049860
|
||||
;board = um_tinys3 ; -> needs workaround from https://github.com/Aircoookie/WLED/pull/2905#issuecomment-1328049860
|
||||
board = esp32-s3-devkitc-1 ;; generic dev board; the next line adds PSRAM support
|
||||
board_build.arduino.memory_type = qio_qspi ;; use with PSRAM: 2MB or 4MB
|
||||
|
||||
@ -308,7 +308,7 @@ platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_USE_SHOJO_PCB ;; NB: WLED_USE_SHOJO_PCB is not used anywhere in the source code. Not sure why its needed.
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_USE_SHOJO_PCB
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
|
||||
[env:d1_mini_debug]
|
||||
@ -363,48 +363,36 @@ board_upload.flash_size = 2MB
|
||||
board_upload.maximum_size = 2097152
|
||||
|
||||
[env:wemos_shield_esp32]
|
||||
extends = esp32 ;; use default esp32 platform
|
||||
board = esp32dev
|
||||
platform = ${esp32.platform}
|
||||
platform_packages = ${esp32.platform_packages}
|
||||
upload_speed = 460800
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32.build_flags}
|
||||
-D WLED_RELEASE_NAME=\"ESP32_wemos_shield\"
|
||||
-D DATA_PINS=16
|
||||
-D RLYPIN=19
|
||||
-D BTNPIN=17
|
||||
-D IRPIN=18
|
||||
-UWLED_USE_MY_CONFIG
|
||||
-D UWLED_USE_MY_CONFIG
|
||||
-D USERMOD_DALLASTEMPERATURE
|
||||
-D USERMOD_FOUR_LINE_DISPLAY
|
||||
-D TEMPERATURE_PIN=23
|
||||
${esp32.AR_build_flags} ;; includes USERMOD_AUDIOREACTIVE
|
||||
-D USE_ALT_DISPlAY ; new versions of USERMOD_FOUR_LINE_DISPLAY and USERMOD_ROTARY_ENCODER_UI
|
||||
-D USERMOD_AUDIOREACTIVE
|
||||
lib_deps = ${esp32.lib_deps}
|
||||
OneWire@~2.3.5 ;; needed for USERMOD_DALLASTEMPERATURE
|
||||
olikraus/U8g2 @ ^2.28.8 ;; needed for USERMOD_FOUR_LINE_DISPLAY
|
||||
${esp32.AR_lib_deps} ;; needed for USERMOD_AUDIOREACTIVE
|
||||
OneWire@~2.3.5
|
||||
olikraus/U8g2 @ ^2.28.8
|
||||
https://github.com/blazoncek/arduinoFFT.git
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
|
||||
[env:esp32_pico-D4]
|
||||
extends = esp32 ;; use default esp32 platform
|
||||
board = pico32 ;; pico32-D4 is different from the standard esp32dev
|
||||
;; hardware details from https://github.com/srg74/WLED-ESP32-pico
|
||||
build_flags = ${common.build_flags} ${esp32.build_flags}
|
||||
-D WLED_RELEASE_NAME=\"pico32-D4\" -D SERVERNAME='"WLED-pico32"'
|
||||
-D WLED_DISABLE_ADALIGHT ;; no serial-to-USB chip on this board - better to disable serial protocols
|
||||
-D DATA_PINS=2,18 ;; LED pins
|
||||
-D RLYPIN=19 -D BTNPIN=0 -D IRPIN=-1 ;; no default pin for IR
|
||||
${esp32.AR_build_flags} ;; include USERMOD_AUDIOREACTIVE
|
||||
-D UM_AUDIOREACTIVE_ENABLE ;; enable AR by default
|
||||
;; Audioreactive settings for on-board microphone (ICS-43432)
|
||||
-D SR_DMTYPE=1 -D I2S_SDPIN=25 -D I2S_WSPIN=15 -D I2S_CKPIN=14
|
||||
-D SR_SQUELCH=5 -D SR_GAIN=30
|
||||
lib_deps = ${esp32.lib_deps}
|
||||
${esp32.AR_lib_deps} ;; needed for USERMOD_AUDIOREACTIVE
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
board_build.f_flash = 80000000L
|
||||
|
||||
[env:m5atom]
|
||||
extends = env:esp32dev # we want to extend the existing esp32dev environment (and define only updated options)
|
||||
board = esp32dev
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32.build_flags} -D DATA_PINS=27 -D BTNPIN=39
|
||||
lib_deps = ${esp32.lib_deps}
|
||||
platform = ${esp32.platform}
|
||||
platform_packages = ${esp32.platform_packages}
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
|
||||
[env:sp501e]
|
||||
board = esp_wroom_02
|
||||
@ -427,7 +415,7 @@ platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_2m512k}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D BTNPIN=-1 -D RLYPIN=-1 -D DATA_PINS=4,12,14,13,5
|
||||
-D LED_TYPES=TYPE_ANALOG_5CH -D WLED_DISABLE_INFRARED -D WLED_MAX_CCT_BLEND=0
|
||||
-D DEFAULT_LED_TYPE=TYPE_ANALOG_5CH -D WLED_DISABLE_INFRARED -D WLED_MAX_CCT_BLEND=0
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
|
||||
[env:Athom_15w_RGBCW] ;15w bulb
|
||||
@ -437,7 +425,7 @@ platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_2m512k}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D BTNPIN=-1 -D RLYPIN=-1 -D DATA_PINS=4,12,14,5,13
|
||||
-D LED_TYPES=TYPE_ANALOG_5CH -D WLED_DISABLE_INFRARED -D WLED_MAX_CCT_BLEND=0 -D WLED_USE_IC_CCT
|
||||
-D DEFAULT_LED_TYPE=TYPE_ANALOG_5CH -D WLED_DISABLE_INFRARED -D WLED_MAX_CCT_BLEND=0 -D WLED_USE_IC_CCT
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
|
||||
[env:Athom_3Pin_Controller] ;small controller with only data
|
||||
@ -503,15 +491,17 @@ lib_deps = ${esp8266.lib_deps}
|
||||
# EleksTube-IPS
|
||||
# ------------------------------------------------------------------------------
|
||||
[env:elekstube_ips]
|
||||
extends = esp32 ;; use default esp32 platform
|
||||
board = esp32dev
|
||||
platform = ${esp32.platform}
|
||||
platform_packages = ${esp32.platform_packages}
|
||||
upload_speed = 921600
|
||||
custom_usermods = ${env:esp32dev.custom_usermods} RTC EleksTube_IPS
|
||||
build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_DISABLE_BROWNOUT_DET -D WLED_DISABLE_INFRARED
|
||||
-D USERMOD_RTC
|
||||
-D USERMOD_ELEKSTUBE_IPS
|
||||
-D DATA_PINS=12
|
||||
-D RLYPIN=27
|
||||
-D BTNPIN=34
|
||||
-D PIXEL_COUNTS=6
|
||||
-D DEFAULT_LED_COUNT=6
|
||||
# Display config
|
||||
-D ST7789_DRIVER
|
||||
-D TFT_WIDTH=135
|
||||
@ -525,14 +515,7 @@ build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_DISABLE_BROWNOU
|
||||
-D SPI_FREQUENCY=40000000
|
||||
-D USER_SETUP_LOADED
|
||||
monitor_filters = esp32_exception_decoder
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Usermod examples
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# 433MHz RF remote example for esp32dev
|
||||
[env:esp32dev_usermod_RF433]
|
||||
extends = env:esp32dev
|
||||
build_flags = ${env:esp32dev.build_flags} -D USERMOD_RF433
|
||||
lib_deps = ${env:esp32dev.lib_deps}
|
||||
sui77/rc-switch @ 2.6.4
|
||||
lib_deps =
|
||||
${esp32.lib_deps}
|
||||
TFT_eSPI @ ^2.3.70
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
|
10
readme.md
10
readme.md
@ -1,18 +1,18 @@
|
||||
<p align="center">
|
||||
<img src="/images/wled_logo_akemi.png">
|
||||
<a href="https://github.com/wled-dev/WLED/releases"><img src="https://img.shields.io/github/release/wled-dev/WLED.svg?style=flat-square"></a>
|
||||
<a href="https://raw.githubusercontent.com/wled-dev/WLED/main/LICENSE"><img src="https://img.shields.io/github/license/wled-dev/wled?color=blue&style=flat-square"></a>
|
||||
<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/QAh7wJHrRM"><img src="https://img.shields.io/discord/473448917040758787.svg?colorB=blue&label=discord&style=flat-square"></a>
|
||||
<a href="https://kno.wled.ge"><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/wled-dev/WLED"><img src="https://img.shields.io/badge/Gitpod-ready--to--code-blue?style=flat-square&logo=gitpod"></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 ESP32 and ESP8266 webserver to control NeoPixel (WS2812B, WS2811, SK6812) LEDs or also SPI based chipsets like the WS2801 and APA102!
|
||||
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 with more than 100 special effects
|
||||
@ -21,7 +21,7 @@ A fast and feature-rich implementation of an ESP32 and ESP8266 webserver to cont
|
||||
- Segments to set different effects and colors to user defined parts of the LED string
|
||||
- Settings page - configuration via the network
|
||||
- Access Point and station mode - automatic failsafe AP
|
||||
- [Up to 10 LED outputs](https://kno.wled.ge/features/multi-strip/#esp32) per instance
|
||||
- Up to 10 LED outputs per instance
|
||||
- Support for RGBW strips
|
||||
- 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
|
||||
|
@ -1 +1 @@
|
||||
platformio>=6.1.17
|
||||
platformio
|
||||
|
@ -1,25 +1,27 @@
|
||||
#
|
||||
# This file is autogenerated by pip-compile with Python 3.11
|
||||
# This file is autogenerated by pip-compile with Python 3.12
|
||||
# by the following command:
|
||||
#
|
||||
# pip-compile requirements.in
|
||||
# pip-compile
|
||||
#
|
||||
ajsonrpc==1.2.0
|
||||
# via platformio
|
||||
anyio==4.8.0
|
||||
anyio==4.6.0
|
||||
# via starlette
|
||||
bottle==0.13.2
|
||||
bottle==0.13.1
|
||||
# via platformio
|
||||
certifi==2025.1.31
|
||||
certifi==2024.8.30
|
||||
# via requests
|
||||
charset-normalizer==3.4.1
|
||||
charset-normalizer==3.3.2
|
||||
# via requests
|
||||
click==8.1.8
|
||||
click==8.1.7
|
||||
# via
|
||||
# platformio
|
||||
# uvicorn
|
||||
colorama==0.4.6
|
||||
# via platformio
|
||||
# via
|
||||
# click
|
||||
# platformio
|
||||
h11==0.14.0
|
||||
# via
|
||||
# uvicorn
|
||||
@ -28,13 +30,13 @@ idna==3.10
|
||||
# via
|
||||
# anyio
|
||||
# requests
|
||||
marshmallow==3.26.1
|
||||
marshmallow==3.22.0
|
||||
# via platformio
|
||||
packaging==24.2
|
||||
packaging==24.1
|
||||
# via marshmallow
|
||||
platformio==6.1.17
|
||||
platformio==6.1.16
|
||||
# via -r requirements.in
|
||||
pyelftools==0.32
|
||||
pyelftools==0.31
|
||||
# via platformio
|
||||
pyserial==3.5
|
||||
# via platformio
|
||||
@ -44,15 +46,13 @@ semantic-version==2.10.0
|
||||
# via platformio
|
||||
sniffio==1.3.1
|
||||
# via anyio
|
||||
starlette==0.45.3
|
||||
starlette==0.39.1
|
||||
# via platformio
|
||||
tabulate==0.9.0
|
||||
# via platformio
|
||||
typing-extensions==4.12.2
|
||||
# via anyio
|
||||
urllib3==2.3.0
|
||||
urllib3==2.2.3
|
||||
# via requests
|
||||
uvicorn==0.34.0
|
||||
uvicorn==0.30.6
|
||||
# via platformio
|
||||
wsproto==1.2.0
|
||||
# via platformio
|
||||
|
Binary file not shown.
@ -17,7 +17,7 @@
|
||||
|
||||
const fs = require("node:fs");
|
||||
const path = require("path");
|
||||
const inline = require("web-resource-inliner");
|
||||
const inliner = require("inliner");
|
||||
const zlib = require("node:zlib");
|
||||
const CleanCSS = require("clean-css");
|
||||
const minifyHtml = require("html-minifier-terser").minify;
|
||||
@ -89,7 +89,7 @@ function adoptVersionAndRepo(html) {
|
||||
repoUrl = repoUrl.replace(/^git\+/, "");
|
||||
repoUrl = repoUrl.replace(/\.git$/, "");
|
||||
html = html.replaceAll("https://github.com/atuline/WLED", repoUrl);
|
||||
html = html.replaceAll("https://github.com/wled-dev/WLED", repoUrl);
|
||||
html = html.replaceAll("https://github.com/Aircoookie/WLED", repoUrl);
|
||||
}
|
||||
let version = packageJson.version;
|
||||
if (version) {
|
||||
@ -101,7 +101,6 @@ function adoptVersionAndRepo(html) {
|
||||
async function minify(str, type = "plain") {
|
||||
const options = {
|
||||
collapseWhitespace: true,
|
||||
conservativeCollapse: true, // preserve spaces in text
|
||||
collapseBooleanAttributes: true,
|
||||
collapseInlineTagWhitespace: true,
|
||||
minifyCSS: true,
|
||||
@ -128,26 +127,21 @@ async function minify(str, type = "plain") {
|
||||
|
||||
async function writeHtmlGzipped(sourceFile, resultFile, page) {
|
||||
console.info("Reading " + sourceFile);
|
||||
inline.html({
|
||||
fileContent: fs.readFileSync(sourceFile, "utf8"),
|
||||
relativeTo: path.dirname(sourceFile),
|
||||
strict: true,
|
||||
},
|
||||
async function (error, html) {
|
||||
if (error) throw error;
|
||||
new inliner(sourceFile, async function (error, html) {
|
||||
if (error) throw error;
|
||||
|
||||
html = adoptVersionAndRepo(html);
|
||||
const originalLength = html.length;
|
||||
html = await minify(html, "html-minify");
|
||||
const result = zlib.gzipSync(html, { level: zlib.constants.Z_BEST_COMPRESSION });
|
||||
console.info("Minified and compressed " + sourceFile + " from " + originalLength + " to " + result.length + " bytes");
|
||||
const array = hexdump(result);
|
||||
let src = singleHeader;
|
||||
src += `const uint16_t PAGE_${page}_L = ${result.length};\n`;
|
||||
src += `const uint8_t PAGE_${page}[] PROGMEM = {\n${array}\n};\n\n`;
|
||||
console.info("Writing " + resultFile);
|
||||
fs.writeFileSync(resultFile, src);
|
||||
});
|
||||
html = adoptVersionAndRepo(html);
|
||||
const originalLength = html.length;
|
||||
html = await minify(html, "html-minify");
|
||||
const result = zlib.gzipSync(html, { level: zlib.constants.Z_BEST_COMPRESSION });
|
||||
console.info("Minified and compressed " + sourceFile + " from " + originalLength + " to " + result.length + " bytes");
|
||||
const array = hexdump(result);
|
||||
let src = singleHeader;
|
||||
src += `const uint16_t PAGE_${page}_L = ${result.length};\n`;
|
||||
src += `const uint8_t PAGE_${page}[] PROGMEM = {\n${array}\n};\n\n`;
|
||||
console.info("Writing " + resultFile);
|
||||
fs.writeFileSync(resultFile, src);
|
||||
});
|
||||
}
|
||||
|
||||
async function specToChunk(srcDir, s) {
|
||||
|
@ -27,7 +27,6 @@ read -a JSON_TINY_TARGETS <<< $(replicate "json/nodes")
|
||||
read -a JSON_SMALL_TARGETS <<< $(replicate "json/info")
|
||||
read -a JSON_LARGE_TARGETS <<< $(replicate "json/si")
|
||||
read -a JSON_LARGER_TARGETS <<< $(replicate "json/fxdata")
|
||||
read -a INDEX_TARGETS <<< $(replicate "")
|
||||
|
||||
# Expand target URLS to full arguments for curl
|
||||
TARGETS=(${TARGET_STR[@]})
|
||||
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"name:": "ADS1115_v2",
|
||||
"dependencies": {
|
||||
"Adafruit BusIO": "https://github.com/adafruit/Adafruit_BusIO#1.13.2",
|
||||
"Adafruit ADS1X15": "https://github.com/adafruit/Adafruit_ADS1X15#2.4.0"
|
||||
}
|
||||
}
|
@ -6,5 +6,5 @@ Configuration is performed via the Usermod menu. There are no parameters to set
|
||||
|
||||
## Installation
|
||||
|
||||
Add 'ADS1115' to `custom_usermods` in your platformio environment.
|
||||
|
||||
Add the build flag `-D USERMOD_ADS1115` to your platformio environment.
|
||||
Uncomment libraries with comment `#For ADS1115 sensor uncomment following`
|
||||
|
@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
#include <Adafruit_ADS1X15.h>
|
||||
#include <math.h>
|
||||
@ -250,7 +252,4 @@ class ADS1115Usermod : public Usermod {
|
||||
int16_t results = ads.getLastConversionResults();
|
||||
readings[activeChannel] = ads.computeVolts(results);
|
||||
}
|
||||
};
|
||||
|
||||
static ADS1115Usermod ads1115_v2;
|
||||
REGISTER_USERMOD(ads1115_v2);
|
||||
};
|
@ -22,9 +22,15 @@ Dependencies, These must be added under `lib_deps` in your `platform.ini` (or `p
|
||||
|
||||
# Compiling
|
||||
|
||||
To enable, add 'AHT10' to `custom_usermods` in your platformio encrionment (e.g. in `platformio_override.ini`)
|
||||
To enable, compile with `USERMOD_AHT10` defined (e.g. in `platformio_override.ini`)
|
||||
```ini
|
||||
[env:aht10_example]
|
||||
extends = env:esp32dev
|
||||
custom_usermods = ${env:esp32dev.custom_usermods} AHT10
|
||||
build_flags =
|
||||
${common.build_flags} ${esp32.build_flags}
|
||||
-D USERMOD_AHT10
|
||||
; -D USERMOD_AHT10_DEBUG ; -- add a debug status to the info modal
|
||||
lib_deps =
|
||||
${esp32.lib_deps}
|
||||
enjoyneering/AHT10@~1.1.0
|
||||
```
|
||||
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"name:": "AHT10_v2",
|
||||
"dependencies": {
|
||||
"enjoyneering/AHT10":"~1.1.0"
|
||||
}
|
||||
}
|
@ -2,4 +2,8 @@
|
||||
extends = env:esp32dev
|
||||
build_flags =
|
||||
${common.build_flags} ${esp32.build_flags}
|
||||
-D USERMOD_AHT10
|
||||
; -D USERMOD_AHT10_DEBUG ; -- add a debug status to the info modal
|
||||
lib_deps =
|
||||
${esp32.lib_deps}
|
||||
enjoyneering/AHT10@~1.1.0
|
@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
#include <AHT10.h>
|
||||
|
||||
@ -52,6 +54,12 @@ private:
|
||||
_lastTemperature = 0;
|
||||
}
|
||||
|
||||
~UsermodAHT10()
|
||||
{
|
||||
delete _aht;
|
||||
_aht = nullptr;
|
||||
}
|
||||
|
||||
#ifndef WLED_DISABLE_MQTT
|
||||
void mqttInitialize()
|
||||
{
|
||||
@ -314,15 +322,6 @@ public:
|
||||
_initDone = true;
|
||||
return configComplete;
|
||||
}
|
||||
|
||||
~UsermodAHT10()
|
||||
{
|
||||
delete _aht;
|
||||
_aht = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
const char UsermodAHT10::_name[] PROGMEM = "AHTxx";
|
||||
|
||||
static UsermodAHT10 aht10_v2;
|
||||
REGISTER_USERMOD(aht10_v2);
|
||||
const char UsermodAHT10::_name[] PROGMEM = "AHTxx";
|
@ -1,3 +1,4 @@
|
||||
#pragma once
|
||||
#include "wled.h"
|
||||
|
||||
/*
|
||||
@ -101,9 +102,9 @@ private:
|
||||
|
||||
void secondsEffectSineFade(int16_t secondLed, Toki::Time const& time) {
|
||||
uint32_t ms = time.ms % 1000;
|
||||
uint8_t b0 = (cos8_t(ms * 64 / 1000) - 128) * 2;
|
||||
uint8_t b0 = (cos8(ms * 64 / 1000) - 128) * 2;
|
||||
setPixelColor(secondLed, gamma32(scale32(secondColor, b0)));
|
||||
uint8_t b1 = (sin8_t(ms * 64 / 1000) - 128) * 2;
|
||||
uint8_t b1 = (sin8(ms * 64 / 1000) - 128) * 2;
|
||||
setPixelColor(inc(secondLed, 1, secondsSegment), gamma32(scale32(secondColor, b1)));
|
||||
}
|
||||
|
||||
@ -253,7 +254,3 @@ public:
|
||||
return USERMOD_ID_ANALOG_CLOCK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static AnalogClockUsermod analog_clock;
|
||||
REGISTER_USERMOD(analog_clock);
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"name:": "Analog_Clock"
|
||||
}
|
@ -7,6 +7,7 @@
|
||||
*
|
||||
* See the accompanying README.md file for more info.
|
||||
*/
|
||||
#pragma once
|
||||
#include "wled.h"
|
||||
|
||||
class Animated_Staircase : public Usermod {
|
||||
@ -561,7 +562,3 @@ const char Animated_Staircase::_bottomEcho_pin[] PROGMEM = "bottomEch
|
||||
const char Animated_Staircase::_topEchoCm[] PROGMEM = "top-dist-cm";
|
||||
const char Animated_Staircase::_bottomEchoCm[] PROGMEM = "bottom-dist-cm";
|
||||
const char Animated_Staircase::_togglePower[] PROGMEM = "toggle-on-off";
|
||||
|
||||
|
||||
static Animated_Staircase animated_staircase;
|
||||
REGISTER_USERMOD(animated_staircase);
|
@ -15,9 +15,10 @@ To include this usermod in your WLED setup, you have to be able to [compile WLED
|
||||
|
||||
Before compiling, you have to make the following modifications:
|
||||
|
||||
Edit your environment in `platformio_override.ini`
|
||||
1. Open `platformio_override.ini`
|
||||
2. add `Animated_Staircase` to the `custom_usermods` line for your environment
|
||||
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 `UsermodManager::add(new Animated_Staircase());` to the end of the `void registerUsermods()` function.
|
||||
|
||||
You can configure usermod using the Usermods settings page.
|
||||
Please enter GPIO pins for PIR or ultrasonic sensors (trigger and echo).
|
||||
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"name:": "Animated_Staircase"
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"name:": "BH1750_v2",
|
||||
"dependencies": {
|
||||
"claws/BH1750":"^1.2.0"
|
||||
}
|
||||
}
|
@ -6,11 +6,22 @@ The luminance is displayed in both the Info section of the web UI, as well as pu
|
||||
## Dependencies
|
||||
- Libraries
|
||||
- `claws/BH1750 @^1.2.0`
|
||||
- This must be added under `lib_deps` in your `platformio.ini` (or `platformio_override.ini`).
|
||||
- Data is published over MQTT - make sure you've enabled the MQTT sync interface.
|
||||
|
||||
## Compilation
|
||||
|
||||
To enable, compile with `BH1750` in `custom_usermods` (e.g. in `platformio_override.ini`)
|
||||
To enable, compile with `USERMOD_BH1750` defined (e.g. in `platformio_override.ini`)
|
||||
```ini
|
||||
[env:usermod_BH1750_d1_mini]
|
||||
extends = env:d1_mini
|
||||
build_flags =
|
||||
${common.build_flags_esp8266}
|
||||
-D USERMOD_BH1750
|
||||
lib_deps =
|
||||
${esp8266.lib_deps}
|
||||
claws/BH1750 @ ^1.2.0
|
||||
```
|
||||
|
||||
### Configuration Options
|
||||
The following settings can be set at compile-time but are configurable on the usermod menu (except First Measurement time):
|
||||
|
@ -1,13 +1,15 @@
|
||||
// force the compiler to show a warning to confirm that this file is included
|
||||
#warning **** Included USERMOD_BH1750 ****
|
||||
|
||||
#include "wled.h"
|
||||
#include <BH1750.h>
|
||||
|
||||
#ifdef WLED_DISABLE_MQTT
|
||||
#ifndef WLED_ENABLE_MQTT
|
||||
#error "This user mod requires MQTT to be enabled."
|
||||
#endif
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
#include <BH1750.h>
|
||||
|
||||
// the max frequency to check photoresistor, 10 seconds
|
||||
#ifndef USERMOD_BH1750_MAX_MEASUREMENT_INTERVAL
|
||||
#define USERMOD_BH1750_MAX_MEASUREMENT_INTERVAL 10000
|
||||
@ -248,7 +250,3 @@ const char Usermod_BH1750::_maxReadInterval[] PROGMEM = "max-read-interval-ms";
|
||||
const char Usermod_BH1750::_minReadInterval[] PROGMEM = "min-read-interval-ms";
|
||||
const char Usermod_BH1750::_HomeAssistantDiscovery[] PROGMEM = "HomeAssistantDiscoveryLux";
|
||||
const char Usermod_BH1750::_offset[] PROGMEM = "offset-lx";
|
||||
|
||||
|
||||
static Usermod_BH1750 bh1750_v2;
|
||||
REGISTER_USERMOD(bh1750_v2);
|
@ -22,6 +22,7 @@ Dependencies
|
||||
- Libraries
|
||||
- `BME280@~3.0.0` (by [finitespace](https://github.com/finitespace/BME280))
|
||||
- `Wire`
|
||||
- These must be added under `lib_deps` in your `platform.ini` (or `platform_override.ini`).
|
||||
- Data is published over MQTT - make sure you've enabled the MQTT sync interface.
|
||||
- This usermod also writes to serial (GPIO1 on ESP8266). Please make sure nothing else is listening to the serial TX pin or your board will get confused by log messages!
|
||||
|
||||
@ -39,11 +40,17 @@ Methods also exist to read the read/calculated values from other WLED modules th
|
||||
|
||||
# Compiling
|
||||
|
||||
To enable, add `BME280_v2` to your `custom_usermods` (e.g. in `platformio_override.ini`)
|
||||
To enable, compile with `USERMOD_BME280` defined (e.g. in `platformio_override.ini`)
|
||||
```ini
|
||||
[env:usermod_bme280_d1_mini]
|
||||
extends = env:d1_mini
|
||||
custom_usermods = ${env:d1_mini.custom_usermods} BME280_v2
|
||||
build_flags =
|
||||
${common.build_flags_esp8266}
|
||||
-D USERMOD_BME280
|
||||
lib_deps =
|
||||
${esp8266.lib_deps}
|
||||
BME280@~3.0.0
|
||||
Wire
|
||||
```
|
||||
|
||||
|
||||
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"name:": "BME280_v2",
|
||||
"dependencies": {
|
||||
"finitespace/BME280":"~3.0.0"
|
||||
}
|
||||
}
|
@ -1,15 +1,17 @@
|
||||
// force the compiler to show a warning to confirm that this file is included
|
||||
#warning **** Included USERMOD_BME280 version 2.0 ****
|
||||
|
||||
#ifndef WLED_ENABLE_MQTT
|
||||
#error "This user mod requires MQTT to be enabled."
|
||||
#endif
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
#include <Arduino.h>
|
||||
#include <BME280I2C.h> // BME280 sensor
|
||||
#include <EnvironmentCalculations.h> // BME280 extended measurements
|
||||
|
||||
#ifdef WLED_DISABLE_MQTT
|
||||
#error "This user mod requires MQTT to be enabled."
|
||||
#endif
|
||||
|
||||
class UsermodBME280 : public Usermod
|
||||
{
|
||||
private:
|
||||
@ -239,7 +241,7 @@ public:
|
||||
// from the UI and values read from sensor, then publish to broker
|
||||
if (temperature != lastTemperature || PublishAlways)
|
||||
{
|
||||
publishMqtt("temperature", String(temperature, (unsigned) TemperatureDecimals).c_str());
|
||||
publishMqtt("temperature", String(temperature, TemperatureDecimals).c_str());
|
||||
}
|
||||
|
||||
lastTemperature = temperature; // Update last sensor temperature for next loop
|
||||
@ -252,17 +254,17 @@ public:
|
||||
|
||||
if (humidity != lastHumidity || PublishAlways)
|
||||
{
|
||||
publishMqtt("humidity", String(humidity, (unsigned) HumidityDecimals).c_str());
|
||||
publishMqtt("humidity", String(humidity, HumidityDecimals).c_str());
|
||||
}
|
||||
|
||||
if (heatIndex != lastHeatIndex || PublishAlways)
|
||||
{
|
||||
publishMqtt("heat_index", String(heatIndex, (unsigned) TemperatureDecimals).c_str());
|
||||
publishMqtt("heat_index", String(heatIndex, TemperatureDecimals).c_str());
|
||||
}
|
||||
|
||||
if (dewPoint != lastDewPoint || PublishAlways)
|
||||
{
|
||||
publishMqtt("dew_point", String(dewPoint, (unsigned) TemperatureDecimals).c_str());
|
||||
publishMqtt("dew_point", String(dewPoint, TemperatureDecimals).c_str());
|
||||
}
|
||||
|
||||
lastHumidity = humidity;
|
||||
@ -279,7 +281,7 @@ public:
|
||||
|
||||
if (pressure != lastPressure || PublishAlways)
|
||||
{
|
||||
publishMqtt("pressure", String(pressure, (unsigned) PressureDecimals).c_str());
|
||||
publishMqtt("pressure", String(pressure, PressureDecimals).c_str());
|
||||
}
|
||||
|
||||
lastPressure = pressure;
|
||||
@ -477,7 +479,3 @@ public:
|
||||
|
||||
const char UsermodBME280::_name[] PROGMEM = "BME280/BMP280";
|
||||
const char UsermodBME280::_enabled[] PROGMEM = "enabled";
|
||||
|
||||
|
||||
static UsermodBME280 bme280_v2;
|
||||
REGISTER_USERMOD(bme280_v2);
|
File diff suppressed because it is too large
Load Diff
@ -1,70 +1,65 @@
|
||||
# Usermod BME68X
|
||||
|
||||
This usermod was developed for a BME680/BME68X sensor. The BME68X is not compatible with the BME280/BMP280 chip. It has its own library. The original 'BSEC Software Library' from Bosch was used to develop the code. The measured values are displayed on the WLED info page.
|
||||
This usermod was developed for a BME680/BME68X sensor. The BME68X is not compatible with the BME280/BMP280 chip. It has its own library. The original 'BSEC Software Library' from Bosch was used to develop the code. The measured values are displayed on the WLED info page.
|
||||
|
||||
<p align="center"><img src="pics/pic1.png" style="width:60%;"></p>
|
||||
|
||||
In addition, the values are published on MQTT if this is active. The topic used for this is: 'wled/[MQTT Client ID]'. The Client ID is set in the WLED MQTT settings.
|
||||
|
||||
<p align="center"><img src="pics/pic2.png"></p>
|
||||
|
||||
If you use HomeAssistance discovery, the device tree for HomeAssistance is created. This is published under the topic 'homeassistant/sensor/[MQTT Client ID]' via MQTT.
|
||||
|
||||
<p align="center"><img src="pics/pic3.png"></p>
|
||||
|
||||
A device with the following sensors appears in HomeAssistant. Please note that MQTT must be activated in HomeAssistant.
|
||||
|
||||
<p align="center"><img src="pics/pic4.png" style="width:60%;"></p>
|
||||
|
||||
## Features
|
||||
|
||||
## Features
|
||||
Raw sensor types
|
||||
|
||||
Sensor Accuracy Scale Range
|
||||
-----------------------------
|
||||
Sensor Accuracy Scale Range
|
||||
--------------------------------------------------------------------------------------------------
|
||||
Temperature +/- 1.0 °C/°F -40 to 85 °C
|
||||
Humidity +/- 3 % 0 to 100 %
|
||||
Pressure +/- 1 hPa 300 to 1100 hPa
|
||||
Gas Resistance Ohm
|
||||
|
||||
Temperature +/- 1.0 °C/°F -40 to 85 °C
|
||||
Humidity +/- 3 % 0 to 100 %
|
||||
Pressure +/- 1 hPa 300 to 1100 hPa
|
||||
Gas Resistance Ohm
|
||||
The BSEC Library calculates the following values via the gas resistance
|
||||
|
||||
Sensor Accuracy Scale Range
|
||||
-----------------------------
|
||||
Sensor Accuracy Scale Range
|
||||
--------------------------------------------------------------------------------------------------
|
||||
IAQ value between 0 and 500
|
||||
Static IAQ same as IAQ but for permanently installed devices
|
||||
CO2 PPM
|
||||
VOC PPM
|
||||
Gas-Percentage %
|
||||
|
||||
|
||||
IAQ value between 0 and 500
|
||||
Static IAQ same as IAQ but for permanently installed devices
|
||||
CO2 PPM
|
||||
VOC PPM
|
||||
Gas-Percentage %
|
||||
In addition the usermod calculates
|
||||
|
||||
Sensor Accuracy Scale Range
|
||||
-----------------------------
|
||||
|
||||
Absolute humidity g/m³
|
||||
Dew point °C/°F
|
||||
Sensor Accuracy Scale Range
|
||||
--------------------------------------------------------------------------------------------------
|
||||
Absolute humidity g/m³
|
||||
Dew point °C/°F
|
||||
|
||||
### IAQ (Indoor Air Quality)
|
||||
|
||||
The IAQ is divided into the following value groups.
|
||||
|
||||
The IAQ is divided into the following value groups.
|
||||
<p align="center"><img src="pics/pic5.png"></p>
|
||||
|
||||
For more detailed information, please consult the enclosed Bosch product description (BME680.pdf).
|
||||
|
||||
|
||||
## Calibration of the device
|
||||
|
||||
The gas sensor of the BME68X must be calibrated. This differs from the BME280, which does not require any calibration.
|
||||
The gas sensor of the BME68X must be calibrated. This differs from the BME280, which does not require any calibration.
|
||||
There is a range of additional information for this, which the driver also provides. These values can be found in HomeAssistant under Diagnostics.
|
||||
|
||||
- **STABILIZATION_STATUS**: Gas sensor stabilization status [boolean] Indicates initial stabilization status of the gas sensor element: stabilization is ongoing (0) or stabilization is finished (1).
|
||||
- **RUN_IN_STATUS**: Gas sensor run-in status [boolean] Indicates power-on stabilization status of the gas sensor element: stabilization is ongoing (0) or stabilization is finished (1)
|
||||
|
||||
Furthermore, all GAS based values have their own accuracy value. These have the following meaning:
|
||||
Furthermore, all GAS based values have their own accuracy value. These have the following meaning:
|
||||
|
||||
- **Accuracy = 0** means the sensor is being stabilized (this can take a while on the first run)
|
||||
- **Accuracy = 1** means that the previous measured values show too few differences and cannot be used for calibration. If the sensor is at accuracy 1 for too long, you must ensure that the ambient air is chaning. Opening the windows is fine. Or sometimes it is sufficient to breathe on the sensor for approx. 5 minutes.
|
||||
- **Accuracy = 0** means the sensor is being stabilized (this can take a while on the first run)
|
||||
- **Accuracy = 1** means that the previous measured values show too few differences and cannot be used for calibration. If the sensor is at accuracy 1 for too long, you must ensure that the ambient air is chaning. Opening the windows is fine. Or sometimes it is sufficient to breathe on the sensor for approx. 5 minutes.
|
||||
- **Accuracy = 2** means the sensor is currently calibrating.
|
||||
- **Accuracy = 3** means that the sensor has been successfully calibrated. Once accuracy 3 is reached, the calibration data is automatically written to the file system. This calibration data will be used again at the next start and will speed up the calibration.
|
||||
|
||||
@ -72,29 +67,28 @@ The IAQ index is therefore only meaningful if IAQ Accuracy = 3. In addition to t
|
||||
|
||||
Reasonably reliable values are therefore only achieved when accuracy displays the value 3.
|
||||
|
||||
|
||||
|
||||
## Settings
|
||||
|
||||
The settings of the usermods are set in the usermod section of wled.
|
||||
|
||||
The settings of the usermods are set in the usermod section of wled.
|
||||
<p align="center"><img src="pics/pic6.png"></p>
|
||||
|
||||
The possible settings are
|
||||
|
||||
- **Enable:** Enables / disables the usermod
|
||||
- **I2C address:** I2C address of the sensor. You can choose between 0X77 & 0X76. The default is 0x77.
|
||||
- **Interval:** Specifies the interval of seconds at which the usermod should be executed. The default is every second.
|
||||
- **Pub Chages Only:** If this item is active, the values are only published if they have changed since the last publication.
|
||||
- **Pub Accuracy:** The Accuracy values associated with the gas values are also published.
|
||||
- **Pub Calib State:** If this item is active, STABILIZATION_STATUS& RUN_IN_STATUS are also published.
|
||||
- **Interval:** Specifies the interval of seconds at which the usermod should be executed. The default is every second.
|
||||
- **Pub Chages Only:** If this item is active, the values are only published if they have changed since the last publication.
|
||||
- **Pub Accuracy:** The Accuracy values associated with the gas values are also published.
|
||||
- **Pub Calib State:** If this item is active, STABILIZATION_STATUS& RUN_IN_STATUS are also published.
|
||||
- **Temp Scale:** Here you can choose between °C and °F.
|
||||
- **Temp Offset:** The temperature offset is always set in °C. It must be converted for Fahrenheit.
|
||||
- **HA Discovery:** If this item is active, the HomeAssistant sensor tree is created.
|
||||
- **Temp Offset:** The temperature offset is always set in °C. It must be converted for Fahrenheit.
|
||||
- **HA Discovery:** If this item is active, the HomeAssistant sensor tree is created.
|
||||
- **Pause While WLED Active:** If WLED has many LEDs to calculate, the computing power may no longer be sufficient to calculate the LEDs and read the sensor data. The LEDs then hang for a few microseconds, which can be seen. If this point is active, no sensor data is fetched as long as WLED is running.
|
||||
- **Del Calibration Hist:** If a check mark is set here, the calibration file saved in the file system is deleted when the settings are saved.
|
||||
- **Del Calibration Hist:** If a check mark is set here, the calibration file saved in the file system is deleted when the settings are saved.
|
||||
|
||||
### Sensors
|
||||
|
||||
Applies to all sensors. The number of decimal places is set here. If the sensor is set to -1, it will no longer be published. In addition, the IAQ values can be activated here in verbal form.
|
||||
Applies to all sensors. The number of decimal places is set here. If the sensor is set to -1, it will no longer be published. In addition, the IAQ values can be activated here in verbal form.
|
||||
|
||||
It is recommended to use the Static IAQ for the IAQ values. This is recommended by Bosch for statically placed devices.
|
||||
|
||||
@ -105,9 +99,8 @@ Data is published over MQTT - make sure you've enabled the MQTT sync interface.
|
||||
In addition to outputting via MQTT, you can read the values from the Info Screen on the dashboard page of the device's web interface.
|
||||
|
||||
Methods also exist to read the read/calculated values from other WLED modules through code.
|
||||
|
||||
- getTemperature(); The scale °C/°F is depended to the settings
|
||||
- getHumidity();
|
||||
- getHumidity();
|
||||
- getPressure();
|
||||
- getGasResistance();
|
||||
- getAbsoluteHumidity();
|
||||
@ -125,36 +118,32 @@ Methods also exist to read the read/calculated values from other WLED modules th
|
||||
- getStabStatus();
|
||||
- getRunInStatus();
|
||||
|
||||
## Compilation
|
||||
|
||||
To enable, compile with `BME68X` in `custom_usermods` (e.g. in `platformio_override.ini`)
|
||||
## Compiling
|
||||
|
||||
Example:
|
||||
To enable, compile with `USERMOD_BME68X` defined (e.g. in `platformio_override.ini`) and add the `BSEC Software Library` to the lib_deps.
|
||||
|
||||
```[env:esp32_mySpecial]
|
||||
extends = env:esp32dev
|
||||
custom_usermods = ${env:esp32dev.custom_usermods} BME68X
|
||||
```
|
||||
[env:esp32-BME680]
|
||||
board = esp32dev
|
||||
platform = ${esp32.platform}
|
||||
platform_packages = ${esp32.platform_packages}
|
||||
lib_deps = ${esp32.lib_deps}
|
||||
boschsensortec/BSEC Software Library @ ^1.8.1492 ; USERMOD: BME680
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags_esp32}
|
||||
-D USERMOD_BME68X ; USERMOD: BME680
|
||||
```
|
||||
|
||||
## Revision History
|
||||
|
||||
### Version 1.0.0
|
||||
|
||||
- First version of the BME68X_v user module
|
||||
|
||||
### Version 1.0.1
|
||||
|
||||
- Rebased to WELD Version 0.15
|
||||
- Reworked some default settings
|
||||
- A problem with the default settings has been fixed
|
||||
|
||||
### Version 1.0.2
|
||||
|
||||
* Rebased to WELD Version 0.16
|
||||
* Fixed: Solved compilation problems related to some macro naming interferences.
|
||||
|
||||
## Known problems
|
||||
|
||||
- MQTT goes online at device start. Shortly afterwards it goes offline and takes quite a while until it goes online again. The problem does not come from this user module, but from the WLED core.
|
||||
- If you save the settings often, WLED can get stuck.
|
||||
- If many LEDS are connected to WLED, reading the sensor can cause a small but noticeable hang. The "Pause While WLED Active" option was introduced as a workaround.
|
||||
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"name:": "BME68X",
|
||||
"dependencies": {
|
||||
"boschsensortec/BSEC Software Library":"^1.8.1492"
|
||||
}
|
||||
}
|
1114
usermods/BME68X_v2/usermod_bme68x.h
Normal file
1114
usermods/BME68X_v2/usermod_bme68x.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,3 +0,0 @@
|
||||
{
|
||||
"name:": "Battery"
|
||||
}
|
@ -23,7 +23,9 @@ Enables battery level monitoring of your project.
|
||||
|
||||
## 🎈 Installation
|
||||
|
||||
In `platformio_override.ini` (or `platformio.ini`)<br>Under: `custom_usermods =`, add the line: `Battery`<br><br>[Example: platformio_override.ini](assets/installation_platformio_override_ini.png) |
|
||||
| **Option 1** | **Option 2** |
|
||||
|--------------|--------------|
|
||||
| In `wled00/my_config.h`<br>Add the line: `#define USERMOD_BATTERY`<br><br>[Example: my_config.h](assets/installation_my_config_h.png) | In `platformio_override.ini` (or `platformio.ini`)<br>Under: `build_flags =`, add the line: `-D USERMOD_BATTERY`<br><br>[Example: platformio_override.ini](assets/installation_platformio_override_ini.png) |
|
||||
|
||||
<br><br>
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
#include "battery_defaults.h"
|
||||
#include "UMBattery.h"
|
||||
@ -855,7 +857,3 @@ const char UsermodBattery::_preset[] PROGMEM = "preset";
|
||||
const char UsermodBattery::_duration[] PROGMEM = "duration";
|
||||
const char UsermodBattery::_init[] PROGMEM = "init";
|
||||
const char UsermodBattery::_haDiscovery[] PROGMEM = "HA-discovery";
|
||||
|
||||
|
||||
static UsermodBattery battery;
|
||||
REGISTER_USERMOD(battery);
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"name:": "Cronixie"
|
||||
}
|
@ -4,5 +4,5 @@ This usermod supports driving the Cronixie M and L clock kits by Diamex.
|
||||
|
||||
## Installation
|
||||
|
||||
Compile and upload after adding `Cronixie` to `custom_usermods` of your PlatformIO environment.
|
||||
Compile and upload after adding `-D USERMOD_CRONIXIE` to `build_flags` of your PlatformIO environment.
|
||||
Make sure the Auto Brightness Limiter is enabled at 420mA (!) and configure 60 WS281x LEDs.
|
@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
|
||||
class UsermodCronixie : public Usermod {
|
||||
@ -297,7 +299,4 @@ class UsermodCronixie : public Usermod {
|
||||
{
|
||||
return USERMOD_ID_CRONIXIE;
|
||||
}
|
||||
};
|
||||
|
||||
static UsermodCronixie cronixie;
|
||||
REGISTER_USERMOD(cronixie);
|
||||
};
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"name:": "DHT",
|
||||
"build": { "libArchive": false},
|
||||
"dependencies": {
|
||||
"DHT_nonblocking":"https://github.com/alwynallan/DHT_nonblocking"
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
; 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
|
||||
@ -10,11 +11,13 @@
|
||||
|
||||
[env:d1_mini_usermod_dht_C]
|
||||
extends = env:d1_mini
|
||||
custom_usermods = ${env:d1_mini.custom_usermods} DHT
|
||||
build_flags = ${env:d1_mini.build_flags} -D USERMOD_DHT_CELSIUS
|
||||
build_flags = ${env:d1_mini.build_flags} -D USERMOD_DHT -D USERMOD_DHT_CELSIUS
|
||||
lib_deps = ${env:d1_mini.lib_deps}
|
||||
https://github.com/alwynallan/DHT_nonblocking
|
||||
|
||||
[env:custom32_LEDPIN_16_usermod_dht_C]
|
||||
extends = env:custom32_LEDPIN_16
|
||||
custom_usermods = ${env:custom32_LEDPIN_16.custom_usermods} DHT
|
||||
build_flags = ${env:custom32_LEDPIN_16.build_flags} -D USERMOD_DHT_CELSIUS -D USERMOD_DHT_STATS
|
||||
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
|
||||
|
||||
|
@ -15,6 +15,7 @@ Copy the example `platformio_override.ini` to the root directory. This file sho
|
||||
|
||||
### Define Your Options
|
||||
|
||||
* `USERMOD_DHT` - define this to include this user mod 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 Celsius, otherwise Fahrenheit will be reported
|
||||
|
@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
#ifdef WLED_DISABLE_MQTT
|
||||
#ifndef WLED_ENABLE_MQTT
|
||||
#error "This user mod requires MQTT to be enabled."
|
||||
#endif
|
||||
|
||||
@ -243,7 +245,3 @@ class UsermodDHT : public Usermod {
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
static UsermodDHT dht;
|
||||
REGISTER_USERMOD(dht);
|
@ -1,4 +0,0 @@
|
||||
{
|
||||
"name:": "EXAMPLE",
|
||||
"dependencies": {}
|
||||
}
|
@ -4,6 +4,7 @@ In this usermod file you can find the documentation on how to take advantage of
|
||||
|
||||
## Installation
|
||||
|
||||
Add `EXAMPLE` to `custom_usermods` in your PlatformIO environment and compile!
|
||||
Copy `usermod_v2_example.h` to the wled00 directory.
|
||||
Uncomment the corresponding lines in `usermods_list.cpp` and compile!
|
||||
_(You shouldn't need to actually install this, it does nothing useful)_
|
||||
|
@ -1,8 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
|
||||
/*
|
||||
* Usermods allow you to add own functionality to WLED more easily
|
||||
* See: https://github.com/wled-dev/WLED/wiki/Add-own-functionality
|
||||
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
|
||||
*
|
||||
* This is an example for a v2 usermod.
|
||||
* v2 usermods are class inheritance based and can (but don't have to) implement more functions, each of them is shown in this example.
|
||||
@ -402,6 +404,3 @@ void MyExampleUsermod::publishMqtt(const char* state, bool retain)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static MyExampleUsermod example_usermod;
|
||||
REGISTER_USERMOD(example_usermod);
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"name:": "EleksTube_IPS",
|
||||
"dependencies": {
|
||||
"TFT_eSPI" : "2.5.33"
|
||||
}
|
||||
}
|
||||
# Seems to add 300kb to the RAM requirement???
|
@ -1,3 +1,4 @@
|
||||
#pragma once
|
||||
#include "TFTs.h"
|
||||
#include "wled.h"
|
||||
|
||||
@ -155,7 +156,3 @@ class ElekstubeIPSUsermod : public Usermod {
|
||||
const char ElekstubeIPSUsermod::_name[] PROGMEM = "EleksTubeIPS";
|
||||
const char ElekstubeIPSUsermod::_tubeSeg[] PROGMEM = "tubeSegment";
|
||||
const char ElekstubeIPSUsermod::_digitOffset[] PROGMEM = "digitOffset";
|
||||
|
||||
|
||||
static ElekstubeIPSUsermod elekstube_ips;
|
||||
REGISTER_USERMOD(elekstube_ips);
|
@ -1,12 +1,11 @@
|
||||
#ifndef WLED_ENABLE_MQTT
|
||||
#error "This user mod requires MQTT to be enabled."
|
||||
#endif
|
||||
|
||||
#include "wled.h"
|
||||
#include <Arduino.h>
|
||||
#include <U8x8lib.h> // from https://github.com/olikraus/u8g2/
|
||||
#include <DallasTemperature.h> //Dallastemperature sensor
|
||||
|
||||
#ifdef WLED_DISABLE_MQTT
|
||||
#error "This user mod requires MQTT to be enabled."
|
||||
#endif
|
||||
|
||||
//The SCL and SDA pins are defined here.
|
||||
//Lolin32 boards use SCL=5 SDA=4
|
||||
#define U8X8_PIN_SCL 5
|
||||
|
@ -1,13 +1,13 @@
|
||||
#ifndef WLED_ENABLE_MQTT
|
||||
#error "This user mod requires MQTT to be enabled."
|
||||
#endif
|
||||
|
||||
#include "wled.h"
|
||||
#include <Arduino.h>
|
||||
#include <U8x8lib.h> // from https://github.com/olikraus/u8g2/
|
||||
#include <Wire.h>
|
||||
#include <BME280I2C.h> //BME280 sensor
|
||||
|
||||
#ifdef WLED_DISABLE_MQTT
|
||||
#error "This user mod requires MQTT to be enabled."
|
||||
#endif
|
||||
|
||||
void UpdateBME280Data();
|
||||
|
||||
#define Celsius // Show temperature measurement in Celsius otherwise is in Fahrenheit
|
||||
|
@ -1,4 +0,0 @@
|
||||
{
|
||||
"name:": "Fix_unreachable_netservices_v2",
|
||||
"platforms": ["espressif8266"]
|
||||
}
|
@ -30,6 +30,41 @@ The usermod supports the following state changes:
|
||||
|
||||
## Installation
|
||||
|
||||
1. Add `Fix_unreachable_netservices` to `custom_usermods` in your PlatformIO environment.
|
||||
1. Copy the file `usermod_Fix_unreachable_netservices.h` to the `wled00` directory.
|
||||
2. Register the usermod by adding `#include "usermod_Fix_unreachable_netservices.h"` in the top and `registerUsermod(new FixUnreachableNetServices());` in the bottom of `usermods_list.cpp`.
|
||||
|
||||
Example **usermods_list.cpp**:
|
||||
|
||||
```cpp
|
||||
#include "wled.h"
|
||||
/*
|
||||
* Register your v2 usermods here!
|
||||
* (for v1 usermods using just usermod.cpp, you can ignore this file)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Add/uncomment your usermod filename here (and once more below)
|
||||
* || || ||
|
||||
* \/ \/ \/
|
||||
*/
|
||||
//#include "usermod_v2_example.h"
|
||||
//#include "usermod_temperature.h"
|
||||
//#include "usermod_v2_empty.h"
|
||||
#include "usermod_Fix_unreachable_netservices.h"
|
||||
|
||||
void registerUsermods()
|
||||
{
|
||||
/*
|
||||
* Add your usermod class name here
|
||||
* || || ||
|
||||
* \/ \/ \/
|
||||
*/
|
||||
//UsermodManager::add(new MyExampleUsermod());
|
||||
//UsermodManager::add(new UsermodTemperature());
|
||||
//UsermodManager::add(new UsermodRenameMe());
|
||||
UsermodManager::add(new FixUnreachableNetServices());
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
Hopefully I can help someone with that - @gegu
|
||||
|
@ -1,4 +1,12 @@
|
||||
#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>
|
||||
@ -8,7 +16,7 @@
|
||||
* By this procedure the net services of WLED remains accessible in some problematic WLAN environments.
|
||||
*
|
||||
* Usermods allow you to add own functionality to WLED more easily
|
||||
* See: https://github.com/wled-dev/WLED/wiki/Add-own-functionality
|
||||
* 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.
|
||||
@ -160,11 +168,4 @@ Delay <input type=\"number\" min=\"5\" max=\"300\" value=\"";
|
||||
return USERMOD_ID_FIXNETSERVICES;
|
||||
}
|
||||
};
|
||||
|
||||
static FixUnreachableNetServices fix_unreachable_net_services;
|
||||
REGISTER_USERMOD(fix_unreachable_net_services);
|
||||
|
||||
#else /* !ESP8266 */
|
||||
#warning "Usermod FixUnreachableNetServices works only with ESP8266 builds"
|
||||
#endif
|
||||
|
@ -22,6 +22,13 @@ The following settings can be configured in the Usermod Menu:
|
||||
- **MqttPublishAlways**: Publish always, regardless if there is a change.
|
||||
- **MqttHomeAssistantDiscovery**: Enable Home Assistant discovery.
|
||||
|
||||
## Dependencies
|
||||
|
||||
These must be added under `lib_deps` in your `platform.ini` (or `platform_override.ini`).
|
||||
|
||||
- Libraries
|
||||
- `wollewald/INA226_WE@~1.2.9` (by [wollewald](https://registry.platformio.org/libraries/wollewald/INA226_WE))
|
||||
- `Wire`
|
||||
|
||||
## Understanding Samples and Conversion Times
|
||||
|
||||
@ -55,12 +62,16 @@ For detailed programming information and register configurations, refer to the [
|
||||
|
||||
## Compiling
|
||||
|
||||
To enable, compile with `INA226` in `custom_usermods` (e.g. in `platformio_override.ini`).
|
||||
To enable, compile with `USERMOD_INA226` defined (e.g. in `platformio_override.ini`).
|
||||
|
||||
```ini
|
||||
[env:ina226_example]
|
||||
extends = env:esp32dev
|
||||
custom_usermods = ${env:esp32dev.custom_usermods} INA226
|
||||
build_flags = ${env:esp32dev.build_flags}
|
||||
build_flags =
|
||||
${common.build_flags} ${esp32.build_flags}
|
||||
-D USERMOD_INA226
|
||||
; -D USERMOD_INA226_DEBUG ; -- add a debug status to the info modal
|
||||
lib_deps =
|
||||
${esp32.lib_deps}
|
||||
wollewald/INA226_WE@~1.2.9
|
||||
```
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"name:": "INA226_v2",
|
||||
"dependencies": {
|
||||
"wollewald/INA226_WE":"~1.2.9"
|
||||
}
|
||||
}
|
@ -1,6 +1,9 @@
|
||||
[env:ina226_example]
|
||||
extends = env:esp32dev
|
||||
custom_usermods = ${env:esp32dev.custom_usermods} INA226_v2
|
||||
build_flags =
|
||||
${env:esp32dev.build_flags}
|
||||
${common.build_flags} ${esp32.build_flags}
|
||||
-D USERMOD_INA226
|
||||
; -D USERMOD_INA226_DEBUG ; -- add a debug status to the info modal
|
||||
lib_deps =
|
||||
${esp32.lib_deps}
|
||||
wollewald/INA226_WE@~1.2.9
|
@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
#include <INA226_WE.h>
|
||||
|
||||
@ -208,6 +210,12 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
~UsermodINA226()
|
||||
{
|
||||
delete _ina226;
|
||||
_ina226 = nullptr;
|
||||
}
|
||||
|
||||
#ifndef WLED_DISABLE_MQTT
|
||||
void mqttInitialize()
|
||||
{
|
||||
@ -543,17 +551,6 @@ public:
|
||||
_initDone = true;
|
||||
return configComplete;
|
||||
}
|
||||
|
||||
~UsermodINA226()
|
||||
{
|
||||
delete _ina226;
|
||||
_ina226 = nullptr;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
const char UsermodINA226::_name[] PROGMEM = "INA226";
|
||||
|
||||
|
||||
static UsermodINA226 ina226_v2;
|
||||
REGISTER_USERMOD(ina226_v2);
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"name:": "Internal_Temperature_v2"
|
||||
}
|
@ -23,7 +23,8 @@
|
||||
|
||||
|
||||
## Installation
|
||||
- Add `Internal_Temperature` to `custom_usermods` in your `platformio.ini` (or `platformio_override.ini`).
|
||||
- Add a build flag `-D USERMOD_INTERNAL_TEMPERATURE` to your `platformio.ini` (or `platformio_override.ini`).
|
||||
|
||||
|
||||
## 📝 Change Log
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
|
||||
class InternalTemperatureUsermod : public Usermod
|
||||
@ -48,7 +50,7 @@ public:
|
||||
#else // ESP32 ESP32S3 and ESP32C3
|
||||
temperature = roundf(temperatureRead() * 10) / 10;
|
||||
#endif
|
||||
if(presetToActivate != 0){
|
||||
|
||||
// Check if temperature has exceeded the activation threshold
|
||||
if (temperature >= activationThreshold) {
|
||||
// Update the state flag if not already set
|
||||
@ -56,7 +58,7 @@ public:
|
||||
isAboveThreshold = true;
|
||||
}
|
||||
// Check if a 'high temperature' preset is configured and it's not already active
|
||||
if (currentPreset != presetToActivate) {
|
||||
if (presetToActivate != 0 && currentPreset != presetToActivate) {
|
||||
// If a playlist is active, store it for reactivation later
|
||||
if (currentPlaylist > 0) {
|
||||
previousPlaylist = currentPlaylist;
|
||||
@ -99,7 +101,6 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef WLED_DISABLE_MQTT
|
||||
if (WLED_MQTT_CONNECTED)
|
||||
@ -191,7 +192,4 @@ void InternalTemperatureUsermod::publishMqtt(const char *state, bool retain)
|
||||
mqtt->publish(subuf, 0, retain, state);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static InternalTemperatureUsermod internal_temperature_v2;
|
||||
REGISTER_USERMOD(internal_temperature_v2);
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"name:": "LD2410_v2",
|
||||
"dependencies": {
|
||||
"ncmreynolds/ld2410":"^0.1.3"
|
||||
}
|
||||
}
|
@ -10,15 +10,21 @@ The movement and presence state are displayed in both the Info section of the we
|
||||
## Dependencies
|
||||
- Libraries
|
||||
- `ncmreynolds/ld2410@^0.1.3`
|
||||
- This must be added under `lib_deps` in your `platformio.ini` (or `platformio_override.ini`).
|
||||
- Data is published over MQTT - make sure you've enabled the MQTT sync interface.
|
||||
|
||||
## Compilation
|
||||
|
||||
To enable, compile with `LD2140` in `custom_usermods` (e.g. in `platformio_override.ini`)
|
||||
To enable, compile with `USERMOD_LD2410` defined (e.g. in `platformio_override.ini`)
|
||||
```ini
|
||||
[env:usermod_USERMOD_LD2410_esp32dev]
|
||||
extends = env:esp32dev
|
||||
custom_usermods = ${env:esp32dev.custom_usermods} LD2140
|
||||
build_flags =
|
||||
${common.build_flags_esp32}
|
||||
-D USERMOD_LD2410
|
||||
lib_deps =
|
||||
${esp32.lib_deps}
|
||||
ncmreynolds/ld2410@^0.1.3
|
||||
```
|
||||
|
||||
### Configuration Options
|
||||
|
@ -1,10 +1,14 @@
|
||||
#include "wled.h"
|
||||
#include <ld2410.h>
|
||||
#warning **** Included USERMOD_LD2410 ****
|
||||
|
||||
#ifdef WLED_DISABLE_MQTT
|
||||
#ifndef WLED_ENABLE_MQTT
|
||||
#error "This user mod requires MQTT to be enabled."
|
||||
#endif
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
#include <ld2410.h>
|
||||
|
||||
class LD2410Usermod : public Usermod {
|
||||
|
||||
private:
|
||||
@ -231,7 +235,3 @@ void LD2410Usermod::publishMqtt(const char* topic, const char* state, bool retai
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static LD2410Usermod ld2410_v2;
|
||||
REGISTER_USERMOD(ld2410_v2);
|
@ -2,14 +2,13 @@
|
||||
This usermod will obtain readings from a Light Dependent Resistor (LDR) and will turn on/off specific presets based on those readings. This is useful for exterior lighting situations where you want the lights to only be on when it is dark out.
|
||||
|
||||
# Installation
|
||||
Add "LDR_Dusk_Dawn" to your platformio.ini environment's custom_usermods and build.
|
||||
Add "-D USERMOD_LDR_DUSK_DAWN" to your platformio.ini [common] build_flags and build.
|
||||
|
||||
Example:
|
||||
```
|
||||
[env:usermod_LDR_Dusk_Dawn_esp32dev]
|
||||
extends = env:esp32dev
|
||||
custom_usermods = ${env:esp32dev.custom_usermods}
|
||||
LDR_Dusk_Dawn # Enable LDR Dusk Dawn Usermod
|
||||
[common]
|
||||
build_flags =
|
||||
-D USERMOD_LDR_DUSK_DAWN # Enable LDR Dusk Dawn Usermod
|
||||
```
|
||||
|
||||
# Usermod Settings
|
||||
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"name:": "LDR_Dusk_Dawn_v2"
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
#pragma once
|
||||
#include "wled.h"
|
||||
|
||||
#ifndef ARDUINO_ARCH_ESP32
|
||||
@ -150,7 +151,3 @@ class LDR_Dusk_Dawn_v2 : public Usermod {
|
||||
};
|
||||
|
||||
const char LDR_Dusk_Dawn_v2::_name[] PROGMEM = "LDR_Dusk_Dawn_v2";
|
||||
|
||||
|
||||
static LDR_Dusk_Dawn_v2 ldr_dusk_dawn_v2;
|
||||
REGISTER_USERMOD(ldr_dusk_dawn_v2);
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"name:": "MAX17048_v2",
|
||||
"build": { "libArchive": false},
|
||||
"dependencies": {
|
||||
"Adafruit_MAX1704X":"https://github.com/adafruit/Adafruit_MAX1704X#1.0.2"
|
||||
}
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
// force the compiler to show a warning to confirm that this file is included
|
||||
#warning **** Included USERMOD_MAX17048 V2.0 ****
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
#include "Adafruit_MAX1704X.h"
|
||||
|
||||
@ -277,7 +279,3 @@ const char Usermod_MAX17048::_enabled[] PROGMEM = "enabled";
|
||||
const char Usermod_MAX17048::_maxReadInterval[] PROGMEM = "max-read-interval-ms";
|
||||
const char Usermod_MAX17048::_minReadInterval[] PROGMEM = "min-read-interval-ms";
|
||||
const char Usermod_MAX17048::_HomeAssistantDiscovery[] PROGMEM = "HomeAssistantDiscovery";
|
||||
|
||||
|
||||
static Usermod_MAX17048 max17048_v2;
|
||||
REGISTER_USERMOD(max17048_v2);
|
@ -1,4 +0,0 @@
|
||||
{
|
||||
"name:": "MY9291",
|
||||
"platforms": ["espressif8266"]
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
#include "MY92xx.h"
|
||||
|
||||
@ -40,7 +42,4 @@ class MY9291Usermod : public Usermod {
|
||||
uint16_t getId() {
|
||||
return USERMOD_ID_MY9291;
|
||||
}
|
||||
};
|
||||
|
||||
static MY9291Usermod my9291;
|
||||
REGISTER_USERMOD(my9291);
|
||||
};
|
@ -42,7 +42,7 @@
|
||||
*
|
||||
*
|
||||
* Usermods allow you to add own functionality to WLED more easily
|
||||
* See: https://github.com/wled-dev/WLED/wiki/Add-own-functionality
|
||||
* 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.
|
||||
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"name:": "PIR_sensor_switch"
|
||||
}
|
@ -5,7 +5,7 @@ This usermod-v2 modification allows the connection of a PIR sensor to switch on
|
||||
_Story:_
|
||||
|
||||
I use the PIR Sensor to automatically turn on the WLED analog clock in my home office room when I am there.
|
||||
The LED strip is switched [using a relay](https://kno.wled.ge/features/relay-control/) to keep the power consumption low when it is switched off.
|
||||
The LED strip is switched [using a relay](https://github.com/Aircoookie/WLED/wiki/Control-a-relay-with-WLED) to keep the power consumption low when it is switched off.
|
||||
|
||||
## Web interface
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
|
||||
#ifndef PIR_SENSOR_PIN
|
||||
@ -24,7 +26,7 @@
|
||||
* Maintained by: @blazoncek
|
||||
*
|
||||
* Usermods allow you to add own functionality to WLED more easily
|
||||
* See: https://github.com/wled-dev/WLED/wiki/Add-own-functionality
|
||||
* 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.
|
||||
@ -569,7 +571,3 @@ bool PIRsensorSwitch::readFromConfig(JsonObject &root)
|
||||
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
||||
return !(pins.isNull() || pins.size() != PIR_SENSOR_MAX_SENSORS);
|
||||
}
|
||||
|
||||
|
||||
static PIRsensorSwitch pir_sensor_switch;
|
||||
REGISTER_USERMOD(pir_sensor_switch);
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"name:": "PWM_fan",
|
||||
"build": {
|
||||
"extraScript": "setup_deps.py"
|
||||
}
|
||||
}
|
@ -11,8 +11,8 @@ If the _tachometer_ is supported, the current speed (in RPM) will be displayed o
|
||||
|
||||
## Installation
|
||||
|
||||
Add the `PWM_fan` to `custom_usermods` in your `platformio.ini` (or `platformio_override.ini`)
|
||||
You will also need `Temperature` or `sht`.
|
||||
Add the compile-time option `-D USERMOD_PWM_FAN` to your `platformio.ini` (or `platformio_override.ini`) or use `#define USERMOD_PWM_FAN` in `myconfig.h`.
|
||||
You will also need `-D USERMOD_DALLASTEMPERATURE`.
|
||||
|
||||
### Define Your Options
|
||||
|
||||
|
@ -1,12 +0,0 @@
|
||||
Import('env')
|
||||
|
||||
|
||||
usermods = env.GetProjectOption("custom_usermods","").split()
|
||||
# Check for dependencies
|
||||
if "Temperature" in usermods:
|
||||
env.Append(CPPDEFINES=[("USERMOD_DALLASTEMPERATURE")])
|
||||
elif "sht" in usermods:
|
||||
env.Append(CPPDEFINES=[("USERMOD_SHT")])
|
||||
else:
|
||||
raise RuntimeError("PWM_fan usermod requires Temperature or sht to be enabled")
|
||||
|
@ -1,14 +1,10 @@
|
||||
#include "wled.h"
|
||||
#pragma once
|
||||
|
||||
#if defined(USERMOD_DALLASTEMPERATURE)
|
||||
#include "UsermodTemperature.h"
|
||||
#elif defined(USERMOD_SHT)
|
||||
#include "ShtUsermod.h"
|
||||
#else
|
||||
#if !defined(USERMOD_DALLASTEMPERATURE) && !defined(USERMOD_SHT)
|
||||
#error The "PWM fan" usermod requires "Dallas Temeprature" or "SHT" usermod to function properly.
|
||||
#endif
|
||||
|
||||
|
||||
#include "wled.h"
|
||||
|
||||
// PWM & tacho code curtesy of @KlausMu
|
||||
// https://github.com/KlausMu/esp32-fan-controller/tree/main/src
|
||||
@ -401,7 +397,3 @@ const char PWMFanUsermod::_maxPWMValuePct[] PROGMEM = "max-PWM-percent";
|
||||
const char PWMFanUsermod::_IRQperRotation[] PROGMEM = "IRQs-per-rotation";
|
||||
const char PWMFanUsermod::_speed[] PROGMEM = "speed";
|
||||
const char PWMFanUsermod::_lock[] PROGMEM = "lock";
|
||||
|
||||
|
||||
static PWMFanUsermod pwm_fan;
|
||||
REGISTER_USERMOD(pwm_fan);
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"name:": "RTC"
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "src/dependencies/time/DS1307RTC.h"
|
||||
#include "wled.h"
|
||||
|
||||
@ -46,7 +48,4 @@ class RTCUsermod : public Usermod {
|
||||
{
|
||||
return USERMOD_ID_RTC;
|
||||
}
|
||||
};
|
||||
|
||||
static RTCUsermod rtc;
|
||||
REGISTER_USERMOD(rtc);
|
||||
};
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"name:": "SN_Photoresistor"
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
|
||||
//Pin defaults for QuinLed Dig-Uno (A0)
|
||||
@ -208,7 +210,3 @@ const char Usermod_SN_Photoresistor::_referenceVoltage[] PROGMEM = "supplied-vol
|
||||
const char Usermod_SN_Photoresistor::_resistorValue[] PROGMEM = "resistor-value";
|
||||
const char Usermod_SN_Photoresistor::_adcPrecision[] PROGMEM = "adc-precision";
|
||||
const char Usermod_SN_Photoresistor::_offset[] PROGMEM = "offset";
|
||||
|
||||
|
||||
static Usermod_SN_Photoresistor sn_photoresistor;
|
||||
REGISTER_USERMOD(sn_photoresistor);
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user