Compare commits

..

140 Commits

Author SHA1 Message Date
Benjam Welker 1103c91c5b Analog button fix (#5659)
* add analog button options

* fix issues with duplicate options for digital vs analog

* dynamic button type options
2026-06-15 21:25:03 +02:00
Damian Schneider 6f849fdc03 Update pixel buffer after changing matrix dimensions (#5675)
* update pixel buffer after changing matrix dimensions
2026-06-15 21:08:57 +02:00
Will Tatam 76ef0d3998 docs: refresh README to reflect current feature set and project state (#5626)
* docs: refresh README to reflect current feature set and project state

* docs: fix HUB75 support note — available on all ESP32 variants, not just S3

* docs: mention network audio sources in AudioReactive feature description

* docs: remove ESP8266 references — EOL platform, not recommended for new installs

* docs: make PayPal donation link clearly attributed to Aircoookie

* docs: add cross-references to kno.wled.ge docs throughout feature list
2026-06-15 12:58:15 +02:00
Damian Schneider 06e6b23314 bugfix in parsePacket(): accept short artnet packets (#5588) for 16_x
* bugfix in parsePacket(): accept short artnet packets
* add min artnet packet size check and fix indentation

---------

Co-authored-by: Frank Möhle <91616163+softhack007@users.noreply.github.com>
2026-06-09 14:42:46 +02:00
Frank Möhle 0828173147 disable fb infer in coderabbit tools list 2026-06-09 14:14:11 +02:00
Frank Möhle 0d4abd2764 Remove outdated Wiki link from CONTRIBUTING.md
Removed link to WIKI for submitting a PR. The information in the wiki is outdated, and it contradicts the "no force-push" rule.
2026-06-09 14:14:10 +02:00
Frank Möhle 1694d383d8 Update links in CONTRIBUTING.md to reference AGENTS.md 2026-06-09 14:14:10 +02:00
Frank Möhle 4d2ad7ace4 Clarify branch maintenance status in instructions
Updated branch descriptions for clarity and maintenance status.
2026-06-09 14:14:10 +02:00
Frank Möhle a8105caa98 Clarify repository language requirement
Emphasize that the repository language is English for all aspects including code, comments, and documentation.
2026-06-05 22:36:09 +02:00
Frank e8820d71e7 Update package-lock.json
fix for outdated version
2026-06-04 23:57:05 +02:00
Frank Möhle cd51a4f157 Update recommendations for synchronization methods
added std::atomic
2026-06-04 23:53:45 +02:00
Frank Möhle 2eb492c3a2 Update verification instructions for AI-generated code
limit "existence" check to preprocessor macros etc.
If a global variable or function does not exist, this would lead to a compilation error.
2026-06-04 16:44:26 +02:00
Frank Möhle 6a44bc01a2 Merge pull request #5665 from wled/hub75_gamma_hotfix
HUB75 hotfix: prevents double-applying color corrections (WLED gamma + HUB75 internal CIE correction), by disabling driver-internal color corrections.
2026-06-04 15:04:08 +02:00
Frank e869a89bad platformio: allow building with espressif framework (instead of tasmota)
* add necessary platform and platform_packages entries (commented out)
* compatibility patch for ADC_ATTEN_DB_11
2026-05-31 22:19:43 +02:00
Copilot 0ca86641ef Pin andelf/nightly-release tospecific commit SHA instead of @main branch (#5386)
The nightly release GitHub Action is pinned from the mutable main branch to a specific immutable commit SHA

we should update the pin when v2 comes out.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: netmindz <442066+netmindz@users.noreply.github.com>
Co-authored-by: Frank Möhle <91616163+softhack007@users.noreply.github.com>
2026-05-30 23:55:58 +02:00
Frank Möhle dafde84338 Update frequency details for usermod loop()
Clarified frequency of calls for usermod loop() based on system load.
2026-05-30 15:15:11 +02:00
Frank Möhle 53e01e8934 Remove duplicate sentence in secure code instructions
Removed redundant text regarding destination capacity and length safety.
2026-05-30 02:38:24 +02:00
Frank Möhle 4c385d4b4b Restructure usermod documentation for AI, and clarify details 2026-05-30 02:38:24 +02:00
Frank 6f1907cbdd more robustness for improv - gracefully handle broken input 2026-05-30 00:19:13 +02:00
Frank Möhle ec8369d557 Update caveats and pitfalls in cpp.instructions.md
WLED-MM backport: Clarify operator precedence in C/C++.
2026-05-29 20:28:44 +02:00
Frank Möhle 2e34fd421a small update 2026-05-29 19:56:36 +02:00
Frank Möhle 47d569f3f2 Modify verification step for numerical accuracy
small clarifications:
* not only applicable to fixed-point
* added sentence to explain why this rule is needed.
2026-05-29 19:56:36 +02:00
Frank Möhle c770e37226 Update auth checks for '/reset' endpoint clarification
Clarified the handling of the '/reset' endpoint in the auth checks section - not security critical because it will not alter any user data.
2026-05-29 18:31:59 +02:00
kaibae19 9af95ecd0b fix(FX): restore palette wrap in color_wheel() (regression since 0.15.x) (#5646)
color_wheel() historically called color_from_palette() with moving=true, so
under the default palette blend mode (paletteBlend=0, "wrap if moving") the
palette's end->start seam was interpolated. Commit ee9ac947 changed that call
to moving=false, dropping the wrap; effects that scroll a palette (e.g. the
Palette effect with Retro Clown) then shows the unblended seam travelling
visibly along the strip light-by-light.

Restore the original moving=true (per maintainer review). This fixes the seam
for the Palette effect and every other color_wheel() caller under the default
blend mode, without adding any new function parameters.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-29 16:45:41 +02:00
Benjam Welker 1bcf58abcd fix button label regression (#5636)
* fix button label regression, also add switch notation
2026-05-29 16:45:41 +02:00
Frank Möhle 317d0ea87b HUB75: use FM6124 driver for 4-scan panels, remove 64x64 limitation if board has PSRAM (partial solution for #5628) (#5647)
* HUB75: use FM6124 driver for 4-scan panels
* Remove 1-panel limit if the board has PSRAM
2026-05-29 16:36:12 +02:00
Copilot dbe8196137 add secure coding guides for AI reviews (#5572)
Added security review guidelines and a short checklist covering critical security areas including buffer safety, input validation, authentication, secure defaults, and protection against common vulnerabilities. Refined rule wording and priorities to better fit WLED’s technical constraints and realistic deployment model.

The lists are based on the OWASP "top 10" from https://github.com/github/awesome-copilot/blob/main/instructions/security-and-owasp.instructions.md, and on lessons learned from past reviews.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: softhack007 <91616163+softhack007@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-05-29 14:00:40 +02:00
Frank 863213f2e7 human-readable wifi events (WLED_DEBUG)
added some missing event names.
2026-05-28 00:07:10 +02:00
Frank 7f640a9dfd extra debug info for wifi disconnect / teardown / setTxPower
should help with debugging connection problems.
2026-05-27 23:28:44 +02:00
Frank 41056f6a3b small addition to anti-slop rules
AI tools often delete code, remove comments, revert recent changes, or modify files that are out-of-scope w.r.t. the PR objectives.
2026-05-27 20:38:29 +02:00
Frank 4e98f97cda adding coderabbit checks for typical AI slop 2026-05-25 22:17:58 +02:00
Frank a01add2d26 update usermod guidelines, update example with "be nice but not too nice" pattern 2026-05-25 21:40:21 +02:00
Frank 87fd423336 move some generic AI rules from copilot-instructions.md to AGENTS.md 2026-05-25 21:40:21 +02:00
Frank Möhle 9dec64c394 Remove 'V5_C6' from the list of base branches
the V5-C6 branch will be merged back into V5 soon.
2026-05-23 23:42:54 +02:00
Frank Möhle 1e3569f78a coderabbit: Add base branches to auto_review configuration 2026-05-23 23:42:54 +02:00
Will Tatam 493b6b7e0f Fix revert button #5574 2026-05-23 19:39:30 +01:00
Will Tatam 500250c117 fix: esp8266_2m_min 2026-05-23 19:39:30 +01:00
Frank Möhle ac1757badd Document branch and release structure in AGENTS.md
Added branch and release structure information to AGENTS.md.
2026-05-23 15:08:48 +02:00
Frank Möhle 69244a8bcf clarify scope of agents.md
Introduction added
2026-05-23 15:08:48 +02:00
Damian Schneider 2f9af5023c add inverse gamma for original looks 2026-05-22 07:53:52 +02:00
Damian Schneider 16c0a27d3b Make twinkle FX look more like it was in the past 2026-05-22 07:53:52 +02:00
Frank Möhle c7100bdaa5 Update AGENTS.md with ESP32 task synchronization guidelines
* Added guidelines for ESP32 task synchronization
* Clarified that PRs must not create file listed in `.gitignore`
2026-05-21 22:05:48 +02:00
Frank Möhle 77937d3a27 Align AGENTS.md with main
fixes some mis-edits from previous commit.
2026-05-21 22:03:10 +02:00
Frank 6e7607102c coding guides: clatify how to check for PSRAM
psramFound() alone is not definite -> nust also check that PSRAM size > 0 to be sure

https://github.com/wled/WLED/issues/5629#issuecomment-4497230168
2026-05-20 12:40:50 +02:00
Frank Möhle a9cb41d767 Add PSRAM guidelines to AGENTS.md
Added PSRAM guidelines including availability checks, DMA compatibility, fragmentation considerations, and performance recommendations.
2026-05-20 12:40:50 +02:00
Frank Möhle 6685ffb774 Update PSRAM guidelines in esp-idf instructions
Clarify PSRAM availability check instructions and usage.
2026-05-20 12:40:50 +02:00
Damian Schneider 8f53447c73 use DRAM as fallback if PSRAM fails 2026-05-20 08:37:09 +02:00
Frank 75faf5efc0 fix esp32s3_4M_none buildenv
tasmota core does not support "dio" mode on S3
2026-05-19 12:43:11 +02:00
Frank Möhle e05e975ce1 Add esp32s3dev_8MB_none to platformio_release.ini.template 2026-05-19 12:29:55 +02:00
Frank Möhle e9f8897772 Add new environments for ESP32-S3 without PSRAM
esp32s3_8MB_none, esp32s3_4M_none
2026-05-19 12:29:55 +02:00
Logan Davis c75fce13d0 Fix KIT-VE PHY address from 0 to 1 (#5618) 2026-05-16 10:36:35 +02:00
Frank Möhle 8300f4d2b4 Audioreactive bugfix: auto-suspend in all realtime modes, but stay active when "Use main segment only" (#5599)
* fixes a minor problem with newer realtime modes (DDP, TPM2NET and DMX) not causing auto-suspend of sound processing.
* ensure that AR audio stays active when "Use main segment only" (other segments are still controlled locally)
* small update for better compatibility with V5 builds
2026-05-15 21:00:34 +02:00
Frank Möhle 75cd8b9fb0 Merge pull request #5608 from wled/softhack007-patch-1
Add sanity checks for ethernet config table and WLED_ETH_DEFAULT
2026-05-12 13:57:49 +02:00
Joeboyc2 a8788a2c89 fix(Fix_unreachable_netservices_v2): v16 compatibility fixes (#5590)
Two issues prevented this usermod from building under v16:

1. library.json is missing "build": {"libArchive": false}, causing the
   build system to reject it with an error before compilation begins.

2. serializeConfig() no longer has a no-argument overload in v16; the
   working replacement is serializeConfigToFS() which creates the JSON
   document internally and writes to the filesystem.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-12 11:29:42 +02:00
recliq 95e6efc164 Fixed top-LED update logic in grav* audioreactive effects (#5602)
Fix topLED fallrate not responding to "Rate of fall" slider.
2026-05-11 19:47:56 +02:00
Frank Möhle 5fcabec9be Update accessibility section in web instructions
Clarify target browser/platform combinations for WLED web UI.
2026-05-11 19:47:56 +02:00
Frank Möhle fceca393b7 Add accessibility guidelines for WLED web UI
Added section on accessibility and interaction for the WLED web UI.
2026-05-11 19:47:56 +02:00
Will Tatam bd45e1ca90 docs: clarify when usermod IDs are required
Add explicit guidance explaining that a unique USERMOD_ID_* is only
needed when a usermod uses inter-mod communication, pin ownership via
pinManager, or needs to be identifiable in JSON info output. Updates
both AGENTS.md and the const.h comment block to reflect this.
2026-05-11 19:47:56 +02:00
Will Tatam 3a28eba9f4 no need to build esp8266_2m_min for PRs 2026-05-07 20:33:12 +01:00
copilot-swe-agent[bot] 0ad958ae17 Add esp8266_2m_min minimal build env for ESP02 OTA recovery
Agent-Logs-Url: https://github.com/wled/WLED/sessions/9d593605-e26a-4bea-b5dd-913d174d5942

Co-authored-by: netmindz <442066+netmindz@users.noreply.github.com>
2026-05-07 20:33:12 +01:00
copilot-swe-agent[bot] ecc7f33907 Initial plan 2026-05-07 20:33:12 +01:00
Will Tatam f08b8b648f Change 'Latest release' to 'Latest version' in update.htm 2026-05-06 08:57:43 +01:00
Will Tatam 81b588f1e4 Improve update page UX and rename OTA button for consistency
- Release name on update page links directly to the matching bin on download.wled.me
- Badge links to GitHub releases page as 'View latest'
- Auto-update button renamed to 'Auto update'
- Manual upload section gets its own subheading; submit button renamed to 'Upload'
- 'Manual OTA Update' button in security settings renamed to 'Update WLED' to match info menu wording
2026-05-06 08:57:43 +01:00
Will Tatam 09384e4bdb Automatically download the right bin for the latest release and install 2026-05-06 08:57:43 +01:00
Will Tatam 6922938e15 Remove usermods from release 2026-05-06 08:57:43 +01:00
Frank Möhle 362fc664aa Add guideline for providing verifiable citations
Anti-hallucination rule: Emphasize the importance of providing verifiable citations in analyses or recommendations.
2026-05-05 14:53:16 +02:00
Will Tatam 527edf3283 16.0.1-dev 2026-05-03 21:31:45 +01:00
Will Tatam 4374f013f5 16.0.0 2026-05-03 21:13:08 +01:00
Will Tatam f90990b869 Upload then add notes 2026-05-03 21:12:50 +01:00
Will Tatam 7d999a6d61 16.0.0-rc1 2026-05-03 21:12:50 +01:00
Damian Schneider dd0a83f9d1 align settings overview page width with rest of config pages 2026-05-03 21:45:30 +02:00
BobLoeffler68 dd01940cf5 Fixes issue in Dissolve when a palette has same color pixel as the current background color when Complete is enabled (#5453)
* Fixes issue in Dissolve when a palette has same color pixel as the current background color when Complete mode is enabled

---------

Co-authored-by: Damian Schneider <daedae@gmx.ch>
2026-05-03 21:28:24 +02:00
Will Tatam 0d93ca8bac Merge pull request #5553 from intermittech/add-quinled-v4-ethernet-profiles
Add Ethernet profiles for QuinLED Dig-Uno/Quad v4 and Dig-Octa 32-8L v4
2026-05-03 18:55:02 +01:00
Will Tatam a083217176 move platformio_release.ini.template to .github/ for cleaner project root 2026-05-03 18:42:43 +01:00
Will Tatam 86a218e2b4 Skip GPIO validation for HUB75 types in pin checks and clarify slot usage in getNumberOfPins logic 2026-05-03 18:42:43 +01:00
Will Tatam 28b441917b Update platformio configurations for 16MB ESP32-S3 MoonHub (HUB75) board 2026-05-03 18:42:43 +01:00
Will Tatam 129c68c6c9 Add support for HD-WF2 ESP32-S3 (HUB75 without PSRAM) 2026-05-03 18:42:43 +01:00
Will Tatam 923a1ec729 fix(ui): derive hasPSRAM from psrSz capability, not free bytes
Free PSRAM (info.psram) can be transiently 0 on PSRAM-capable boards,
which would wrongly reject multi-panel HUB75 setups in the LED settings
validation. Prefer info.psrSz (total PSRAM size) and fall back to
info.psram only if psrSz is unavailable.

Suggested in PR #5558 review.
2026-05-03 18:42:43 +01:00
Will Tatam 2ceeb67007 Relax panel limit for devices with PSRAM 2026-05-03 18:42:43 +01:00
Will Tatam 13aa7ed787 ci: build HUB75 envs in release workflow
Move the four HUB75 envs from platformio_override.sample.ini into
platformio.ini (refactored with a shared [hub75] section and extends=
to deduplicate), and gate them behind a release-only config template
so nightly/PR CI keep building only the standard env matrix.

The release workflow now copies platformio_release.ini.template into
place, which extends default_envs with the HUB75 envs.
2026-05-03 18:42:43 +01:00
Will Tatam 68640f5dd8 Fix AudioReactive palette names to avoid duplication with usermod prefix
Since the display format is now "UMName: palName", shorten the palette
names to just "Ratio", "Hue", and "Spectrum" — rendering as
"AudioReactive: Ratio" etc. rather than "AudioReactive: Audio Responsive Ratio".
2026-05-03 18:41:50 +01:00
Will Tatam 8a653ebb29 Use usermod name prefix for usermod-supplied palette names
Palette display names now follow the format "UMName: palName" (e.g.
"AudioReactive: Audio Responsive Hue") when a usermod supplies a
specific palName, keeping the usermod name as a consistent prefix.
Fallback when palName is nullptr remains "UMName index".

Update AudioReactive palette names to the full descriptive names from
the original WLED-MM port: "Audio Responsive Ratio", "Audio Responsive
Hue", and "Audio Responsive Spectrum".
2026-05-03 18:41:50 +01:00
Will Tatam dc5ee3f2fa Add name to usermod palette 2026-05-03 18:41:50 +01:00
Damian Schneider 5dc627ef5a remove unneeded check 2026-05-03 18:41:50 +01:00
Damian Schneider 520d8704c5 fix typo 2026-05-03 18:41:50 +01:00
Damian Schneider 55219980c6 rename removeUsermodPalettes 2026-05-03 18:41:50 +01:00
Damian Schneider 6dcae505a0 apply default pal before bounds check 2026-05-03 18:41:50 +01:00
Damian Schneider 52d897ed7a rename and bugfixes 2026-05-03 18:41:50 +01:00
Damian Schneider ef354d0119 add usermod palettes to fix AR palette indexing 2026-05-03 18:41:50 +01:00
Damian Schneider 89aae707d0 fix refresh of custom palettes 2026-05-03 18:41:50 +01:00
Will Miles 25668bb068 Validate gzipped firmware on ESP8266
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-03 18:41:17 +01:00
copilot-swe-agent[bot] 2c1f3c581d Refactor AR init debug logging for network-only sentinel
Agent-Logs-Url: https://github.com/wled/WLED/sessions/85b2a158-f6ba-45cf-88af-0d51b9202cab

Co-authored-by: netmindz <442066+netmindz@users.noreply.github.com>
2026-05-03 15:01:39 +01:00
copilot-swe-agent[bot] 1c8cd15cd1 Fix network-only dmType handling and debug diagnostics
Agent-Logs-Url: https://github.com/wled/WLED/sessions/85b2a158-f6ba-45cf-88af-0d51b9202cab

Co-authored-by: netmindz <442066+netmindz@users.noreply.github.com>
2026-05-03 15:01:39 +01:00
Will Tatam 32de108f4c Clean up redundant preprocessor directive in audio_reactive.cpp 2026-05-03 15:01:39 +01:00
Will Tatam e551ca833b Add audioreactive custom_usermod to multiple ESP8266 environments in platformio.ini now that we support network only option for 8266 2026-05-03 15:01:39 +01:00
Will Tatam 2fa5266dbf Enhance audio reactive logic with improved input validation and new "network receive only" option. 2026-05-03 15:01:39 +01:00
Will Tatam 46dafa2c6b ci: opt into Node.js 24 for GitHub Actions runners
Set FORCE_JAVASCRIPT_ACTIONS_TO_NODE24=true across all affected workflows
to avoid deprecation warnings ahead of the June 2026 forced migration.
2026-05-03 15:01:39 +01:00
Will Tatam 967ef0720c Relax artifact name regex to support forks with different project names 2026-05-03 15:01:39 +01:00
Will Tatam 82489664a0 Name CI artifacts by WLED_RELEASE_NAME instead of PlatformIO env
PR build artifact zips are now named firmware-<RELEASE_NAME> (e.g.
firmware-ESP32.zip) rather than firmware-<pio_env> (e.g.
firmware-esp32dev.zip), making it easier for users to identify the
correct build when testing PRs.
2026-05-03 15:01:39 +01:00
Damian Schneider 9fdd48776d relax restrictions on DDP protocol, minimal check for artNet (#5554) 2026-05-01 22:55:14 +02:00
Damian Schneider 74e0b166ba auto-migration for sunrise/sunset legacy config (#5555)
* add auto-migration for sunris/sunset legacy config
2026-05-01 14:44:07 +02:00
Damian Schneider 61bd8bf5b4 update VERSION 2026-05-01 13:34:40 +02:00
Damian Schneider f79cf568b2 move pixelforge json list and cpt city palettes to wled repo (#5541)
also removed commented code
2026-04-26 03:58:05 +02:00
Damian Schneider c53511b5aa add placeholder to keep custom palette ID's consistent (#5537) 2026-04-25 10:54:07 +02:00
Damian Schneider 0325e30bef cleanup of PR #5503: remove unnecessary changes (#5536) 2026-04-25 10:54:07 +02:00
Will Tatam 456ddee962 Merge pull request #5503 from RobertoD91/main
fix for serial port on esp32 (#5501)
2026-04-25 17:17:15 +01:00
Will Tatam 41e4bbf2bd Merge pull request #5473 from DedeHai/pin_dropdowns
Use drop-downs for pins
2026-04-25 17:17:15 +01:00
Damian Schneider 7f292b9ecd fix indentation 2026-04-22 09:57:21 +02:00
Brandon502 6afc990397 GoL missing return. (#5523) 2026-04-22 06:45:22 +02:00
Damian Schneider 974c15c1d3 Fix blending style options list filter for iOS (#5513)
* fix blending style options list filter for iOS
* fix default fallback
2026-04-20 07:52:18 +02:00
Damian Schneider 96b0c7b4ae better packet queuing & pacing for custom palette live preview (#5515)
* better packet queuing / pacing for custom palette live preview
* fix leak
* remove window prefix from variables
2026-04-20 07:37:33 +02:00
Frank Möhle 6394bec21b Highlight target branch for pull requests
Emphasize the importance of targeting the main branch for PRs.
2026-04-20 15:25:36 +02:00
Frank 79fde56b0e align AI instructions with `main` branch
some files were a bit behind - make sure the same instructions apply everywhere.
2026-04-20 14:27:32 +02:00
Frank Möhle e6077acb78 Update rules for PR descriptions and change logs
Added a guideline to prevent agents from overwriting PR descriptions (see https://github.com/orgs/community/discussions/187027).
2026-04-20 14:25:23 +02:00
Frank Möhle 83dd1b078d Merge pull request #5516 from kilrah/fix_dmx_ident
Add identifier string for DMX realtime mode
2026-04-19 18:44:34 +02:00
Damian Schneider c1e5ac5bd1 bugfixes in PS effects
- fix PS Sparkler for large setups: need 32bit random position, 16bit is not enough
- fix PS Fireworks 1D: need to `break` if no particles are available or it can lead to stalls on large setups
- do not use collisions by default PS Fuzzy Noise: its very slow on larger setups
2026-04-17 15:29:53 +02:00
Damian Schneider 1e42ebf852 mask out flag bits in DDP type for compatibility 2026-04-12 19:50:07 +02:00
Damian Schneider e4a7effdb0 add search icon back(#5500) 2026-04-12 19:08:05 +02:00
Damian Schneider ae36f7e203 use memory aligned allocations, fix bug in FFT magnitude (integer path) (#5499)
* use memory aligned allocations, fix bug in FFT magnitude (integer path)
* assign pointer to globals not local copy
2026-04-12 19:06:16 +02:00
Will Miles 4cdc23a48b Merge pull request #5497 from willmmiles/16_x-dynarray-fixes
0.16 - Backport dynarray fixes from V5 WIP
2026-04-12 11:34:41 -04:00
Will Miles 48ab88e11e Fix up usermod validation again
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 10:03:11 -04:00
Will Miles fd890b3d58 dynarray: Support ESP-IDF 2026-04-12 10:03:05 -04:00
Will Miles f994c5e995 validate_modules: Improve performance
Use readelf instead of nm for great speed.
2026-04-12 10:02:59 -04:00
Will Miles c789e3d187 Fix usermod count for LTO 2026-04-12 10:02:53 -04:00
Will Miles fadc75da55 dynarray: Directly apply linker fix
Rather than append a linker file, we edit the upstream supplied ones to
add our section to the binaries.  Works better on all platforms.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-04-12 10:02:47 -04:00
Will Tatam 945896ddb7 Merge pull request #5462 from willmmiles/16_x-unlimited-fxdata-size
Serialize fxdata without ArduinoJSON
2026-04-11 10:42:22 +01:00
Will Tatam 188beec614 Merge pull request #5465 from netmindz/usage-extended
New extended data for usage report
2026-04-11 08:21:06 +01:00
Will Tatam 19947ec07e Merge pull request #5489 from wled/copilot/fix-wled-discovery-issues
Fix Alexa/Hue discovery by correcting SSDP response to match UPnP spec
2026-04-10 18:30:07 +01:00
Damian Schneider 8228c7eea4 bugfix in pixelforge (no blur by default), fix glitch in animated gifs for C3 2026-04-07 23:52:28 +02:00
Will Miles 1aba7057a5 Merge pull request #5477 from willmmiles/16_x-ipv6-filter-oops
Fix leak in blockRouterAdvertisements
2026-04-04 21:21:22 -04:00
Will Miles 227d535404 Fix leak in blockRouterAdvertisements 2026-04-04 21:12:17 -04:00
Damian Schneider da8bfda2f0 bugfix: do not restrict segment inputs to allow trailing strips 2026-04-03 14:22:08 +02:00
Damian Schneider e4f2964bd6 hotfix: critical bug in candle FX, integer issue in flow FX 2026-04-02 18:44:52 +02:00
Will Miles a3f730275a Factor out streaming JSON primitives
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 23:30:32 -04:00
Frank b5556aa977 fix for HUB75 builds
replaces the last remaining FastLED.h with fstled_slim.h
2026-03-30 11:45:30 +02:00
Will Miles 82ddefff87 Remove declaration of removed function
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-03-29 23:48:43 -04:00
Will Miles 56a97a0caa Fix off-by-one in fxdata serializer
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-03-29 23:15:27 -04:00
Will Miles 679bb39922 Serialize fxdata without ArduinoJSON
Eliminates size limit.  Fixes #5458
2026-03-29 22:49:26 -04:00
Frank Möhle b293db6af5 Clarify instructions to always use the correct source code branch
Updated instructions for providing references in analysis results.
2026-03-30 00:38:34 +02:00
Will Tatam 774fbc5fab 16.0.0-beta 2026-03-29 22:35:23 +01:00
42 changed files with 543 additions and 676 deletions
+8 -1
View File
@@ -17,7 +17,7 @@ language: en-US
reviews:
# generic review setting, see https://docs.coderabbit.ai/reference/configuration#reference
auto_apply_labels: false
auto_apply_labels: true
# abort_on_close: false
high_level_summary: true
review_status: true
@@ -33,6 +33,13 @@ 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}"
-14
View File
@@ -1,14 +0,0 @@
{
"features": {
"ghcr.io/ar90n/devcontainer-features/platformio:1": {
"version": "1.0.2",
"resolved": "ghcr.io/ar90n/devcontainer-features/platformio@sha256:4a28f8c147d81ff996afebe6f43e453355b6373dd4022960351090b532ac9dd3",
"integrity": "sha256:4a28f8c147d81ff996afebe6f43e453355b6373dd4022960351090b532ac9dd3"
},
"ghcr.io/devcontainers/features/node:2": {
"version": "2.0.0",
"resolved": "ghcr.io/devcontainers/features/node@sha256:fedd4c11f7adfb64283b578dddc7da906728daa25fa293351c9d913231acf12f",
"integrity": "sha256:fedd4c11f7adfb64283b578dddc7da906728daa25fa293351c9d913231acf12f"
}
}
}
+9 -9
View File
@@ -1,10 +1,11 @@
{
"name": "WLED-dev",
"image": "mcr.microsoft.com/devcontainers/python:3",
"features": {
"ghcr.io/ar90n/devcontainer-features/platformio:1": {},
"ghcr.io/devcontainers/features/node:2": {
"version": "v20.18.3"
"name": "Python 3",
"build": {
"dockerfile": "Dockerfile",
"context": "..",
"args": {
// Update 'VARIANT' to pick a Python version: 3, 3.6, 3.7, 3.8, 3.9
"VARIANT": "3"
}
},
@@ -42,8 +43,7 @@
},
"extensions": [
"ms-python.python",
"platformio.platformio-ide",
"ms-vscode.cpptools-extension-pack"
"platformio.platformio-ide"
]
}
},
@@ -52,7 +52,7 @@
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "",
"postCreateCommand": "bash -i -c 'nvm install && npm ci'",
// Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "vscode"
+4 -7
View File
@@ -5,9 +5,7 @@ body:
- type: markdown
attributes:
value: |
Please quickly search existing issues first before submitting a bug.
Please don't submit long error analyses created by an AI agent, these are often totally wrong.
Just describe the problem in your own words.
Please quickly search existing issues first before submitting a bug.
- type: textarea
id: what-happened
attributes:
@@ -61,13 +59,12 @@ body:
options:
- ESP8266
- ESP32
- ESP32 with ethernet
- ESP32-S2
- ESP32-S3
- ESP32-S2
- ESP32-C3
- ESP32-C5 (experimental)
- Other
- ESP32-C6 (experimental)
- ESP32-P4 (experimental)
- ESP32-C5 (experimental)
validations:
required: true
- type: textarea
+2 -1
View File
@@ -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
+1 -1
View File
@@ -29,7 +29,7 @@ jobs:
uses: janheinrichmerker/action-github-changelog-generator@v2.4
with:
token: ${{ secrets.GITHUB_TOKEN }}
sinceTag: v16.0.0
sinceTag: v0.15.0
output: CHANGELOG_NIGHTLY.md
# Exclude issues that were closed without resolution from changelog
excludeLabels: 'stale,wontfix,duplicate,invalid,external,question,use-as-is,not_planned'
+3 -3
View File
@@ -17,8 +17,8 @@ Always reference these instructions - including coding guidelines in `docs/` - f
| `npm run build` | Build web UI into `wled00/html_*.h` / `wled00/js_*.h` | 30s |
| `npm test` | Run test suite (Node.js built-in `node --test`) | 2 min |
| `npm run dev` | Watch mode — auto-rebuilds web UI on changes | continuous |
| `pio run -e esp32dev` | Build firmware (ESP32, most common target) | 5 min |
| `pio run -e nodemcuv2` | Build firmware (ESP8266) | 5 min |
| `pio run -e esp32dev` | Build firmware (ESP32, most common target) | 30 min |
| `pio run -e nodemcuv2` | Build firmware (ESP8266) | 30 min |
**Always run `npm ci && npm run build` before `pio run`.** The web UI build generates
required C headers for firmware compilation.
@@ -233,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.
+2 -4
View File
@@ -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).
+8 -8
View File
@@ -1,12 +1,12 @@
{
"name": "wled",
"version": "17.0.0-dev",
"version": "16.0.1-dev",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "wled",
"version": "17.0.0-dev",
"version": "16.0.1-dev",
"license": "ISC",
"dependencies": {
"clean-css": "^5.3.3",
@@ -132,9 +132,9 @@
}
},
"node_modules/brace-expansion": {
"version": "5.0.5",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
"integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz",
"integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==",
"license": "MIT",
"dependencies": {
"balanced-match": "^4.0.2"
@@ -611,9 +611,9 @@
}
},
"node_modules/picomatch": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
"integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"license": "MIT",
"engines": {
"node": ">=8.6"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "wled",
"version": "17.0.0-dev",
"version": "16.0.1-dev",
"description": "Tools for WLED project",
"main": "tools/cdata.js",
"directories": {
+2 -8
View File
@@ -2,7 +2,6 @@
# This is implemented as a pio post-script to ensure that we can
# place our linker script at the correct point in the command arguments.
Import("env")
import shutil
from pathlib import Path
# Linker script fragment injected into the rodata output section of whichever
@@ -19,13 +18,7 @@ DYNARRAY_INJECTION = (
def inject_before_marker(path, marker):
"""Patch a linker script file in-place, inserting DYNARRAY_INJECTION before marker."""
original = path.read_text()
marker_pos = original.find(marker)
if marker_pos < 0:
raise RuntimeError(
f"DYNARRAY injection marker not found in linker script: path={path}, marker={marker!r}"
)
patched = original[:marker_pos] + DYNARRAY_INJECTION + original[marker_pos:]
path.write_text(patched)
path.write_text(original.replace(marker, DYNARRAY_INJECTION + marker, 1))
if env.get("PIOPLATFORM") == "espressif32":
@@ -45,6 +38,7 @@ if env.get("PIOPLATFORM") == "espressif32":
# leaves the ASSERTs satisfied.
build_dir = Path(env.subst("$BUILD_DIR"))
patched_path = build_dir / "dynarray_sections.ld"
import shutil
shutil.copy(sections_ld_path, patched_path)
inject_before_marker(patched_path, "_rodata_end = ABSOLUTE(.);")
+5 -12
View File
@@ -37,14 +37,14 @@ def check_elf_modules(elf_path: Path, env, module_lib_builders) -> set[str]:
Returns the set of build_dir basenames for confirmed modules.
"""
readelf_path = _get_readelf_path(env)
secho(f"INFO: Checking for usermod compilation units...")
try:
result = subprocess.run(
[readelf_path, "--debug-dump=info", "--dwarf-depth=1", str(elf_path)],
capture_output=True, text=True, errors="ignore", timeout=120,
)
output = result.stdout
if result.returncode != 0 or result.stderr.strip():
secho(f"WARNING: readelf exited {result.returncode}: {result.stderr.strip()}", fg="yellow", err=True)
except (subprocess.TimeoutExpired, FileNotFoundError, OSError) as e:
secho(f"WARNING: readelf failed ({e}); skipping per-module validation", fg="yellow", err=True)
return {Path(b.build_dir).name for b in module_lib_builders} # conservative pass
@@ -143,27 +143,20 @@ def validate_map_file(source, target, env):
Exit(1)
# Identify the WLED module builders, set by load_usermods.py
module_lib_builders = env.get('WLED_MODULES')
if module_lib_builders is None:
secho("ERROR: WLED_MODULES not set — ensure load_usermods.py is run as a pre: script", fg="red", err=True)
Exit(1)
module_lib_builders = env['WLED_MODULES']
# Extract the values we care about
modules = {Path(builder.build_dir).name: builder.name for builder in module_lib_builders}
secho(f"INFO: {len(modules)} libraries included as WLED optional/user modules")
secho(f"INFO: {len(modules)} libraries linked as WLED optional/user modules")
# Now parse the map file
map_file_contents = read_lines(map_file_path)
usermod_object_count = count_usermod_objects(map_file_contents)
secho(f"INFO: {usermod_object_count} usermod object entries found")
secho(f"INFO: {usermod_object_count} usermod object entries")
elf_path = build_dir / env.subst("${PROGNAME}.elf")
confirmed_modules = check_elf_modules(elf_path, env, module_lib_builders)
if confirmed_modules:
secho(f"INFO: Code from usermod libraries found in binary: {', '.join(confirmed_modules)}")
# else - if there's no usermods found, don't generate a message. If we're legitimately missing all entries, the error report on the
# next line will trip; and if the usermod set is expected to be empty, then there's no need for yet another null message.
missing_modules = [modname for mdir, modname in modules.items() if mdir not in confirmed_modules]
if missing_modules:
+123 -73
View File
@@ -42,6 +42,40 @@ extra_configs =
platformio_release.ini
[common]
# ------------------------------------------------------------------------------
# PLATFORM:
# !! DO NOT confuse platformio's ESP8266 development platform with Arduino core for ESP8266
#
# arduino core 2.6.3 = platformIO 2.3.2
# arduino core 2.7.0 = platformIO 2.5.0
# ------------------------------------------------------------------------------
arduino_core_2_6_3 = espressif8266@2.3.3
arduino_core_2_7_4 = espressif8266@2.6.2
arduino_core_3_0_0 = espressif8266@3.0.0
arduino_core_3_0_2 = espressif8266@3.2.0
arduino_core_3_1_0 = espressif8266@4.1.0
arduino_core_3_1_2 = espressif8266@4.2.1
# Development platforms
arduino_core_develop = https://github.com/platformio/platform-espressif8266#develop
arduino_core_git = https://github.com/platformio/platform-espressif8266#feature/stage
# Platform to use for ESP8266
platform_wled_default = ${common.arduino_core_3_1_2}
# We use 2.7.4.7 for all, includes PWM flicker fix and Wstring optimization
#platform_packages = tasmota/framework-arduinoespressif8266 @ 3.20704.7
platform_packages = platformio/toolchain-xtensa @ ~2.100300.220621 #2.40802.200502
platformio/tool-esptool #@ ~1.413.0
platformio/tool-esptoolpy #@ ~1.30000.0
## previous platform for 8266, in case of problems with the new one
## you'll need makuna/NeoPixelBus@ 2.6.9 for arduino_core_3_0_2, which does not support Ucs890x
;; platform_wled_default = ${common.arduino_core_3_0_2}
;; platform_packages = tasmota/framework-arduinoespressif8266 @ 3.20704.7
;; platformio/toolchain-xtensa @ ~2.40802.200502
;; platformio/tool-esptool @ ~1.413.0
;; platformio/tool-esptoolpy @ ~1.30000.0
# ------------------------------------------------------------------------------
# FLAGS: DEBUG
# esp8266 : see https://docs.platformio.org/en/latest/platforms/espressif8266.html#debug-level
@@ -160,41 +194,6 @@ lib_deps =
extra_scripts = ${scripts_defaults.extra_scripts}
[esp8266]
# ------------------------------------------------------------------------------
# PLATFORM:
# !! DO NOT confuse platformio's ESP8266 development platform with Arduino core for ESP8266
#
# arduino core 2.6.3 = platformIO 2.3.2
# arduino core 2.7.0 = platformIO 2.5.0
# ------------------------------------------------------------------------------
arduino_core_2_6_3 = espressif8266@2.3.3
arduino_core_2_7_4 = espressif8266@2.6.2
arduino_core_3_0_0 = espressif8266@3.0.0
arduino_core_3_0_2 = espressif8266@3.2.0
arduino_core_3_1_0 = espressif8266@4.1.0
arduino_core_3_1_2 = espressif8266@4.2.1
# Development platforms
arduino_core_develop = https://github.com/platformio/platform-espressif8266#develop
arduino_core_git = https://github.com/platformio/platform-espressif8266#feature/stage
# Platform to use for ESP8266
platform_wled_default = ${esp8266.arduino_core_3_1_2}
# We use 2.7.4.7 for all, includes PWM flicker fix and Wstring optimization
#platform_packages = tasmota/framework-arduinoespressif8266 @ 3.20704.7
platform_packages = platformio/toolchain-xtensa @ ~2.100300.220621 #2.40802.200502
platformio/tool-esptool #@ ~1.413.0
platformio/tool-esptoolpy #@ ~1.30000.0
## previous platform for 8266, in case of problems with the new one
## you'll need makuna/NeoPixelBus@ 2.6.9 for arduino_core_3_0_2, which does not support Ucs890x
;; platform_wled_default = ${esp8266.arduino_core_3_0_2}
;; platform_packages = tasmota/framework-arduinoespressif8266 @ 3.20704.7
;; platformio/toolchain-xtensa @ ~2.40802.200502
;; platformio/tool-esptool @ ~1.413.0
;; platformio/tool-esptoolpy @ ~1.30000.0
platform = ${esp8266.platform_wled_default}
build_unflags = ${common.build_unflags}
build_flags =
-DESP8266
@@ -227,8 +226,6 @@ lib_deps =
https://github.com/tignioj/ArduinoUZlib.git#20aff95cd80c141f80bdbf66895409a0046d2c2f
${env.lib_deps}
monitor_filters = esp8266_exception_decoder
;; compatibilty flags - same as 0.14.0 which seems to work better on some 8266 boards. Not using PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48
build_flags_compat =
-DESP8266
@@ -276,7 +273,6 @@ platform_packages =
build_unflags = ${common.build_unflags}
build_flags = ${esp32_idf_V4.build_flags}
lib_deps = ${esp32_idf_V4.lib_deps}
monitor_filters = esp32_exception_decoder
tiny_partitions = tools/WLED_ESP32_2MB_noOTA.csv
default_partitions = tools/WLED_ESP32_4MB_1MB_FS.csv
@@ -339,7 +335,6 @@ build_flags = -g
lib_deps =
${esp32_idf_V4.lib_deps}
board_build.partitions = ${esp32.default_partitions} ;; default partioning for 4MB Flash - can be overridden in build envs
monitor_filters = esp32_exception_decoder
[esp32c3]
;; generic definitions for all ESP32-C3 boards
@@ -359,7 +354,6 @@ lib_deps =
${esp32_idf_V4.lib_deps}
board_build.partitions = ${esp32.default_partitions} ;; default partioning for 4MB Flash - can be overridden in build envs
board_build.flash_mode = qio
monitor_filters = esp32_exception_decoder
[esp32s3]
;; generic definitions for all ESP32-S3 boards
@@ -379,8 +373,6 @@ build_flags = -g
lib_deps =
${esp32_idf_V4.lib_deps}
board_build.partitions = ${esp32.large_partitions} ;; default partioning for 8MB flash - can be overridden in build envs
upload_speed = 921600
monitor_filters = esp32_exception_decoder
# ------------------------------------------------------------------------------
@@ -388,11 +380,15 @@ monitor_filters = esp32_exception_decoder
# ------------------------------------------------------------------------------
[env:nodemcuv2]
extends = esp8266
board = nodemcuv2
platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_4m1m}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP8266\" #-DWLED_DISABLE_2D
-D WLED_DISABLE_PARTICLESYSTEM2D
lib_deps = ${esp8266.lib_deps}
monitor_filters = esp8266_exception_decoder
custom_usermods = audioreactive
[env:nodemcuv2_compat]
@@ -413,12 +409,15 @@ build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=
custom_usermods = audioreactive
[env:esp8266_2m]
extends = esp8266
board = esp_wroom_02
platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_2m512k}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP02\"
-D WLED_DISABLE_PARTICLESYSTEM2D
-D WLED_DISABLE_PARTICLESYSTEM1D
lib_deps = ${esp8266.lib_deps}
custom_usermods = audioreactive
[env:esp8266_2m_compat]
@@ -443,7 +442,7 @@ custom_usermods = audioreactive
;; Minimal-feature build for ESP02 (2MB flash).
;; Use this to recover from a failed OTA: flash via serial, then OTA-upload the regular esp8266_2m binary.
;; OTA is intentionally kept enabled. All other optional features are stripped to minimise binary size.
extends = esp8266
extends = env:esp8266_2m
board = esp_wroom_02
board_build.ldscript = ${common.ldscript_2m512k}
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP02_min\"
@@ -462,14 +461,17 @@ build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=
-D WLED_DISABLE_IMPROV_WIFISCAN
[env:esp01_1m_full]
extends = esp8266
board = esp01_1m
platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_1m128k}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP01\" -D WLED_DISABLE_OTA
; -D WLED_USE_REAL_MATH ;; may fix wrong sunset/sunrise times, at the cost of 7064 bytes FLASH and 975 bytes RAM
-D WLED_DISABLE_PARTICLESYSTEM1D
-D WLED_DISABLE_PARTICLESYSTEM2D
-D WLED_DISABLE_PIXELFORGE
lib_deps = ${esp8266.lib_deps}
[env:esp01_1m_full_compat]
extends = env:esp01_1m_full
@@ -492,11 +494,15 @@ build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=
custom_usermods = audioreactive
[env:esp32dev]
extends = esp32
board = esp32dev
platform = ${esp32_idf_V4.platform}
platform_packages = ${esp32_idf_V4.platform_packages}
build_unflags = ${common.build_unflags}
custom_usermods = audioreactive
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32\" #-D WLED_DISABLE_BROWNOUT_DET
-DARDUINO_USB_CDC_ON_BOOT=0 ;; this flag is mandatory for "classic ESP32" when building with arduino-esp32 >=2.0.3
lib_deps = ${esp32_idf_V4.lib_deps}
monitor_filters = esp32_exception_decoder
board_build.partitions = ${esp32.default_partitions}
board_build.flash_mode = dio
@@ -508,33 +514,50 @@ build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags}
-D WLED_RELEASE_NAME=\"ESP32_DEBUG\"
[env:esp32dev_8M]
extends = env:esp32dev
board = esp32dev
platform = ${esp32_idf_V4.platform}
platform_packages = ${esp32_idf_V4.platform_packages}
custom_usermods = audioreactive
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_8M\" #-D WLED_DISABLE_BROWNOUT_DET
-DARDUINO_USB_CDC_ON_BOOT=0 ;; this flag is mandatory for "classic ESP32" when building with arduino-esp32 >=2.0.3
lib_deps = ${esp32_idf_V4.lib_deps}
monitor_filters = esp32_exception_decoder
board_build.partitions = ${esp32.large_partitions}
board_upload.flash_size = 8MB
board_upload.maximum_size = 8388608
; board_build.f_flash = 80000000L
board_build.flash_mode = dio
[env:esp32dev_16M]
extends = env:esp32dev
board = esp32dev
platform = ${esp32_idf_V4.platform}
platform_packages = ${esp32_idf_V4.platform_packages}
custom_usermods = audioreactive
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_16M\" #-D WLED_DISABLE_BROWNOUT_DET
-DARDUINO_USB_CDC_ON_BOOT=0 ;; this flag is mandatory for "classic ESP32" when building with arduino-esp32 >=2.0.3
lib_deps = ${esp32_idf_V4.lib_deps}
monitor_filters = esp32_exception_decoder
board_build.partitions = ${esp32.extreme_partitions}
board_upload.flash_size = 16MB
board_upload.maximum_size = 16777216
board_build.f_flash = 80000000L
board_build.flash_mode = dio
[env:esp32_eth]
extends = esp32
board = esp32-poe
platform = ${esp32_idf_V4.platform}
platform_packages = ${esp32_idf_V4.platform_packages}
upload_speed = 921600
custom_usermods = audioreactive
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"ESP32_Ethernet\" -D RLYPIN=-1 -D WLED_USE_ETHERNET -D BTNPIN=-1
-D SR_DMTYPE=-1 -D AUDIOPIN=-1 -D I2S_SDPIN=-1 -D I2S_WSPIN=-1 -D I2S_CKPIN=-1 -D MCLK_PIN=-1 ;; force AR to not allocate any PINs at startup
-D DATA_PINS=4 ;; default led pin = 16 conflicts with pins used for ethernet
; -D WLED_DISABLE_ESPNOW ;; ESP-NOW requires wifi, may crash with ethernet only => uncomment if your board uses ETH_CLOCK_GPIO0_OUT, ETH_CLOCK_GPIO16_OUT, ETH_CLOCK_GPIO17_OUT
-DARDUINO_USB_CDC_ON_BOOT=0 ;; this flag is mandatory for "classic ESP32" when building with arduino-esp32 >=2.0.3
lib_deps = ${esp32.lib_deps}
board_build.partitions = ${esp32.default_partitions}
board_build.flash_mode = dio
@@ -545,14 +568,20 @@ board_build.f_flash = 80000000L
board_build.flash_mode = qio
board_build.partitions = ${esp32.extended_partitions}
custom_usermods = audioreactive
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_WROVER\"
-DARDUINO_USB_CDC_ON_BOOT=0 ;; this flag is mandatory for "classic ESP32" when building with arduino-esp32 >=2.0.3
-DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue ;; Older ESP32 (rev.<3) need a PSRAM fix (increases static RAM used) https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/external-ram.html
-D DATA_PINS=25
lib_deps = ${esp32_idf_V4.lib_deps}
[env:esp32c3dev]
extends = esp32c3
platform = ${esp32c3.platform}
platform_packages = ${esp32c3.platform_packages}
framework = arduino
board = esp32-c3-devkitm-1
board_build.partitions = ${esp32.default_partitions}
custom_usermods = audioreactive
build_flags = ${common.build_flags} ${esp32c3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-C3\"
-D WLED_WATCHDOG_TIMEOUT=0
@@ -560,6 +589,8 @@ build_flags = ${common.build_flags} ${esp32c3.build_flags} -D WLED_RELEASE_NAME=
-DARDUINO_USB_CDC_ON_BOOT=1 ;; for virtual CDC USB
;-DARDUINO_USB_CDC_ON_BOOT=0 ;; for serial-to-USB chip
upload_speed = 460800
build_unflags = ${common.build_unflags}
lib_deps = ${esp32c3.lib_deps}
board_build.flash_mode = dio ; safe default, required for OTA updates to 0.16 from older version which used dio (must match the bootloader!)
[env:esp32c3dev_qio]
@@ -569,34 +600,45 @@ board_build.flash_mode = qio ; qio is faster and works on almost all boards (som
[env:esp32s3dev_16MB_opi]
;; ESP32-S3 development board, with 16MB FLASH and >= 8MB PSRAM (memory_type: qio_opi)
extends = esp32s3
board = esp32-s3-devkitc-1 ;; generic dev board; the next line adds PSRAM support
board_build.arduino.memory_type = qio_opi ;; use with PSRAM: 8MB or 16MB
platform = ${esp32s3.platform}
platform_packages = ${esp32s3.platform_packages}
upload_speed = 921600
custom_usermods = audioreactive
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_16MB_opi\"
-D WLED_WATCHDOG_TIMEOUT=0
;-D ARDUINO_USB_CDC_ON_BOOT=0 ;; -D ARDUINO_USB_MODE=1 ;; for boards with serial-to-USB chip
-D ARDUINO_USB_CDC_ON_BOOT=1 ;; -D ARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB")
-DBOARD_HAS_PSRAM
lib_deps = ${esp32s3.lib_deps}
board_build.partitions = ${esp32.extreme_partitions}
board_upload.flash_size = 16MB
board_upload.maximum_size = 16777216
board_build.f_flash = 80000000L
board_build.flash_mode = qio
monitor_filters = esp32_exception_decoder
[env:esp32s3dev_8MB_opi]
;; ESP32-S3 development board, with 8MB FLASH and >= 8MB PSRAM (memory_type: qio_opi)
extends = esp32s3
board = esp32-s3-devkitc-1 ;; generic dev board; the next line adds PSRAM support
board_build.arduino.memory_type = qio_opi ;; use with PSRAM: 8MB or 16MB
platform = ${esp32s3.platform}
platform_packages = ${esp32s3.platform_packages}
upload_speed = 921600
custom_usermods = audioreactive
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_8MB_opi\"
-D WLED_WATCHDOG_TIMEOUT=0
;-D ARDUINO_USB_CDC_ON_BOOT=0 ;; -D ARDUINO_USB_MODE=1 ;; for boards with serial-to-USB chip
-D ARDUINO_USB_CDC_ON_BOOT=1 ;; -D ARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB")
-DBOARD_HAS_PSRAM
lib_deps = ${esp32s3.lib_deps}
board_build.partitions = ${esp32.large_partitions}
board_build.f_flash = 80000000L
board_build.flash_mode = qio
monitor_filters = esp32_exception_decoder
[env:esp32s3dev_8MB_qspi]
;; generic ESP32-S3 board with 8MB FLASH and PSRAM (memory_type: qio_qspi). Try this one if esp32s3dev_8MB_opi does not work on your board
@@ -609,6 +651,7 @@ build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=
-D ARDUINO_USB_CDC_ON_BOOT=1 ;; -D ARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB")
-DBOARD_HAS_PSRAM
;; -DLOLIN_WIFI_FIX ;; uncomment if you have WiFi connectivity problems
monitor_filters = esp32_exception_decoder
[env:esp32s3dev_8MB_none]
;; ESP32-S3 development board, 8MB FLASH, no PSRAM
@@ -626,10 +669,13 @@ board_build.flash_mode = qio
[env:esp32S3_wroom2]
;; For ESP32-S3 WROOM-2, a.k.a. ESP32-S3 DevKitC-1 v1.1
;; with >= 16MB FLASH and >= 8MB PSRAM (memory_type: opi_opi)
extends = esp32s3
platform = ${esp32s3.platform}
platform_packages = ${esp32s3.platform_packages}
board = esp32s3camlcd ;; this is the only standard board with "opi_opi"
board_build.arduino.memory_type = opi_opi
upload_speed = 921600
custom_usermods = audioreactive
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_WROOM-2\"
-D WLED_WATCHDOG_TIMEOUT=0
-D ARDUINO_USB_CDC_ON_BOOT=0 ;; -D ARDUINO_USB_MODE=1 ;; for boards with serial-to-USB chip
@@ -639,9 +685,12 @@ build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=
-D BTNPIN=0 -D RLYPIN=16 -D IRPIN=17 -D AUDIOPIN=-1
;;-D WLED_DEBUG
-D SR_DMTYPE=1 -D I2S_SDPIN=13 -D I2S_CKPIN=14 -D I2S_WSPIN=15 -D MCLK_PIN=4 ;; I2S mic
lib_deps = ${esp32s3.lib_deps}
board_build.partitions = ${esp32.extreme_partitions}
board_upload.flash_size = 16MB
board_upload.maximum_size = 16777216
monitor_filters = esp32_exception_decoder
[env:esp32S3_wroom2_32MB]
;; For ESP32-S3 WROOM-2 with 32MB Flash, and >= 8MB PSRAM (memory_type: opi_opi)
@@ -658,20 +707,26 @@ build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=
board_build.partitions = tools/WLED_ESP32_32MB.csv
board_upload.flash_size = 32MB
board_upload.maximum_size = 33554432
monitor_filters = esp32_exception_decoder
[env:esp32s3_4M_qspi]
;; ESP32-S3, with 4MB FLASH and <= 4MB PSRAM (memory_type: qio_qspi)
extends = esp32s3
board = lolin_s3_mini ;; -S3 mini, 4MB flash 2MB PSRAM
board = lolin_s3_mini ;; -S3 mini, 4MB flash 2MB PSRAM
platform = ${esp32s3.platform}
platform_packages = ${esp32s3.platform_packages}
upload_speed = 921600
custom_usermods = audioreactive
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_4M_qspi\"
-DARDUINO_USB_CDC_ON_BOOT=1 ;; -DARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB")
-DBOARD_HAS_PSRAM
-DLOLIN_WIFI_FIX ; seems to work much better with this
-D WLED_WATCHDOG_TIMEOUT=0
lib_deps = ${esp32s3.lib_deps}
board_build.partitions = ${esp32.default_partitions}
board_build.f_flash = 80000000L
board_build.flash_mode = qio
monitor_filters = esp32_exception_decoder
[env:esp32s3_4M_none]
;; ESP32-S3 with 4MB FLASH, no PSRAM
@@ -689,11 +744,14 @@ board_build.flash_mode = qio
[env:lolin_s2_mini]
extends = esp32s2
platform = ${esp32s2.platform}
platform_packages = ${esp32s2.platform_packages}
board = lolin_s2_mini
board_build.partitions = ${esp32.default_partitions}
board_build.flash_mode = qio
board_build.f_flash = 80000000L
custom_usermods = audioreactive
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp32s2.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S2\"
-DARDUINO_USB_CDC_ON_BOOT=1
-DARDUINO_USB_MSC_ON_BOOT=0
@@ -708,12 +766,19 @@ build_flags = ${common.build_flags} ${esp32s2.build_flags} -D WLED_RELEASE_NAME=
-D HW_PIN_DATASPI=11
-D HW_PIN_MISOSPI=9
; -D STATUSLED=15
lib_deps = ${esp32s2.lib_deps}
[env:usermods]
extends = env:esp32dev
board = esp32dev
platform = ${esp32_idf_V4.platform}
platform_packages = ${esp32_idf_V4.platform_packages}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_USERMODS\"
-DTOUCH_CS=9
lib_deps = ${esp32_idf_V4.lib_deps}
monitor_filters = esp32_exception_decoder
board_build.flash_mode = dio
custom_usermods = * ; Expands to all usermods in usermods folder
board_build.partitions = ${esp32.extreme_partitions} ; We're gonna need a bigger boat
@@ -790,21 +855,6 @@ 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
+56 -59
View File
@@ -13,8 +13,8 @@ default_envs = WLED_generic8266_1M, esp32dev_V4_dio80 # put the name(s) of your
[env:WLED_generic8266_1M]
extends = env:esp01_1m_full # when you want to extend the existing environment (define only updated options)
; board = esp01_1m # uncomment when ou need different board
; platform = ${esp8266.platform_wled_default} # uncomment and change when you want particular platform
; platform_packages = ${esp8266.platform_packages}
; platform = ${common.platform_wled_default} # uncomment and change when you want particular platform
; platform_packages = ${common.platform_packages}
; board_build.ldscript = ${common.ldscript_1m128k}
; upload_speed = 921600 # fast upload speed (remove ';' if your board supports fast upload speed)
# Sample libraries used for various usermods. Uncomment when using particular usermod.
@@ -33,12 +33,7 @@ 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\"
;
@@ -103,17 +98,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
; custom_usermods = ${env:esp32dev.custom_usermods} auto_save
; -D USERMOD_AUTO_SAVE
; -D AUTOSAVE_AFTER_SEC=90
;
; Use AHT10/AHT15/AHT20 usermod
; custom_usermods = ${env:esp32dev.custom_usermods} AHT10_v2
; -D USERMOD_AHT10
;
; Use INA226 usermod
; custom_usermods = ${env:esp32dev.custom_usermods} INA226_v2
; -D USERMOD_INA226
;
; Use 4 Line Display usermod with SPI display
; custom_usermods = ${env:esp32dev.custom_usermods} four_line_display_ALT
; -D USERMOD_FOUR_LINE_DISPLAY
; -DFLD_SPI_DEFAULT
; -D FLD_TYPE=SSD1306_SPI64
; -D FLD_PIN_CLOCKSPI=14
@@ -123,22 +118,22 @@ build_flags = ${common.build_flags} ${esp8266.build_flags}
; -D FLD_PIN_RESET=27
;
; Use Rotary encoder usermod (in conjunction with 4LD)
; custom_usermods = ${env:esp32dev.custom_usermods} rotary_encoder_ui_ALT
; -D USERMOD_ROTARY_ENCODER_UI
; -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
; custom_usermods = ${env:esp32dev.custom_usermods} Temperature
; -D USERMOD_DALLASTEMPERATURE
; -D TEMPERATURE_PIN=13
;
; Use Multi Relay usermod and configure it to use 6 relays and appropriate GPIO
; custom_usermods = ${env:esp32dev.custom_usermods} multi_relay
; -D USERMOD_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
; custom_usermods = ${env:esp32dev.custom_usermods} PIR_sensor_switch
; -D USERMOD_PIRSWITCH
; -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)
@@ -151,12 +146,12 @@ build_flags = ${common.build_flags} ${esp8266.build_flags}
; -D I2S_CKPIN=19
;
; Use PWM fan usermod
; custom_usermods = ${env:esp32dev.custom_usermods} PWM_fan
; -D USERMOD_PWM_FAN
; -D TACHO_PIN=33
; -D PWM_PIN=32
;
; Use POV Display usermod
; custom_usermods = ${env:esp32dev.custom_usermods} pov_display
; -D USERMOD_POV_DISPLAY
; Use built-in or custom LED as a status indicator (assumes LED is connected to GPIO16)
; -D STATUSLED=16
;
@@ -220,8 +215,8 @@ build_flags =
[env:esp07]
board = esp07
platform = ${esp8266.platform_wled_default}
platform_packages = ${esp8266.platform_packages}
platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_4m1m}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp8266.build_flags}
@@ -229,8 +224,8 @@ lib_deps = ${esp8266.lib_deps}
[env:d1_mini]
board = d1_mini
platform = ${esp8266.platform_wled_default}
platform_packages = ${esp8266.platform_packages}
platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
upload_speed = 921600
board_build.ldscript = ${common.ldscript_4m1m}
build_unflags = ${common.build_unflags}
@@ -240,8 +235,8 @@ monitor_filters = esp8266_exception_decoder
[env:heltec_wifi_kit_8]
board = d1_mini
platform = ${esp8266.platform_wled_default}
platform_packages = ${esp8266.platform_packages}
platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_4m1m}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp8266.build_flags}
@@ -249,8 +244,8 @@ lib_deps = ${esp8266.lib_deps}
[env:h803wf]
board = d1_mini
platform = ${esp8266.platform_wled_default}
platform_packages = ${esp8266.platform_packages}
platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_4m1m}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp8266.build_flags} -D DATA_PINS=1 -D WLED_DISABLE_INFRARED
@@ -300,8 +295,8 @@ board_build.arduino.memory_type = qio_qspi ;; use with PSRAM: 2MB or 4MB
[env:esp8285_4CH_MagicHome]
board = esp8285
platform = ${esp8266.platform_wled_default}
platform_packages = ${esp8266.platform_packages}
platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_1m128k}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_DISABLE_OTA
@@ -309,8 +304,8 @@ lib_deps = ${esp8266.lib_deps}
[env:esp8285_H801]
board = esp8285
platform = ${esp8266.platform_wled_default}
platform_packages = ${esp8266.platform_packages}
platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_1m128k}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_DISABLE_OTA
@@ -318,8 +313,8 @@ lib_deps = ${esp8266.lib_deps}
[env:d1_mini_5CH_Shojo_PCB]
board = d1_mini
platform = ${esp8266.platform_wled_default}
platform_packages = ${esp8266.platform_packages}
platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_4m1m}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_USE_SHOJO_PCB ;; NB: WLED_USE_SHOJO_PCB is not used anywhere in the source code. Not sure why its needed.
@@ -328,8 +323,8 @@ lib_deps = ${esp8266.lib_deps}
[env:d1_mini_debug]
board = d1_mini
build_type = debug
platform = ${esp8266.platform_wled_default}
platform_packages = ${esp8266.platform_packages}
platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_4m1m}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp8266.build_flags} ${common.debug_flags}
@@ -340,8 +335,8 @@ board = d1_mini
upload_protocol = espota
# exchange for your WLED IP
upload_port = "10.10.1.27"
platform = ${esp8266.platform_wled_default}
platform_packages = ${esp8266.platform_packages}
platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_4m1m}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp8266.build_flags}
@@ -349,8 +344,8 @@ lib_deps = ${esp8266.lib_deps}
[env:anavi_miracle_controller]
board = d1_mini
platform = ${esp8266.platform_wled_default}
platform_packages = ${esp8266.platform_packages}
platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_4m1m}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp8266.build_flags} -D DATA_PINS=12 -D IRPIN=-1 -D RLYPIN=2
@@ -380,7 +375,6 @@ 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
@@ -388,8 +382,12 @@ 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]
@@ -415,22 +413,22 @@ build_flags = ${common.build_flags} ${esp32.build_flags} -D DATA_PINS=27 -D BTNP
[env:sp501e]
board = esp_wroom_02
platform = ${esp8266.platform_wled_default}
platform = ${common.platform_wled_default}
board_build.ldscript = ${common.ldscript_2m512k}
build_flags = ${common.build_flags} ${esp8266.build_flags} -D DATA_PINS=3 -D BTNPIN=1
lib_deps = ${esp8266.lib_deps}
[env:sp511e]
board = esp_wroom_02
platform = ${esp8266.platform_wled_default}
platform = ${common.platform_wled_default}
board_build.ldscript = ${common.ldscript_2m512k}
build_flags = ${common.build_flags} ${esp8266.build_flags} -D DATA_PINS=3 -D BTNPIN=2 -D IRPIN=5 -D WLED_MAX_BUTTONS=3
lib_deps = ${esp8266.lib_deps}
[env:Athom_RGBCW] ;7w and 5w(GU10) bulbs
board = esp8285
platform = ${esp8266.platform_wled_default}
platform_packages = ${esp8266.platform_packages}
platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_2m512k}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp8266.build_flags} -D BTNPIN=-1 -D RLYPIN=-1 -D DATA_PINS=4,12,14,13,5
@@ -439,8 +437,8 @@ lib_deps = ${esp8266.lib_deps}
[env:Athom_15w_RGBCW] ;15w bulb
board = esp8285
platform = ${esp8266.platform_wled_default}
platform_packages = ${esp8266.platform_packages}
platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_2m512k}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp8266.build_flags} -D BTNPIN=-1 -D RLYPIN=-1 -D DATA_PINS=4,12,14,5,13
@@ -449,8 +447,8 @@ lib_deps = ${esp8266.lib_deps}
[env:Athom_3Pin_Controller] ;small controller with only data
board = esp8285
platform = ${esp8266.platform_wled_default}
platform_packages = ${esp8266.platform_packages}
platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_2m512k}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp8266.build_flags} -D BTNPIN=0 -D RLYPIN=-1 -D DATA_PINS=1 -D WLED_DISABLE_INFRARED
@@ -458,8 +456,8 @@ lib_deps = ${esp8266.lib_deps}
[env:Athom_4Pin_Controller] ; With clock and data interface
board = esp8285
platform = ${esp8266.platform_wled_default}
platform_packages = ${esp8266.platform_packages}
platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_2m512k}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp8266.build_flags} -D BTNPIN=0 -D RLYPIN=12 -D DATA_PINS=1 -D WLED_DISABLE_INFRARED
@@ -467,8 +465,8 @@ lib_deps = ${esp8266.lib_deps}
[env:Athom_5Pin_Controller] ;Analog light strip controller
board = esp8285
platform = ${esp8266.platform_wled_default}
platform_packages = ${esp8266.platform_packages}
platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_2m512k}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp8266.build_flags} -D BTNPIN=0 -D RLYPIN=-1 DATA_PINS=4,12,14,13 -D WLED_DISABLE_INFRARED
@@ -476,12 +474,11 @@ lib_deps = ${esp8266.lib_deps}
[env:MY9291]
board = esp01_1m
platform = ${esp8266.platform_wled_default}
platform_packages = ${esp8266.platform_packages}
platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_1m128k}
build_unflags = ${common.build_unflags}
custom_usermods = ${env:esp01_1m_full.custom_usermods} MY9291
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_DISABLE_OTA
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_DISABLE_OTA -D USERMOD_MY9291
lib_deps = ${esp8266.lib_deps}
# ------------------------------------------------------------------------------
@@ -491,8 +488,8 @@ lib_deps = ${esp8266.lib_deps}
[env:codm-controller-0_6]
board = esp_wroom_02
platform = ${esp8266.platform_wled_default}
platform_packages = ${esp8266.platform_packages}
platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_2m512k}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp8266.build_flags}
@@ -500,8 +497,8 @@ lib_deps = ${esp8266.lib_deps}
[env:codm-controller-0_6-rev2]
board = esp_wroom_02
platform = ${esp8266.platform_wled_default}
platform_packages = ${esp8266.platform_packages}
platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_4m1m}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp8266.build_flags}
+63 -47
View File
@@ -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://img.shields.io/badge/send%20me%20a%20small%20gift-paypal-blue.svg?style=flat-square)](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.
+1 -1
View File
@@ -38,7 +38,7 @@ pyelftools==0.32
# via platformio
pyserial==3.5
# via platformio
requests==2.33.0
requests==2.32.4
# via platformio
semantic-version==2.10.0
# via platformio
+6 -12
View File
@@ -119,7 +119,7 @@ describe('Script', () => {
async function checkIfFileWasNewlyCreated(file) {
const modifiedTime = fs.statSync(file).mtimeMs;
assert(Date.now() - modifiedTime < 850, file + ' was not modified');
assert(Date.now() - modifiedTime < 500, file + ' was not modified');
}
async function testFileModification(sourceFilePath, resultFile) {
@@ -129,7 +129,7 @@ describe('Script', () => {
// modify file
fs.appendFileSync(sourceFilePath, ' ');
// delay for 1 second to ensure the modified time is different
await new Promise(resolve => setTimeout(resolve, 1400));
await new Promise(resolve => setTimeout(resolve, 1000));
// run script cdata.js again and wait for it to finish
await execPromise('node tools/cdata.js');
@@ -175,19 +175,13 @@ describe('Script', () => {
});
it('a settings file changes', async () => {
await testFileModification(path.join(dataPath, 'settings_leds.htm'), 'html_settings.h');
await testFileModification(path.join(dataPath, 'settings_leds.htm'), 'html_ui.h');
});
it('common.js changes', async () => {
await testFileModification(path.join(dataPath, 'common.js'), 'html_settings.h');
it('the favicon changes', async () => {
await testFileModification(path.join(dataPath, 'favicon.ico'), 'html_ui.h');
});
// this testcase currently fails - might be due to npm updates (maybe "faking" a favicon.ico change is harder now), or a real regression
// see https://github.com/wled/WLED/issues/5581
// it('the favicon changes', async () => {
// await testFileModification(path.join(dataPath, 'favicon.ico'), 'html_other.h');
// });
it('cdata.js changes', async () => {
await testFileModification('tools/cdata.js', 'html_ui.h');
});
@@ -215,4 +209,4 @@ describe('Script', () => {
assert(secondRunTime < firstRunTime / 2, 'html_*.h files were rebuilt');
});
});
});
});
+2 -10
View File
@@ -141,16 +141,8 @@ discover_devices() {
exit 1
fi
# Map avahi responses to strings separated by 0x1F (unit separator), deduplicated
mapfile -t raw_devices < <(
avahi-browse _wled._tcp --terminate -r -p |
awk -F';' '
/^=/ {
key = $7 "\x1F" $8 "\x1F" $9
if (!seen[key]++) print key
}
'
)
# Map avahi responses to strings seperated by 0x1F (unit separator)
mapfile -t raw_devices < <(avahi-browse _wled._tcp --terminate -r -p | awk -F';' '/^=/ {print $7"\x1F"$8"\x1F"$9}')
local devices_array=()
for device in "${raw_devices[@]}"; do
+11 -12
View File
@@ -28,19 +28,18 @@ class ADS1115Usermod : public Usermod {
}
void loop() {
if (!isEnabled || strip.isUpdating() || millis() - lastTime <= loopInterval)
return;
if (isEnabled && millis() - lastTime > loopInterval) {
lastTime = millis();
lastTime = millis();
// If we don't have new data, skip this iteration.
if (!ads.conversionComplete()) {
return;
}
// If we don't have new data, skip this iteration.
if (!ads.conversionComplete()) {
return;
updateResult();
moveToNextChannel();
startReading();
}
updateResult();
moveToNextChannel();
startReading();
}
void addToJsonInfo(JsonObject& root)
@@ -70,8 +69,6 @@ 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);
@@ -82,6 +79,8 @@ class ADS1115Usermod : public Usermod {
channel[F("Offset")] = settingsPtr->offset;
channel[F("Decimals")] = settingsPtr->decimals;
}
top[F("Loop Interval")] = loopInterval;
}
bool readFromConfig(JsonObject& root)
+2 -2
View File
@@ -2,7 +2,7 @@
"name": "ADS1115_v2",
"build": { "libArchive": false },
"dependencies": {
"Adafruit BusIO": "https://github.com/adafruit/Adafruit_BusIO#1.17.4",
"Adafruit ADS1X15": "https://github.com/adafruit/Adafruit_ADS1X15#2.6.2"
"Adafruit BusIO": "https://github.com/adafruit/Adafruit_BusIO#1.13.2",
"Adafruit ADS1X15": "https://github.com/adafruit/Adafruit_ADS1X15#2.4.0"
}
}
+5 -24
View File
@@ -1,29 +1,10 @@
# ADS1115 Usermod
# ADS1115 16-Bit ADC with four inputs
Reads values from an ADS1115 16-bit ADC and exposes them in the `Info` tab.
This usermod will read from an ADS1115 ADC. The voltages are displayed in the Info section of the web UI.
## 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.
Configuration is performed via the Usermod menu. There are no parameters to set in code!
## Compatibility
- Requires an ADS1115 module connected via I2C.
- Works on targets with I2C support.
- Default ADC gain is `1x` (input range `+/-4.096V`).
## Installation
## Installation
- Add `ADS1115` to `custom_usermods` in your `platformio.ini` (or `platformio_override.ini`).
## Author
- Dima Zhemkov [@dima-zhemkov](https://github.com/dima-zhemkov)
Add 'ADS1115' to `custom_usermods` in your platformio environment.
@@ -25,8 +25,6 @@ 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;
@@ -93,8 +91,6 @@ 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
@@ -160,12 +156,6 @@ 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;
@@ -174,15 +164,15 @@ class Animated_Staircase : public Usermod {
bottomSensorRead = bottomSensorWrite ||
(!useUSSensorBottom ?
(bottomPIRorTriggerPin<0 ? false : readPIRPin(bottomPIRorTriggerPin, bottomAPinInvert)) :
(bottomPIRorTriggerPin<0 ? false : digitalRead(bottomPIRorTriggerPin)) :
ultrasoundRead(bottomPIRorTriggerPin, bottomEchoPin, bottomMaxDist*59) // cm to us
);
topSensorRead = topSensorWrite ||
(!useUSSensorTop ?
(topPIRorTriggerPin<0 ? false : readPIRPin(topPIRorTriggerPin, topAPinInvert)) :
(topPIRorTriggerPin<0 ? false : digitalRead(topPIRorTriggerPin)) :
ultrasoundRead(topPIRorTriggerPin, topEchoPin, topMaxDist*59) // cm to us
);
if (bottomSensorRead != bottomSensorState) {
bottomSensorState = bottomSensorRead; // change previous state
sensorChanged = true;
@@ -449,20 +439,18 @@ 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(_topPIRorTrigger_pin_invert)] = topAPinInvert;
staircase[FPSTR(_bottomPIRorTrigger_pin_invert)] = bottomAPinInvert;
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;
DEBUG_PRINTLN(F("Staircase config saved."));
}
@@ -474,13 +462,11 @@ 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));
@@ -499,12 +485,10 @@ 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)
@@ -570,15 +554,14 @@ 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);
+1 -1
View File
@@ -1,5 +1,5 @@
{
"name": "EleksTube_IPS",
"name:": "EleksTube_IPS",
"build": { "libArchive": false },
"dependencies": {
"TFT_eSPI" : "2.5.33"
+35 -114
View File
@@ -1,38 +1,14 @@
#include "wled.h"
#include <INA226_WE.h>
#ifndef INA226_ADDRESS
#define INA226_ADDRESS 0x40 // Default I2C address for INA226
#endif
#ifndef INA226_CHECK_INTERVAL_MS
#define INA226_CHECK_INTERVAL_MS 60000 // Default check interval in milliseconds
#endif
#define DEFAULT_CHECKINTERVAL INA226_CHECK_INTERVAL_MS
#define DEFAULT_CHECKINTERVAL 60000
#define DEFAULT_INASAMPLES 128
#define DEFAULT_INASAMPLESENUM AVERAGE_128
#define DEFAULT_INACONVERSIONTIME 1100
#define DEFAULT_INACONVERSIONTIMEENUM CONV_TIME_1100
// Compile-time defaults for shunt resistor (micro-ohms), current range (mA), and current offset (mA)
// These can be overridden via -D flags in platformio.ini / platformio_override.ini
#ifndef INA226_SHUNT_MICRO_OHMS
#define INA226_SHUNT_MICRO_OHMS 1000000 // 1 Ohm = 1,000,000 μΩ
#endif
#ifndef INA226_DEFAULT_CURRENT_RANGE
#define INA226_DEFAULT_CURRENT_RANGE 1000 // 1000 mA = 1 A
#endif
#ifndef INA226_CURRENT_OFFSET_MA
#define INA226_CURRENT_OFFSET_MA 0 // No offset by default
#endif
#ifndef INA226_ENABLED_DEFAULT
#define INA226_ENABLED_DEFAULT false
#endif
// A packed version of all INA settings enums and their human friendly counterparts packed into a 32 bit structure
// Some values are shifted and need to be preprocessed before usage
struct InaSettingLookup
@@ -105,11 +81,10 @@ private:
uint16_t _settingInaSamples : 11; // Number of samples for averaging, max 1024
uint8_t _i2cAddress;
uint32_t _checkIntervalMs; // milliseconds, user settings is in seconds
float _decimalFactor; // a power of 10 factor. 1 would be no change, 10 is one decimal, 100 is two etc. User sees a power of 10 (0, 1, 2, ..)
uint32_t _shuntResistorUOhm; // Shunt resistor value in micro-ohms (μΩ)
uint16_t _currentRangeMa; // Expected maximum current in milliamps
int16_t _currentOffsetMa; // Current offset in milliamps, subtracted from readings
uint16_t _checkInterval; // milliseconds, user settings is in seconds
float _decimalFactor; // a power of 10 factor. 1 would be no change, 10 is one decimal, 100 is two etc. User sees a power of 10 (0, 1, 2, ..)
uint16_t _shuntResistor; // Shunt resistor value in milliohms
uint16_t _currentRange; // Expected maximum current in milliamps
uint8_t _lastStatus = 0;
float _lastCurrent = 0;
@@ -118,7 +93,7 @@ private:
float _lastShuntVoltage = 0;
bool _lastOverflow = false;
#ifndef WLED_DISABLE_MQTT
#ifndef WLED_MQTT_DISABLE
float _lastCurrentSent = 0;
float _lastVoltageSent = 0;
float _lastPowerSent = 0;
@@ -143,11 +118,9 @@ private:
_ina226 = new INA226_WE(_i2cAddress);
if (!_ina226->init())
{
DEBUG_PRINTLN(F("INA226: init failed!"));
DEBUG_PRINTLN(F("INA226 initialization failed!"));
return;
}
DEBUG_PRINTF_P(PSTR("INA226: addr=0x%02X shunt=%luμΩ range=%umA offset=%dmA\n"),
_i2cAddress, _shuntResistorUOhm, _currentRangeMa, _currentOffsetMa);
_ina226->setCorrectionFactor(1.0);
uint16_t tmpShort = _settingInaSamples;
@@ -156,7 +129,7 @@ private:
tmpShort = _settingInaConversionTimeUs << 2;
_ina226->setConversionTime(getConversionTimeEnum(tmpShort));
if (_checkIntervalMs >= 20000)
if (_checkInterval >= 20000)
{
_isTriggeredOperationMode = true;
_ina226->setMeasureMode(TRIGGERED);
@@ -167,11 +140,7 @@ private:
_ina226->setMeasureMode(CONTINUOUS);
}
_ina226->setResistorRange(static_cast<float>(_shuntResistorUOhm) / 1000000.0f, static_cast<float>(_currentRangeMa) / 1000.0f);
DEBUG_PRINTF_P(PSTR("INA226: mode=%s interval=%lums samples=%u convTime=%uμs\n"),
_isTriggeredOperationMode ? "triggered" : "continuous",
_checkIntervalMs, _settingInaSamples, _settingInaConversionTimeUs << 2);
_ina226->setResistorRange(static_cast<float>(_shuntResistor) / 1000.0, static_cast<float>(_currentRange) / 1000.0);
}
void fetchAndPushValues()
@@ -181,19 +150,17 @@ private:
if (_lastStatus != 0)
return;
float current = truncateDecimals((_ina226->getCurrent_mA() - _currentOffsetMa) / 1000.0f);
float current = truncateDecimals(_ina226->getCurrent_mA() / 1000.0);
float voltage = truncateDecimals(_ina226->getBusVoltage_V());
float power = truncateDecimals(_ina226->getBusPower() / 1000.0f);
float shuntVoltage = truncateDecimals(_ina226->getShuntVoltage_mV());
float power = truncateDecimals(_ina226->getBusPower() / 1000.0);
float shuntVoltage = truncateDecimals(_ina226->getShuntVoltage_V());
bool overflow = _ina226->overflow;
#ifndef WLED_DISABLE_MQTT
mqttPublishIfChanged(F("current"), _lastCurrentSent, current, 0.01f);
mqttPublishIfChanged(F("voltage"), _lastVoltageSent, voltage, 0.01f);
mqttPublishIfChanged(F("power"), _lastPowerSent, power, 0.1f);
// Publish in V for backward compatibility
float shuntVoltageV = shuntVoltage / 1000.0f;
mqttPublishIfChanged(F("shunt_voltage"), _lastShuntVoltageSent, shuntVoltageV, 0.01f);
mqttPublishIfChanged(F("shunt_voltage"), _lastShuntVoltageSent, shuntVoltage, 0.01f);
mqttPublishIfChanged(F("overflow"), _lastOverflowSent, overflow);
#endif
@@ -202,9 +169,6 @@ private:
_lastPower = power;
_lastShuntVoltage = shuntVoltage;
_lastOverflow = overflow;
DEBUG_PRINTF_P(PSTR("INA226: %.3fA %.2fV %.2fW shunt=%.2fmV%s\n"),
current, voltage, power, shuntVoltage, overflow ? " OVF" : "");
}
void handleTriggeredMode(unsigned long currentTime)
@@ -224,7 +188,7 @@ private:
}
else
{
if (currentTime - _lastLoopCheck >= _checkIntervalMs)
if (currentTime - _lastLoopCheck >= _checkInterval)
{
// Start a measurement and use isBusy() later to determine when it is done
_ina226->startSingleMeasurementNoWait();
@@ -237,7 +201,7 @@ private:
void handleContinuousMode(unsigned long currentTime)
{
if (currentTime - _lastLoopCheck >= _checkIntervalMs)
if (currentTime - _lastLoopCheck >= _checkInterval)
{
_lastLoopCheck = currentTime;
fetchAndPushValues();
@@ -251,23 +215,19 @@ private:
return;
char topic[128];
auto buildTopic = [&](const char *suffix) {
snprintf_P(topic, sizeof(topic), PSTR("%s/%s"), mqttDeviceTopic, suffix);
};
buildTopic("current");
snprintf_P(topic, 127, "%s/current", mqttDeviceTopic);
mqttCreateHassSensor(F("Current"), topic, F("current"), F("A"));
buildTopic("voltage");
snprintf_P(topic, 127, "%s/voltage", mqttDeviceTopic);
mqttCreateHassSensor(F("Voltage"), topic, F("voltage"), F("V"));
buildTopic("power");
snprintf_P(topic, 127, "%s/power", mqttDeviceTopic);
mqttCreateHassSensor(F("Power"), topic, F("power"), F("W"));
buildTopic("shunt_voltage");
snprintf_P(topic, 127, "%s/shunt_voltage", mqttDeviceTopic);
mqttCreateHassSensor(F("Shunt Voltage"), topic, F("voltage"), F("V"));
buildTopic("overflow");
snprintf_P(topic, 127, "%s/overflow", mqttDeviceTopic);
mqttCreateHassBinarySensor(F("Overflow"), topic);
}
@@ -355,23 +315,14 @@ public:
UsermodINA226()
{
// Default values
_settingEnabled = INA226_ENABLED_DEFAULT;
_settingInaSamples = DEFAULT_INASAMPLES;
_settingInaConversionTimeUs = DEFAULT_INACONVERSIONTIME >> 2; // stored shifted to fit 12-bit field
_settingInaConversionTimeUs = DEFAULT_INACONVERSIONTIME;
_i2cAddress = INA226_ADDRESS;
_checkIntervalMs = DEFAULT_CHECKINTERVAL;
_checkInterval = DEFAULT_CHECKINTERVAL;
_decimalFactor = 100;
_shuntResistorUOhm = INA226_SHUNT_MICRO_OHMS;
_currentRangeMa = INA226_DEFAULT_CURRENT_RANGE;
_currentOffsetMa = INA226_CURRENT_OFFSET_MA;
_mqttPublish = false;
_mqttPublishAlways = false;
_mqttHomeAssistant = false;
_initDone = false;
_isTriggeredOperationMode = false;
_measurementTriggered = false;
_shuntResistor = 1000;
_currentRange = 1000;
}
void setup()
@@ -448,7 +399,7 @@ public:
JsonArray jsonCurrent = user.createNestedArray(F("Current"));
JsonArray jsonVoltage = user.createNestedArray(F("Voltage"));
JsonArray jsonPower = user.createNestedArray(F("Power"));
JsonArray jsonShuntVoltage = user.createNestedArray(F("Shunt Voltage Drop"));
JsonArray jsonShuntVoltage = user.createNestedArray(F("Shunt Voltage"));
JsonArray jsonOverflow = user.createNestedArray(F("Overflow"));
if (_lastLoopCheck == 0)
@@ -481,7 +432,7 @@ public:
jsonPower.add(F("W"));
jsonShuntVoltage.add(_lastShuntVoltage);
jsonShuntVoltage.add(F("mV"));
jsonShuntVoltage.add(F("V"));
jsonOverflow.add(_lastOverflow ? F("true") : F("false"));
}
@@ -491,13 +442,12 @@ public:
JsonObject top = root.createNestedObject(FPSTR(_name));
top[F("Enabled")] = _settingEnabled;
top[F("I2CAddress")] = static_cast<uint8_t>(_i2cAddress);
top[F("CheckInterval")] = _checkIntervalMs / 1000;
top[F("CheckInterval")] = _checkInterval / 1000;
top[F("INASamples")] = _settingInaSamples;
top[F("INAConversionTime")] = _settingInaConversionTimeUs << 2;
top[F("Decimals")] = log10f(_decimalFactor);
top[F("ShuntResistor")] = static_cast<float>(_shuntResistorUOhm) / 1000.0f;
top[F("CurrentRange")] = _currentRangeMa;
top[F("CurrentOffset")] = _currentOffsetMa;
top[F("ShuntResistor")] = _shuntResistor;
top[F("CurrentRange")] = _currentRange;
#ifndef WLED_DISABLE_MQTT
top[F("MqttPublish")] = _mqttPublish;
top[F("MqttPublishAlways")] = _mqttPublishAlways;
@@ -507,17 +457,6 @@ public:
DEBUG_PRINTLN(F("INA226 config saved."));
}
void appendConfigData() override
{
oappend(F("addInfo('INA226:CheckInterval',1,'seconds');"));
oappend(F("addInfo('INA226:INASamples',1,'samples (1-1024)');"));
oappend(F("addInfo('INA226:INAConversionTime',1,'&micro;s');"));
oappend(F("addInfo('INA226:Decimals',1,'(0-5)');"));
oappend(F("addInfo('INA226:ShuntResistor',1,'m&Omega;');"));
oappend(F("addInfo('INA226:CurrentRange',1,'mA');"));
oappend(F("addInfo('INA226:CurrentOffset',1,'mA');"));
}
bool readFromConfig(JsonObject &root) override
{
JsonObject top = root[FPSTR(_name)];
@@ -533,12 +472,12 @@ public:
configComplete = false;
configComplete &= getJsonValue(top[F("I2CAddress")], _i2cAddress);
if (getJsonValue(top[F("CheckInterval")], _checkIntervalMs))
if (getJsonValue(top[F("CheckInterval")], _checkInterval))
{
if (1 <= _checkIntervalMs && _checkIntervalMs <= 600)
_checkIntervalMs *= 1000;
if (1 <= _checkInterval && _checkInterval <= 600)
_checkInterval *= 1000;
else
_checkIntervalMs = DEFAULT_CHECKINTERVAL;
_checkInterval = DEFAULT_CHECKINTERVAL;
}
else
configComplete = false;
@@ -572,26 +511,8 @@ public:
else
configComplete = false;
float shuntMilliOhms;
if (getJsonValue(top[F("ShuntResistor")], shuntMilliOhms))
{
if (shuntMilliOhms > 0)
_shuntResistorUOhm = static_cast<uint32_t>(shuntMilliOhms * 1000.0f + 0.5f);
else
_shuntResistorUOhm = INA226_SHUNT_MICRO_OHMS;
}
else
configComplete = false;
if (getJsonValue(top[F("CurrentRange")], _currentRangeMa))
{
if (_currentRangeMa == 0 || _currentRangeMa > 20000)
_currentRangeMa = INA226_DEFAULT_CURRENT_RANGE;
}
else
configComplete = false;
if (!getJsonValue(top[F("CurrentOffset")], _currentOffsetMa))
_currentOffsetMa = INA226_CURRENT_OFFSET_MA; // Use compile-time default if missing from config
configComplete &= getJsonValue(top[F("ShuntResistor")], _shuntResistor);
configComplete &= getJsonValue(top[F("CurrentRange")], _currentRange);
#ifndef WLED_DISABLE_MQTT
if (getJsonValue(top[F("MqttPublish")], tmpBool))
+1 -31
View File
@@ -18,7 +18,6 @@ The following settings can be configured in the Usermod Menu:
- **Decimals**: Number of decimals in the output.
- **ShuntResistor**: Shunt resistor value in milliohms. An R100 shunt resistor should be written as "100", while R010 should be "10".
- **CurrentRange**: Expected maximum current in milliamps (e.g., 5 A = 5000 mA).
- **CurrentOffset**: Current offset in milliamps, subtracted from raw readings. Useful for compensating a consistent bias in the sensor. Default is 0.
- **MqttPublish**: Enable or disable MQTT publishing.
- **MqttPublishAlways**: Publish always, regardless if there is a change.
- **MqttHomeAssistantDiscovery**: Enable Home Assistant discovery.
@@ -64,33 +63,4 @@ extends = env:esp32dev
custom_usermods = ${env:esp32dev.custom_usermods} INA226
build_flags = ${env:esp32dev.build_flags}
; -D USERMOD_INA226_DEBUG ; -- add a debug status to the info modal
```
### Compile-time Defaults
Several parameters can be overridden at compile time via `-D` build flags. This is useful for setting board-specific defaults so the device works correctly on first boot without manual configuration.
| Build Flag | Default | Unit | Description |
|---|---|---|---|
| `INA226_ADDRESS` | `0x40` | — | I2C address of the INA226 |
| `INA226_SHUNT_MICRO_OHMS` | `1000000` | μΩ | Shunt resistor value (1 000 000 μΩ = 1 Ω) |
| `INA226_DEFAULT_CURRENT_RANGE` | `1000` | mA | Expected maximum current (1000 mA = 1 A) |
| `INA226_CURRENT_OFFSET_MA` | `0` | mA | Current offset subtracted from readings |
| `INA226_CHECK_INTERVAL_MS` | `60000` | ms | Default interval between readings on first boot |
| `INA226_ENABLED_DEFAULT` | `false` | — | Enable the usermod on first boot |
Example for a board with a 2.888 mΩ effective shunt, 10 A range, -118 mA offset, 1 second polling, and enabled by default:
```ini
[env:my_board]
extends = env:esp32dev
custom_usermods = ${env:esp32dev.custom_usermods} INA226
build_flags = ${env:esp32dev.build_flags}
-D INA226_ENABLED_DEFAULT=true
-D INA226_SHUNT_MICRO_OHMS=2888
-D INA226_DEFAULT_CURRENT_RANGE=10000
-D INA226_CURRENT_OFFSET_MA=-118
-D INA226_CHECK_INTERVAL_MS=1000
```
All compile-time defaults can still be changed at runtime through the Usermod settings page.
```
@@ -1,4 +1,4 @@
{
"name": "ST7789_display",
"name:": "ST7789_display",
"build": { "libArchive": false }
}
+20 -17
View File
@@ -296,17 +296,17 @@ void FFTcode(void * parameter)
ArduinoFFT<float> FFT = ArduinoFFT<float>(valFFT, vImag, samplesFFT, SAMPLE_RATE, true);
#elif !defined(UM_AUDIOREACTIVE_USE_INTEGER_FFT)
// allocate and initialize FFT buffers on first call
// note: free() is never used on these pointers. If it ever is implemented, this implementation can cause memory leaks (need to free raw pointers)
if (valFFT == nullptr) {
float* raw_buffer = (float*)heap_caps_malloc((2 * samplesFFT * sizeof(float)) + 16, MALLOC_CAP_8BIT);
if ((raw_buffer == nullptr)) return; // something went wrong
valFFT = (float*)(((uintptr_t)raw_buffer + 15) & ~15); // SIMD requires aligned memory to 16-byte boundary. note in IDF5 there is MALLOC_CAP_SIMD available
valFFT = (float*)heap_caps_aligned_calloc(16, 2 * samplesFFT, sizeof(float), MALLOC_CAP_8BIT); // SIMD requires aligned memory to 16-byte boundary. note in IDF5 there is MALLOC_CAP_SIMD available
if ((valFFT == nullptr)) return; // something went wrong
}
// create window
if (windowFFT == nullptr) {
float* raw_buffer = (float*)heap_caps_malloc((samplesFFT * sizeof(float)) + 16, MALLOC_CAP_8BIT);
if ((raw_buffer == nullptr)) return; // something went wrong
windowFFT = (float*)(((uintptr_t)raw_buffer + 15) & ~15); // SIMD requires aligned memory to 16-byte boundary
windowFFT = (float*)heap_caps_aligned_calloc(16, samplesFFT, sizeof(float), MALLOC_CAP_8BIT); // SIMD requires aligned memory to 16-byte boundary. note in IDF5 there is MALLOC_CAP_SIMD available
if ((windowFFT == nullptr)) {
heap_caps_free(valFFT); valFFT = nullptr;
return; // something went wrong
}
}
if (dsps_fft2r_init_fc32(NULL, samplesFFT) != ESP_OK) return; // initialize FFT tables
// create window function for FFT
@@ -316,16 +316,20 @@ void FFTcode(void * parameter)
dsps_wind_flat_top_f32(windowFFT, samplesFFT);
#endif
#else
// allocate and initialize integer FFT buffers on first call
if (valFFT == nullptr) valFFT = (int16_t*) calloc(sizeof(int16_t), samplesFFT * 2);
if ((valFFT == nullptr)) return; // something went wrong
// use integer FFT - allocate and initialize integer FFT buffers on first call, 4 bytes aligned (just in case, even if not strictly needed for int16_t)
if (valFFT == nullptr) valFFT = (int16_t*) heap_caps_aligned_calloc(4, samplesFFT * 2, sizeof(int16_t), MALLOC_CAP_8BIT);
// create window
if (windowFFT == nullptr) windowFFT = (int16_t*) calloc(sizeof(int16_t), samplesFFT);
if ((windowFFT == nullptr)) return; // something went wrong
if (dsps_fft2r_init_sc16(NULL, samplesFFT) != ESP_OK) return; // initialize FFT tables
if (windowFFT == nullptr) windowFFT = (int16_t*) heap_caps_aligned_calloc(4, samplesFFT, sizeof(int16_t), MALLOC_CAP_8BIT);
// create window function for FFT
float *windowFloat = (float*) calloc(sizeof(float), samplesFFT); // temporary buffer for window function
if ((windowFloat == nullptr)) return; // something went wrong
float *windowFloat = (float*) heap_caps_aligned_calloc(4, samplesFFT, sizeof(float), MALLOC_CAP_8BIT); // temporary buffer for window function
if (windowFloat == nullptr || windowFFT == nullptr || valFFT == nullptr) { // something went wrong
if (windowFloat) heap_caps_free(windowFloat);
if (windowFFT) heap_caps_free(windowFFT); windowFFT = nullptr;
if (valFFT) heap_caps_free(valFFT); valFFT = nullptr;
return;
}
if (dsps_fft2r_init_sc16(NULL, samplesFFT) != ESP_OK) return; // initialize FFT tables
#ifdef FFT_PREFER_EXACT_PEAKS
dsps_wind_blackman_harris_f32(windowFloat, samplesFFT);
#else
@@ -335,7 +339,7 @@ void FFTcode(void * parameter)
for (int i = 0; i < samplesFFT; i++) {
windowFFT[i] = (int16_t)(windowFloat[i] * 32767.0f);
}
free(windowFloat); // free temporary buffer
heap_caps_free(windowFloat); // free temporary buffer
#endif
// see https://www.freertos.org/vtaskdelayuntil.html
@@ -468,7 +472,6 @@ void FFTcode(void * parameter)
}
FFT_Magnitude = FFT_Magnitude_int * 512; // scale to match raw float value
FFT_MajorPeak = FFT_MajorPeak_int;
FFT_Magnitude = FFT_Magnitude_int;
#endif
#endif
FFT_MajorPeak = constrain(FFT_MajorPeak, 1.0f, 11025.0f); // restrict value to range expected by effects
+1 -1
View File
@@ -1,5 +1,5 @@
{
"name": "pov_display",
"name:": "pov_display",
"build": { "libArchive": false},
"platforms": ["espressif32"]
}
+1
View File
@@ -879,6 +879,7 @@ class WS2812FX {
printSize(), // prints memory usage for strip components
#endif
finalizeInit(), // initialises strip components
updatePixelBuffer(), // (re)allocate memory for _pixels[]
service(), // executes effect functions when due and calls strip.show()
setCCT(uint16_t k), // sets global CCT (either in relative 0-255 value or in K)
setBrightness(uint8_t b, bool direct = false), // sets strip brightness
+20 -66
View File
@@ -1272,11 +1272,17 @@ void WS2812FX::finalizeInit() {
deserializeMap(); // (re)load default ledmap (will also setUpMatrix() if ledmap does not exist)
// allocate frame buffer after matrix has been set up (gaps!)
updatePixelBuffer();
DEBUG_PRINTF_P(PSTR("Heap after strip init: %uB\n"), getFreeHeapSize());
}
// update global _pixels[] buffer to match getLengthTotal() note: if allocation fails, WLED will not render anything
void WS2812FX::updatePixelBuffer() {
uint32_t requiredMem = getLengthTotal() * sizeof(uint32_t);
p_free(_pixels); // using realloc on large buffers can cause additional fragmentation instead of reducing it
// use PSRAM if available: there is no measurable perfomance impact between PSRAM and DRAM on S2/S3 with QSPI PSRAM for this buffer
_pixels = static_cast<uint32_t*>(allocate_buffer(getLengthTotal() * sizeof(uint32_t), BFRALLOC_ENFORCE_PSRAM | BFRALLOC_NOBYTEACCESS | BFRALLOC_CLEAR));
DEBUG_PRINTF_P(PSTR("strip buffer size: %uB\n"), getLengthTotal() * sizeof(uint32_t));
DEBUG_PRINTF_P(PSTR("Heap after strip init: %uB\n"), getFreeHeapSize());
_pixels = static_cast<uint32_t*>(allocate_buffer(requiredMem, BFRALLOC_ENFORCE_PSRAM | BFRALLOC_NOBYTEACCESS | BFRALLOC_CLEAR));
DEBUG_PRINTF_P(PSTR("strip buffer size: %uB\n"), requiredMem);
}
void WS2812FX::service() {
@@ -1382,7 +1388,6 @@ static uint8_t _dummy (uint8_t a, uint8_t b) { return a; } // dummy (same as
void WS2812FX::blendSegment(const Segment &topSegment) const {
typedef uint8_t(*FuncType)(uint8_t, uint8_t);
// function pointer array: fill with _dummy if using special case: avoid OOB access and always provide a valid path
// note: making the function array static const uses more ram and comes at no significant speed gain
FuncType funcs[] = {
_dummy, _dummy, _dummy, _subtract,
_difference, _average, _dummy, _divide,
@@ -1414,71 +1419,14 @@ void WS2812FX::blendSegment(const Segment &topSegment) const {
const size_t matrixSize = Segment::maxWidth * Segment::maxHeight;
const size_t startIndx = XY(topSegment.start, topSegment.startY);
const size_t stopIndx = startIndx + length;
const unsigned progress = topSegment.progress();
const unsigned progInv = 0xFFFFU - progress;
uint8_t opacity = topSegment.currentBri(); // returns transitioned opacity for style FADE
uint8_t cct = topSegment.currentCCT();
if (gammaCorrectCol) opacity = gamma8inv(opacity); // use inverse gamma on brightness for correct color scaling after gamma correction (see #5343 for details)
const Segment *segO = topSegment.getOldSegment();
const bool hasGrouping = topSegment.groupLength() != 1;
Segment::setClippingRect(0, 0); // disable clipping by default
// fast path: handle the default case - no transitions, no grouping/spacing, no mirroring, no CCT
if (!segO && blendingStyle == TRANSITION_FADE && !hasGrouping && !topSegment.mirror && !topSegment.mirror_y) {
if (isMatrix && stopIndx <= matrixSize && !_pixelCCT) {
#ifndef WLED_DISABLE_2D
// Calculate pointer steps to avoid 'if' and 'XY()' inside loops
int x_inc = 1;
int y_inc = Segment::maxWidth;
int start_offset = XY(topSegment.start, topSegment.startY);
// adjust starting position and steps based on Reverse/Transpose
// note: transpose is handled in separate loop so it is still fast and no branching is needed in default path
if (!topSegment.transpose) {
if (topSegment.reverse) { start_offset += (width - 1); x_inc = -1; }
if (topSegment.reverse_y) { start_offset += (height - 1) * Segment::maxWidth; y_inc = -Segment::maxWidth; }
for (int y = 0; y < height; y++) {
uint32_t* pRow = &_pixels[start_offset + y * y_inc];
const int y_width = y * width;
for (int x = 0; x < width; x++) {
uint32_t* p = pRow + x * x_inc;
uint32_t c_a = topSegment.getPixelColorRaw(x + y_width);
*p = color_blend(*p, segblend(c_a, *p), opacity);
}
}
} else { // transposed
for (int y = 0; y < height; y++) {
const int px = topSegment.reverse ? (height - y - 1) : y; // source pixel: swap y into x, reverse if needed
for (int x = 0; x < width; x++) {
const int py = topSegment.reverse_y ? (width - x - 1) : x; // source pixel: swap x into y, reverse if needed
const uint32_t c_a = topSegment.getPixelColorRaw(px + py * height); // height = virtual width
const size_t idx = XY(topSegment.start + x, topSegment.startY + y); // write logical (non swapped) pixel coordinate
_pixels[idx] = color_blend(_pixels[idx], segblend(c_a, _pixels[idx]), opacity);
}
}
}
return;
#endif
} else if (!isMatrix) {
// 1D fast path, include CCT as it is more common on 1D setups
uint32_t* strip = _pixels;
int start = topSegment.start;
int off = topSegment.offset;
for (int i = 0; i < length; i++) {
uint32_t c_a = topSegment.getPixelColorRaw(i);
int p = topSegment.reverse ? (length - i - 1) : i;
int idx = start + p + off;
if (idx >= topSegment.stop) idx -= length;
strip[idx] = color_blend(strip[idx], segblend(c_a, strip[idx]), opacity);
if (_pixelCCT) _pixelCCT[idx] = cct;
}
return;
}
}
// slow path: handle transitions, grouping/spacing, segments with clipping and CCT pixels
Segment::setClippingRect(0, 0); // disable clipping by default
const unsigned progress = topSegment.progress();
const unsigned progInv = 0xFFFFU - progress;
const unsigned dw = (blendingStyle==TRANSITION_OUTSIDE_IN ? progInv : progress) * width / 0xFFFFU + 1;
const unsigned dh = (blendingStyle==TRANSITION_OUTSIDE_IN ? progInv : progress) * height / 0xFFFFU + 1;
const unsigned orgBS = blendingStyle;
@@ -1539,6 +1487,7 @@ void WS2812FX::blendSegment(const Segment &topSegment) const {
#ifndef WLED_DISABLE_2D
const int nCols = topSegment.virtualWidth();
const int nRows = topSegment.virtualHeight();
const Segment *segO = topSegment.getOldSegment();
const int oCols = segO ? segO->virtualWidth() : nCols;
const int oRows = segO ? segO->virtualHeight() : nRows;
@@ -1634,8 +1583,8 @@ void WS2812FX::blendSegment(const Segment &topSegment) const {
}
#endif
} else {
// 1D Slow Path
const int nLen = topSegment.virtualLength();
const Segment *segO = topSegment.getOldSegment();
const int oLen = segO ? segO->virtualLength() : nLen;
const auto setMirroredPixel = [&](int i, uint32_t c, uint8_t o) {
@@ -1715,7 +1664,7 @@ void WS2812FX::show() {
if (realtimeMode == REALTIME_MODE_INACTIVE || useMainSegmentOnly || realtimeOverride > REALTIME_OVERRIDE_NONE) {
// clear frame buffer
memset(_pixels, 0, sizeof(uint32_t) * totalLen);
for (size_t i = 0; i < totalLen; i++) _pixels[i] = BLACK; // memset(_pixels, 0, sizeof(uint32_t) * getLengthTotal());
// blend all segments into (cleared) buffer
for (Segment &seg : _segments) if (seg.isActive() && (seg.on || seg.isInTransition())) {
blendSegment(seg); // blend segment's buffer into frame buffer
@@ -2080,10 +2029,13 @@ bool WS2812FX::deserializeMap(unsigned n) {
customMappingSize = 0; // prevent use of mapping if anything goes wrong
currentLedmap = 0;
if (n == 0 || isFile) interfaceUpdateCallMode = CALL_MODE_WS_SEND; // schedule WS update (to inform UI)
uint32_t lengthTotalBefore = strip.getLengthTotal();
if (!isFile && n==0 && isMatrix) {
// 2D panel support creates its own ledmap (on the fly) if a ledmap.json does not exist
setUpMatrix();
if (strip.getLengthTotal() != lengthTotalBefore)
strip.updatePixelBuffer(); // allocate _pixels[] to match new length
return false;
}
@@ -2158,6 +2110,8 @@ bool WS2812FX::deserializeMap(unsigned n) {
}
releaseJSONBufferLock();
if (strip.getLengthTotal() != lengthTotalBefore)
strip.updatePixelBuffer(); // allocate _pixels[] to match new length
return (customMappingSize > 0);
}
+14 -27
View File
@@ -802,11 +802,10 @@ BusHub75Matrix::BusHub75Matrix(const BusConfig &bc) : Bus(bc.type, bc.start, bc.
_hasRgb = true;
_hasWhite = false;
virtualDisp = nullptr; // todo: this should be solved properly, can cause memory leak (if omitted here, nothing seems to work)
_isVirtual = false;
// aliases for easier reading
unsigned panelWidth = bc.pins[0];
unsigned panelHeight = bc.pins[1];
unsigned chainLength = bc.pins[2];
uint8_t panelWidth = bc.pins[0];
uint8_t panelHeight = bc.pins[1];
uint8_t chainLength = bc.pins[2];
_rows = bc.pins[3];
_cols = bc.pins[4];
@@ -823,7 +822,7 @@ BusHub75Matrix::BusHub75Matrix(const BusConfig &bc) : Bus(bc.type, bc.start, bc.
mxconfig.clkphase = bc.reversed;
// allow chain length up to 4, limit to prevent bad data from preventing boot due to low memory
mxconfig.chain_length = max(1U, min(chainLength, 4U));
mxconfig.chain_length = max((uint8_t) 1, min(chainLength, (uint8_t) 4));
if (mxconfig.mx_height >= 64 && (mxconfig.chain_length > 1)) {
#if defined(BOARD_HAS_PSRAM) // limitation to one panel only applies to boards without PSRAM
@@ -836,12 +835,12 @@ BusHub75Matrix::BusHub75Matrix(const BusConfig &bc) : Bus(bc.type, bc.start, bc.
}
if (bc.type == TYPE_HUB75MATRIX_HS) {
mxconfig.mx_width = min(128U, panelWidth); // UI limit is 128
mxconfig.mx_height = min(64U, panelHeight);
mxconfig.mx_width = min((uint8_t) 64, panelWidth); // TODO: UI limit is 128, this limits to 64
mxconfig.mx_height = min((uint8_t) 64, panelHeight);
} else if (bc.type == TYPE_HUB75MATRIX_QS) {
_isVirtual = true;
mxconfig.mx_width = min(128U, panelWidth) * 2;
mxconfig.mx_height = min(64U, panelHeight) / 2;
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");
@@ -882,18 +881,6 @@ 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};
#elif defined(SEENGREAT_V2_PINOUT)
DEBUGBUS_PRINTLN("MatrixPanel_I2S_DMA - S3 devKit-C with PSRAM, SEENGREAT_V2 pinout");
mxconfig.gpio = { 18, 8, 17, // R1_PIN, G1_PIN, B1_PIN,
16, 1, 15, // R2_PIN, G2_PIN, B2_PIN,
7, 48, 6, 47, 2, // A_PIN, B_PIN, C_PIN, D_PIN, E_PIN,
21, 4, 5 }; //LAT_PIN, OE_PIN,CLK_PIN
#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};
@@ -1018,15 +1005,15 @@ BusHub75Matrix::BusHub75Matrix(const BusConfig &bc) : Bus(bc.type, bc.start, bc.
// chained panels with cols and rows define need the virtual display driver, so do quarter-scan panels
if (chainLength > 1 && (_rows > 1 || _cols > 1) || bc.type == TYPE_HUB75MATRIX_QS) {
_isVirtual = true;
if (chainLength > 1 && (_rows > 1 || _cols > 1)) chainType = CHAIN_TOP_RIGHT_DOWN; // we need to use a _DOWN chainType, otherwise the display is upside-down
DEBUGBUS_PRINTF_P(PSTR("Using virtual matrix: %ux%u panels of %ux%u pixels\n"), _cols, _rows, mxconfig.mx_width/2, mxconfig.mx_height*2);
chainType = CHAIN_BOTTOM_LEFT_UP; // TODO: is there any need to support other chaining types?
DEBUGBUS_PRINTF_P(PSTR("Using virtual matrix: %ux%u panels of %ux%u pixels\n"), _cols, _rows, mxconfig.mx_width, mxconfig.mx_height);
}
else {
_isVirtual = false;
}
if (_isVirtual) {
virtualDisp = new VirtualMatrixPanel((*display), _rows, _cols, mxconfig.mx_width/2, mxconfig.mx_height*2, chainType);
virtualDisp = new VirtualMatrixPanel((*display), _rows, _cols, mxconfig.mx_width, mxconfig.mx_height, chainType);
virtualDisp->setRotation(0);
if (bc.type == TYPE_HUB75MATRIX_QS) {
switch(panelHeight) {
@@ -1097,7 +1084,7 @@ void IRAM_ATTR BusHub75Matrix::setPixelColor(unsigned pix, uint32_t c) {
uint32_t BusHub75Matrix::getPixelColor(unsigned pix) const {
if (!_valid) return IS_BLACK; // note: no need to check pix >= _len as that is checked in containsPixel()
if (_ledBuffer)
return uint32_t(_ledBuffer[pix]) & 0x00FFFFFF; // FastLED 32bit is RGBA, we need RGBW
return uint32_t(_ledBuffer[pix]);
else
return getBitFromArray(_ledsDirty, pix) ? IS_DARKGREY: IS_BLACK; // just a hack - we only know if the pixel is black or not
}
@@ -1162,8 +1149,8 @@ std::vector<LEDType> BusHub75Matrix::getLEDTypes() {
size_t BusHub75Matrix::getPins(uint8_t* pinArray) const {
if (pinArray) {
pinArray[0] = _isVirtual ? mxconfig.mx_width /2 : mxconfig.mx_width;
pinArray[1] = _isVirtual ? mxconfig.mx_height *2 : mxconfig.mx_height;
pinArray[0] = mxconfig.mx_width;
pinArray[1] = mxconfig.mx_height;
pinArray[2] = mxconfig.chain_length;
pinArray[3] = _rows;
pinArray[4] = _cols;
+90 -25
View File
@@ -190,7 +190,7 @@
}
}
function pMP() { // populateMacroPresets
var presetOpts = '<option value="0">Default Action</option>' + sortedPresetOptions;
var presetOpts = '<option value="0">Default Action (0)</option>' + sortedPresetOptions;
var fields = ['A0','A1','MC','MN'];
for (var f of fields) {
var inp = gN(f);
@@ -219,13 +219,38 @@
rPS(sel, presetOpts, "data-preset");
}
}
function bAO() { // buildAnalogOptions: analog functions + per-segment opacity (segment 0 included; MD=0 => segment 0)
var o = '<optgroup label="Analog Functions"><option value="250">Global brightness (250)</option><option value="249">Effect speed (249)</option><option value="248">Effect intensity (248)</option><option value="247">Palette (247)</option><option value="200">Primary color hue (200)</option></optgroup><optgroup label="Analog Segment Opacity">';
for (var j=0; j<=32; j++) o += `<option value="${j}">Segment ${j} opacity</option>`;
o += '</optgroup>';
return o;
}
function isAnalogBtn(t) { return t==7 || t==8; } // BTN_TYPE_ANALOG / BTN_TYPE_ANALOG_INVERTED
function isSwitchBtn(t) { return t==4 || t==5 || t==9; } // BTN_TYPE_SWITCH / BTN_TYPE_PIR_SENSOR / BTN_TYPE_TOUCH_SWITCH
function btnTypeName(t) { // mirrors the button type dropdown on the LED settings page
switch (+t) {
case 2: return 'Pushbutton';
case 3: return 'Push inverted';
case 4: return 'Switch';
case 5: return 'PIR sensor';
case 6: return 'Touch';
case 7: return 'Analog';
case 8: return 'Analog inverted';
case 9: return 'Touch (switch)';
default: return 'Disabled';
}
}
function rBPO() { // refreshButtonPresetOptions
var presetOpts = '<option value="0">Default Action</option>' + sortedPresetOptions;
var presetOpts = '<option value="0">Default Action (0)</option>' + sortedPresetOptions;
var analogOpts = bAO();
var container = gId("macros");
if (!container) return;
// analog buttons only have an MD select (MP/ML are hidden 0 inputs); MD uses analog options, never presets
var sels = container.querySelectorAll('select[name^="MP"],select[name^="ML"],select[name^="MD"]');
for (var sel of sels) {
rPS(sel, presetOpts, "data-preset");
var bb = sel.closest ? sel.closest(".bb") : null;
var t = bb ? parseInt(bb.getAttribute("data-btype")||"0",10) : 0;
rPS(sel, isAnalogBtn(t) ? analogOpts : presetOpts, "data-preset");
}
}
function Wd()
@@ -246,33 +271,73 @@
if (d.Sf.LTR.value==="S") { d.Sf.LT.value = -1*parseFloat(d.Sf.LT.value); }
if (d.Sf.LNR.value==="W") { d.Sf.LN.value = -1*parseFloat(d.Sf.LN.value); }
}
function addRow(i,p,l,d) {
function addRow(i,p,l,d,t) {
if (t===undefined) t = 0;
var b = String.fromCharCode((i<10?48:55)+i);
var presetOpts = '<option value="0">Default Action</option>' + sortedPresetOptions;
var presetOpts = '<option value="0">Default Action (0)</option>' + sortedPresetOptions;
var typeName = btnTypeName(t);
var buttonBlock = document.createElement('div');
buttonBlock.className = 'bb';
buttonBlock.innerHTML = `
<div class="bh">Button (switch) ${i}</div>
<div class="bs">
<div class="ba">
<label>Short (on → off)</label>
<select name="MP${b}" class="s" required>${presetOpts}</select>
buttonBlock.setAttribute('data-btype', t); // read back by rBPO() to rebuild selects correctly
if (isAnalogBtn(t)) {
// analog buttons: MD holds the function/segment; short/long press are unused (firmware defaults missing MP/ML to 0)
buttonBlock.innerHTML = `
<div class="bh">Analog ${i} - ${typeName}</div>
<div class="bs">
<div class="ba">
<label>Analog function</label>
<select name="MD${b}" class="s" required>${bAO()}</select>
</div>
</div>
<div class="ba">
<label>Long (off → on)</label>
<select name="ML${b}" class="s" required>${presetOpts}</select>
<hr style="width:100%;margin:8px 0 0 0;">
`;
sPSV(buttonBlock.querySelector('select[name="MD'+b+'"]'), String(d), "data-preset");
} else if (isSwitchBtn(t)) {
// switches: MP fires on On->Off, ML on Off->On; double press (MD) is unused (firmware defaults missing MD to 0)
buttonBlock.innerHTML = `
<div class="bh">Switch ${i} - ${typeName}</div>
<div class="bs">
<div class="ba">
<label>On → Off</label>
<select name="MP${b}" class="s" required>${presetOpts}</select>
</div>
<div class="ba">
<label>Off → On</label>
<select name="ML${b}" class="s" required>${presetOpts}</select>
</div>
</div>
<div class="ba">
<label>Double press (n/a)</label>
<select name="MD${b}" class="s" required>${presetOpts}</select>
<hr style="width:100%;margin:8px 0 0 0;">
`;
var switchSels = buttonBlock.querySelectorAll("select");
var switchVals = [String(p), String(l)];
for (var si=0; si<switchSels.length; si++) {
sPSV(switchSels[si], switchVals[si], "data-preset");
}
} else {
// pushbuttons: short (MP), long (ML) and double (MD) press
buttonBlock.innerHTML = `
<div class="bh">Button ${i} - ${typeName}</div>
<div class="bs">
<div class="ba">
<label>Short press</label>
<select name="MP${b}" class="s" required>${presetOpts}</select>
</div>
<div class="ba">
<label>Long press</label>
<select name="ML${b}" class="s" required>${presetOpts}</select>
</div>
<div class="ba">
<label>Double press</label>
<select name="MD${b}" class="s" required>${presetOpts}</select>
</div>
</div>
</div>
<hr style="width:100%;margin:8px 0 0 0;">
`;
var buttonSels = buttonBlock.querySelectorAll("select");
var buttonVals = [String(p), String(l), String(d)];
for (var si=0; si<buttonSels.length; si++) {
sPSV(buttonSels[si], buttonVals[si], "data-preset");
<hr style="width:100%;margin:8px 0 0 0;">
`;
var buttonSels = buttonBlock.querySelectorAll("select");
var buttonVals = [String(p), String(l), String(d)];
for (var si=0; si<buttonSels.length; si++) {
sPSV(buttonSels[si], buttonVals[si], "data-preset");
}
}
gId("macros").appendChild(buttonBlock);
}
@@ -372,7 +437,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 (switch) Action Presets</h3>
<h3>Button Action Presets</h3>
<div id="macros"></div>
<a href="https://kno.wled.ge/features/macros/#analog-button" target="_blank">Analog Button setup</a>
</div>
+1 -11
View File
@@ -106,17 +106,12 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol, size_
handleArtnetPollReply(clientIP);
return;
}
if (packetLen < 18) return; // need art_length (offset 16, 2 bytes) for DMX data
uni = p->art_universe;
dmxChannels = htons(p->art_length);
const int artNetMaxData = (packetLen >= 18) ? (int)(packetLen - 18) : 0; // art_data at offset 18; clamp so e131_data[dmxChannels] stays in bounds
if (dmxChannels > artNetMaxData) dmxChannels = artNetMaxData;
if (dmxChannels > MAX_CHANNELS_PER_UNIVERSE) dmxChannels = MAX_CHANNELS_PER_UNIVERSE;
e131_data = p->art_data;
seq = p->art_sequence_number;
mde = REALTIME_MODE_ARTNET;
} else if (protocol == P_E131) {
if (packetLen < 126) return; // need up to property_values[0] (offset 125) and property_value_count (offset 123)
// Ignore PREVIEW data (E1.31: 6.2.6)
if ((p->options & 0x80) != 0) return;
dmxChannels = htons(p->property_value_count) - 1; // on malformed packets, this can become negative, checked below
@@ -125,9 +120,6 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol, size_
uni = htons(p->universe);
e131_data = p->property_values;
seq = p->sequence_number;
const int e131MaxData = (packetLen > 126) ? (int)(packetLen - 126) : 0; // property_values at offset 125; clamp so e131_data[dmxChannels] stays in bounds
if (dmxChannels > e131MaxData) dmxChannels = e131MaxData;
if (dmxChannels > MAX_CHANNELS_PER_UNIVERSE) dmxChannels = MAX_CHANNELS_PER_UNIVERSE;
if (e131Priority != 0) {
if (p->priority < e131Priority ) return;
// track highest priority & skip all lower priorities
@@ -143,10 +135,8 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol, size_
#ifdef WLED_ENABLE_DMX
// does not act on out-of-order packets yet
if (e131ProxyUniverse > 0 && uni == e131ProxyUniverse) {
// Art-Net: art_data is 0-indexed (channel 1 at index 0)
// E1.31: property_values[0] is start code, (channel 1 at index 1)
for (uint16_t i = 1; i <= dmxChannels; i++)
dmx.write(i, mde == REALTIME_MODE_ARTNET ? e131_data[i-1] : e131_data[i]);
dmx.write(i, e131_data[i]);
dmx.update();
}
#endif
-1
View File
@@ -188,7 +188,6 @@ static bool appendObjectToFile(const char* key, const JsonDocument* content, uin
if (f.size() < 3) {
char init[10];
strcpy_P(init, PSTR("{\"0\":{}}"));
f.seek(0, SeekSet); // rewind to ensure we overwrite from the start, instead of appending
f.print(init);
}
+1 -3
View File
@@ -520,9 +520,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
if (root["win"].isNull() && getVal(root["ps"], presetCycCurr, 1, 250) && presetCycCurr > 0 && presetCycCurr < 251 && presetCycCurr != currentPreset) {
DEBUG_PRINTF_P(PSTR("Preset select: %d\n"), presetCycCurr);
// b) preset ID only or preset that does not change state (use embedded cycling limits if they exist in getVal())
// async load from file system (only preset ID was specified)
// avoid propogating CALL_MODE_INIT, which may cause accidental recursion
applyPreset(presetCycCurr, callMode == CALL_MODE_INIT ? CALL_MODE_DIRECT_CHANGE : callMode);
applyPreset(presetCycCurr, callMode); // async load from file system (only preset ID was specified)
return stateResponse;
} else presetCycCurr = currentPreset; // restore presetCycCurr
}
+2 -2
View File
@@ -194,8 +194,8 @@ void handlePresets()
changePreset = true;
} else {
if (!fdo["seg"].isNull() || !fdo["on"].isNull() || !fdo["bri"].isNull() || !fdo["nl"].isNull() || !fdo["ps"].isNull() || !fdo[F("playlist")].isNull()) changePreset = true;
if (!(tmpMode == CALL_MODE_INIT || (tmpMode == CALL_MODE_BUTTON_PRESET && fdo["ps"].is<const char *>() && strchr(fdo["ps"].as<const char *>(),'~') != strrchr(fdo["ps"].as<const char *>(),'~'))))
fdo.remove("ps"); // remove load request for presets to prevent recursive crash (if not called by boot preset or button which contains preset cycling string "1~5~")
if (!(tmpMode == CALL_MODE_BUTTON_PRESET && fdo["ps"].is<const char *>() && strchr(fdo["ps"].as<const char *>(),'~') != strrchr(fdo["ps"].as<const char *>(),'~')))
fdo.remove("ps"); // remove load request for presets to prevent recursive crash (if not called by button and contains preset cycling string "1~5~")
deserializeState(fdo, CALL_MODE_NO_NOTIFY, tmpPreset); // may change presetToApply by calling applyPreset()
}
if (!errorFlag && tmpPreset < 255 && changePreset) currentPreset = tmpPreset;
+16 -16
View File
@@ -110,24 +110,24 @@ void ESPAsyncE131::parsePacket(AsyncUDPPacket _packet) {
protocol = P_E131;
}
if (protocol == P_ARTNET) {
if (memcmp(sbuff->art_id, ESPAsyncE131::ART_ID, sizeof(sbuff->art_id)))
error = true; //not ART_ID = "Art-Net"
if (sbuff->art_opcode != ARTNET_OPCODE_OPDMX && sbuff->art_opcode != ARTNET_OPCODE_OPPOLL)
error = true; //not a DMX or poll packet
} else { //E1.31 error handling
if (pktLen < 126) { // need up to property_values[0] at offset 125
error = true;
if (protocol == P_ARTNET) {
if (pktLen < 10) {
error = true; // Need at least Art-Net ID (8) + opcode (2)
} else {
if (htonl(sbuff->root_vector) != ESPAsyncE131::VECTOR_ROOT)
error = true;
if (htonl(sbuff->frame_vector) != ESPAsyncE131::VECTOR_FRAME)
error = true;
if (sbuff->dmp_vector != ESPAsyncE131::VECTOR_DMP)
error = true;
if (sbuff->property_values[0] != 0)
error = true;
if (memcmp(sbuff->art_id, ESPAsyncE131::ART_ID, sizeof(sbuff->art_id)))
error = true; //not "Art-Net"
if (sbuff->art_opcode != ARTNET_OPCODE_OPDMX && sbuff->art_opcode != ARTNET_OPCODE_OPPOLL)
error = true; //not a DMX or poll packet
}
} else { //E1.31 error handling
if (htonl(sbuff->root_vector) != ESPAsyncE131::VECTOR_ROOT)
error = true;
if (htonl(sbuff->frame_vector) != ESPAsyncE131::VECTOR_FRAME)
error = true;
if (sbuff->dmp_vector != ESPAsyncE131::VECTOR_DMP)
error = true;
if (sbuff->property_values[0] != 0)
error = true;
}
if (error && _packet.localPort() == DDP_DEFAULT_PORT) { //DDP packet
+1 -1
View File
@@ -272,4 +272,4 @@ class E131Priority {
}
};
#endif // ESPASYNCE131_H_
#endif // ESPASYNCE131_H_
+3 -6
View File
@@ -6,7 +6,7 @@
#define UDP_SEG_SIZE 36
#define SEG_OFFSET (41)
static constexpr size_t WLEDPACKETSIZE = 41+(WS2812FX::getMaxSegments()*UDP_SEG_SIZE); // make sure this is known at compile-time
#define WLEDPACKETSIZE (41+(WS2812FX::getMaxSegments()*UDP_SEG_SIZE)+0)
#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,7 +268,6 @@ 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;
@@ -500,7 +499,7 @@ void handleNotifications()
packetSize = rgbUdp.parsePacket();
if (packetSize) {
if (!receiveDirect) return;
if (packetSize > UDP_IN_MAXSIZE || packetSize < 3) return; // packetSize must not exceed buffersize (UDP_IN_MAXSIZE)
if (packetSize > UDP_IN_MAXSIZE || packetSize < 3) return;
realtimeIP = rgbUdp.remoteIP();
DEBUG_PRINTLN(rgbUdp.remoteIP());
uint8_t lbuf[packetSize];
@@ -588,9 +587,7 @@ void handleNotifications()
unsigned id = (tpmPayloadFrameSize/3)*(packetNum-1); //start LED
unsigned totalLen = strip.getLengthTotal();
// 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++) {
for (size_t i = 6; i < tpmPayloadFrameSize + 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
-6
View File
@@ -503,12 +503,6 @@ void WLED::setup()
if (needsCfgSave) serializeConfigToFS(); // usermods required new parameters; need to wait for strip to be initialised #4752
if (bootPreset > 0) {
handlePresets(); // handle boot preset
handlePlaylist(); // handle playlist if preset queued one
handlePresets(); // handle presets again to give a chance for anything queued by the boot preset or playlist
}
if (strcmp(multiWiFi[0].clientSSID, DEFAULT_CLIENT_SSID) == 0 && !configBackupExists())
showWelcomePage = true;
+2 -2
View File
@@ -7,7 +7,7 @@
*/
// version code in format yymmddb (b = daily build)
#define VERSION 2605011
#define VERSION 2605010
//uncomment this if you have a "my_config.h" file you'd like to use
//#define WLED_USE_MY_CONFIG
@@ -274,7 +274,7 @@ using PSRAMDynamicJsonDocument = BasicJsonDocument<PSRAM_Allocator>;
#define STRINGIFY(X) #X
#define TOSTRING(X) STRINGIFY(X)
#define WLED_CODENAME "Kagayaki"
#define WLED_CODENAME "Niji"
// AP and OTA default passwords (for maximum security change them!)
WLED_GLOBAL char apPass[65] _INIT(WLED_AP_PASS);
+1 -1
View File
@@ -628,7 +628,7 @@ void getSettingsJS(byte subPage, Print& settingsScript)
printSetFormValue(settingsScript,PSTR("MN"),macroNl);
int ii = 0;
for (const auto &button : buttons) {
settingsScript.printf_P(PSTR("addRow(%d,%d,%d,%d);"), ii++, button.macroButton, button.macroLongPress, button.macroDoublePress);
settingsScript.printf_P(PSTR("addRow(%d,%d,%d,%d,%d);"), ii++, button.macroButton, button.macroLongPress, button.macroDoublePress, button.type);
}
settingsScript.printf_P(PSTR("maxTimers=%d;"), WLED_MAX_TIMERS);