mirror of
https://github.com/wled/WLED.git
synced 2026-06-15 09:21:46 +00:00
Compare commits
49 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4efb02de58 | |||
| a4b14c0191 | |||
| d8e3578084 | |||
| 30abc01c0c | |||
| dea6ec0e4c | |||
| dfd78f4903 | |||
| 5f7910742e | |||
| 3a5026886f | |||
| 1dbceed9dc | |||
| be264fb210 | |||
| 7bd387444d | |||
| 174ff022cb | |||
| bd0ebf90c0 | |||
| 0a1a7fc26f | |||
| 659f698144 | |||
| bf948fadb5 | |||
| d884a3e692 | |||
| 82c4ce580e | |||
| bb495f7879 | |||
| 6bd90abac7 | |||
| d6482e99bb | |||
| c399d712c9 | |||
| fd162cee43 | |||
| 43278a5d0f | |||
| bd8a16a6f3 | |||
| 73898ddf5d | |||
| cdf1f80a81 | |||
| 1825ce7fec | |||
| b4747a827b | |||
| e2708be4a9 | |||
| 79bfc8b223 | |||
| f98e19c965 | |||
| 5d00dd0394 | |||
| beaa5001b6 | |||
| 33fe82c207 | |||
| 36fa42d7ea | |||
| 555d0cfbf7 | |||
| 090ab59a9c | |||
| c0a90ea470 | |||
| 7a37579ef8 | |||
| 58bf4c83e9 | |||
| 69c2b2d5c2 | |||
| 830f5df465 | |||
| ce249aef64 | |||
| ff97ad5fe0 | |||
| 68b61f0831 | |||
| 6cdf650535 | |||
| 0a0800d98d | |||
| cc26179e56 |
+151
-10
@@ -6,6 +6,8 @@
|
||||
# docs/cpp.instructions.md — C++ coding conventions
|
||||
# docs/web.instructions.md — Web UI coding conventions
|
||||
# docs/cicd.instructions.md — GitHub Actions / CI-CD conventions
|
||||
# docs/hardening.instructions.md — basic rules for code hardening and robustness
|
||||
# docs/securecode.instructions.md — more detailed checklists for common vulnerabilities
|
||||
#
|
||||
# NOTE: This file must be committed (tracked by git) for CodeRabbit to read
|
||||
# it from the repository. If it is listed in .gitignore, CodeRabbit will
|
||||
@@ -15,7 +17,7 @@ language: en-US
|
||||
|
||||
reviews:
|
||||
# generic review setting, see https://docs.coderabbit.ai/reference/configuration#reference
|
||||
auto_apply_labels: true
|
||||
auto_apply_labels: false
|
||||
# abort_on_close: false
|
||||
high_level_summary: true
|
||||
review_status: true
|
||||
@@ -31,12 +33,19 @@ reviews:
|
||||
- V5
|
||||
ignore_title_keywords:
|
||||
- WIP
|
||||
tools:
|
||||
fbinfer:
|
||||
enabled: false # Arduino.h not available on Linux analysis host
|
||||
cppcheck:
|
||||
enabled: true # cppcheck works fine without Arduino headers
|
||||
clang:
|
||||
enabled: true # clang tidy likewise works
|
||||
|
||||
path_instructions:
|
||||
- path: "**/*.{cpp,h,hpp,ino}"
|
||||
instructions: >
|
||||
Follow the C++ coding conventions documented in docs/cpp.instructions.md
|
||||
and the general project guidelines in .github/copilot-instructions.md.
|
||||
and the general project guidelines in AGENTS.md and .github/copilot-instructions.md.
|
||||
|
||||
Key rules: 2-space indentation (no tabs), camelCase functions/variables,
|
||||
PascalCase classes, UPPER_CASE macros. No C++ exceptions — use return codes and debug macros.
|
||||
@@ -44,8 +53,37 @@ reviews:
|
||||
Hot-path optimization guidelines (attributes, uint_fast types, caching,
|
||||
unsigned range checks) apply from pixel set/get operations and strip.show() downward —
|
||||
NOT to effect functions in FX.cpp, which have diverse contributor styles.
|
||||
# disabled - the below instruction has no effect
|
||||
# When initially reviewing a PR, summarize good practices (top 5) and create a prioritized list of suggested improvements (focus on major ones).
|
||||
|
||||
When reviewing PRs labeled "AI" or when source code appears to be AI-generated, perform these additional checks:
|
||||
1. VERIFY all referenced preprocessor macros, constants and flags exist by searching the codebase - do not trust the AI's claims about what exists.
|
||||
2. CHECK for reinvention: search for existing functions/patterns that already solve the same problem.
|
||||
3. CHECK for singleton data (defined but never used) and for dead/disabled code, and suggest to remove them.
|
||||
4. VERIFY comments match code behavior - AI frequently generates plausible but incorrect comments.
|
||||
5. VERIFY numerical stability / accuracy of arithmetic expressions. AI is often wrong when it comes to math and numbers.
|
||||
6. CHECK for implied but weakly justified assumptions - like usermod loop() call frequency - and ask for clarification.
|
||||
7. FLAG changes that appear unrelated: deleted comments, unnecessary re-formatting or re-factoring, and modifications in files that seem unrelated to the PR description.
|
||||
|
||||
# ── Security hardening — firmware (trust-boundary-aware) ────────────────
|
||||
- path: "wled00/**/*.{cpp,h,hpp,ino}"
|
||||
instructions: >
|
||||
Apply the WLED security hardening rules from docs/hardening.instructions.md,
|
||||
and consult docs/securecode.instructions.md when more details are needed for actionable recommendations.
|
||||
|
||||
Trust Boundary Model — enforce input-validation and bounds-checking rules
|
||||
ONLY at the first untrusted ingress point. Untrusted ingress points are:
|
||||
- HTTP/JSON API request bodies and query parameters (/json/*, /win, etc.)
|
||||
- WebSocket message payloads
|
||||
- UDP datagrams (parsePacket() / recvfrom() and protocol wrappers for
|
||||
E1.31, DDP, Art-Net, TPM2.net)
|
||||
- TCP socket reads
|
||||
- Serial/UART command input
|
||||
- ESP-NOW raw messages input
|
||||
|
||||
A value that has been validated and range-clamped at its ingress handler is
|
||||
considered TRUSTED for all subsequent WLED core processing. Do NOT flag or suggest
|
||||
repeated bounds/range checks or internal uses of already-sanitized data.
|
||||
When it is unclear whether a value has been sanitized upstream, prefer
|
||||
requesting clarification over raising a false-positive finding.
|
||||
|
||||
- path: "wled00/data/**"
|
||||
instructions: >
|
||||
@@ -54,8 +92,21 @@ reviews:
|
||||
Key rules: indent HTML and JavaScript with tabs, CSS with tabs.
|
||||
Files here are built into wled00/html_*.h and wled00/js_*.h by tools/cdata.js — never
|
||||
edit those generated headers directly.
|
||||
# disabled - the below instruction has no effect
|
||||
# When initially reviewing a PR, summarize good practices (top 5) and create a prioritized list of suggested improvements (focus on major ones).
|
||||
|
||||
# ── Security hardening — WebUI (always an ingress/output surface) ────────
|
||||
- path: "wled00/data/**"
|
||||
instructions: >
|
||||
Apply the WLED web UI security rules from docs/securecode.instructions.md
|
||||
(sections WEB1-WEB7).
|
||||
|
||||
The Trust Boundary Model does NOT reduce scope here: the WebUI is both
|
||||
an ingress point (user input, postMessage, fetched config data) and an
|
||||
output/rendering surface. Always flag DOM XSS risks, unsafe
|
||||
innerHTML / document.write / insertAdjacentHTML / outerHTML assignments,
|
||||
postMessage handlers without origin validation, eval() / new Function(),
|
||||
unsafe location.href or location.replace() assignments, and DOM insertion
|
||||
from fetched or config-derived data — regardless of where the data
|
||||
originates.
|
||||
|
||||
- path: "wled00/html_*.h"
|
||||
instructions: >
|
||||
@@ -75,8 +126,33 @@ reviews:
|
||||
Each usermod lives in its own directory under usermods/ and is implemented
|
||||
as a .cpp file with a dedicated library.json file to manage dependencies.
|
||||
Follow the same C++ conventions as the core firmware (docs/cpp.instructions.md).
|
||||
# disabled - the below instruction has no effect
|
||||
# When initially reviewing a PR, summarize good practices (top 6) and create a prioritized list of suggested improvements (skip minor ones).
|
||||
|
||||
# ── Security hardening — usermods (trust-boundary-aware, narrow scope) ───
|
||||
- path: "usermods/**/*.{cpp,h,hpp}"
|
||||
instructions: >
|
||||
For usermods, the untrusted ingress points are:
|
||||
- readFromConfig(JsonObject& root) and calls to getJsonValue()
|
||||
- readFromJsonState(JsonObject& obj) — JSON is parsed, but values are client-supplied
|
||||
- onMqttMessage(char* topic, char* payload) — raw network strings, no core sanitization
|
||||
- onEspNowMessage(uint8_t* sender, uint8_t* payload, uint8_t len) — raw radio bytes
|
||||
- onUdpPacket(uint8_t* payload, size_t len) — raw UDP buffer, no core filtering
|
||||
Values retrieved at these ingress points are considered trusted only after the
|
||||
usermod itself has validated and range-clamped them.
|
||||
|
||||
Flag ONLY downstream uses of ingress-derived values where an out-of-range or
|
||||
unexpected value can cause misbehaviour that is not already guarded, for example:
|
||||
- `switch` statements on an ingress-derived value with no `default` branch,
|
||||
or with a missing `break` where fall-through is unintentional
|
||||
- array or buffer indexing with an ingress-derived value where the index is
|
||||
not clamped before use
|
||||
- arithmetic with an ingress-derived value that can overflow or produce a
|
||||
negative result used as a size or count
|
||||
|
||||
Do NOT flag:
|
||||
- getJsonValue() call sites themselves (type coercion is handled by ArduinoJson)
|
||||
- Internal logic that operates on values already confirmed safe at ingress
|
||||
- Repeated range checks on values that have already been clamped
|
||||
- General memory-safety patterns unrelated to ingress-derived data flow
|
||||
|
||||
- path: ".github/workflows/*.{yml,yaml}"
|
||||
instructions: >
|
||||
@@ -88,8 +164,6 @@ reviews:
|
||||
scoped to least privilege. Never interpolate github.event.* values directly
|
||||
into run: steps — pass them through an env: variable to prevent script
|
||||
injection. Do not use pull_request_target unless fully justified.
|
||||
# disabled - the below instruction has no effect
|
||||
# When initially reviewing a PR, summarize good practices (top 6) and create a prioritized list of suggested improvements.
|
||||
|
||||
- path: "**/*.instructions.md"
|
||||
instructions: |
|
||||
@@ -107,6 +181,73 @@ reviews:
|
||||
3. If new AI-facing rules were added without updating a related HUMAN_ONLY
|
||||
reference section, note this as a suggestion (not a required fix).
|
||||
|
||||
# ── Secrets / sensitive information scanning ────────────────────────────
|
||||
- path: "platformio*.ini*"
|
||||
instructions: >
|
||||
Scan for secrets, passwords, and other sensitive information accidentally
|
||||
committed to PlatformIO configuration files (platformio.ini,
|
||||
platformio_override.ini, platformio_override.ini.sample).
|
||||
|
||||
Flag any of the following:
|
||||
- build_flags entries that define credentials as literal values, e.g.:
|
||||
-DWIFI_SSID=\"<YOUR_SSID>\" -DWIFI_PASS=\"<YOUR_PASSWORD>\"
|
||||
-DOTA_PASS=\"<OTA_PASSWORD>\" -DMQTT_PASS=\"<MQTT_PASSWORD>\"
|
||||
Flag only when the value is not a recognisable placeholder (see below).
|
||||
- upload_flags or upload_port values that embed a password or auth token (e.g., --auth=<PASSWORD> or any URL using credential-bearing userinfo).
|
||||
- Any key = <value> pair whose key name contains "pass", "password",
|
||||
"secret", "token", "key", "credential", or "auth" where the value is
|
||||
a non-empty, non-placeholder literal string.
|
||||
- Hardcoded IP addresses or hostnames paired with credentials in the
|
||||
same environment section.
|
||||
- API keys or access tokens as literal strings in any field.
|
||||
|
||||
Do NOT flag:
|
||||
- Values that are clearly template placeholders (e.g., YOUR_SSID,
|
||||
<YOUR_PASSWORD>, changeme, example_token, your_password_here).
|
||||
- Values that use PlatformIO environment variable substitution (${sysenv.WIFI_PASS} or ${env:WIFI_PASS}).
|
||||
- Comments that only explain what a field should contain.
|
||||
- platformio_override.ini.sample entries that contain only
|
||||
placeholder/example values.
|
||||
|
||||
- path: "usermods/**/library.json"
|
||||
instructions: >
|
||||
Scan for secrets and sensitive information in usermod dependency manifests.
|
||||
|
||||
Flag any of the following:
|
||||
- Dependency URLs that embed credentials in the URL itself (e.g., any URL containing credential-bearing userinfo).
|
||||
- Personal access tokens, OAuth tokens, or API keys as literal strings
|
||||
anywhere in the file.
|
||||
- Values matching well-known secret patterns: GitHub PATs (ghp_...,
|
||||
github_pat_...), AWS access keys (AKIA...), or similarly structured
|
||||
high-entropy tokens.
|
||||
|
||||
Do NOT flag:
|
||||
- Plain HTTPS or SSH URLs without embedded credentials.
|
||||
- Version specifiers, semver ranges, or commit SHA references that
|
||||
contain no credential prefix.
|
||||
- Repository owner/name path segments (not credential material).
|
||||
|
||||
- path: "usermods/**/{readme,README,Readme}.md"
|
||||
instructions: >
|
||||
Scan for secrets, passwords, and sensitive information in usermod
|
||||
documentation files, including inside code blocks, inline code, and prose.
|
||||
|
||||
Flag any of the following:
|
||||
- Hardcoded Wi-Fi SSID or password values that appear to be real (non-placeholder)
|
||||
strings in configuration or installation examples.
|
||||
- Hardcoded OTA, AP, or MQTT passwords in code snippets or step-by-step
|
||||
instructions.
|
||||
- API keys, bearer tokens, or access tokens shown as literal values.
|
||||
- Example platformio_override.ini snippets that contain real-looking
|
||||
credential values instead of placeholders.
|
||||
- Hardcoded IP addresses combined with credentials in the same example.
|
||||
|
||||
Do NOT flag:
|
||||
- Values that are clearly template placeholders (e.g., YOUR_SSID,
|
||||
<password>, my_secret, changeme, ****).
|
||||
- Generic prose describing what a field means without supplying a value.
|
||||
- Asterisk-masked values (e.g., ******, ••••••).
|
||||
|
||||
finishing_touches:
|
||||
# Docstrings | Options for generating Docstrings for your PRs/MRs.
|
||||
docstrings:
|
||||
|
||||
@@ -50,7 +50,7 @@ For detailed build timeouts, development workflows, troubleshooting, and validat
|
||||
main # Main development trunk (daily/nightly) 17.0.0-dev
|
||||
├── V5 # special branch: code rework for esp-idf 5.5.x (unstable)
|
||||
├── V5-C6 # special branch: integration of new MCU types: esp32-c5, esp32-c6, esp32-p4 (unstable)
|
||||
16_x # current beta, preparations for next release 16.0.0
|
||||
16_x # maintenance for release 16.x.y
|
||||
0_15_x # maintenance (bugfixes only) for current release 0.15.4
|
||||
(tag) v0.14.4 # previous version 0.14.4 (no maintenance)
|
||||
(tag) v0.13.3 # old version 0.13.3 (no maintenance)
|
||||
@@ -60,6 +60,7 @@ main # Main development trunk (daily/nightly) 17.0.0-dev
|
||||
|
||||
- ``main``: development trunk (daily/nightly)
|
||||
- ``V5`` and ``V5-C6``: code rework for esp-idf 5.5.x (unstable) - branched from ``main``.
|
||||
- ``16_x``: maintenance for release 16.x.y
|
||||
- ``0_15_x``: bugfixing / maintenance for release 0.15.x
|
||||
|
||||
### Repository Structure
|
||||
@@ -120,20 +121,8 @@ docs/ # Contributor docs, coding guidelines
|
||||
|
||||
Refer to `docs/cpp.instructions.md` and `docs/web.instructions.md` for language-specific conventions, and `docs/cicd.instructions.md` for GitHub Actions workflows.
|
||||
|
||||
### Attribution for AI-generated code
|
||||
Using AI-generated code can hide the source of the inspiration / knowledge / sources it used.
|
||||
- Document attribution of inspiration / knowledge / sources used in the code, e.g. link to GitHub repositories or other websites describing the principles / algorithms used.
|
||||
- When a larger block of code is generated by an AI tool, embed it into `// AI: below section was generated by an AI` ... `// AI: end` comments (see C++ guidelines).
|
||||
- Every non-trivial AI-generated function should have a brief comment describing what it does. Explain parameters when their names alone are not self-explanatory.
|
||||
- AI-generated code must be well documented with meaningful comments that explain intent, assumptions, and non-obvious logic. Do not rephrase source code; explain concepts and reasoning.
|
||||
|
||||
### Pull Request Expectations
|
||||
|
||||
- **No force-push on open PRs.** Once a pull request is open and being reviewed, do not force-push (`git push --force`) to the branch. Force-pushing rewrites history that reviewers may have already commented on, making it impossible to track incremental changes. Use regular commits or `git merge` to incorporate feedback; the branch will be squash-merged when it is accepted.
|
||||
- **Modifications to ``platformio.ini`` MUST be approved explicitly** by a *maintainer* or *WLED organisation Member*. Modifications to the global build environment may break github action builds. Always flag them.
|
||||
- **Document your changes in the PR.** Every pull request should include a clear description of *what* changed and *why*. If the change affects user-visible behavior, describe the expected impact. Link to related issues where applicable. Provide screenshots to showcase new features.
|
||||
|
||||
### Supporting Reviews and Discussions
|
||||
- **For "is it worth doing?" debates** about proposed reliability, safety, or data-integrity mechanisms (CRC checks, backups, power-loss protection): suggest a software **FMEA** (Failure Mode and Effects Analysis).
|
||||
Clarify the main feared events, enumerate failure modes, assess each mitigation's effectiveness per failure mode, note common-cause failures, and rate credibility for the typical WLED use case.
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
# Exclude issues that were closed without resolution from changelog
|
||||
excludeLabels: 'stale,wontfix,duplicate,invalid,external,question,use-as-is,not_planned'
|
||||
- name: Update Nightly Release
|
||||
uses: andelf/nightly-release@main
|
||||
uses: andelf/nightly-release@5834076edc55cc05975561c9722043f072ac5c26
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
|
||||
+106
-10
@@ -4,6 +4,9 @@ on:
|
||||
pull_request:
|
||||
paths:
|
||||
- usermods/**
|
||||
push:
|
||||
paths:
|
||||
- usermods/**
|
||||
|
||||
env:
|
||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
||||
@@ -12,28 +15,40 @@ jobs:
|
||||
|
||||
get_usermod_envs:
|
||||
# Only run for pull requests from forks (not from branches within wled/WLED)
|
||||
if: github.event.pull_request.head.repo.full_name != github.repository
|
||||
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository
|
||||
name: Gather Usermods
|
||||
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
|
||||
fetch-depth: 0
|
||||
- name: Get changed usermod environments
|
||||
id: envs
|
||||
run: |
|
||||
echo "usermods=$(find usermods/ -name library.json | xargs dirname | xargs -n 1 basename | jq -R | grep -v PWM_fan | grep -v BME68X_v2| grep -v pixels_dice_tray | jq --slurp -c)" >> $GITHUB_OUTPUT
|
||||
# Usermods whose directories changed in this PR
|
||||
changed=$(git diff --name-only ${{ github.event.pull_request.base.sha }} HEAD \
|
||||
| grep '^usermods/' | cut -d/ -f2 | sort -u || true)
|
||||
|
||||
# All usermods with a library.json (excluding known-incompatible ones)
|
||||
all=$(find usermods/ -name library.json \
|
||||
| xargs dirname | xargs -n 1 basename \
|
||||
| grep -v PWM_fan | grep -v BME68X_v2 | grep -v pixels_dice_tray \
|
||||
| sort || true)
|
||||
|
||||
if [ -z "$changed" ] || [ -z "$all" ]; then
|
||||
echo "usermods=[]" >> $GITHUB_OUTPUT
|
||||
else
|
||||
usermods=$(comm -12 <(echo "$all") <(echo "$changed") | jq -R | jq --slurp -c)
|
||||
echo "usermods=$usermods" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
outputs:
|
||||
usermods: ${{ steps.envs.outputs.usermods }}
|
||||
|
||||
|
||||
build:
|
||||
# Only run for pull requests from forks (not from branches within wled/WLED)
|
||||
if: github.event.pull_request.head.repo.full_name != github.repository
|
||||
# Skip when no changed usermods were found (e.g. only non-library changes)
|
||||
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository && needs.get_usermod_envs.outputs.usermods != '[]'
|
||||
name: Build Enviornments
|
||||
runs-on: ubuntu-latest
|
||||
needs: get_usermod_envs
|
||||
@@ -74,4 +89,85 @@ jobs:
|
||||
cat platformio_override.ini
|
||||
|
||||
- name: Build firmware
|
||||
run: pio run -e ${{ matrix.environment }}
|
||||
run: pio run -e ${{ matrix.environment }}
|
||||
|
||||
|
||||
get_custom_build_envs:
|
||||
name: Gather Custom Build Environments
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Find usermods with custom build environments
|
||||
id: custom_envs
|
||||
run: |
|
||||
# On PRs: only scan usermods whose directories changed.
|
||||
# On push: scan all usermods (validates the full set on merge).
|
||||
if [ "${{ github.event_name }}" = "pull_request" ]; then
|
||||
changed=$(git diff --name-only ${{ github.event.pull_request.base.sha }} HEAD \
|
||||
| grep '^usermods/' | cut -d/ -f2 | sort -u || true)
|
||||
if [ -z "$changed" ]; then
|
||||
echo "matrix=[]" >> $GITHUB_OUTPUT
|
||||
exit 0
|
||||
fi
|
||||
samples=$(for mod in $changed; do
|
||||
f="usermods/$mod/platformio_override.ini.sample"
|
||||
[ -f "$f" ] && echo "$f"
|
||||
done | sort)
|
||||
else
|
||||
samples=$(find usermods/ -name "platformio_override.ini.sample" | sort)
|
||||
fi
|
||||
|
||||
result='[]'
|
||||
for sample in $samples; do
|
||||
usermod=$(dirname "$sample" | xargs basename)
|
||||
# Skip usermods known to be incompatible (same list as get_usermod_envs)
|
||||
case "$usermod" in PWM_fan|BME68X_v2|pixels_dice_tray) continue ;; esac
|
||||
envs=$(grep -E '^\[env:[^]]+\]' "$sample" | sed 's/^\[env:\(.*\)\]$/\1/')
|
||||
for env in $envs; do
|
||||
result=$(echo "$result" | jq --arg u "$usermod" --arg e "$env" '. + [{usermod: $u, env: $e}]')
|
||||
done
|
||||
done
|
||||
echo "matrix=$(echo "$result" | jq -c '.')" >> $GITHUB_OUTPUT
|
||||
outputs:
|
||||
matrix: ${{ steps.custom_envs.outputs.matrix }}
|
||||
|
||||
|
||||
build_custom:
|
||||
name: Build Custom Env (${{ matrix.usermod }} / ${{ matrix.env }})
|
||||
runs-on: ubuntu-latest
|
||||
needs: get_custom_build_envs
|
||||
if: needs.get_custom_build_envs.outputs.matrix != '[]'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include: ${{ fromJSON(needs.get_custom_build_envs.outputs.matrix) }}
|
||||
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.env }}-${{ hashFiles('platformio.ini', 'pio-scripts/output_bins.py') }}-${{ hashFiles('wled00/**', 'usermods/**') }}
|
||||
restore-keys: pio-${{ runner.os }}-${{ matrix.env }}-${{ 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: Apply custom build environment
|
||||
run: cp -v "usermods/${{ matrix.usermod }}/platformio_override.ini.sample" platformio_override.ini
|
||||
- name: Build firmware
|
||||
run: pio run -e ${{ matrix.env }}
|
||||
|
||||
@@ -4,7 +4,8 @@ WLED is C++ firmware for ESP32/ESP8266 microcontrollers controlling addressable
|
||||
with a web UI (HTML/JS/CSS). Built with PlatformIO (Arduino framework) and Node.js tooling.
|
||||
|
||||
See also: `.github/copilot-instructions.md`, `.github/agent-build.instructions.md`,
|
||||
`docs/cpp.instructions.md`, `docs/web.instructions.md`, `docs/cicd.instructions.md`.
|
||||
`docs/cpp.instructions.md`, `docs/web.instructions.md`, `docs/cicd.instructions.md`,
|
||||
`docs/hardening.instructions.md`, `docs/securecode.instructions.md`.
|
||||
|
||||
Always reference these instructions - including coding guidelines in `docs/` - first and fallback to search or bash commands only when you encounter unexpected information that does not match the info here.
|
||||
|
||||
@@ -27,7 +28,7 @@ required C headers for firmware compilation.
|
||||
Tests use Node.js built-in test runner (`node:test`). The single test file is
|
||||
`tools/cdata-test.js`. Run it with:
|
||||
|
||||
```sh
|
||||
```bash
|
||||
npm test # runs all tests via `node --test`
|
||||
node --test tools/cdata-test.js # run just that file directly
|
||||
```
|
||||
@@ -41,7 +42,7 @@ target environments. Always build after code changes: `pio run -e esp32dev`.
|
||||
|
||||
### Recovery / Troubleshooting
|
||||
|
||||
```sh
|
||||
```bash
|
||||
npm run build -- -f # force web UI rebuild
|
||||
rm -f wled00/html_*.h wled00/js_*.h && npm run build # clean + rebuild UI
|
||||
pio run --target clean # clean PlatformIO build artifacts
|
||||
@@ -50,7 +51,7 @@ rm -rf node_modules && npm ci # reinstall Node.js deps
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
```text
|
||||
wled00/ # Main firmware source (C++)
|
||||
data/ # Web UI source (HTML/JS/CSS) — tabs for indentation
|
||||
html_*.h, js_*.h # Auto-generated (NEVER edit or commit)
|
||||
@@ -132,6 +133,7 @@ main # Main development trunk (daily/nightly) 17.0.0-dev. Target
|
||||
- **Performance**: Prefer DRAM (or IRAM) for hot-path data that is *frequently* used. Prefer PSRAM for capacity-oriented buffers where slightly slower access times can be tolerated.
|
||||
|
||||
Background Info:
|
||||
|
||||
- PSRAM access is up to 18× slower than DRAM on ESP32 (dual-SPI bus), 3–10× slower than DRAM on ESP32-S3/-S2 with quad-SPI bus. On ESP32-S3 with octal PSRAM (`CONFIG_SPIRAM_MODE_OCT`), the penalty is smaller (~2×) because the 8-line DTR bus can transfer 8 bits in parallel. On ESP32-P4 with hex PSRAM (`CONFIG_SPIRAM_MODE_HEX`), the 16-line bus runs at 200 MHz which brings it on-par with DRAM.
|
||||
- Consider that ESP32 often crashes when the largest DRAM chunk gets below 10 KB.
|
||||
|
||||
@@ -158,10 +160,10 @@ Background Info:
|
||||
|
||||
#### ESP32 Task Synchronization
|
||||
|
||||
* Use FreeRTOS mutexes, semaphores or queues when true concurrent access from multiple FreeRTOS tasks is possible, and race-conditions can lead to unexpected behaviour.
|
||||
* **Avoid `portENTER_CRITICAL()` / `portEXIT_CRITICAL()`**, as these functions stall the complete system and may cause LEDs flickering. Prefer FreeRTOS mutexes, semaphores or queues.
|
||||
* **Important**: Not every shared resource needs a mutex. Some synchronization is guaranteed by the overall control flow, for example when function calls are sequenced within the same loop iteration.
|
||||
* Consider RAII as an alternative to mutexes or semaphores.
|
||||
- Use FreeRTOS mutexes, semaphores or queues when true concurrent access from multiple FreeRTOS tasks is possible, and race-conditions can lead to unexpected behaviour.
|
||||
- **Avoid `portENTER_CRITICAL()` / `portEXIT_CRITICAL()`**, as these functions stall the complete system and may cause LEDs flickering. Prefer FreeRTOS mutexes, semaphores or queues.
|
||||
- **Important**: Not every shared resource needs a mutex. Some synchronization is guaranteed by the overall control flow, for example when function calls are sequenced within the same loop iteration.
|
||||
- Consider using `std::atomic` or RAII scoped guards as alternatives to mutexes, semaphores or queues.
|
||||
|
||||
## Web UI Code Style (wled00/data/)
|
||||
|
||||
@@ -181,17 +183,26 @@ class MyUsermod : public Usermod {
|
||||
bool enabled = false;
|
||||
static const char _name[];
|
||||
public:
|
||||
void setup() override { /* ... */ }
|
||||
void loop() override { /* ... */ }
|
||||
void addToConfig(JsonObject& root) override { /* ... */ }
|
||||
bool readFromConfig(JsonObject& root) override { /* ... */ }
|
||||
void setup() override { /* ... */ } // runs once at start-up
|
||||
void loop() override { /* ... */ } // runs once per main loop iteration
|
||||
void addToConfig(JsonObject& root) override { /* ... */ } // create/add persistent settings (usermod settings)
|
||||
bool readFromConfig(JsonObject& root) override { /* ... */ } // read from persistent settings (usermod settings UI)
|
||||
uint16_t getId() override { return USERMOD_ID_MYMOD; }
|
||||
void addToJsonInfo(JsonObject& root) override { /* ... */ } // Add custom items to the "info" page and to /json/info
|
||||
void appendConfigData() override { /* ... */ } // Customize the settings page: dropdowns, checkboxes, extra text, etc. Buffer size is limited!
|
||||
};
|
||||
const char MyUsermod::_name[] PROGMEM = "MyUsermod";
|
||||
static MyUsermod myUsermod;
|
||||
REGISTER_USERMOD(myUsermod);
|
||||
```
|
||||
|
||||
refer to detailed examples in `usermods/EXAMPLE/`, `usermods/user_fx/` and [in the user documentation for custom features](https://kno.wled.ge/advanced/custom-features/).
|
||||
|
||||
- Activate via `custom_usermods = ` in platformio build config. The `usermod_v2_` prefix or `_v2` suffix can be omitted.
|
||||
- Base new usermods on `usermods/EXAMPLE/` (never edit the example directly)
|
||||
- Store repeated strings as `static const char[] PROGMEM`
|
||||
- Add usermod IDs to `wled00/const.h` **only when a unique ID is required** (see below)
|
||||
|
||||
### Usermod IDs
|
||||
|
||||
A unique ID (registered in `wled00/const.h` and overriding `getId()`) is **only required** when a usermod needs one or more of the following:
|
||||
@@ -202,14 +213,18 @@ A unique ID (registered in `wled00/const.h` and overriding `getId()`) is **only
|
||||
|
||||
If none of the above apply, the usermod may omit `getId()` (or return the default `USERMOD_ID_UNSPECIFIED`) and does **not** need an entry in `const.h`.
|
||||
|
||||
- Add usermod IDs to `wled00/const.h` **only when a unique ID is required** (see above)
|
||||
- Activate via `custom_usermods` in platformio build config
|
||||
- Base new usermods on `usermods/EXAMPLE/` (never edit the example directly)
|
||||
- Store repeated strings as `static const char[] PROGMEM`
|
||||
### Usermod `loop()`
|
||||
|
||||
- Called once per main loop iteration. Usermods should simply `return` when `!enabled`.
|
||||
- Frequency of calls varies with system load:
|
||||
* up to 2000 times/sec with few LEDs and little background activity,
|
||||
* between 20 and 300 times/second during high workload from effects and other usermods,
|
||||
* (worst case) down to 1-3 times/sec during FS activity or when serving lots of network API requests.
|
||||
|
||||
## CI/CD
|
||||
|
||||
CI runs on every push/PR via GitHub Actions (`.github/workflows/wled-ci.yml`):
|
||||
|
||||
1. `npm test` (web UI build validation)
|
||||
2. Firmware compilation for all default environments (~22 targets)
|
||||
3. Post-link validation of usermod linkage (`validate_modules.py`)
|
||||
@@ -218,7 +233,7 @@ No automated linting is configured. Match existing code style in files you edit.
|
||||
|
||||
## General Rules
|
||||
|
||||
- Repository language is English.
|
||||
- Important: Repository language is **English**. This applies to source code (including comments), commit messages and any kind of documentation for developer or users.
|
||||
- The `docs/` folder is for developer/contributor information (coding conventions, architecture, etc.). User documentation is maintained in the [wled/WLED-Docs](https://github.com/wled/WLED-Docs) repository.
|
||||
- Never edit or commit auto-generated `wled00/html_*.h` / `wled00/js_*.h`.
|
||||
- When updating an existing PR, retain the original description. Only modify it to ensure technical accuracy. Add change logs after the existing description.
|
||||
@@ -228,3 +243,25 @@ No automated linting is configured. Match existing code style in files you edit.
|
||||
- Remove dead/unused code — justify or delete it.
|
||||
- Verify feature-flag spelling exactly (misspellings are silently ignored by preprocessor).
|
||||
- Provide references when making analyses or recommendations. Support factual claims with verifiable citations, references or concrete evidence; **never fabricate citations**.
|
||||
- **Highlight user-visible breaking changes and ripple effects** during reviews. Ask for confirmation that these were introduced intentionally.
|
||||
|
||||
### Security Hardening
|
||||
|
||||
When writing or reviewing code in `wled00/`, `usermods/`, `wled00/data/`, or `.github/workflows/`,
|
||||
consult `docs/hardening.instructions.md` (concise checklist) and `docs/securecode.instructions.md` (detailed rules with examples).
|
||||
These files define WLED's threat model, trust boundary model, and WLED-specific constraints (no TLS baseline, no UDP authentication for protocol-defined
|
||||
multicast/broadcast, firewall-isolated deployment assumed).
|
||||
|
||||
### Attribution for AI-generated code
|
||||
|
||||
Using AI-generated code can hide the source of the inspiration / knowledge / sources it used.
|
||||
|
||||
- Document attribution of inspiration / knowledge / sources used in the code, e.g. link to GitHub repositories or other websites describing the principles / algorithms used.
|
||||
- When a larger block of code is generated by an AI tool, embed it into `// AI: below section was generated by an AI` ... `// AI: end` comments (see Comments section).
|
||||
- Every non-trivial AI-generated function should have a brief comment describing what it does. Explain parameters when their names alone are not self-explanatory.
|
||||
- AI-generated code must be well documented with meaningful comments that explain intent, assumptions, and non-obvious logic. Do not rephrase source code; explain concepts and reasoning.
|
||||
|
||||
### Supporting Reviews and Discussions
|
||||
|
||||
- **For "is it worth doing?" debates** about proposed reliability, safety, or data-integrity mechanisms (CRC checks, backups, power-loss protection): suggest a software **FMEA** (Failure Mode and Effects Analysis).
|
||||
Clarify the main feared events, enumerate failure modes, assess each mitigation's effectiveness per failure mode, note common-cause failures, and rate credibility for the typical WLED use case.
|
||||
|
||||
+2
-4
@@ -10,8 +10,8 @@ We'll work with you to refine your contribution, but we'll also push back if som
|
||||
Here are a few suggestions to make it easier for you to contribute:
|
||||
|
||||
### Important Developer Infos
|
||||
* [Project Structure, Files and Directories](.github/copilot-instructions.md#project-structure-overview) (in our AI instructions)
|
||||
* [Instructions for creating usermods](.github/copilot-instructions.md#usermod-guidelines) (in our AI instructions)
|
||||
* [Project Structure, Files and Directories](AGENTS.md#project-structure) (in our AI instructions)
|
||||
* [Instructions for creating usermods](AGENTS.md#usermod-pattern) (in our AI instructions)
|
||||
* KB: [Compiling WLED](https://kno.wled.ge/advanced/compiling-wled/) - slightly outdated but still helpful :-)
|
||||
* Arduino IDE is not supported any more. Use VSCode with the PlatformIO extension.
|
||||
* [Compiling in VSCode/Platformio](https://github.com/wled/WLED-Docs/issues/161) - modern way without command line or platformio.ini changes.
|
||||
@@ -141,8 +141,6 @@ Sometimes you might hit merge conflicts with `main` that are harder to solve. He
|
||||
### Additional Resources
|
||||
Want to know more? Check out:
|
||||
- 📚 [GitHub Desktop documentation](https://docs.github.com/en/desktop) - if you prefer GUI tools
|
||||
- 🎓 [How to properly submit a PR](https://github.com/wled-dev/WLED/wiki/How-to-properly-submit-a-PR) - detailed tips and tricks
|
||||
|
||||
|
||||
## After Approval
|
||||
Once approved, a maintainer will merge your PR (possibly squashing commits).
|
||||
|
||||
@@ -515,6 +515,8 @@ void myTask(void*) {
|
||||
|
||||
- **LittleFS filenames**: File paths passed to `file.open()` must not exceed 255 bytes (`LFS_NAME_MAX`). Validate constructed paths (e.g., `/ledmap_` + segment name + `.json`) stay within this limit (assume standard configurations, like WLED_MAX_SEGNAME_LEN = 64).
|
||||
|
||||
- In C/C++, additive operators (`+`, `-`) have HIGHER precedence than shift operators (`<<`, `>>`). Therefore `x - edge0 << 8` correctly parses as `(x - edge0) << 8`. Do NOT flag this pattern as a precedence bug. When reviewing WLED fixed-point code or any C/C++ shift expressions, verify against cppreference before claiming precedence issues with mixed `-`/`+` and `<<`/`>>` expressions.
|
||||
|
||||
- **Float-to-unsigned conversion is undefined behavior when the value is out of range.** Converting a negative `float` directly to an unsigned integer type (`uint8_t`, `uint16_t`, …) is UB per the C++ standard — the Xtensa (ESP32) toolchain may silently wrap, but RISC-V (ESP32-C3/C5/C6/P4) can produce different results due to clamping. Cast through a signed integer first:
|
||||
```cpp
|
||||
// Undefined behavior — avoid:
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
---
|
||||
applyTo: "**/*.{cpp,h,hpp,ino,js,htm,html,css,yml,yaml}"
|
||||
description: "WLED strict-mode security review: low-noise checklist."
|
||||
---
|
||||
|
||||
# WLED Security Review — Low Noise Mode
|
||||
|
||||
Use these code hardening rules for automated reviews with minimal false positives.
|
||||
|
||||
## WLED Constraints (apply to all rules)
|
||||
|
||||
- Assume firewall/DMZ/VPN deployment; focus on realistic LAN-local and supply-chain risks.
|
||||
- Do **not** require TLS/HTTPS as a baseline control.
|
||||
- Do **not** require authentication for standards-based UDP multicast/broadcast paths where authentication is not defined in the protocol specification.
|
||||
|
||||
> **Trust boundary model**: Apply input-validation rules **only at the first untrusted ingress point**
|
||||
> (HTTP/JSON API body or query string, WebSocket payload, UDP datagram, TCP read, serial command, ESP-NOW raw messages).
|
||||
> Values that have been validated and range-clamped at ingress are **trusted** for internal WLED
|
||||
> processing. Do not flag subsequent uses or internal copies of already-sanitized data.
|
||||
|
||||
## CRITICAL Rules
|
||||
|
||||
1. **No unchecked buffer copies** (`memcpy`, `memmove`, `strcpy`) in firmware paths when source buffer or size comes from an untrusted origin; prefer bounded alternatives (`strncpy`, `strlcpy`); require length validation before copying.
|
||||
2. **No user-controlled format strings** in `DEBUG_PRINTF*` and similar logging APIs.
|
||||
3. **Validate all untrusted external input** (HTTP/JSON/UDP/serial) before index/length/pin usage.
|
||||
4. **Auth required for state-changing control endpoints where feasible** (for example HTTP/JSON); do not flag protocol-defined unauthenticated UDP multicast/broadcast channels solely for missing auth.
|
||||
5. **No fail-open on parse/allocation errors** for config/state updates.
|
||||
6. **No DOM XSS sinks with untrusted data** (`innerHTML`, unsafe HTML insertion). Server-side generation of JavaScript property-assignment statements (as used in WLED's printSetForm* helpers) is exempt.
|
||||
7. **No dynamic code execution** (`eval`, `new Function`, string timers).
|
||||
8. **No hardcoded secrets/credentials/tokens/keys** in committed files.
|
||||
9. **No sensitive data in logs** (passwords, tokens, Wi-Fi secrets, auth headers).
|
||||
10. **No secret exposure in workflows/log output, or in LittleFS files other than `wsec.json`**.
|
||||
11. **No unsafe third-party GitHub Action pinning** (`@main`/`@master` disallowed).
|
||||
12. **No untrusted expression interpolation in workflow shell commands**.
|
||||
|
||||
## IMPORTANT Rules
|
||||
|
||||
13. Avoid potentially unbounded string/memory operations (`strcmp`, `strchr`, `strlen`, `sprintf`) in firmware paths; prefer bounded alternatives (`strnlen`, `strncmp`, `snprintf`).
|
||||
14. Check integer overflow risks in size/index arithmetic, but consider that unsigned wrap-around on small types might be intentional.
|
||||
15. Reject repeated heap allocation churn in hot render/effect loops.
|
||||
16. Avoid repeated `String` growth in hot paths; prefer bounded/pre-allocated buffers.
|
||||
17. Ensure UI validation is mirrored by firmware-side validation.
|
||||
18. Require strict origin checks for `postMessage` listeners.
|
||||
19. Disallow untrusted redirect/navigation targets.
|
||||
20. Prevent verbose error responses that leak internals.
|
||||
21. Review new dependencies for typosquatting and known vulnerability risk.
|
||||
22. Keep workflow `permissions` least-privilege.
|
||||
23. Verify new `WLED_ENABLE_*` / `WLED_DISABLE_*` names are valid known flags.
|
||||
24. New privileged behavior must not be enabled by insecure defaults; first-use default-credential change required where applicable.
|
||||
25. OTA paths (Update.begin(), Update.write()) must verify firmware integrity (checksum/hash); TLS not required.
|
||||
26. Flag xTaskCreate/xTaskCreatePinnedToCore tasks with insufficient stack for String/JSON use; flag MDNS.begin() / ArduinoOTA.setHostname() with unsanitized hostnames.
|
||||
27. Flag API/config serialization that exposes Wi-Fi/AP/MQTT password fields to unauthenticated clients.
|
||||
28. Treat fetched and config-derived strings as untrusted when inserting into the DOM; explicit sanitization required for HTML contexts.
|
||||
|
||||
## Reviewer Output Format
|
||||
|
||||
- Include severity, exact file and line, and one concrete fix direction.
|
||||
- Prioritize CRITICAL findings before IMPORTANT findings.
|
||||
@@ -0,0 +1,227 @@
|
||||
---
|
||||
applyTo: "**/*.{cpp,h,hpp,ino,js,htm,html,css,yml,yaml}"
|
||||
description: "WLED-focused security review guide based on OWASP Top 10 for embedded firmware and web UI."
|
||||
---
|
||||
|
||||
# WLED Security Review Standards (Embedded + Web UI)
|
||||
|
||||
Use this guide for AI-assisted code reviews in:
|
||||
- `wled00/`
|
||||
- `usermods/`
|
||||
- `.github/workflows/`
|
||||
|
||||
## WLED Constraints and Threat Model Assumptions
|
||||
|
||||
- Assume typical deployment behind a firewall/DMZ/VPN; prioritize LAN-local and supply-chain risks.
|
||||
- Do **not** require TLS/HTTPS as a baseline control for findings in this repo.
|
||||
- Do **not** require authentication for standards-based UDP multicast/broadcast protocols where auth is not part of the spec.
|
||||
- Do not propose mitigations that break protocol compliance just to add authentication.
|
||||
|
||||
### Trust Boundary Model
|
||||
|
||||
**Untrusted data** enters WLED only at the following explicit ingress points:
|
||||
- HTTP/JSON API request bodies and query parameters (e.g., `/json/*`, `/win`)
|
||||
- WebSocket message payloads
|
||||
- UDP datagrams (`parsePacket()` / `recvfrom()` and higher-level protocol wrappers)
|
||||
- TCP socket reads
|
||||
- Serial/UART input used as commands
|
||||
- ESP-NOW raw messages input
|
||||
|
||||
**Validation and range-clamping applied at the ingress point renders data trusted** for all subsequent use within the WLED core.
|
||||
|
||||
**Do not flag:**
|
||||
- Repeated bounds or range checks on a value that has already been validated and clamped at its ingress handler.
|
||||
- Internal WLED core logic that operates on values confirmed safe by the ingress layer.
|
||||
|
||||
If it is unclear whether a value has been sanitized upstream (e.g., passed through multiple function calls without a clear annotation), prefer asking for clarification over raising a false-positive finding.
|
||||
|
||||
### Locally-Stored Configuration Files (Robustness, not a primary trust boundary)
|
||||
|
||||
Files read from LittleFS (`presets.json`, `cfg.json`, `ledmap.json`, `ir.json`, etc.) are written only via privileged access (`/edit`) and are considered trusted in the threat model.
|
||||
However, parse them defensively (validate structure, clamp array sizes, handle missing keys gracefully) to avoid bootloops from filesystem corruption or accidental malformation.
|
||||
|
||||
## Severity
|
||||
|
||||
- **CRITICAL** — exploitable vulnerability; block merge.
|
||||
- **IMPORTANT** — meaningful risk; fix before or with merge when practical.
|
||||
- **SUGGESTION** — defense-in-depth; track for follow-up.
|
||||
|
||||
## Scope (WLED-relevant)
|
||||
|
||||
Prioritize:
|
||||
- C++ memory safety and input validation
|
||||
- Auth and access checks for state-changing HTTP/JSON APIs
|
||||
- XSS and DOM safety in `wled00/data/*`
|
||||
- Secrets handling (`wsec.json`) and secure logging
|
||||
- Dependency and GitHub Actions supply-chain hygiene
|
||||
- Fail-safe behavior on constrained devices
|
||||
|
||||
De-prioritize unless explicitly introduced by a PR:
|
||||
- SQL/NoSQL checks, JWT/OAuth flows, GraphQL-specific checks, generic backend framework checks not used by WLED.
|
||||
|
||||
## Firmware Security (C++, OWASP A01/A04/A05/A10)
|
||||
|
||||
### FW1: Unsafe buffer operations
|
||||
- **Severity**: CRITICAL
|
||||
- Flag `strcpy`, `sprintf`, unchecked memory access (`memcpy`, `memmove`, `memcmp`, `strcmp`, `strlen`), unchecked pointer arithmetic.
|
||||
- Require explicit bounds checks and length validation.
|
||||
- Prefer bounded alternatives for string operations (`strnlen`, `strncmp`, `strncpy`, `strlcpy`, `snprintf`).
|
||||
- Treat a finding against FW1 as **suggestion** only when the operation is provably bounded
|
||||
and both the destination capacity and copied/compared length are known safe.
|
||||
|
||||
### FW2: Format-string injection
|
||||
- **Severity**: CRITICAL
|
||||
- Do not pass untrusted input as a format string to `DEBUG_PRINTF*` or similar APIs.
|
||||
|
||||
### FW3: Integer overflow in length and offset math
|
||||
- **Severity**: IMPORTANT
|
||||
- Review `count * size`, index math, narrowing casts before allocations or copies.
|
||||
|
||||
### FW4: Unvalidated external input
|
||||
- **Severity**: CRITICAL
|
||||
- At each **untrusted ingress point** (see Trust Boundary Model above), validate and clamp values from HTTP/JSON/UDP/serial before use as lengths, indices, IDs, or pin references.
|
||||
- Do not flag repeated range checks on values that have already been validated at their ingress point.
|
||||
- In UDP handlers (`parsePacket()`, `read()`, and any lower-level socket wrappers), validate `packetSize` before buffer writes and clamp protocol-specific universe/channel ranges to valid limits.
|
||||
|
||||
### FW5: Missing auth checks on state-changing endpoints (where auth is feasible)
|
||||
- **Severity**: CRITICAL
|
||||
- HTTP/JSON and other control paths that support auth must enforce configured auth policy.
|
||||
- Do not flag the HTTP endpoint `/reset` as state-changing. This endpoint triggers a reboot, causing a short interruption without loss of user data.
|
||||
- Do not flag standards-based UDP multicast/broadcast paths solely for lacking authentication when authentication is not defined in the protocol specification.
|
||||
|
||||
### FW6: Fail-open behavior after parse or allocation errors
|
||||
- **Severity**: IMPORTANT
|
||||
- On error, reject update and preserve safe previous state.
|
||||
- Explicitly check parse status (`DeserializationError error = deserializeJson(...); if (error) return/reject;`) and avoid silently applying unsafe zero/default values to safety-relevant fields (for example LED count and pin assignment).
|
||||
|
||||
### FW7: Heap churn in hot paths
|
||||
- **Severity**: IMPORTANT
|
||||
- Avoid repeated dynamic allocation in render/effect loops; prefer pre-allocation and reuse.
|
||||
- Flag allocation patterns in loop and ISR-adjacent paths that can trigger fragmentation or timing instability.
|
||||
|
||||
### FW8: Unsafe use of `String` in performance-critical paths
|
||||
- **Severity**: IMPORTANT
|
||||
- In hot paths, avoid repeated `String` growth; reserve or use fixed buffers.
|
||||
- Flag repeated `String` concatenation inside loop-heavy or ISR-adjacent code.
|
||||
|
||||
### FW9: Unsafe feature flag names
|
||||
- **Severity**: IMPORTANT
|
||||
- Verify all new `WLED_ENABLE_*`/`WLED_DISABLE_*` names are valid known flags; typos silently alter build behavior.
|
||||
|
||||
### FW10: OTA integrity verification (without TLS requirement)
|
||||
- **Severity**: IMPORTANT
|
||||
- OTA update flows should validate firmware integrity using the checksum/hash/signature mechanism available in the firmware/platform implementation.
|
||||
- Do not require TLS/certificate pinning as a mandatory review criterion.
|
||||
- In OTA paths (`Update.begin()`, `Update.write()`, and related flows), flag flashing without integrity verification.
|
||||
|
||||
### FW11: FreeRTOS task stack and recursion safety
|
||||
- **Severity**: IMPORTANT
|
||||
- In `xTaskCreate`/`xTaskCreatePinnedToCore` tasks that process `String`/JSON-heavy data, verify stack-size sufficiency and avoid unbounded recursion.
|
||||
|
||||
### FW12: mDNS and hostname sanitization
|
||||
- **Severity**: IMPORTANT
|
||||
- For `MDNS.begin()`, `MDNS.addService()`, and `ArduinoOTA.setHostname()`, ensure user-provided hostnames are RFC-compliant (letters/digits/hyphen, no leading/trailing hyphen) and clamped to 63 characters.
|
||||
|
||||
### FW13: Outbound URL validation (no HTTPS requirement)
|
||||
- **Severity**: SUGGESTION
|
||||
- When using user-provided URL strings with `HTTPClient.begin()`/equivalent, validate scheme/format and constrain host targets (allowlist or equivalent policy).
|
||||
- Do not require HTTPS/TLS as a baseline review rule.
|
||||
|
||||
### FW14: Optional unicast UDP source filtering
|
||||
- **Severity**: SUGGESTION
|
||||
- For unicast UDP receive paths, prefer optional user-configurable source filtering.
|
||||
- Do not require this for multicast/broadcast protocol flows.
|
||||
|
||||
## Web UI Security (`wled00/data/*`, OWASP A01/A02/A05)
|
||||
|
||||
### WEB1: DOM XSS through `innerHTML`
|
||||
- **Severity**: CRITICAL
|
||||
- Prefer `textContent`; if HTML is required, sanitize trusted content path explicitly.
|
||||
|
||||
### WEB2: Dynamic code execution
|
||||
- **Severity**: CRITICAL
|
||||
- Reject `eval`, `new Function`, and string-based timer execution.
|
||||
|
||||
### WEB3: `postMessage` without origin validation
|
||||
- **Severity**: IMPORTANT
|
||||
- Require strict origin allowlist checks before processing payloads.
|
||||
|
||||
### WEB4: Unsafe redirects/navigation
|
||||
- **Severity**: IMPORTANT
|
||||
- Do not navigate directly from untrusted query/input without relative-path or allowlist checks.
|
||||
|
||||
### WEB5: Client-only validation
|
||||
- **Severity**: IMPORTANT
|
||||
- UI validation is not sufficient; equivalent firmware-side validation is required.
|
||||
|
||||
### WEB6: Direct DOM insertion from fetched/config data
|
||||
- **Severity**: IMPORTANT
|
||||
- Treat fetched and config-derived strings as untrusted unless proven otherwise.
|
||||
|
||||
### WEB7: CSRF checks for state-changing HTTP routes (advisory)
|
||||
- **Severity**: SUGGESTION
|
||||
- For state-changing HTTP routes (for example `/json/state`, `/win`), prefer `Origin`/`Referer` header validation as low-cost defense-in-depth for deployments that are not directly internet-exposed.
|
||||
- Treat this as advisory only, since some legitimate clients may omit these headers.
|
||||
|
||||
## Secrets and Logging (OWASP A04/A09/A10)
|
||||
|
||||
### SEC1: Hardcoded secrets and credentials
|
||||
- **Severity**: CRITICAL
|
||||
- Reject committed API keys, passwords, tokens, private keys, or test backdoors with potential security impact.
|
||||
|
||||
### SEC2: Sensitive values in logs
|
||||
- **Severity**: CRITICAL
|
||||
- Do not log passwords, tokens, Wi-Fi keys, auth headers, or full sensitive payloads.
|
||||
|
||||
### SEC3: Insecure defaults
|
||||
- **Severity**: IMPORTANT
|
||||
- Reject new default credentials or insecure auto-enable behavior for privileged functions.
|
||||
- For setup/onboarding flows, require first-change behavior for default credentials where applicable.
|
||||
|
||||
### SEC4: Overly detailed error responses
|
||||
- **Severity**: IMPORTANT
|
||||
- Avoid exposing stack traces or internal details to API/UI consumers.
|
||||
|
||||
### SEC5: Credential exposure in API/config responses
|
||||
- **Severity**: IMPORTANT
|
||||
- Flag API/config serialization that exposes password-like fields (for example Wi-Fi/AP/MQTT passwords) to unauthenticated or untrusted clients.
|
||||
|
||||
### SEC6: Security-relevant event logging coverage
|
||||
- **Severity**: SUGGESTION
|
||||
- Prefer explicit logging for auth failures, OTA attempts, config resets, and AP activation events, without logging secret values.
|
||||
|
||||
## Supply Chain and CI/CD (OWASP A03/A08)
|
||||
|
||||
### SC1: New dependency risk
|
||||
- **Severity**: IMPORTANT
|
||||
- Review new npm/pip/PlatformIO dependencies for legitimacy, pinning, and known vulnerabilities.
|
||||
|
||||
### SC2: Workflow permission hardening regressions
|
||||
- **Severity**: IMPORTANT
|
||||
- Check for broad `permissions`, unpinned third-party actions, or unsafe secret exposure.
|
||||
- Flag mutable third-party action refs (`@main`, `@master`, broad tags) where SHA pinning is expected by project policy.
|
||||
- Flag overly broad permissions such as `write-all` without clear need.
|
||||
|
||||
### SC3: Script injection in workflows
|
||||
- **Severity**: IMPORTANT
|
||||
- Avoid direct interpolation of untrusted `${{ github.event.* }}` values in `run` commands.
|
||||
|
||||
## Reviewer Checklist
|
||||
|
||||
- [ ] No new memory-safety hazards (bounds, overflow, unsafe copies/format strings)
|
||||
- [ ] External input is validated and range-clamped at ingress points (HTTP/JSON, WebSocket, UDP, TCP, serial, ESP-NOW)
|
||||
- [ ] State-changing API paths enforce auth policy
|
||||
- [ ] OTA paths enforce integrity verification (without requiring TLS baseline)
|
||||
- [ ] Suggested rule patterns are checked where relevant (UDP bounds, hostname sanitization, workflow pinning/permissions)
|
||||
- [ ] Web UI changes avoid unsafe DOM execution/injection patterns
|
||||
- [ ] No secrets added; no sensitive logging introduced
|
||||
- [ ] Error handling remains fail-safe and non-leaky
|
||||
- [ ] Dependency/workflow changes are supply-chain safe
|
||||
- [ ] Feature-flag names are valid and not typoed
|
||||
|
||||
## AI Review Behavior
|
||||
|
||||
- Prefer concrete, file/line-specific findings over generic guidance.
|
||||
- Prioritize **CRITICAL** and **IMPORTANT** findings.
|
||||
- Skip irrelevant framework checks not used by WLED.
|
||||
- If control-flow trust is unclear, ask for clarification instead of guessing.
|
||||
@@ -298,8 +298,18 @@ 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.
|
||||
|
||||
;; tasmota platform (default)
|
||||
platform = https://github.com/tasmota/platform-espressif32/releases/download/2024.06.00/platform-espressif32.zip ;; Tasmota Arduino Core 2.0.18 with IPv6 support, based on IDF 4.4.8
|
||||
platform_packages =
|
||||
|
||||
;; espressif platform (optional - needs 300KB extra flash)
|
||||
;;; arduino-esp32 2.0.17 + esp-idf 4.4.7
|
||||
;; platform = espressif32@ ~6.13.0
|
||||
;; platform_packages =
|
||||
;;; arduino-esp32 2.0.14 + esp-idf 4.4.6
|
||||
;; platform = espressif32@ ~6.6.0
|
||||
;; platform_packages = platformio/framework-arduinoespressif32 @ 3.20014.231204
|
||||
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = -g
|
||||
-Wshadow=compatible-local ;; emit warning in case a local variable "shadows" another local one
|
||||
@@ -720,6 +730,7 @@ board_build.partitions = ${esp32.extreme_partitions} ; We're gonna need a bigge
|
||||
;; Core HUB75 flags - common to every HUB75 build
|
||||
build_flags =
|
||||
-D WLED_ENABLE_HUB75MATRIX -D NO_GFX
|
||||
-D NO_CIE1931 ;; disable driver-internal gamma correction
|
||||
-D WLED_DEBUG_BUS
|
||||
-D LED_TYPES=TYPE_HUB75MATRIX_HS
|
||||
; -D WLED_DEBUG
|
||||
@@ -779,6 +790,21 @@ lib_deps = ${esp32s3.lib_deps}
|
||||
${hub75.lib_deps}
|
||||
;; board_build.partitions = tools/partitions-8MB_spiffs-tinyuf2.csv ;; supports adafruit UF2 bootloader
|
||||
|
||||
[env:waveshare_esp32s3_32MB_hub75]
|
||||
;; Waveshare ESP32-S3-RGB-Matrix (memory_type: opi_opi); see https://docs.waveshare.com/ESP32-S3-RGB-Matrix
|
||||
extends = env:esp32S3_wroom2_32MB
|
||||
monitor_filters = esp32_exception_decoder
|
||||
build_unflags = ${env:esp32S3_wroom2_32MB.build_unflags}
|
||||
-D WLED_RELEASE_NAME=\"ESP32-S3_WROOM-2_32MB\" ;; need to un-set the relese name before setting a new one
|
||||
build_flags = ${common.build_flags} ${esp32s3.build_flags} ${hub75.build_flags} ${hub75.s3_build_flags} ${hub75.i2s_disable_flags}
|
||||
-D WLED_RELEASE_NAME=\"ESP32-S3_Waveshare_HUB75\"
|
||||
-D WAVESHARE_S3_PINOUT
|
||||
; -D WLED_USE_SD_SPI
|
||||
; -D SD_PRINT_HOME_DIR
|
||||
; -D WLED_DEBUG
|
||||
lib_deps = ${esp32s3.lib_deps}
|
||||
${hub75.lib_deps}
|
||||
|
||||
[env:esp32s3dev_16MB_opi_hub75]
|
||||
;; MOONHUB HUB75 adapter board (lilygo T7-S3 with 16MB flash and octal PSRAM)
|
||||
extends = env:esp32s3dev_8MB_opi
|
||||
|
||||
@@ -33,7 +33,12 @@ 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.
|
||||
;
|
||||
; *** Note: on adding custom usermods
|
||||
; custom_usermods entries are a separate key in the env section (not inside build_flags). Place them on their own line in the env.
|
||||
; Multiple usermods are separated by a space, the names can be found in the library.json file of the usermod.
|
||||
; Example: use the default usermods from the esp32dev env and add the Temperature and four_line_display_ALT usermods
|
||||
; custom_usermods = ${env:esp32dev.custom_usermods} Temperature four_line_display_ALT
|
||||
;
|
||||
; Set a release name that may be used to distinguish required binary for flashing
|
||||
; -D WLED_RELEASE_NAME=\"ESP32_MULTI_USREMODS\"
|
||||
;
|
||||
@@ -98,17 +103,17 @@ build_flags = ${common.build_flags} ${esp8266.build_flags}
|
||||
; -D WLED_DEBUG_PORT=7868
|
||||
;
|
||||
; Use Autosave usermod and set it to do save after 90s
|
||||
; -D USERMOD_AUTO_SAVE
|
||||
; custom_usermods = ${env:esp32dev.custom_usermods} auto_save
|
||||
; -D AUTOSAVE_AFTER_SEC=90
|
||||
;
|
||||
; Use AHT10/AHT15/AHT20 usermod
|
||||
; -D USERMOD_AHT10
|
||||
; custom_usermods = ${env:esp32dev.custom_usermods} AHT10_v2
|
||||
;
|
||||
; Use INA226 usermod
|
||||
; -D USERMOD_INA226
|
||||
; custom_usermods = ${env:esp32dev.custom_usermods} INA226_v2
|
||||
;
|
||||
; Use 4 Line Display usermod with SPI display
|
||||
; -D USERMOD_FOUR_LINE_DISPLAY
|
||||
; custom_usermods = ${env:esp32dev.custom_usermods} four_line_display_ALT
|
||||
; -DFLD_SPI_DEFAULT
|
||||
; -D FLD_TYPE=SSD1306_SPI64
|
||||
; -D FLD_PIN_CLOCKSPI=14
|
||||
@@ -118,22 +123,22 @@ build_flags = ${common.build_flags} ${esp8266.build_flags}
|
||||
; -D FLD_PIN_RESET=27
|
||||
;
|
||||
; Use Rotary encoder usermod (in conjunction with 4LD)
|
||||
; -D USERMOD_ROTARY_ENCODER_UI
|
||||
; custom_usermods = ${env:esp32dev.custom_usermods} rotary_encoder_ui_ALT
|
||||
; -D ENCODER_DT_PIN=5
|
||||
; -D ENCODER_CLK_PIN=18
|
||||
; -D ENCODER_SW_PIN=19
|
||||
;
|
||||
; Use Dallas DS18B20 temperature sensor usermod and configure it to use GPIO13
|
||||
; -D USERMOD_DALLASTEMPERATURE
|
||||
; custom_usermods = ${env:esp32dev.custom_usermods} Temperature
|
||||
; -D TEMPERATURE_PIN=13
|
||||
;
|
||||
; Use Multi Relay usermod and configure it to use 6 relays and appropriate GPIO
|
||||
; -D USERMOD_MULTI_RELAY
|
||||
; custom_usermods = ${env:esp32dev.custom_usermods} multi_relay
|
||||
; -D MULTI_RELAY_MAX_RELAYS=6
|
||||
; -D MULTI_RELAY_PINS=12,23,22,21,24,25
|
||||
;
|
||||
; Use PIR sensor usermod and configure it to use GPIO4 and timer of 60s
|
||||
; -D USERMOD_PIRSWITCH
|
||||
; custom_usermods = ${env:esp32dev.custom_usermods} PIR_sensor_switch
|
||||
; -D PIR_SENSOR_PIN=4 # use -1 to disable usermod
|
||||
; -D PIR_SENSOR_OFF_SEC=60
|
||||
; -D PIR_SENSOR_MAX_SENSORS=2 # max allowable sensors (uses OR logic for triggering)
|
||||
@@ -146,12 +151,12 @@ build_flags = ${common.build_flags} ${esp8266.build_flags}
|
||||
; -D I2S_CKPIN=19
|
||||
;
|
||||
; Use PWM fan usermod
|
||||
; -D USERMOD_PWM_FAN
|
||||
; custom_usermods = ${env:esp32dev.custom_usermods} PWM_fan
|
||||
; -D TACHO_PIN=33
|
||||
; -D PWM_PIN=32
|
||||
;
|
||||
; Use POV Display usermod
|
||||
; -D USERMOD_POV_DISPLAY
|
||||
; custom_usermods = ${env:esp32dev.custom_usermods} pov_display
|
||||
; Use built-in or custom LED as a status indicator (assumes LED is connected to GPIO16)
|
||||
; -D STATUSLED=16
|
||||
;
|
||||
@@ -375,6 +380,7 @@ board_upload.maximum_size = 2097152
|
||||
extends = esp32 ;; use default esp32 platform
|
||||
board = esp32dev
|
||||
upload_speed = 460800
|
||||
custom_usermods = ${env:esp32dev.custom_usermods} Temperature four_line_display_ALT
|
||||
build_flags = ${common.build_flags} ${esp32.build_flags}
|
||||
-D WLED_RELEASE_NAME=\"ESP32_wemos_shield\"
|
||||
-D DATA_PINS=16
|
||||
@@ -382,12 +388,8 @@ build_flags = ${common.build_flags} ${esp32.build_flags}
|
||||
-D BTNPIN=17
|
||||
-D IRPIN=18
|
||||
-UWLED_USE_MY_CONFIG
|
||||
-D USERMOD_DALLASTEMPERATURE
|
||||
-D USERMOD_FOUR_LINE_DISPLAY
|
||||
-D TEMPERATURE_PIN=23
|
||||
lib_deps = ${esp32.lib_deps}
|
||||
OneWire@~2.3.5 ;; needed for USERMOD_DALLASTEMPERATURE
|
||||
olikraus/U8g2 @ ^2.28.8 ;; needed for USERMOD_FOUR_LINE_DISPLAY
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
|
||||
[env:esp32_pico-D4]
|
||||
@@ -478,7 +480,8 @@ platform = ${esp8266.platform_wled_default}
|
||||
platform_packages = ${esp8266.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_1m128k}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_DISABLE_OTA -D USERMOD_MY9291
|
||||
custom_usermods = ${env:esp01_1m_full.custom_usermods} MY9291
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_DISABLE_OTA
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
@@ -506,42 +509,15 @@ lib_deps = ${esp8266.lib_deps}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# EleksTube-IPS
|
||||
# See usermods/EleksTube_IPS/platformio_override.ini.sample
|
||||
# ------------------------------------------------------------------------------
|
||||
[env:elekstube_ips]
|
||||
extends = esp32 ;; use default esp32 platform
|
||||
board = esp32dev
|
||||
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 DATA_PINS=12
|
||||
-D RLYPIN=27
|
||||
-D BTNPIN=34
|
||||
-D PIXEL_COUNTS=6
|
||||
# Display config
|
||||
-D ST7789_DRIVER
|
||||
-D TFT_WIDTH=135
|
||||
-D TFT_HEIGHT=240
|
||||
-D CGRAM_OFFSET
|
||||
-D TFT_SDA_READ
|
||||
-D TFT_MOSI=23
|
||||
-D TFT_SCLK=18
|
||||
-D TFT_DC=25
|
||||
-D TFT_RST=26
|
||||
-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
|
||||
custom_usermods =
|
||||
${env:esp32dev.custom_usermods}
|
||||
RF433
|
||||
# 433MHz RF remote example: see usermods/usermod_v2_RF433/platformio_override.ini.sample
|
||||
|
||||
# External usermod from a git repository.
|
||||
# The library's `library.json` must include `"build": {"libArchive": false}`.
|
||||
|
||||
@@ -7,81 +7,97 @@
|
||||
<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>
|
||||
|
||||
</p>
|
||||
</p>
|
||||
|
||||
# Welcome to 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 firmware for ESP32 microcontrollers to control addressable LEDs — from simple strips to large 2D matrices and HUB75 panels.
|
||||
|
||||
Originally created by [Aircoookie](https://github.com/Aircoookie)
|
||||
Originally created by [Aircoookie](https://github.com/Aircoookie), now maintained by a community of contributors.
|
||||
|
||||
## ⚙️ Features
|
||||
- WS2812FX library with more than 100 special effects
|
||||
- FastLED noise effects and 50 palettes
|
||||
- Modern UI with color, effect and segment controls
|
||||
- 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
|
||||
- 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
|
||||
- Nightlight function (gradually dims down)
|
||||
- Full OTA software updateability (HTTP + ArduinoOTA), password protectable
|
||||
- Configurable analog clock (Cronixie, 7-segment and EleksTube IPS clock support via usermods)
|
||||
- Configurable Auto Brightness limit for safe operation
|
||||
- Filesystem-based config for easier backup of presets and settings
|
||||
|
||||
## 💡 Supported light control interfaces
|
||||
- WLED app for [Android](https://play.google.com/store/apps/details?id=ca.cgagnier.wlednativeandroid) and [iOS](https://apps.apple.com/gb/app/wled-native/id6446207239)
|
||||
- JSON and HTTP request APIs
|
||||
- MQTT
|
||||
- E1.31, Art-Net, DDP and TPM2.net
|
||||
- [diyHue](https://github.com/diyhue/diyHue) (Wled is supported by diyHue, including Hue Sync Entertainment under udp. Thanks to [Gregory Mallios](https://github.com/gmallios))
|
||||
- [Hyperion](https://github.com/hyperion-project/hyperion.ng)
|
||||
- UDP realtime
|
||||
- Alexa voice control (including dimming and color)
|
||||
- Sync to Philips hue lights
|
||||
- Adalight (PC ambilight via serial) and TPM2
|
||||
- Sync color of multiple WLED devices (UDP notifier)
|
||||
- Infrared remotes (24-key RGB, receiver required)
|
||||
- Simple timers/schedules (time from NTP, timezones/DST supported)
|
||||
### Effects & Visuals
|
||||
- [**200+ built-in effects**](https://kno.wled.ge/features/effects/) including classic animations, audio-reactive, and 2D/matrix effects
|
||||
- [50+ color palettes](https://kno.wled.ge/features/palettes/) plus a built-in **custom palette editor** (PixelForge)
|
||||
- [**2D LED matrix support**](https://kno.wled.ge/advanced/mapping/) with dedicated 2D effects and flexible panel mapping
|
||||
- [**HUB75 RGB matrix panel support**](https://kno.wled.ge/advanced/HUB75/) (ESP32)
|
||||
- [**AudioReactive**](https://kno.wled.ge/advanced/audio-reactive/) effects — included by default, responding to sound via microphone, line-in, or network audio source
|
||||
- Effect blending for smooth transitions between animations
|
||||
- Antialiased drawing functions for smooth graphics
|
||||
|
||||
### Segments & Control
|
||||
- [**Segments**](https://kno.wled.ge/features/segments/) — apply different effects, colors and palettes to independent parts of your LED setup simultaneously
|
||||
- Up to **250 presets** to save and recall colors, effects and segment configurations — supports [playlists](https://kno.wled.ge/features/presets/) for automated cycling
|
||||
- Nightlight function with configurable dimming curve
|
||||
- Configurable **Auto Brightness Limiter** (per output) for safe operation
|
||||
|
||||
### Hardware Support
|
||||
- **ESP32** (all variants: original, S2, S3, C3)
|
||||
- [**Up to 17 LED outputs**](https://kno.wled.ge/features/multi-strip/) on ESP32 using parallel I2S + RMT
|
||||
- [Addressable LED support](https://kno.wled.ge/basics/compatible-led-strips/): WS2812B, WS2811, WS2815, SK6812, WS2805, TM1914, APA102, WS2801, LPD8806, and many more
|
||||
- RGBW, [RGB+CCT](https://kno.wled.ge/features/cct/) and white-only strips
|
||||
- PWM outputs for analog LEDs and dimmers
|
||||
- [**Ethernet** support](https://kno.wled.ge/features/ethernet-lan/) for a wide range of boards (QuinLED, LILYGO, Olimex, and more)
|
||||
- Filesystem-based config for easy backup and restore of presets and settings
|
||||
- Full OTA firmware updates (HTTP + ArduinoOTA), password-protectable
|
||||
|
||||
### Connectivity & Integrations
|
||||
- **WLED app** for [Android](https://play.google.com/store/apps/details?id=ca.cgagnier.wlednativeandroid) and [iOS](https://apps.apple.com/gb/app/wled-native/id6446207239)
|
||||
- [JSON](https://kno.wled.ge/interfaces/json-api/) and [HTTP request](https://kno.wled.ge/interfaces/http-api/) APIs
|
||||
- **Multi-WiFi** — connect to up to 3 networks with automatic AP fallback
|
||||
- **ESP-NOW** wireless sync between devices (no WiFi router required)
|
||||
- [**MQTT**](https://kno.wled.ge/interfaces/mqtt/) with Home Assistant discovery
|
||||
- [**E1.31, Art-Net**](https://kno.wled.ge/interfaces/e1.31-dmx/), [DDP](https://kno.wled.ge/interfaces/ddp/) and [TPM2.net](https://kno.wled.ge/interfaces/udp-realtime/) for DMX/professional lighting control
|
||||
- [UDP realtime sync](https://kno.wled.ge/interfaces/udp-notifier/) across multiple WLED devices
|
||||
- Alexa voice control (on/off, brightness, color)
|
||||
- [Philips Hue sync](https://kno.wled.ge/interfaces/philips-hue/)
|
||||
- [diyHue](https://github.com/diyhue/diyHue) and [Hyperion](https://github.com/hyperion-project/hyperion.ng) integration
|
||||
- [Adalight / TPM2](https://kno.wled.ge/interfaces/serial/) (PC ambilight via serial)
|
||||
- [Infrared remote control](https://kno.wled.ge/interfaces/infrared/) (24-key RGB, receiver required)
|
||||
- Timers and schedules (NTP time sync, full timezone and DST support)
|
||||
|
||||
### Developer-Friendly
|
||||
- **Usermod system** — extend WLED with community or custom modules without modifying core code
|
||||
- Large and active [usermod library](https://kno.wled.ge/advanced/community-usermods/) including AudioReactive, temperature sensors, rotary encoders, displays, and much more
|
||||
- Well-documented [JSON API](https://kno.wled.ge/interfaces/json-api/)
|
||||
- Licensed under the **EUPL v1.2**
|
||||
|
||||
## 📲 Quick start guide and documentation
|
||||
|
||||
See the [documentation on our official site](https://kno.wled.ge)!
|
||||
See the [documentation at kno.wled.ge](https://kno.wled.ge)!
|
||||
|
||||
[On this page](https://kno.wled.ge/basics/tutorials/) you can find excellent tutorials and tools to help you get your new project up and running!
|
||||
[Tutorials and getting-started guides](https://kno.wled.ge/basics/tutorials/) to help you get your project running quickly.
|
||||
|
||||
## 🖼️ User interface
|
||||
|
||||
<img src="/images/macbook-pro-space-gray-on-the-wooden-table.jpg" width="50%"><img src="/images/walking-with-iphone-x.jpg" width="50%">
|
||||
|
||||
## 💾 Compatible hardware
|
||||
|
||||
See [here](https://kno.wled.ge/basics/compatible-hardware)!
|
||||
See the [compatible hardware list](https://kno.wled.ge/basics/compatible-hardware) on the wiki.
|
||||
|
||||
## ✌️ Other
|
||||
|
||||
Licensed under the EUPL v1.2 license
|
||||
Credits [here](https://kno.wled.ge/about/contributors/)!
|
||||
CORS proxy by [Corsfix](https://corsfix.com/)
|
||||
Licensed under the [EUPL v1.2](https://raw.githubusercontent.com/wled-dev/WLED/main/LICENSE).
|
||||
Credits to all [contributors](https://kno.wled.ge/about/contributors/)!
|
||||
CORS proxy by [Corsfix](https://corsfix.com/).
|
||||
|
||||
Join the Discord server to discuss everything about WLED!
|
||||
|
||||
<a href="https://discord.gg/QAh7wJHrRM"><img src="https://discordapp.com/api/guilds/473448917040758787/widget.png?style=banner2" width="25%"></a>
|
||||
|
||||
Check out the WLED [Discourse forum](https://wled.discourse.group)!
|
||||
Check out the WLED [Discourse forum](https://wled.discourse.group)!
|
||||
|
||||
You can also send me mails to [dev.aircoookie@gmail.com](mailto:dev.aircoookie@gmail.com), but please, only do so if you want to talk to me privately.
|
||||
If you'd like to reach the original creator privately: [dev.aircoookie@gmail.com](mailto:dev.aircoookie@gmail.com).
|
||||
|
||||
If WLED really brightens up your day, you can [](https://paypal.me/aircoookie)
|
||||
If WLED brightens up your day, you can [send a gift to Aircoookie via PayPal](https://paypal.me/aircoookie).
|
||||
|
||||
---
|
||||
|
||||
*Disclaimer:*
|
||||
*Disclaimer:*
|
||||
|
||||
If you are prone to photosensitive epilepsy, we recommended you do **not** use this software.
|
||||
If you still want to try, don't use strobe, lighting or noise modes or high effect speed settings.
|
||||
|
||||
As per the EUPL license, I assume no liability for any damage to you or any other person or equipment.
|
||||
If you are prone to photosensitive epilepsy, we recommend you do **not** use this software.
|
||||
If you still want to try, avoid strobe, lightning or noise modes and high effect speed settings.
|
||||
|
||||
As per the EUPL license, no liability is assumed for any damage to you or any other person or equipment.
|
||||
|
||||
@@ -28,18 +28,19 @@ class ADS1115Usermod : public Usermod {
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (isEnabled && millis() - lastTime > loopInterval) {
|
||||
lastTime = millis();
|
||||
if (!isEnabled || strip.isUpdating() || millis() - lastTime <= loopInterval)
|
||||
return;
|
||||
|
||||
// If we don't have new data, skip this iteration.
|
||||
if (!ads.conversionComplete()) {
|
||||
return;
|
||||
}
|
||||
lastTime = millis();
|
||||
|
||||
updateResult();
|
||||
moveToNextChannel();
|
||||
startReading();
|
||||
// If we don't have new data, skip this iteration.
|
||||
if (!ads.conversionComplete()) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateResult();
|
||||
moveToNextChannel();
|
||||
startReading();
|
||||
}
|
||||
|
||||
void addToJsonInfo(JsonObject& root)
|
||||
@@ -69,6 +70,8 @@ class ADS1115Usermod : public Usermod {
|
||||
{
|
||||
JsonObject top = root.createNestedObject(F("ADC ADS1115"));
|
||||
|
||||
top[F("Loop Interval")] = loopInterval;
|
||||
|
||||
for (uint8_t i = 0; i < channelsCount; i++) {
|
||||
ChannelSettings* settingsPtr = &(channelSettings[i]);
|
||||
JsonObject channel = top.createNestedObject(settingsPtr->settingName);
|
||||
@@ -79,8 +82,6 @@ class ADS1115Usermod : public Usermod {
|
||||
channel[F("Offset")] = settingsPtr->offset;
|
||||
channel[F("Decimals")] = settingsPtr->decimals;
|
||||
}
|
||||
|
||||
top[F("Loop Interval")] = loopInterval;
|
||||
}
|
||||
|
||||
bool readFromConfig(JsonObject& root)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "ADS1115_v2",
|
||||
"build": { "libArchive": false },
|
||||
"dependencies": {
|
||||
"Adafruit BusIO": "https://github.com/adafruit/Adafruit_BusIO#1.13.2",
|
||||
"Adafruit ADS1X15": "https://github.com/adafruit/Adafruit_ADS1X15#2.4.0"
|
||||
"Adafruit BusIO": "https://github.com/adafruit/Adafruit_BusIO#1.17.4",
|
||||
"Adafruit ADS1X15": "https://github.com/adafruit/Adafruit_ADS1X15#2.6.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,29 @@
|
||||
# ADS1115 16-Bit ADC with four inputs
|
||||
# ADS1115 Usermod
|
||||
|
||||
This usermod will read from an ADS1115 ADC. The voltages are displayed in the Info section of the web UI.
|
||||
Reads values from an ADS1115 16-bit ADC and exposes them in the `Info` tab.
|
||||
|
||||
Configuration is performed via the Usermod menu. There are no parameters to set in code!
|
||||
## Features
|
||||
- Reads values from an ADS1115 over I2C.
|
||||
- Supports 8 ADS1115 input modes:
|
||||
- 4 single-ended inputs (`AIN0` to `AIN3`)
|
||||
- 4 differential pairs (`AIN0-AIN1`, `AIN0-AIN3`, `AIN1-AIN3`, `AIN2-AIN3`)
|
||||
- Per-channel configuration in the Usermod settings:
|
||||
- Enable/disable
|
||||
- Display name
|
||||
- Units
|
||||
- Multiplier and offset
|
||||
- Decimal precision
|
||||
- Configurable measurement loop interval.
|
||||
- Publishes configured channel values to the `Info` tab.
|
||||
|
||||
## Installation
|
||||
## Compatibility
|
||||
- Requires an ADS1115 module connected via I2C.
|
||||
- Works on targets with I2C support.
|
||||
- Default ADC gain is `1x` (input range `+/-4.096V`).
|
||||
|
||||
Add 'ADS1115' to `custom_usermods` in your platformio environment.
|
||||
## Installation
|
||||
- Add `ADS1115` to `custom_usermods` in your `platformio.ini` (or `platformio_override.ini`).
|
||||
|
||||
## Author
|
||||
- Dima Zhemkov [@dima-zhemkov](https://github.com/dima-zhemkov)
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
[env:aht10_example]
|
||||
extends = env:esp32dev
|
||||
build_flags =
|
||||
${common.build_flags} ${esp32.build_flags}
|
||||
; -D USERMOD_AHT10_DEBUG ; -- add a debug status to the info modal
|
||||
@@ -25,6 +25,8 @@ class Animated_Staircase : public Usermod {
|
||||
unsigned int topMaxDist = 50; // default maximum measured distance in cm, top
|
||||
unsigned int bottomMaxDist = 50; // default maximum measured distance in cm, bottom
|
||||
bool togglePower = false; // toggle power on/off with staircase on/off
|
||||
bool topAPinInvert = false; // invert output of top sensor
|
||||
bool bottomAPinInvert = false; // invert output of bottom sensor
|
||||
|
||||
/* runtime variables */
|
||||
bool initDone = false;
|
||||
@@ -91,6 +93,8 @@ class Animated_Staircase : public Usermod {
|
||||
static const char _topEchoCm[];
|
||||
static const char _bottomEchoCm[];
|
||||
static const char _togglePower[];
|
||||
static const char _topPIRorTrigger_pin_invert[];
|
||||
static const char _bottomPIRorTrigger_pin_invert[];
|
||||
|
||||
void publishMqtt(bool bottom, const char* state) {
|
||||
#ifndef WLED_DISABLE_MQTT
|
||||
@@ -156,6 +160,12 @@ class Animated_Staircase : public Usermod {
|
||||
return pulseIn(echoPin, HIGH, maxTimeUs) > 0;
|
||||
}
|
||||
|
||||
bool readPIRPin(int8_t pin, bool invert) {
|
||||
if (pin < 0) return false;
|
||||
bool v = digitalRead(pin);
|
||||
return invert ? !v : v;
|
||||
}
|
||||
|
||||
bool checkSensors() {
|
||||
bool sensorChanged = false;
|
||||
|
||||
@@ -164,15 +174,15 @@ class Animated_Staircase : public Usermod {
|
||||
|
||||
bottomSensorRead = bottomSensorWrite ||
|
||||
(!useUSSensorBottom ?
|
||||
(bottomPIRorTriggerPin<0 ? false : digitalRead(bottomPIRorTriggerPin)) :
|
||||
(bottomPIRorTriggerPin<0 ? false : readPIRPin(bottomPIRorTriggerPin, bottomAPinInvert)) :
|
||||
ultrasoundRead(bottomPIRorTriggerPin, bottomEchoPin, bottomMaxDist*59) // cm to us
|
||||
);
|
||||
topSensorRead = topSensorWrite ||
|
||||
(!useUSSensorTop ?
|
||||
(topPIRorTriggerPin<0 ? false : digitalRead(topPIRorTriggerPin)) :
|
||||
(topPIRorTriggerPin<0 ? false : readPIRPin(topPIRorTriggerPin, topAPinInvert)) :
|
||||
ultrasoundRead(topPIRorTriggerPin, topEchoPin, topMaxDist*59) // cm to us
|
||||
);
|
||||
|
||||
|
||||
if (bottomSensorRead != bottomSensorState) {
|
||||
bottomSensorState = bottomSensorRead; // change previous state
|
||||
sensorChanged = true;
|
||||
@@ -439,18 +449,20 @@ class Animated_Staircase : public Usermod {
|
||||
if (staircase.isNull()) {
|
||||
staircase = root.createNestedObject(FPSTR(_name));
|
||||
}
|
||||
staircase[FPSTR(_enabled)] = enabled;
|
||||
staircase[FPSTR(_segmentDelay)] = segment_delay_ms;
|
||||
staircase[FPSTR(_onTime)] = on_time_ms / 1000;
|
||||
staircase[FPSTR(_useTopUltrasoundSensor)] = useUSSensorTop;
|
||||
staircase[FPSTR(_topPIRorTrigger_pin)] = topPIRorTriggerPin;
|
||||
staircase[FPSTR(_topEcho_pin)] = useUSSensorTop ? topEchoPin : -1;
|
||||
staircase[FPSTR(_useBottomUltrasoundSensor)] = useUSSensorBottom;
|
||||
staircase[FPSTR(_bottomPIRorTrigger_pin)] = bottomPIRorTriggerPin;
|
||||
staircase[FPSTR(_bottomEcho_pin)] = useUSSensorBottom ? bottomEchoPin : -1;
|
||||
staircase[FPSTR(_topEchoCm)] = topMaxDist;
|
||||
staircase[FPSTR(_bottomEchoCm)] = bottomMaxDist;
|
||||
staircase[FPSTR(_togglePower)] = togglePower;
|
||||
staircase[FPSTR(_enabled)] = enabled;
|
||||
staircase[FPSTR(_segmentDelay)] = segment_delay_ms;
|
||||
staircase[FPSTR(_onTime)] = on_time_ms / 1000;
|
||||
staircase[FPSTR(_useTopUltrasoundSensor)] = useUSSensorTop;
|
||||
staircase[FPSTR(_topPIRorTrigger_pin)] = topPIRorTriggerPin;
|
||||
staircase[FPSTR(_topEcho_pin)] = useUSSensorTop ? topEchoPin : -1;
|
||||
staircase[FPSTR(_useBottomUltrasoundSensor)] = useUSSensorBottom;
|
||||
staircase[FPSTR(_bottomPIRorTrigger_pin)] = bottomPIRorTriggerPin;
|
||||
staircase[FPSTR(_bottomEcho_pin)] = useUSSensorBottom ? bottomEchoPin : -1;
|
||||
staircase[FPSTR(_topEchoCm)] = topMaxDist;
|
||||
staircase[FPSTR(_bottomEchoCm)] = bottomMaxDist;
|
||||
staircase[FPSTR(_togglePower)] = togglePower;
|
||||
staircase[FPSTR(_topPIRorTrigger_pin_invert)] = topAPinInvert;
|
||||
staircase[FPSTR(_bottomPIRorTrigger_pin_invert)] = bottomAPinInvert;
|
||||
DEBUG_PRINTLN(F("Staircase config saved."));
|
||||
}
|
||||
|
||||
@@ -462,11 +474,13 @@ class Animated_Staircase : public Usermod {
|
||||
bool readFromConfig(JsonObject& root) {
|
||||
bool oldUseUSSensorTop = useUSSensorTop;
|
||||
bool oldUseUSSensorBottom = useUSSensorBottom;
|
||||
bool oldTopAPinInvert = topAPinInvert;
|
||||
bool oldBottomAPinInvert = bottomAPinInvert;
|
||||
int8_t oldTopAPin = topPIRorTriggerPin;
|
||||
int8_t oldTopBPin = topEchoPin;
|
||||
int8_t oldBottomAPin = bottomPIRorTriggerPin;
|
||||
int8_t oldBottomBPin = bottomEchoPin;
|
||||
|
||||
|
||||
JsonObject top = root[FPSTR(_name)];
|
||||
if (top.isNull()) {
|
||||
DEBUG_PRINT(FPSTR(_name));
|
||||
@@ -485,10 +499,12 @@ class Animated_Staircase : public Usermod {
|
||||
useUSSensorTop = top[FPSTR(_useTopUltrasoundSensor)] | useUSSensorTop;
|
||||
topPIRorTriggerPin = top[FPSTR(_topPIRorTrigger_pin)] | topPIRorTriggerPin;
|
||||
topEchoPin = top[FPSTR(_topEcho_pin)] | topEchoPin;
|
||||
|
||||
topAPinInvert = top[FPSTR(_topPIRorTrigger_pin_invert)] | topAPinInvert;
|
||||
|
||||
useUSSensorBottom = top[FPSTR(_useBottomUltrasoundSensor)] | useUSSensorBottom;
|
||||
bottomPIRorTriggerPin = top[FPSTR(_bottomPIRorTrigger_pin)] | bottomPIRorTriggerPin;
|
||||
bottomEchoPin = top[FPSTR(_bottomEcho_pin)] | bottomEchoPin;
|
||||
bottomAPinInvert = top[FPSTR(_bottomPIRorTrigger_pin_invert)] | bottomAPinInvert;
|
||||
|
||||
topMaxDist = top[FPSTR(_topEchoCm)] | topMaxDist;
|
||||
topMaxDist = min(150,max(30,(int)topMaxDist)); // max distance ~1.5m (a lag of 9ms may be expected)
|
||||
@@ -554,14 +570,15 @@ const char Animated_Staircase::_segmentDelay[] PROGMEM = "segment-d
|
||||
const char Animated_Staircase::_onTime[] PROGMEM = "on-time-s";
|
||||
const char Animated_Staircase::_useTopUltrasoundSensor[] PROGMEM = "useTopUltrasoundSensor";
|
||||
const char Animated_Staircase::_topPIRorTrigger_pin[] PROGMEM = "topPIRorTrigger_pin";
|
||||
const char Animated_Staircase::_topPIRorTrigger_pin_invert[] PROGMEM = "topPIRorTrigger_pin_invert";
|
||||
const char Animated_Staircase::_topEcho_pin[] PROGMEM = "topEcho_pin";
|
||||
const char Animated_Staircase::_useBottomUltrasoundSensor[] PROGMEM = "useBottomUltrasoundSensor";
|
||||
const char Animated_Staircase::_bottomPIRorTrigger_pin[] PROGMEM = "bottomPIRorTrigger_pin";
|
||||
const char Animated_Staircase::_bottomPIRorTrigger_pin_invert[] PROGMEM = "bottomPIRorTrigger_pin_invert";
|
||||
const char Animated_Staircase::_bottomEcho_pin[] PROGMEM = "bottomEcho_pin";
|
||||
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);
|
||||
@@ -8,13 +8,13 @@
|
||||
; USERMOD_DHT_MQTT - publish measurements to the MQTT broker
|
||||
; USERMOD_DHT_STATS - For debug, report delay stats
|
||||
|
||||
[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
|
||||
[env:esp8266_2m_usermod_dht_C]
|
||||
extends = env:esp8266_2m
|
||||
custom_usermods = ${env:esp8266_2m.custom_usermods} DHT
|
||||
build_flags = ${env:esp8266_2m.build_flags} -D USERMOD_DHT_CELSIUS
|
||||
|
||||
[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
|
||||
[env:esp32dev_LEDPIN_16_usermod_dht_C]
|
||||
extends = env:esp32dev
|
||||
custom_usermods = ${env:esp32dev.custom_usermods} DHT
|
||||
build_flags = ${env:esp32dev.build_flags} -D LEDPIN=16 -D USERMOD_DHT_CELSIUS -D USERMOD_DHT_STATS
|
||||
|
||||
@@ -114,7 +114,7 @@ class MyExampleUsermod : public Usermod {
|
||||
void loop() override {
|
||||
// if usermod is disabled or called during strip updating just exit
|
||||
// NOTE: on very long strips strip.isUpdating() may always return true so update accordingly
|
||||
if (!enabled || strip.isUpdating()) return;
|
||||
if (!enabled || (strip.isUpdating() && (millis() - lastTime < 200))) return; // adjust "200" (in millisecond) to your needs - prevents starvation with very long strips
|
||||
|
||||
// do your magic here
|
||||
if (millis() - lastTime > 1000) {
|
||||
@@ -176,7 +176,7 @@ class MyExampleUsermod : public Usermod {
|
||||
JsonObject usermod = root[FPSTR(_name)];
|
||||
if (!usermod.isNull()) {
|
||||
// expect JSON usermod data in usermod name object: {"ExampleUsermod:{"user0":10}"}
|
||||
userVar0 = usermod["user0"] | userVar0; //if "user0" key exists in JSON, update, else keep old value
|
||||
userVar0 = usermod["user0"] | userVar0; //if "user0" key exists in JSON, update, else keep old value (userVar0 is defined in wled.h)
|
||||
}
|
||||
// you can as well check WLED state JSON keys
|
||||
//if (root["bri"] == 255) Serial.println(F("Don't burn down your garage!"));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name:": "EleksTube_IPS",
|
||||
"name": "EleksTube_IPS",
|
||||
"build": { "libArchive": false },
|
||||
"dependencies": {
|
||||
"TFT_eSPI" : "2.5.33"
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
[env:ina226_example]
|
||||
extends = env:esp32dev
|
||||
custom_usermods = ${env:esp32dev.custom_usermods} INA226_v2
|
||||
build_flags =
|
||||
${env:esp32dev.build_flags}
|
||||
; -D USERMOD_INA226_DEBUG ; -- add a debug status to the info modal
|
||||
+6
-6
@@ -1,6 +1,5 @@
|
||||
; Options
|
||||
; -------
|
||||
; USERMOD_SN_PHOTORESISTOR - define this to have this user mod included wled00\usermods_list.cpp
|
||||
; USERMOD_SN_PHOTORESISTOR_MEASUREMENT_INTERVAL - the number of milliseconds between measurements, defaults to 60 seconds
|
||||
; USERMOD_SN_PHOTORESISTOR_FIRST_MEASUREMENT_AT - the number of milliseconds after boot to take first measurement, defaults to 20 seconds
|
||||
; USERMOD_SN_PHOTORESISTOR_REFERENCE_VOLTAGE - the voltage supplied to the sensor, defaults to 5v
|
||||
@@ -8,9 +7,10 @@
|
||||
; USERMOD_SN_PHOTORESISTOR_RESISTOR_VALUE - the resistor size, defaults to 10000.0 (10K hms)
|
||||
; USERMOD_SN_PHOTORESISTOR_OFFSET_VALUE - the offset value to report on, defaults to 25
|
||||
;
|
||||
[env:usermod_sn_photoresistor_d1_mini]
|
||||
extends = env:d1_mini
|
||||
[env:usermod_sn_photoresistor_esp8266_2m]
|
||||
extends = env:esp8266_2m
|
||||
custom_usermods = ${env:esp8266_2m.custom_usermods} SN_Photoresistor
|
||||
build_flags =
|
||||
${common.build_flags_esp8266}
|
||||
-D USERMOD_SN_PHOTORESISTOR
|
||||
lib_deps = ${env.lib_deps}
|
||||
${env:esp8266_2m.build_flags}
|
||||
-D USERMOD_SN_PHOTORESISTOR_MEASUREMENT_INTERVAL=60
|
||||
lib_deps = ${env:esp8266_2m.lib_deps}
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"name:": "ST7789_display",
|
||||
"name": "ST7789_display",
|
||||
"build": { "libArchive": false }
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
[env:esp32dev]
|
||||
build_flags = ${common.build_flags_esp32}
|
||||
; PIN defines - uncomment and change, if needed:
|
||||
; -D LEDPIN=2
|
||||
-D BTNPIN=35
|
||||
; -D IRPIN=4
|
||||
; -D RLYPIN=12
|
||||
; -D RLYMDE=1
|
||||
@@ -1,5 +0,0 @@
|
||||
; Options
|
||||
; -------
|
||||
; USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL - the number of milliseconds between measurements, defaults to 60 seconds
|
||||
;
|
||||
|
||||
@@ -13,7 +13,7 @@ board_build.partitions = ${esp32.large_partitions}
|
||||
board_build.f_flash = 80000000L
|
||||
board_build.flash_mode = qio
|
||||
monitor_filters = esp32_exception_decoder
|
||||
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=T-QT-PRO-8MB
|
||||
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"T-QT-PRO-8MB_dice\"
|
||||
-D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0
|
||||
-D ARDUINO_USB_CDC_ON_BOOT=1 -D ARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB")
|
||||
|
||||
@@ -75,7 +75,7 @@ board_build.partitions = ${esp32.large_partitions}
|
||||
board_build.f_flash = 80000000L
|
||||
board_build.flash_mode = qio
|
||||
monitor_filters = esp32_exception_decoder
|
||||
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=ESP32-S3_8MB_qspi
|
||||
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_8MB_qspi_dice\"
|
||||
-D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0
|
||||
-D ARDUINO_USB_CDC_ON_BOOT=1 -D ARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB")
|
||||
|
||||
@@ -105,7 +105,7 @@ lib_deps = ${esp32s3.lib_deps}
|
||||
# https://github.com/wled-dev/WLED/issues/1382
|
||||
; [env:esp32dev_dice]
|
||||
; extends = env:esp32dev
|
||||
; build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=ESP32
|
||||
; build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"ESP32_dice\"
|
||||
; ; Enable Pixels dice mod
|
||||
; -D USERMOD_PIXELS_DICE_TRAY
|
||||
; lib_deps = ${esp32.lib_deps}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name:": "pov_display",
|
||||
"name": "pov_display",
|
||||
"build": { "libArchive": false},
|
||||
"platforms": ["espressif32"]
|
||||
}
|
||||
|
||||
@@ -143,7 +143,13 @@ void ShtUsermod::appendDeviceToMqttDiscoveryMessage(JsonDocument& root) {
|
||||
device[F("ids")] = escapedMac.c_str();
|
||||
device[F("name")] = serverDescription;
|
||||
device[F("sw")] = versionString;
|
||||
// AI: below section was generated by an AI
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
device[F("mdl")] = ESP.getChipModel();
|
||||
#else
|
||||
device[F("mdl")] = F("ESP8266");
|
||||
#endif
|
||||
// AI: end
|
||||
device[F("mf")] = F("espressif");
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -2,10 +2,10 @@
|
||||
default_envs = esp32dev_fld
|
||||
|
||||
[env:esp32dev_fld]
|
||||
extends = env:esp32dev_V4
|
||||
custom_usermods = ${env:esp32dev_V4.custom_usermods} four_line_display_ALT
|
||||
extends = env:esp32dev
|
||||
custom_usermods = ${env:esp32dev.custom_usermods} four_line_display_ALT
|
||||
build_flags =
|
||||
${env:esp32dev_V4.build_flags}
|
||||
${env:esp32dev.build_flags}
|
||||
-D FLD_TYPE=SH1106
|
||||
-D I2CSCLPIN=27
|
||||
-D I2CSDAPIN=26
|
||||
+3
-3
@@ -2,10 +2,10 @@
|
||||
default_envs = esp32dev_re
|
||||
|
||||
[env:esp32dev_re]
|
||||
extends = env:esp32dev_V4
|
||||
custom_usermods = ${env:esp32dev_V4.custom_usermods} rotary_encoder_ui_ALT
|
||||
extends = env:esp32dev
|
||||
custom_usermods = ${env:esp32dev.custom_usermods} rotary_encoder_ui_ALT
|
||||
build_flags =
|
||||
${env:esp32dev_V4.build_flags}
|
||||
${env:esp32dev.build_flags}
|
||||
-D USERMOD_ROTARY_ENCODER_GPIO=INPUT
|
||||
-D ENCODER_DT_PIN=21
|
||||
-D ENCODER_CLK_PIN=23
|
||||
+1
-1
@@ -1117,7 +1117,7 @@ void Segment::blur(uint8_t blur_amount, bool smear) const {
|
||||
* Rotates the color in HSV space, where pos is H. (0=0deg, 256=360deg)
|
||||
*/
|
||||
uint32_t Segment::color_wheel(uint8_t pos) const {
|
||||
if (palette) return color_from_palette(pos, false, false, 0); // only wrap if "always wrap" is set
|
||||
if (palette) return color_from_palette(pos, false, true, 0); // color_wheel is a continuous (moving) wheel, so wrap end->start (restores pre-0.16 behaviour)
|
||||
uint8_t w = W(getCurrentColor(0));
|
||||
CRGBW rgb;
|
||||
rgb = CHSV32(static_cast<uint16_t>(pos << 8), 255, 255);
|
||||
|
||||
+17
-6
@@ -813,6 +813,7 @@ BusHub75Matrix::BusHub75Matrix(const BusConfig &bc) : Bus(bc.type, bc.start, bc.
|
||||
|
||||
// mxconfig.driver = HUB75_I2S_CFG::ICN2038S; // experimental - use specific shift register driver
|
||||
// mxconfig.driver = HUB75_I2S_CFG::FM6124; // try this driver in case you panel stays dark, or when colors look too pastel
|
||||
// Other possible shiftreg drivers: HUB75_I2S_CFG::FM6126A, HUB75_I2S_CFG::ICN2038S, HUB75_I2S_CFG::MBI5124, HUB75_I2S_CFG::DP3246
|
||||
|
||||
// mxconfig.latch_blanking = 3;
|
||||
// mxconfig.i2sspeed = HUB75_I2S_CFG::HZ_10M; // experimental - 5MHZ should be enugh, but colours looks slightly better at 10MHz
|
||||
@@ -824,8 +825,13 @@ BusHub75Matrix::BusHub75Matrix(const BusConfig &bc) : Bus(bc.type, bc.start, bc.
|
||||
mxconfig.chain_length = max((uint8_t) 1, min(chainLength, (uint8_t) 4));
|
||||
|
||||
if (mxconfig.mx_height >= 64 && (mxconfig.chain_length > 1)) {
|
||||
DEBUGBUS_PRINTLN(F("WARNING, only single panel can be used of 64 pixel boards due to memory"));
|
||||
mxconfig.chain_length = 1;
|
||||
#if defined(BOARD_HAS_PSRAM) // limitation to one panel only applies to boards without PSRAM
|
||||
if (!psramFound() || ESP.getPsramSize() == 0) // PSRAM sanity check
|
||||
#endif
|
||||
{
|
||||
DEBUGBUS_PRINTLN(F("WARNING, only single panel can be used of 64 pixel boards due to memory"));
|
||||
mxconfig.chain_length = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (bc.type == TYPE_HUB75MATRIX_HS) {
|
||||
@@ -835,6 +841,7 @@ BusHub75Matrix::BusHub75Matrix(const BusConfig &bc) : Bus(bc.type, bc.start, bc.
|
||||
_isVirtual = true;
|
||||
mxconfig.mx_width = min((uint8_t) 64, panelWidth) * 2;
|
||||
mxconfig.mx_height = min((uint8_t) 64, panelHeight) / 2;
|
||||
mxconfig.driver = HUB75_I2S_CFG::FM6124; // use FM6124 for "outdoor" 4-scan panels - workaround until we can make the driver user-configurable
|
||||
} else {
|
||||
DEBUGBUS_PRINTLN("Unknown type");
|
||||
return;
|
||||
@@ -874,6 +881,12 @@ BusHub75Matrix::BusHub75Matrix(const BusConfig &bc) : Bus(bc.type, bc.start, bc.
|
||||
// HUB75_I2S_CFG::i2s_pins _pins={R1_PIN, G1_PIN, B1_PIN, R2_PIN, G2_PIN, B2_PIN, A_PIN, B_PIN, C_PIN, D_PIN, E_PIN, LAT_PIN, OE_PIN, CLK_PIN};
|
||||
mxconfig.gpio = { 1, 5, 6, 7, 13, 9, 16, 48, 47, 21, 38, 8, 4, 18 };
|
||||
|
||||
#elif defined(WAVESHARE_S3_PINOUT)
|
||||
DEBUGBUS_PRINTLN("MatrixPanel_I2S_DMA - Waveshare S3 with PSRAM, Waveshare pinout");
|
||||
|
||||
// HUB75_I2S_CFG::i2s_pins _pins={R1_PIN, G1_PIN, B1_PIN, R2_PIN, G2_PIN, B2_PIN, A_PIN, B_PIN, C_PIN, D_PIN, E_PIN, LAT_PIN, OE_PIN, CLK_PIN};
|
||||
mxconfig.gpio = {4, 5, 6, 7, 15, 16, 18, 8, 3, 42, 9, 40, 2, 41};
|
||||
|
||||
#else
|
||||
DEBUGBUS_PRINTLN("MatrixPanel_I2S_DMA - S3 with PSRAM");
|
||||
// HUB75_I2S_CFG::i2s_pins _pins={R1_PIN, G1_PIN, B1_PIN, R2_PIN, G2_PIN, B2_PIN, A_PIN, B_PIN, C_PIN, D_PIN, E_PIN, LAT_PIN, OE_PIN, CLK_PIN};
|
||||
@@ -990,10 +1003,8 @@ BusHub75Matrix::BusHub75Matrix(const BusConfig &bc) : Bus(bc.type, bc.start, bc.
|
||||
}
|
||||
setBitArray(_ledsDirty, _len, false); // reset dirty bits
|
||||
|
||||
if (mxconfig.double_buff == false) {
|
||||
// create LEDs buffer (initialized to BLACK), prefer DRAM if enough heap is available (faster in case global _pixels buffer is in PSRAM as not both will fit the cache)
|
||||
_ledBuffer = static_cast<CRGB*>(allocate_buffer(_len * sizeof(CRGB), BFRALLOC_PREFER_DRAM | BFRALLOC_CLEAR));
|
||||
}
|
||||
// create LEDs buffer (initialized to BLACK), prefer DRAM if enough heap is available (faster in case global _pixels buffer is in PSRAM as not both will fit the cache)
|
||||
_ledBuffer = static_cast<CRGB*>(allocate_buffer(_len * sizeof(CRGB), BFRALLOC_PREFER_DRAM | BFRALLOC_CLEAR));
|
||||
}
|
||||
|
||||
PANEL_CHAIN_TYPE chainType = CHAIN_NONE; // default for quarter-scan panels that do not use chaining
|
||||
|
||||
@@ -252,18 +252,18 @@
|
||||
var buttonBlock = document.createElement('div');
|
||||
buttonBlock.className = 'bb';
|
||||
buttonBlock.innerHTML = `
|
||||
<div class="bh">Button ${i}</div>
|
||||
<div class="bh">Button (switch) ${i}</div>
|
||||
<div class="bs">
|
||||
<div class="ba">
|
||||
<label>Push/Switch</label>
|
||||
<label>Short (on → off)</label>
|
||||
<select name="MP${b}" class="s" required>${presetOpts}</select>
|
||||
</div>
|
||||
<div class="ba">
|
||||
<label>Short (on→off)</label>
|
||||
<label>Long (off → on)</label>
|
||||
<select name="ML${b}" class="s" required>${presetOpts}</select>
|
||||
</div>
|
||||
<div class="ba">
|
||||
<label>Long (off→on)</label>
|
||||
<label>Double press (n/a)</label>
|
||||
<select name="MD${b}" class="s" required>${presetOpts}</select>
|
||||
</div>
|
||||
</div>
|
||||
@@ -372,7 +372,7 @@
|
||||
Alexa On/Off Preset: <input name="A0" class="m" type="number" min="0" max="250" required> <input name="A1" class="m" type="number" min="0" max="250" required><br>
|
||||
</div>
|
||||
<div class="sec">
|
||||
<h3>Button Action Presets</h3>
|
||||
<h3>Button (switch) Action Presets</h3>
|
||||
<div id="macros"></div>
|
||||
<a href="https://kno.wled.ge/features/macros/#analog-button" target="_blank">Analog Button setup</a>
|
||||
</div>
|
||||
|
||||
+6
-7
@@ -116,8 +116,8 @@ void handleImprovPacket() {
|
||||
return;
|
||||
}
|
||||
} else if (packetByte > 9) { //RPC data
|
||||
rpcData[packetByte - 10] = next;
|
||||
if (packetByte > 137) return; //prevent buffer overflow
|
||||
rpcData[packetByte - 10] = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -238,8 +238,8 @@ void handleImprovWifiScan() {
|
||||
bool isOpen = WiFi.encryptionType(i) == WIFI_AUTH_OPEN;
|
||||
#endif
|
||||
|
||||
char ssidStr[33];
|
||||
strcpy(ssidStr, WiFi.SSID(i).c_str());
|
||||
char ssidStr[33] = {'\0'};
|
||||
strlcpy(ssidStr, WiFi.SSID(i).c_str(), sizeof(ssidStr));
|
||||
const char *str[3] = {ssidStr, rssiStr, isOpen ? "NO":"YES"};
|
||||
sendImprovRPCResult(ImprovRPCType::Request_Scan, 3, str);
|
||||
}
|
||||
@@ -258,14 +258,13 @@ static void parseWiFiCommand(char* rpcData) {
|
||||
|
||||
unsigned ssidLen = rpcData[1];
|
||||
if (ssidLen > len -1 || ssidLen > 32) return;
|
||||
memset(multiWiFi[0].clientSSID, 0, 32);
|
||||
memset(multiWiFi[0].clientSSID, 0, sizeof(multiWiFi[0].clientSSID));
|
||||
memcpy(multiWiFi[0].clientSSID, rpcData+2, ssidLen);
|
||||
|
||||
memset(multiWiFi[0].clientPass, 0, 64);
|
||||
memset(multiWiFi[0].clientPass, 0, sizeof(multiWiFi[0].clientPass));
|
||||
if (len > ssidLen +1) {
|
||||
unsigned passLen = rpcData[2+ssidLen];
|
||||
memset(multiWiFi[0].clientPass, 0, 64);
|
||||
memcpy(multiWiFi[0].clientPass, rpcData+3+ssidLen, passLen);
|
||||
memcpy(multiWiFi[0].clientPass, rpcData+3+ssidLen, min(size_t(passLen), sizeof(multiWiFi[0].clientPass)));
|
||||
}
|
||||
|
||||
sendImprovStateResponse(0x03); //provisioning
|
||||
|
||||
@@ -448,10 +448,26 @@ void WiFiEvent(WiFiEvent_t event)
|
||||
}
|
||||
break;
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
case ARDUINO_EVENT_WIFI_READY:
|
||||
DEBUG_PRINTLN(F("WiFi-E: driver ready."));
|
||||
break;
|
||||
case ARDUINO_EVENT_WIFI_SCAN_DONE:
|
||||
// also triggered when connected to selected SSID
|
||||
DEBUG_PRINTLN(F("WiFi-E: SSID scan completed."));
|
||||
break;
|
||||
case ARDUINO_EVENT_WIFI_STA_START:
|
||||
DEBUG_PRINTLN(F("WiFi-E: STA Started"));
|
||||
break;
|
||||
case ARDUINO_EVENT_WIFI_STA_STOP:
|
||||
DEBUG_PRINTLN(F("WiFi-E: STA Stopped"));
|
||||
break;
|
||||
case ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE:
|
||||
DEBUG_PRINTLN(F("WiFi-E: STA authentication mode change."));
|
||||
break;
|
||||
case ARDUINO_EVENT_WIFI_STA_LOST_IP:
|
||||
DEBUG_PRINTLN(F("WiFi-E: IP address lost."));
|
||||
break;
|
||||
|
||||
case ARDUINO_EVENT_WIFI_AP_START:
|
||||
DEBUG_PRINTLN(F("WiFi-E: AP Started"));
|
||||
break;
|
||||
|
||||
+6
-3
@@ -6,7 +6,7 @@
|
||||
|
||||
#define UDP_SEG_SIZE 36
|
||||
#define SEG_OFFSET (41)
|
||||
#define WLEDPACKETSIZE (41+(WS2812FX::getMaxSegments()*UDP_SEG_SIZE)+0)
|
||||
static constexpr size_t WLEDPACKETSIZE = 41+(WS2812FX::getMaxSegments()*UDP_SEG_SIZE); // make sure this is known at compile-time
|
||||
#define UDP_IN_MAXSIZE 1472
|
||||
#define PRESUMED_NETWORK_DELAY 3 //how many ms could it take on avg to reach the receiver? This will be added to transmitted times
|
||||
|
||||
@@ -268,6 +268,7 @@ static void parseNotifyPacket(const uint8_t *udpIn) {
|
||||
size_t inactiveSegs = 0;
|
||||
for (size_t i = 0; i < numSrcSegs && i < WS2812FX::getMaxSegments(); i++) {
|
||||
unsigned ofs = 41 + i*udpIn[40]; //start of segment offset byte
|
||||
if (ofs + 36 > UDP_IN_MAXSIZE) break; // avoid reading outside of array
|
||||
unsigned id = udpIn[0 +ofs];
|
||||
DEBUG_PRINTF_P(PSTR("UDP segment received: %u\n"), id);
|
||||
if (id > strip.getSegmentsNum()) break;
|
||||
@@ -499,7 +500,7 @@ void handleNotifications()
|
||||
packetSize = rgbUdp.parsePacket();
|
||||
if (packetSize) {
|
||||
if (!receiveDirect) return;
|
||||
if (packetSize > UDP_IN_MAXSIZE || packetSize < 3) return;
|
||||
if (packetSize > UDP_IN_MAXSIZE || packetSize < 3) return; // packetSize must not exceed buffersize (UDP_IN_MAXSIZE)
|
||||
realtimeIP = rgbUdp.remoteIP();
|
||||
DEBUG_PRINTLN(rgbUdp.remoteIP());
|
||||
uint8_t lbuf[packetSize];
|
||||
@@ -587,7 +588,9 @@ void handleNotifications()
|
||||
|
||||
unsigned id = (tpmPayloadFrameSize/3)*(packetNum-1); //start LED
|
||||
unsigned totalLen = strip.getLengthTotal();
|
||||
for (size_t i = 6; i < tpmPayloadFrameSize + 4U && id < totalLen; i += 3, id++) {
|
||||
// Clamp to prevent buffer overread: loop accesses up to udpIn[tpmPayloadFrameSize + 5]
|
||||
size_t currentPayloadFrameSize = (packetSize >= 5) ? min(tpmPayloadFrameSize, uint16_t(packetSize - 5)) : 0;
|
||||
for (size_t i = 6; i < currentPayloadFrameSize + 4U && id < totalLen; i += 3, id++) {
|
||||
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
|
||||
}
|
||||
if (tpmPacketCount == numPackets) { //reset packet count and show if all packets were received
|
||||
|
||||
@@ -1296,6 +1296,9 @@ String computeSHA1(const String& input) {
|
||||
|
||||
#ifdef ESP32
|
||||
#include "esp_adc_cal.h"
|
||||
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4,4,7) // backwards compatibility patch
|
||||
#define ADC_ATTEN_DB_12 ADC_ATTEN_DB_11
|
||||
#endif
|
||||
String generateDeviceFingerprint() {
|
||||
uint32_t fp[2] = {0, 0}; // create 64 bit fingerprint
|
||||
esp_chip_info_t chip_info;
|
||||
|
||||
@@ -657,6 +657,7 @@ void WLED::initAP(bool resetAP)
|
||||
WiFi.softAPConfig(IPAddress(4, 3, 2, 1), IPAddress(4, 3, 2, 1), IPAddress(255, 255, 255, 0));
|
||||
WiFi.softAP(apSSID, apPass, apChannel, apHide);
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
DEBUG_PRINT(F("access point maxTxPower set to ")); DEBUG_PRINTLN(txPower);
|
||||
WiFi.setTxPower(wifi_power_t(txPower));
|
||||
#endif
|
||||
|
||||
@@ -697,6 +698,7 @@ void WLED::initConnection()
|
||||
}
|
||||
#endif
|
||||
|
||||
DEBUG_PRINTLN(F("WiFi disconnect."));
|
||||
WiFi.disconnect(true); // close old connections
|
||||
delay(5); // wait for hardware to be ready
|
||||
#ifdef ESP8266
|
||||
@@ -709,6 +711,7 @@ void WLED::initConnection()
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
// Reset mode to NULL to force a full STA mode transition, so that WiFi.mode(WIFI_STA) below actually applies the hostname (and TX power, etc.).
|
||||
// This is required on reconnects when mode is already WIFI_STA.
|
||||
DEBUG_PRINTLN(F("WiFi mode_null: driver teardown / re-init."));
|
||||
WiFi.mode(WIFI_MODE_NULL);
|
||||
apActive = false; // the AP is physically torn down by WIFI_MODE_NULL
|
||||
delay(5); // give the WiFi stack time to complete the mode transition
|
||||
@@ -792,9 +795,12 @@ void WLED::initConnection()
|
||||
#endif // WLED_ENABLE_WPA_ENTERPRISE
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
DEBUG_PRINT(F("WiFi maxTxPower set to ")); DEBUG_PRINT(txPower);
|
||||
DEBUG_PRINT(F("; WiFi sleep ")); DEBUG_PRINTLN(noWifiSleep ? F("disabled."):F("enabled."));
|
||||
WiFi.setTxPower(wifi_power_t(txPower));
|
||||
WiFi.setSleep(!noWifiSleep);
|
||||
#else // ESP8266 accepts a hostname set after WiFi interface initialization
|
||||
DEBUG_PRINT(F("WiFi sleep ")); DEBUG_PRINTLN(noWifiSleep ? F("disabled."):F("enabled."));
|
||||
wifi_set_sleep_type((noWifiSleep) ? NONE_SLEEP_T : MODEM_SLEEP_T);
|
||||
WiFi.hostname(hostname);
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -274,7 +274,7 @@ using PSRAMDynamicJsonDocument = BasicJsonDocument<PSRAM_Allocator>;
|
||||
#define STRINGIFY(X) #X
|
||||
#define TOSTRING(X) STRINGIFY(X)
|
||||
|
||||
#define WLED_CODENAME "Niji"
|
||||
#define WLED_CODENAME "Kagayaki"
|
||||
|
||||
// AP and OTA default passwords (for maximum security change them!)
|
||||
WLED_GLOBAL char apPass[65] _INIT(WLED_AP_PASS);
|
||||
|
||||
Reference in New Issue
Block a user