Compare commits

...

32 Commits

Author SHA1 Message Date
Will Miles
cab2f91bc6 handleHttpApi: Move web response to web context
No need to even consider this for non-web requests.  Move the request
special case to that context as well.
2024-11-10 19:30:01 -05:00
Will Miles
e65f6c7bc7 handleHttpApi: Remove 'IN' tag
Internal requests are indicated by passing nullptr for the request
argument.  If we *are* in fact called from an HTTP request, we must
generate some kind of reply anyways, so this parameter is obsolete.
2024-11-10 19:30:01 -05:00
Will Miles
4d0b79f300 HTTP API: Extract 'win' prefix to web server only
Rather add this token in to all call sites, check for it only where it
matters: when we've got an HTTP request.  If it's passed in other
contexts, it will be safely ignored.
2024-11-10 19:30:01 -05:00
Will Miles
e570460cd9 Rename handleSet to handleHttpApi
Clarify what this function does: it implements the legacy HTTP
API parser.
2024-11-10 19:30:01 -05:00
Will Miles
223b97b884 handleSet: Fix incorrect response generation
Don't generate a response if there's no HTTP request.

Fixes #4269
2024-11-10 19:30:01 -05:00
Frank
70323b9477 rename delay -> frameDelay
Avoiding name collisions with the 'delay' function.
2024-11-02 17:50:30 +01:00
Frank
7d0951a08a Merge pull request #4243 from MoonModules/AC_0_15_S3-WROOM2
Add support for ESP32-S3 WROOM-2 (solves #4099)
2024-11-01 22:04:21 +01:00
Frank
d98ca9a202 show correct flash mode in WLED_DEBUG 2024-11-01 21:51:46 +01:00
Frank
3c2c5bedc5 LEDPIN --> DATA_PINS 2024-11-01 21:42:54 +01:00
Frank
749d34cd30 pinmanager support for S3 WROOM-2 (pin 33-37 reserved for flash) 2024-11-01 21:31:57 +01:00
Frank
1898be2fe1 S3 WROOM-2 buildenv
this chip has 16MB or 32MB flash, and requires .memory_type = opi_opi
2024-11-01 21:13:43 +01:00
Blaž Kristan
af34da4160 Merge pull request #4231 from Aircoookie/b7
WLED 0.15.0-b7 release
2024-10-30 20:59:00 +01:00
Blaž Kristan
4588219e31 Update changelog 2024-10-28 12:42:53 +01:00
Blaž Kristan
6e89346f00 WLED 0.15.0-b7 release
- fix for #4172
- fix for #4230
- /json/live enabled when WS disabled
2024-10-27 18:47:10 +01:00
Damian Schneider
2703c9899a Bugfix in FX ripple_base() 2024-10-27 15:08:25 +01:00
Blaž Kristan
4cc2cc4ad4 Multiple fixes
- increase WLED_MAX_BUSSES for C3 (fixes #4215)
- fix for #4228
- fix for very long running effect (strip.now, strip.timebase)
- C++ API change to allow `seg.setColor().setOpacity()`
2024-10-26 15:16:11 +02:00
Svennte
832599b8c5 Fix alexa devices invisible/uncontrollable (#4214)
Fix for LED and Scenes uncontrollable using Alexa.
Weird behavior regarding to the device names and shared scenes fixed with this.

Seen in issue Aircoookie/Espalexa#228 and fixed from @ams-hh
Tested by myself and works just fine. Created second pull request here because the library seems to be a bit different from the official Espalexa repo.

---------
Co-authored-by: Frank <91616163+softhack007@users.noreply.github.com>
Co-authored-by: Blaz Kristan <blaz@kristan-sp.si>
2024-10-25 09:33:05 +02:00
Will Miles
c81ef2669e Merge pull request #4223 from willmmiles/f-string-hygiene
Usermod F-string hygiene
2024-10-24 15:23:11 -04:00
Will Miles
19d837c222 Merge pull request #4222 from Aircoookie/esp8266-oappend-fix
Esp8266 oappend fix
2024-10-24 15:22:46 -04:00
Will Miles
4f48ddfaec Replace SET_F with F in usermods
Since oappend() is now strongly typed, pass the correct type.  This is a
step towards removing the extra shim logic on ESP8266.
2024-10-23 21:35:30 -04:00
Will Miles
2e01fe0b5b Revert "Replace SET_F with F in usermods"
This reverts commit 7d067d8c30.
2024-10-23 21:34:35 -04:00
Will Miles
7d067d8c30 Replace SET_F with F in usermods
Since oappend() is now strongly typed, pass the correct type.  This is a
step towards removing the extra shim logic on ESP8266.
2024-10-23 21:28:21 -04:00
Will Miles
b3b326738c Fix incorrect SET_F calls
Replace with F() or PSTR() as appropriate.
2024-10-23 21:26:40 -04:00
Will Miles
2bb2caf2d2 Enable NON32XFER_HANDLER on ESP8266
This is a platform feature that asks forgiveness for PROGMEM misuse:
it adds a handler such that incorrectly used PROGMEM will work without
crashing, just really, *really* inefficiently.

Given that most of our real-world use cases for PROGMEM strings are
relatively infrequent text calls, we can err on the side of developer
convenience and address performance problems if and when they arise.
2024-10-23 20:01:42 -04:00
Will Miles
2a094883ad Better oappend shim on ESP8266
Detect IRAM pointers if we can't be sure.
2024-10-23 20:01:42 -04:00
Frank
6d1126b8aa Update audioreactive readme.md
added `-D sqrt_internal=sqrtf` -> needed for good performance
2024-10-22 16:19:46 +02:00
Frank
26a47537f9 AR memory optimization - part 2
shorten strings in UI script - saves a few hundred bytes on RAM
2024-10-22 15:15:14 +02:00
Frank
01d43c69fb AR memory optimization - part 1
allocating FFT buffers late makes up to 16Kb heap available when audioreactive is not enabled.

Already tested in MM fork.
2024-10-22 14:45:32 +02:00
Frank
7db1989093 fix major performance regression in ArduinoFFT
since v2.0.0, we cannot override the internal sqrt function by #define --> moved to build_flags.

Average FFT time on esp32 : 4.5ms --> 1.8ms
2024-10-22 14:42:48 +02:00
Frank
0a97e28aab bugfix: prevent preset loading from resetting other errors
without this fix, any not-yet reported error - like filesystem problems at startup, or out-of-memory - was rest by successfully loading a preset.
2024-10-19 18:43:10 +02:00
Christian Schwinne
e9d2182390 Re-license the WLED project from MIT to EUPL (#4194) 2024-10-16 00:07:19 +02:00
Damian Schneider
44e28f96e0 Fix for Octopus on ESP32 C3
Apparently the C3 can not convert negative floats to uint8_t directly, casting it into an int first fixes it.
2024-10-15 13:49:58 +02:00
49 changed files with 688 additions and 428 deletions

View File

@@ -1,5 +1,14 @@
## WLED changelog
#### Build 2410270
- WLED 0.15.0-b7 release
- Re-license the WLED project from MIT to EUPL (#4194 by @Aircoookie)
- Fix alexa devices invisible/uncontrollable (#4214 by @Svennte)
- Add visual expand button on hover (#4172)
- Usermod: Audioreactive tuning and performance enhancements (by @softhack007)
- `/json/live` (JSON live data/peek) only enabled when WebSockets are disabled
- Various bugfixes and optimisations: #4179, #4215, #4219, #4222, #4223, #4224, #4228, #4230
#### Build 2410140
- WLED 0.15.0-b6 release
- Added BRT timezone (#4188 by @LuisFadini)

307
LICENSE
View File

@@ -1,21 +1,294 @@
MIT License
Copyright (c) 2016-present Christian Schwinne and individual WLED contributors
Licensed under the EUPL v. 1.2 or later
Copyright (c) 2016 Christian Schwinne
EUROPEAN UNION PUBLIC LICENCE v. 1.2
EUPL © the European Union 2007, 2016
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
This European Union Public Licence (the EUPL) applies to the Work (as
defined below) which is provided under the terms of this Licence. Any use of
the Work, other than as authorised under this Licence is prohibited (to the
extent such use is covered by a right of the copyright holder of the Work).
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
The Work is provided under the terms of this Licence when the Licensor (as
defined below) has placed the following notice immediately following the
copyright notice for the Work:
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Licensed under the EUPL
or has expressed by any other means his willingness to license under the EUPL.
1. Definitions
In this Licence, the following terms have the following meaning:
- The Licence: this Licence.
- The Original Work: the work or software distributed or communicated by the
Licensor under this Licence, available as Source Code and also as Executable
Code as the case may be.
- Derivative Works: the works or software that could be created by the
Licensee, based upon the Original Work or modifications thereof. This
Licence does not define the extent of modification or dependence on the
Original Work required in order to classify a work as a Derivative Work;
this extent is determined by copyright law applicable in the country
mentioned in Article 15.
- The Work: the Original Work or its Derivative Works.
- The Source Code: the human-readable form of the Work which is the most
convenient for people to study and modify.
- The Executable Code: any code which has generally been compiled and which
is meant to be interpreted by a computer as a program.
- The Licensor: the natural or legal person that distributes or communicates
the Work under the Licence.
- Contributor(s): any natural or legal person who modifies the Work under
the Licence, or otherwise contributes to the creation of a Derivative Work.
- The Licensee or You: any natural or legal person who makes any usage of
the Work under the terms of the Licence.
- Distribution or Communication: any act of selling, giving, lending,
renting, distributing, communicating, transmitting, or otherwise making
available, online or offline, copies of the Work or providing access to its
essential functionalities at the disposal of any other natural or legal
person.
2. Scope of the rights granted by the Licence
The Licensor hereby grants You a worldwide, royalty-free, non-exclusive,
sublicensable licence to do the following, for the duration of copyright
vested in the Original Work:
- use the Work in any circumstance and for all usage,
- reproduce the Work,
- modify the Work, and make Derivative Works based upon the Work,
- communicate to the public, including the right to make available or display
the Work or copies thereof to the public and perform publicly, as the case
may be, the Work,
- distribute the Work or copies thereof,
- lend and rent the Work or copies thereof,
- sublicense rights in the Work or copies thereof.
Those rights can be exercised on any media, supports and formats, whether now
known or later invented, as far as the applicable law permits so.
In the countries where moral rights apply, the Licensor waives his right to
exercise his moral right to the extent allowed by law in order to make
effective the licence of the economic rights here above listed.
The Licensor grants to the Licensee royalty-free, non-exclusive usage rights
to any patents held by the Licensor, to the extent necessary to make use of
the rights granted on the Work under this Licence.
3. Communication of the Source Code
The Licensor may provide the Work either in its Source Code form, or as
Executable Code. If the Work is provided as Executable Code, the Licensor
provides in addition a machine-readable copy of the Source Code of the Work
along with each copy of the Work that the Licensor distributes or indicates,
in a notice following the copyright notice attached to the Work, a repository
where the Source Code is easily and freely accessible for as long as the
Licensor continues to distribute or communicate the Work.
4. Limitations on copyright
Nothing in this Licence is intended to deprive the Licensee of the benefits
from any exception or limitation to the exclusive rights of the rights owners
in the Work, of the exhaustion of those rights or of other applicable
limitations thereto.
5. Obligations of the Licensee
The grant of the rights mentioned above is subject to some restrictions and
obligations imposed on the Licensee. Those obligations are the following:
Attribution right: The Licensee shall keep intact all copyright, patent or
trademarks notices and all notices that refer to the Licence and to the
disclaimer of warranties. The Licensee must include a copy of such notices and
a copy of the Licence with every copy of the Work he/she distributes or
communicates. The Licensee must cause any Derivative Work to carry prominent
notices stating that the Work has been modified and the date of modification.
Copyleft clause: If the Licensee distributes or communicates copies of the
Original Works or Derivative Works, this Distribution or Communication will be
done under the terms of this Licence or of a later version of this Licence
unless the Original Work is expressly distributed only under this version of
the Licence — for example by communicating EUPL v. 1.2 only. The Licensee
(becoming Licensor) cannot offer or impose any additional terms or conditions
on the Work or Derivative Work that alter or restrict the terms of the
Licence.
Compatibility clause: If the Licensee Distributes or Communicates Derivative
Works or copies thereof based upon both the Work and another work licensed
under a Compatible Licence, this Distribution or Communication can be done
under the terms of this Compatible Licence. For the sake of this clause,
Compatible Licence refers to the licences listed in the appendix attached to
this Licence. Should the Licensee's obligations under the Compatible Licence
conflict with his/her obligations under this Licence, the obligations of the
Compatible Licence shall prevail.
Provision of Source Code: When distributing or communicating copies of the
Work, the Licensee will provide a machine-readable copy of the Source Code or
indicate a repository where this Source will be easily and freely available
for as long as the Licensee continues to distribute or communicate the Work.
Legal Protection: This Licence does not grant permission to use the trade
names, trademarks, service marks, or names of the Licensor, except as required
for reasonable and customary use in describing the origin of the Work and
reproducing the content of the copyright notice.
6. Chain of Authorship
The original Licensor warrants that the copyright in the Original Work granted
hereunder is owned by him/her or licensed to him/her and that he/she has the
power and authority to grant the Licence.
Each Contributor warrants that the copyright in the modifications he/she
brings to the Work are owned by him/her or licensed to him/her and that he/she
has the power and authority to grant the Licence.
Each time You accept the Licence, the original Licensor and subsequent
Contributors grant You a licence to their contributions to the Work, under the
terms of this Licence.
7. Disclaimer of Warranty
The Work is a work in progress, which is continuously improved by numerous
Contributors. It is not a finished work and may therefore contain defects or
bugs inherent to this type of development.
For the above reason, the Work is provided under the Licence on an as is
basis and without warranties of any kind concerning the Work, including
without limitation merchantability, fitness for a particular purpose, absence
of defects or errors, accuracy, non-infringement of intellectual property
rights other than copyright as stated in Article 6 of this Licence.
This disclaimer of warranty is an essential part of the Licence and a
condition for the grant of any rights to the Work.
8. Disclaimer of Liability
Except in the cases of wilful misconduct or damages directly caused to natural
persons, the Licensor will in no event be liable for any direct or indirect,
material or moral, damages of any kind, arising out of the Licence or of the
use of the Work, including without limitation, damages for loss of goodwill,
work stoppage, computer failure or malfunction, loss of data or any commercial
damage, even if the Licensor has been advised of the possibility of such
damage. However, the Licensor will be liable under statutory product liability
laws as far such laws apply to the Work.
9. Additional agreements
While distributing the Work, You may choose to conclude an additional
agreement, defining obligations or services consistent with this Licence.
However, if accepting obligations, You may act only on your own behalf and on
your sole responsibility, not on behalf of the original Licensor or any other
Contributor, and only if You agree to indemnify, defend, and hold each
Contributor harmless for any liability incurred by, or claims asserted against
such Contributor by the fact You have accepted any warranty or additional
liability.
10. Acceptance of the Licence
The provisions of this Licence can be accepted by clicking on an icon I
agree placed under the bottom of a window displaying the text of this Licence
or by affirming consent in any other similar way, in accordance with the rules
of applicable law. Clicking on that icon indicates your clear and irrevocable
acceptance of this Licence and all of its terms and conditions.
Similarly, you irrevocably accept this Licence and all of its terms and
conditions by exercising any rights granted to You by Article 2 of this
Licence, such as the use of the Work, the creation by You of a Derivative Work
or the Distribution or Communication by You of the Work or copies thereof.
11. Information to the public
In case of any Distribution or Communication of the Work by means of
electronic communication by You (for example, by offering to download the Work
from a remote location) the distribution channel or media (for example, a
website) must at least provide to the public the information requested by the
applicable law regarding the Licensor, the Licence and the way it may be
accessible, concluded, stored and reproduced by the Licensee.
12. Termination of the Licence
The Licence and the rights granted hereunder will terminate automatically upon
any breach by the Licensee of the terms of the Licence.
Such a termination will not terminate the licences of any person who has
received the Work from the Licensee under the Licence, provided such persons
remain in full compliance with the Licence.
13. Miscellaneous
Without prejudice of Article 9 above, the Licence represents the complete
agreement between the Parties as to the Work.
If any provision of the Licence is invalid or unenforceable under applicable
law, this will not affect the validity or enforceability of the Licence as a
whole. Such provision will be construed or reformed so as necessary to make it
valid and enforceable.
The European Commission may publish other linguistic versions or new versions
of this Licence or updated versions of the Appendix, so far this is required
and reasonable, without reducing the scope of the rights granted by the
Licence. New versions of the Licence will be published with a unique version
number.
All linguistic versions of this Licence, approved by the European Commission,
have identical value. Parties can take advantage of the linguistic version of
their choice.
14. Jurisdiction
Without prejudice to specific agreement between parties,
- any litigation resulting from the interpretation of this License, arising
between the European Union institutions, bodies, offices or agencies, as a
Licensor, and any Licensee, will be subject to the jurisdiction of the Court
of Justice of the European Union, as laid down in article 272 of the Treaty
on the Functioning of the European Union,
- any litigation arising between other parties and resulting from the
interpretation of this License, will be subject to the exclusive
jurisdiction of the competent court where the Licensor resides or conducts
its primary business.
15. Applicable Law
Without prejudice to specific agreement between parties,
- this Licence shall be governed by the law of the European Union Member State
where the Licensor has his seat, resides or has his registered office,
- this licence shall be governed by Belgian law if the Licensor has no seat,
residence or registered office inside a European Union Member State.
Appendix
Compatible Licences according to Article 5 EUPL are:
- GNU General Public License (GPL) v. 2, v. 3
- GNU Affero General Public License (AGPL) v. 3
- Open Software License (OSL) v. 2.1, v. 3.0
- Eclipse Public License (EPL) v. 1.0
- CeCILL v. 2.0, v. 2.1
- Mozilla Public Licence (MPL) v. 2
- GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3
- Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) for
works other than software
- European Union Public Licence (EUPL) v. 1.1, v. 1.2
- Québec Free and Open-Source Licence — Reciprocity (LiLiQ-R) or Strong
Reciprocity (LiLiQ-R+).
The European Commission may update this Appendix to later versions of the
above licences without producing a new version of the EUPL, as long as they
provide the rights granted in Article 2 of this Licence and protect the
covered Source Code from exclusive appropriation.
All other changes or additions to this Appendix require the production of a
new EUPL version.

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "wled",
"version": "0.15.0-b6",
"version": "0.15.0-b7",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "wled",
"version": "0.15.0-b6",
"version": "0.15.0-b7",
"license": "ISC",
"dependencies": {
"clean-css": "^5.3.3",

View File

@@ -1,6 +1,6 @@
{
"name": "wled",
"version": "0.15.0-b6",
"version": "0.15.0-b7",
"description": "Tools for WLED project",
"main": "tools/cdata.js",
"directories": {

View File

@@ -197,6 +197,7 @@ build_flags =
; decrease code cache size and increase IRAM to fit all pixel functions
-D PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48 ;; in case of linker errors like "section `.text1' will not fit in region `iram1_0_seg'"
; -D PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48_SECHEAP_SHARED ;; (experimental) adds some extra heap, but may cause slowdown
-D NON32XFER_HANDLER ;; ask forgiveness for PROGMEM misuse
lib_deps =
#https://github.com/lorol/LITTLEFS.git
@@ -259,7 +260,8 @@ lib_deps =
https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
${env.lib_deps}
# additional build flags for audioreactive
AR_build_flags = -D USERMOD_AUDIOREACTIVE
AR_build_flags = -D USERMOD_AUDIOREACTIVE
-D sqrt_internal=sqrtf ;; -fsingle-precision-constant ;; forces ArduinoFFT to use float math (2x faster)
AR_lib_deps = kosme/arduinoFFT @ 2.0.1
[esp32_idf_V4]
@@ -554,6 +556,33 @@ board_build.f_flash = 80000000L
board_build.flash_mode = qio
monitor_filters = esp32_exception_decoder
[env:esp32S3_wroom2]
;; For ESP32-S3 WROOM-2, a.k.a. ESP32-S3 DevKitC-1 v1.1
;; with >= 16MB FLASH and >= 8MB PSRAM (memory_type: opi_opi)
platform = ${esp32s3.platform}
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
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=ESP32-S3_WROOM-2
-D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0
-D ARDUINO_USB_CDC_ON_BOOT=0 ;; -D ARDUINO_USB_MODE=1 ;; for boards with serial-to-USB chip
;; -D ARDUINO_USB_CDC_ON_BOOT=1 -D ARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB")
-DBOARD_HAS_PSRAM
-D LEDPIN=38 -D DATA_PINS=38 ;; buildin WS2812b LED
-D BTNPIN=0 -D RLYPIN=16 -D IRPIN=17 -D AUDIOPIN=-1
-D WLED_DEBUG
${esp32.AR_build_flags}
-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}
${esp32.AR_lib_deps}
board_build.partitions = ${esp32.extreme_partitions}
board_upload.flash_size = 16MB
board_upload.maximum_size = 16777216
monitor_filters = esp32_exception_decoder
[env:esp32s3_4M_qspi]
;; ESP32-S3, with 4MB FLASH and <= 4MB PSRAM (memory_type: qio_qspi)
board = lolin_s3_mini ;; -S3 mini, 4MB flash 2MB PSRAM

View File

@@ -61,7 +61,7 @@ See [here](https://kno.wled.ge/basics/compatible-hardware)!
## ✌️ Other
Licensed under the MIT license
Licensed under the EUPL v1.2 license
Credits [here](https://kno.wled.ge/about/contributors/)!
Join the Discord server to discuss everything about WLED!
@@ -80,5 +80,5 @@ If WLED really brightens up your day, you can [![](https://img.shields.io/badge/
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 MIT license, I assume no liability for any damage to you or any other person or equipment.
As per the EUPL license, I assume no liability for any damage to you or any other person or equipment.

View File

@@ -425,10 +425,10 @@ class Animated_Staircase : public Usermod {
}
void appendConfigData() {
//oappend(SET_F("dd=addDropdown('staircase','selectfield');"));
//oappend(SET_F("addOption(dd,'1st value',0);"));
//oappend(SET_F("addOption(dd,'2nd value',1);"));
//oappend(SET_F("addInfo('staircase:selectfield',1,'additional info');")); // 0 is field type, 1 is actual field
//oappend(F("dd=addDropdown('staircase','selectfield');"));
//oappend(F("addOption(dd,'1st value',0);"));
//oappend(F("addOption(dd,'2nd value',1);"));
//oappend(F("addInfo('staircase:selectfield',1,'additional info');")); // 0 is field type, 1 is actual field
}

View File

@@ -767,22 +767,22 @@ void UsermodBME68X::appendConfigData() {
// snprintf_P(charbuffer, 127, PSTR("addInfo('%s:%s',1,'*) Set to minus to deactivate (all sensors)');"), UMOD_NAME, _nameTemp); oappend(charbuffer);
/* Dropdown for Celsius/Fahrenheit*/
oappend(SET_F("dd=addDropdown('"));
oappend(F("dd=addDropdown('"));
oappend(UMOD_NAME);
oappend(SET_F("','"));
oappend(F("','"));
oappend(_nameTempScale);
oappend(SET_F("');"));
oappend(SET_F("addOption(dd,'Celsius',0);"));
oappend(SET_F("addOption(dd,'Fahrenheit',1);"));
oappend(F("');"));
oappend(F("addOption(dd,'Celsius',0);"));
oappend(F("addOption(dd,'Fahrenheit',1);"));
/* i²C Address*/
oappend(SET_F("dd=addDropdown('"));
oappend(F("dd=addDropdown('"));
oappend(UMOD_NAME);
oappend(SET_F("','"));
oappend(F("','"));
oappend(_nameI2CAdr);
oappend(SET_F("');"));
oappend(SET_F("addOption(dd,'0x76',0x76);"));
oappend(SET_F("addOption(dd,'0x77',0x77);"));
oappend(F("');"));
oappend(F("addOption(dd,'0x76',0x76);"));
oappend(F("addOption(dd,'0x77',0x77);"));
}
/**

View File

@@ -478,29 +478,29 @@ class UsermodBattery : public Usermod
void appendConfigData()
{
// Total: 462 Bytes
oappend(SET_F("td=addDropdown('Battery','type');")); // 34 Bytes
oappend(SET_F("addOption(td,'Unkown','0');")); // 28 Bytes
oappend(SET_F("addOption(td,'LiPo','1');")); // 26 Bytes
oappend(SET_F("addOption(td,'LiOn','2');")); // 26 Bytes
oappend(SET_F("addInfo('Battery:type',1,'<small style=\"color:orange\">requires reboot</small>');")); // 81 Bytes
oappend(SET_F("addInfo('Battery:min-voltage',1,'v');")); // 38 Bytes
oappend(SET_F("addInfo('Battery:max-voltage',1,'v');")); // 38 Bytes
oappend(SET_F("addInfo('Battery:interval',1,'ms');")); // 36 Bytes
oappend(SET_F("addInfo('Battery:HA-discovery',1,'');")); // 38 Bytes
oappend(SET_F("addInfo('Battery:auto-off:threshold',1,'%');")); // 45 Bytes
oappend(SET_F("addInfo('Battery:indicator:threshold',1,'%');")); // 46 Bytes
oappend(SET_F("addInfo('Battery:indicator:duration',1,'s');")); // 45 Bytes
oappend(F("td=addDropdown('Battery','type');")); // 34 Bytes
oappend(F("addOption(td,'Unkown','0');")); // 28 Bytes
oappend(F("addOption(td,'LiPo','1');")); // 26 Bytes
oappend(F("addOption(td,'LiOn','2');")); // 26 Bytes
oappend(F("addInfo('Battery:type',1,'<small style=\"color:orange\">requires reboot</small>');")); // 81 Bytes
oappend(F("addInfo('Battery:min-voltage',1,'v');")); // 38 Bytes
oappend(F("addInfo('Battery:max-voltage',1,'v');")); // 38 Bytes
oappend(F("addInfo('Battery:interval',1,'ms');")); // 36 Bytes
oappend(F("addInfo('Battery:HA-discovery',1,'');")); // 38 Bytes
oappend(F("addInfo('Battery:auto-off:threshold',1,'%');")); // 45 Bytes
oappend(F("addInfo('Battery:indicator:threshold',1,'%');")); // 46 Bytes
oappend(F("addInfo('Battery:indicator:duration',1,'s');")); // 45 Bytes
// this option list would exeed the oappend() buffer
// a list of all presets to select one from
// oappend(SET_F("bd=addDropdown('Battery:low-power-indicator', 'preset');"));
// the loop generates: oappend(SET_F("addOption(bd, 'preset name', preset id);"));
// oappend(F("bd=addDropdown('Battery:low-power-indicator', 'preset');"));
// the loop generates: oappend(F("addOption(bd, 'preset name', preset id);"));
// for(int8_t i=1; i < 42; i++) {
// oappend(SET_F("addOption(bd, 'Preset#"));
// oappend(F("addOption(bd, 'Preset#"));
// oappendi(i);
// oappend(SET_F("',"));
// oappend(F("',"));
// oappendi(i);
// oappend(SET_F(");"));
// oappend(F(");"));
// }
}

View File

@@ -287,11 +287,11 @@ class MyExampleUsermod : public Usermod {
*/
void appendConfigData() override
{
oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":great")); oappend(SET_F("',1,'<i>(this is a great config value)</i>');"));
oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":testString")); oappend(SET_F("',1,'enter any string you want');"));
oappend(SET_F("dd=addDropdown('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F("','testInt');"));
oappend(SET_F("addOption(dd,'Nothing',0);"));
oappend(SET_F("addOption(dd,'Everything',42);"));
oappend(F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(F(":great")); oappend(F("',1,'<i>(this is a great config value)</i>');"));
oappend(F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(F(":testString")); oappend(F("',1,'enter any string you want');"));
oappend(F("dd=addDropdown('")); oappend(String(FPSTR(_name)).c_str()); oappend(F("','testInt');"));
oappend(F("addOption(dd,'Nothing',0);"));
oappend(F("addOption(dd,'Everything',42);"));
}

View File

@@ -149,11 +149,11 @@ public:
void appendConfigData()
{
// Display 'ms' next to the 'Loop Interval' setting
oappend(SET_F("addInfo('Internal Temperature:Loop Interval', 1, 'ms');"));
oappend(F("addInfo('Internal Temperature:Loop Interval', 1, 'ms');"));
// Display '°C' next to the 'Activation Threshold' setting
oappend(SET_F("addInfo('Internal Temperature:Activation Threshold', 1, '°C');"));
oappend(F("addInfo('Internal Temperature:Activation Threshold', 1, '°C');"));
// Display '0 = Disabled' next to the 'Preset To Activate' setting
oappend(SET_F("addInfo('Internal Temperature:Preset To Activate', 1, '0 = unused');"));
oappend(F("addInfo('Internal Temperature:Preset To Activate', 1, '0 = unused');"));
}
bool readFromConfig(JsonObject &root)

View File

@@ -511,8 +511,8 @@ void PIRsensorSwitch::addToConfig(JsonObject &root)
void PIRsensorSwitch::appendConfigData()
{
oappend(SET_F("addInfo('PIRsensorSwitch:HA-discovery',1,'HA=Home Assistant');")); // 0 is field type, 1 is actual field
oappend(SET_F("addInfo('PIRsensorSwitch:override',1,'Cancel timer on change');")); // 0 is field type, 1 is actual field
oappend(F("addInfo('PIRsensorSwitch:HA-discovery',1,'HA=Home Assistant');")); // 0 is field type, 1 is actual field
oappend(F("addInfo('PIRsensorSwitch:override',1,'Cancel timer on change');")); // 0 is field type, 1 is actual field
for (int i = 0; i < PIR_SENSOR_MAX_SENSORS; i++) {
char str[128];
sprintf_P(str, PSTR("addInfo('PIRsensorSwitch:pin[]',%d,'','#%d');"), i, i);

View File

@@ -377,10 +377,10 @@ class St7789DisplayUsermod : public Usermod {
void appendConfigData() override {
oappend(SET_F("addInfo('ST7789:pin[]',0,'','SPI CS');"));
oappend(SET_F("addInfo('ST7789:pin[]',1,'','SPI DC');"));
oappend(SET_F("addInfo('ST7789:pin[]',2,'','SPI RST');"));
oappend(SET_F("addInfo('ST7789:pin[]',3,'','SPI BL');"));
oappend(F("addInfo('ST7789:pin[]',0,'','SPI CS');"));
oappend(F("addInfo('ST7789:pin[]',1,'','SPI DC');"));
oappend(F("addInfo('ST7789:pin[]',2,'','SPI RST');"));
oappend(F("addInfo('ST7789:pin[]',3,'','SPI BL');"));
}
/*

View File

@@ -435,10 +435,10 @@ bool UsermodTemperature::readFromConfig(JsonObject &root) {
}
void UsermodTemperature::appendConfigData() {
oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":")); oappend(String(FPSTR(_parasite)).c_str());
oappend(SET_F("',1,'<i>(if no Vcc connected)</i>');")); // 0 is field type, 1 is actual field
oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":")); oappend(String(FPSTR(_parasitePin)).c_str());
oappend(SET_F("',1,'<i>(for external MOSFET)</i>');")); // 0 is field type, 1 is actual field
oappend(F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(F(":")); oappend(String(FPSTR(_parasite)).c_str());
oappend(F("',1,'<i>(if no Vcc connected)</i>');")); // 0 is field type, 1 is actual field
oappend(F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(F(":")); oappend(String(FPSTR(_parasitePin)).c_str());
oappend(F("',1,'<i>(for external MOSFET)</i>');")); // 0 is field type, 1 is actual field
}
float UsermodTemperature::getTemperature() {

View File

@@ -191,8 +191,8 @@ constexpr uint16_t samplesFFT_2 = 256; // meaningfull part of FFT resul
#define LOG_256 5.54517744f // log(256)
// These are the input and output vectors. Input vectors receive computed results from FFT.
static float vReal[samplesFFT] = {0.0f}; // FFT sample inputs / freq output - these are our raw result bins
static float vImag[samplesFFT] = {0.0f}; // imaginary parts
static float* vReal = nullptr; // FFT sample inputs / freq output - these are our raw result bins
static float* vImag = nullptr; // imaginary parts
// Create FFT object
// lib_deps += https://github.com/kosme/arduinoFFT#develop @ 1.9.2
@@ -200,14 +200,9 @@ static float vImag[samplesFFT] = {0.0f}; // imaginary parts
// #define FFT_SPEED_OVER_PRECISION // enables use of reciprocals (1/x etc) - not faster on ESP32
// #define FFT_SQRT_APPROXIMATION // enables "quake3" style inverse sqrt - slower on ESP32
// Below options are forcing ArduinoFFT to use sqrtf() instead of sqrt()
#define sqrt(x) sqrtf(x) // little hack that reduces FFT time by 10-50% on ESP32
#define sqrt_internal sqrtf // see https://github.com/kosme/arduinoFFT/pull/83
#include <arduinoFFT.h>
/* Create FFT object with weighing factor storage */
static ArduinoFFT<float> FFT = ArduinoFFT<float>( vReal, vImag, samplesFFT, SAMPLE_RATE, true);
// #define sqrt_internal sqrtf // see https://github.com/kosme/arduinoFFT/pull/83 - since v2.0.0 this must be done in build_flags
#include <arduinoFFT.h> // FFT object is created in FFTcode
// Helper functions
// compute average of several FFT result bins
@@ -226,6 +221,18 @@ void FFTcode(void * parameter)
{
DEBUGSR_PRINT("FFT started on core: "); DEBUGSR_PRINTLN(xPortGetCoreID());
// allocate FFT buffers on first call
if (vReal == nullptr) vReal = (float*) calloc(sizeof(float), samplesFFT);
if (vImag == nullptr) vImag = (float*) calloc(sizeof(float), samplesFFT);
if ((vReal == nullptr) || (vImag == nullptr)) {
// something went wrong
if (vReal) free(vReal); vReal = nullptr;
if (vImag) free(vImag); vImag = nullptr;
return;
}
// Create FFT object with weighing factor storage
ArduinoFFT<float> FFT = ArduinoFFT<float>( vReal, vImag, samplesFFT, SAMPLE_RATE, true);
// see https://www.freertos.org/vtaskdelayuntil.html
const TickType_t xFrequency = FFT_MIN_CYCLE * portTICK_PERIOD_MS;
@@ -247,6 +254,7 @@ void FFTcode(void * parameter)
// get a fresh batch of samples from I2S
if (audioSource) audioSource->getSamples(vReal, samplesFFT);
memset(vImag, 0, samplesFFT * sizeof(float)); // set imaginary parts to 0
#if defined(WLED_DEBUG) || defined(SR_DEBUG)
if (start < esp_timer_get_time()) { // filter out overflows
@@ -265,8 +273,6 @@ void FFTcode(void * parameter)
// find highest sample in the batch
float maxSample = 0.0f; // max sample from FFT batch
for (int i=0; i < samplesFFT; i++) {
// set imaginary parts to 0
vImag[i] = 0;
// pick our our current mic sample - we take the max value from all samples that go into FFT
if ((vReal[i] <= (INT16_MAX - 1024)) && (vReal[i] >= (INT16_MIN + 1024))) //skip extreme values - normally these are artefacts
if (fabsf((float)vReal[i]) > maxSample) maxSample = fabsf((float)vReal[i]);
@@ -297,7 +303,7 @@ void FFTcode(void * parameter)
#endif
} else { // noise gate closed - only clear results as FFT was skipped. MIC samples are still valid when we do this.
memset(vReal, 0, sizeof(vReal));
memset(vReal, 0, samplesFFT * sizeof(float));
FFT_MajorPeak = 1;
FFT_Magnitude = 0.001;
}
@@ -1879,57 +1885,59 @@ class AudioReactive : public Usermod {
}
void appendConfigData() override
void appendConfigData(Print& uiScript) override
{
#ifdef ARDUINO_ARCH_ESP32
oappend(SET_F("dd=addDropdown('AudioReactive','digitalmic:type');"));
uiScript.print(F("ux='AudioReactive';")); // ux = shortcut for Audioreactive - fingers crossed that "ux" isn't already used as JS var, html post parameter or css style
#ifdef ARDUINO_ARCH_ESP32
uiScript.print(F("uxp=ux+':digitalmic:pin[]';")); // uxp = shortcut for AudioReactive:digitalmic:pin[]
uiScript.print(F("dd=addDropdown(ux,'digitalmic:type');"));
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3)
oappend(SET_F("addOption(dd,'Generic Analog',0);"));
uiScript.print(F("addOption(dd,'Generic Analog',0);"));
#endif
oappend(SET_F("addOption(dd,'Generic I2S',1);"));
oappend(SET_F("addOption(dd,'ES7243',2);"));
oappend(SET_F("addOption(dd,'SPH0654',3);"));
oappend(SET_F("addOption(dd,'Generic I2S with Mclk',4);"));
uiScript.print(F("addOption(dd,'Generic I2S',1);"));
uiScript.print(F("addOption(dd,'ES7243',2);"));
uiScript.print(F("addOption(dd,'SPH0654',3);"));
uiScript.print(F("addOption(dd,'Generic I2S with Mclk',4);"));
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
oappend(SET_F("addOption(dd,'Generic I2S PDM',5);"));
uiScript.print(F("addOption(dd,'Generic I2S PDM',5);"));
#endif
oappend(SET_F("addOption(dd,'ES8388',6);"));
uiScript.print(F("addOption(dd,'ES8388',6);"));
oappend(SET_F("dd=addDropdown('AudioReactive','config:AGC');"));
oappend(SET_F("addOption(dd,'Off',0);"));
oappend(SET_F("addOption(dd,'Normal',1);"));
oappend(SET_F("addOption(dd,'Vivid',2);"));
oappend(SET_F("addOption(dd,'Lazy',3);"));
uiScript.print(F("dd=addDropdown(ux,'config:AGC');"));
uiScript.print(F("addOption(dd,'Off',0);"));
uiScript.print(F("addOption(dd,'Normal',1);"));
uiScript.print(F("addOption(dd,'Vivid',2);"));
uiScript.print(F("addOption(dd,'Lazy',3);"));
oappend(SET_F("dd=addDropdown('AudioReactive','dynamics:limiter');"));
oappend(SET_F("addOption(dd,'Off',0);"));
oappend(SET_F("addOption(dd,'On',1);"));
oappend(SET_F("addInfo('AudioReactive:dynamics:limiter',0,' On ');")); // 0 is field type, 1 is actual field
oappend(SET_F("addInfo('AudioReactive:dynamics:rise',1,'ms <i>(&#x266A; effects only)</i>');"));
oappend(SET_F("addInfo('AudioReactive:dynamics:fall',1,'ms <i>(&#x266A; effects only)</i>');"));
uiScript.print(F("dd=addDropdown(ux,'dynamics:limiter');"));
uiScript.print(F("addOption(dd,'Off',0);"));
uiScript.print(F("addOption(dd,'On',1);"));
uiScript.print(F("addInfo(ux+':dynamics:limiter',0,' On ');")); // 0 is field type, 1 is actual field
uiScript.print(F("addInfo(ux+':dynamics:rise',1,'ms <i>(&#x266A; effects only)</i>');"));
uiScript.print(F("addInfo(ux+':dynamics:fall',1,'ms <i>(&#x266A; effects only)</i>');"));
oappend(SET_F("dd=addDropdown('AudioReactive','frequency:scale');"));
oappend(SET_F("addOption(dd,'None',0);"));
oappend(SET_F("addOption(dd,'Linear (Amplitude)',2);"));
oappend(SET_F("addOption(dd,'Square Root (Energy)',3);"));
oappend(SET_F("addOption(dd,'Logarithmic (Loudness)',1);"));
uiScript.print(F("dd=addDropdown(ux,'frequency:scale');"));
uiScript.print(F("addOption(dd,'None',0);"));
uiScript.print(F("addOption(dd,'Linear (Amplitude)',2);"));
uiScript.print(F("addOption(dd,'Square Root (Energy)',3);"));
uiScript.print(F("addOption(dd,'Logarithmic (Loudness)',1);"));
#endif
oappend(SET_F("dd=addDropdown('AudioReactive','sync:mode');"));
oappend(SET_F("addOption(dd,'Off',0);"));
uiScript.print(F("dd=addDropdown(ux,'sync:mode');"));
uiScript.print(F("addOption(dd,'Off',0);"));
#ifdef ARDUINO_ARCH_ESP32
oappend(SET_F("addOption(dd,'Send',1);"));
uiScript.print(F("addOption(dd,'Send',1);"));
#endif
oappend(SET_F("addOption(dd,'Receive',2);"));
uiScript.print(F("addOption(dd,'Receive',2);"));
#ifdef ARDUINO_ARCH_ESP32
oappend(SET_F("addInfo('AudioReactive:digitalmic:type',1,'<i>requires reboot!</i>');")); // 0 is field type, 1 is actual field
oappend(SET_F("addInfo('AudioReactive:digitalmic:pin[]',0,'<i>sd/data/dout</i>','I2S SD');"));
oappend(SET_F("addInfo('AudioReactive:digitalmic:pin[]',1,'<i>ws/clk/lrck</i>','I2S WS');"));
oappend(SET_F("addInfo('AudioReactive:digitalmic:pin[]',2,'<i>sck/bclk</i>','I2S SCK');"));
uiScript.print(F("addInfo(ux+':digitalmic:type',1,'<i>requires reboot!</i>');")); // 0 is field type, 1 is actual field
uiScript.print(F("addInfo(uxp,0,'<i>sd/data/dout</i>','I2S SD');"));
uiScript.print(F("addInfo(uxp,1,'<i>ws/clk/lrck</i>','I2S WS');"));
uiScript.print(F("addInfo(uxp,2,'<i>sck/bclk</i>','I2S SCK');"));
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3)
oappend(SET_F("addInfo('AudioReactive:digitalmic:pin[]',3,'<i>only use -1, 0, 1 or 3</i>','I2S MCLK');"));
uiScript.print(F("addInfo(uxp,3,'<i>only use -1, 0, 1 or 3</i>','I2S MCLK');"));
#else
oappend(SET_F("addInfo('AudioReactive:digitalmic:pin[]',3,'<i>master clock</i>','I2S MCLK');"));
uiScript.print(F("addInfo(uxp,3,'<i>master clock</i>','I2S MCLK');"));
#endif
#endif
}

View File

@@ -30,7 +30,7 @@ There are however plans to create a lightweight audioreactive for the 8266, with
### using latest _arduinoFFT_ library version 2.x
The latest arduinoFFT release version should be used for audioreactive.
* `build_flags` = `-D USERMOD_AUDIOREACTIVE`
* `build_flags` = `-D USERMOD_AUDIOREACTIVE -D sqrt_internal=sqrtf`
* `lib_deps`= `kosme/arduinoFFT @ 2.0.1`
## Configuration

View File

@@ -305,14 +305,14 @@ class BobLightUsermod : public Usermod {
}
void appendConfigData() override {
//oappend(SET_F("dd=addDropdown('usermod','selectfield');"));
//oappend(SET_F("addOption(dd,'1st value',0);"));
//oappend(SET_F("addOption(dd,'2nd value',1);"));
oappend(SET_F("addInfo('BobLight:top',1,'LEDs');")); // 0 is field type, 1 is actual field
oappend(SET_F("addInfo('BobLight:bottom',1,'LEDs');")); // 0 is field type, 1 is actual field
oappend(SET_F("addInfo('BobLight:left',1,'LEDs');")); // 0 is field type, 1 is actual field
oappend(SET_F("addInfo('BobLight:right',1,'LEDs');")); // 0 is field type, 1 is actual field
oappend(SET_F("addInfo('BobLight:pct',1,'Depth of scan [%]');")); // 0 is field type, 1 is actual field
//oappend(F("dd=addDropdown('usermod','selectfield');"));
//oappend(F("addOption(dd,'1st value',0);"));
//oappend(F("addOption(dd,'2nd value',1);"));
oappend(F("addInfo('BobLight:top',1,'LEDs');")); // 0 is field type, 1 is actual field
oappend(F("addInfo('BobLight:bottom',1,'LEDs');")); // 0 is field type, 1 is actual field
oappend(F("addInfo('BobLight:left',1,'LEDs');")); // 0 is field type, 1 is actual field
oappend(F("addInfo('BobLight:right',1,'LEDs');")); // 0 is field type, 1 is actual field
oappend(F("addInfo('BobLight:pct',1,'Depth of scan [%]');")); // 0 is field type, 1 is actual field
}
void addToConfig(JsonObject& root) override {

View File

@@ -264,7 +264,7 @@ void MultiRelay::handleOffTimer() {
void MultiRelay::InitHtmlAPIHandle() { // https://github.com/me-no-dev/ESPAsyncWebServer
DEBUG_PRINTLN(F("Relays: Initialize HTML API"));
server.on(SET_F("/relays"), HTTP_GET, [this](AsyncWebServerRequest *request) {
server.on(F("/relays"), HTTP_GET, [this](AsyncWebServerRequest *request) {
DEBUG_PRINTLN(F("Relays: HTML API"));
String janswer;
String error = "";
@@ -765,10 +765,10 @@ void MultiRelay::addToConfig(JsonObject &root) {
}
void MultiRelay::appendConfigData() {
oappend(SET_F("addInfo('MultiRelay:PCF8574-address',1,'<i>(not hex!)</i>');"));
oappend(SET_F("addInfo('MultiRelay:broadcast-sec',1,'(MQTT message)');"));
//oappend(SET_F("addInfo('MultiRelay:relay-0:pin',1,'(use -1 for PCF8574)');"));
oappend(SET_F("d.extra.push({'MultiRelay':{pin:[['P0',100],['P1',101],['P2',102],['P3',103],['P4',104],['P5',105],['P6',106],['P7',107]]}});"));
oappend(F("addInfo('MultiRelay:PCF8574-address',1,'<i>(not hex!)</i>');"));
oappend(F("addInfo('MultiRelay:broadcast-sec',1,'(MQTT message)');"));
//oappend(F("addInfo('MultiRelay:relay-0:pin',1,'(use -1 for PCF8574)');"));
oappend(F("d.extra.push({'MultiRelay':{pin:[['P0',100],['P1',101],['P2',102],['P3',103],['P4',104],['P5',105],['P6',106],['P7',107]]}});"));
}
/**

View File

@@ -387,23 +387,23 @@ class PixelsDiceTrayUsermod : public Usermod {
// To work around this, add info text to the end of the preceding item.
//
// See addInfo in wled00/data/settings_um.htm for details on what this function does.
oappend(SET_F(
oappend(F(
"addInfo('DiceTray:ble_scan_duration',1,'<br><br><i>Set to \"*\" to "
"connect to any die.<br>Leave Blank to disable.</i><br><i "
"class=\"warn\">Saving will replace \"*\" with die names.</i>','');"));
#if USING_TFT_DISPLAY
oappend(SET_F("ddr=addDropdown('DiceTray','rotation');"));
oappend(SET_F("addOption(ddr,'0 deg',0);"));
oappend(SET_F("addOption(ddr,'90 deg',1);"));
oappend(SET_F("addOption(ddr,'180 deg',2);"));
oappend(SET_F("addOption(ddr,'270 deg',3);"));
oappend(SET_F(
oappend(F("ddr=addDropdown('DiceTray','rotation');"));
oappend(F("addOption(ddr,'0 deg',0);"));
oappend(F("addOption(ddr,'90 deg',1);"));
oappend(F("addOption(ddr,'180 deg',2);"));
oappend(F("addOption(ddr,'270 deg',3);"));
oappend(F(
"addInfo('DiceTray:rotation',1,'<br><i class=\"warn\">DO NOT CHANGE "
"SPI PINS.</i><br><i class=\"warn\">CHANGES ARE IGNORED.</i>','');"));
oappend(SET_F("addInfo('TFT:pin[]',0,'','SPI CS');"));
oappend(SET_F("addInfo('TFT:pin[]',1,'','SPI DC');"));
oappend(SET_F("addInfo('TFT:pin[]',2,'','SPI RST');"));
oappend(SET_F("addInfo('TFT:pin[]',3,'','SPI BL');"));
oappend(F("addInfo('TFT:pin[]',0,'','SPI CS');"));
oappend(F("addInfo('TFT:pin[]',1,'','SPI DC');"));
oappend(F("addInfo('TFT:pin[]',2,'','SPI RST');"));
oappend(F("addInfo('TFT:pin[]',3,'','SPI BL');"));
#endif
}

View File

@@ -310,22 +310,22 @@ void ShtUsermod::onMqttConnect(bool sessionPresent) {
* @return void
*/
void ShtUsermod::appendConfigData() {
oappend(SET_F("dd=addDropdown('"));
oappend(F("dd=addDropdown('"));
oappend(_name);
oappend(SET_F("','"));
oappend(F("','"));
oappend(_shtType);
oappend(SET_F("');"));
oappend(SET_F("addOption(dd,'SHT30',0);"));
oappend(SET_F("addOption(dd,'SHT31',1);"));
oappend(SET_F("addOption(dd,'SHT35',2);"));
oappend(SET_F("addOption(dd,'SHT85',3);"));
oappend(SET_F("dd=addDropdown('"));
oappend(F("');"));
oappend(F("addOption(dd,'SHT30',0);"));
oappend(F("addOption(dd,'SHT31',1);"));
oappend(F("addOption(dd,'SHT35',2);"));
oappend(F("addOption(dd,'SHT85',3);"));
oappend(F("dd=addDropdown('"));
oappend(_name);
oappend(SET_F("','"));
oappend(F("','"));
oappend(_unitOfTemp);
oappend(SET_F("');"));
oappend(SET_F("addOption(dd,'Celsius',0);"));
oappend(SET_F("addOption(dd,'Fahrenheit',1);"));
oappend(F("');"));
oappend(F("addOption(dd,'Celsius',0);"));
oappend(F("addOption(dd,'Fahrenheit',1);"));
}
/**

View File

@@ -96,7 +96,7 @@ void setup() {
jsonTransitionOnce = true;
strip.setTransition(0); //no transition
effectCurrent = FX_MODE_COLOR_WIPE;
resetTimebase(); //make sure wipe starts from beginning
strip.resetTimebase(); //make sure wipe starts from beginning
//set wipe direction
Segment& seg = strip.getSegment(0);

View File

@@ -86,7 +86,7 @@ void startWipe()
bri = briLast; //turn on
transitionDelayTemp = 0; //no transition
effectCurrent = FX_MODE_COLOR_WIPE;
resetTimebase(); //make sure wipe starts from beginning
strip.resetTimebase(); //make sure wipe starts from beginning
//set wipe direction
Segment& seg = strip.getSegment(0);

View File

@@ -1202,21 +1202,21 @@ void FourLineDisplayUsermod::onUpdateBegin(bool init) {
//}
void FourLineDisplayUsermod::appendConfigData() {
oappend(SET_F("dd=addDropdown('4LineDisplay','type');"));
oappend(SET_F("addOption(dd,'None',0);"));
oappend(SET_F("addOption(dd,'SSD1306',1);"));
oappend(SET_F("addOption(dd,'SH1106',2);"));
oappend(SET_F("addOption(dd,'SSD1306 128x64',3);"));
oappend(SET_F("addOption(dd,'SSD1305',4);"));
oappend(SET_F("addOption(dd,'SSD1305 128x64',5);"));
oappend(SET_F("addOption(dd,'SSD1309 128x64',9);"));
oappend(SET_F("addOption(dd,'SSD1306 SPI',6);"));
oappend(SET_F("addOption(dd,'SSD1306 SPI 128x64',7);"));
oappend(SET_F("addOption(dd,'SSD1309 SPI 128x64',8);"));
oappend(SET_F("addInfo('4LineDisplay:type',1,'<br><i class=\"warn\">Change may require reboot</i>','');"));
oappend(SET_F("addInfo('4LineDisplay:pin[]',0,'','SPI CS');"));
oappend(SET_F("addInfo('4LineDisplay:pin[]',1,'','SPI DC');"));
oappend(SET_F("addInfo('4LineDisplay:pin[]',2,'','SPI RST');"));
oappend(F("dd=addDropdown('4LineDisplay','type');"));
oappend(F("addOption(dd,'None',0);"));
oappend(F("addOption(dd,'SSD1306',1);"));
oappend(F("addOption(dd,'SH1106',2);"));
oappend(F("addOption(dd,'SSD1306 128x64',3);"));
oappend(F("addOption(dd,'SSD1305',4);"));
oappend(F("addOption(dd,'SSD1305 128x64',5);"));
oappend(F("addOption(dd,'SSD1309 128x64',9);"));
oappend(F("addOption(dd,'SSD1306 SPI',6);"));
oappend(F("addOption(dd,'SSD1306 SPI 128x64',7);"));
oappend(F("addOption(dd,'SSD1309 SPI 128x64',8);"));
oappend(F("addInfo('4LineDisplay:type',1,'<br><i class=\"warn\">Change may require reboot</i>','');"));
oappend(F("addInfo('4LineDisplay:pin[]',0,'','SPI CS');"));
oappend(F("addInfo('4LineDisplay:pin[]',1,'','SPI DC');"));
oappend(F("addInfo('4LineDisplay:pin[]',2,'','SPI RST');"));
}
/*

View File

@@ -1090,8 +1090,8 @@ void RotaryEncoderUIUsermod::addToConfig(JsonObject &root) {
}
void RotaryEncoderUIUsermod::appendConfigData() {
oappend(SET_F("addInfo('Rotary-Encoder:PCF8574-address',1,'<i>(not hex!)</i>');"));
oappend(SET_F("d.extra.push({'Rotary-Encoder':{pin:[['P0',100],['P1',101],['P2',102],['P3',103],['P4',104],['P5',105],['P6',106],['P7',107]]}});"));
oappend(F("addInfo('Rotary-Encoder:PCF8574-address',1,'<i>(not hex!)</i>');"));
oappend(F("d.extra.push({'Rotary-Encoder':{pin:[['P0',100],['P1',101],['P2',102],['P3',103],['P4',104],['P5',105],['P6',106],['P7',107]]}});"));
}
/**

View File

@@ -433,8 +433,8 @@ class WordClockUsermod : public Usermod
void appendConfigData()
{
oappend(SET_F("addInfo('WordClockUsermod:ledOffset', 1, 'Number of LEDs before the letters');"));
oappend(SET_F("addInfo('WordClockUsermod:Norddeutsch', 1, 'Viertel vor instead of Dreiviertel');"));
oappend(F("addInfo('WordClockUsermod:ledOffset', 1, 'Number of LEDs before the letters');"));
oappend(F("addInfo('WordClockUsermod:Norddeutsch', 1, 'Viertel vor instead of Dreiviertel');"));
}
/*

View File

@@ -54,13 +54,13 @@ class WireguardUsermod : public Usermod {
}
void appendConfigData() {
oappend(SET_F("addInfo('WireGuard:host',1,'Server Hostname');")); // 0 is field type, 1 is actual field
oappend(SET_F("addInfo('WireGuard:port',1,'Server Port');")); // 0 is field type, 1 is actual field
oappend(SET_F("addInfo('WireGuard:ip',1,'Device IP');")); // 0 is field type, 1 is actual field
oappend(SET_F("addInfo('WireGuard:psk',1,'Pre Shared Key (optional)');")); // 0 is field type, 1 is actual field
oappend(SET_F("addInfo('WireGuard:pem',1,'Private Key');")); // 0 is field type, 1 is actual field
oappend(SET_F("addInfo('WireGuard:pub',1,'Public Key');")); // 0 is field type, 1 is actual field
oappend(SET_F("addInfo('WireGuard:tz',1,'POSIX timezone string');")); // 0 is field type, 1 is actual field
oappend(F("addInfo('WireGuard:host',1,'Server Hostname');")); // 0 is field type, 1 is actual field
oappend(F("addInfo('WireGuard:port',1,'Server Port');")); // 0 is field type, 1 is actual field
oappend(F("addInfo('WireGuard:ip',1,'Device IP');")); // 0 is field type, 1 is actual field
oappend(F("addInfo('WireGuard:psk',1,'Pre Shared Key (optional)');")); // 0 is field type, 1 is actual field
oappend(F("addInfo('WireGuard:pem',1,'Private Key');")); // 0 is field type, 1 is actual field
oappend(F("addInfo('WireGuard:pub',1,'Public Key');")); // 0 is field type, 1 is actual field
oappend(F("addInfo('WireGuard:tz',1,'POSIX timezone string');")); // 0 is field type, 1 is actual field
}
void addToConfig(JsonObject& root) {

View File

@@ -2,24 +2,10 @@
WS2812FX.cpp contains all effect methods
Harm Aldick - 2016
www.aldick.org
LICENSE
The MIT License (MIT)
Copyright (c) 2016 Harm Aldick
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Licensed under the EUPL v. 1.2 or later
Adapted from code originally licensed under the MIT license
Modified heavily for WLED
*/
@@ -2520,9 +2506,9 @@ static uint16_t ripple_base() {
#endif
{
int left = rippleorigin - propI -1;
int right = rippleorigin + propI +3;
int right = rippleorigin + propI +2;
for (int v = 0; v < 4; v++) {
unsigned mag = scale8(cubicwave8((propF>>2)+(v-left)*64), amp);
unsigned mag = scale8(cubicwave8((propF>>2) + v * 64), amp);
SEGMENT.setPixelColor(left + v, color_blend(SEGMENT.getPixelColor(left + v), col, mag)); // TODO
SEGMENT.setPixelColor(right - v, color_blend(SEGMENT.getPixelColor(right - v), col, mag)); // TODO
}
@@ -7749,7 +7735,7 @@ uint16_t mode_2Doctopus() {
const int C_Y = (rows / 2) + ((SEGMENT.custom2 - 128)*rows)/255;
for (int x = 0; x < cols; x++) {
for (int y = 0; y < rows; y++) {
rMap[XY(x, y)].angle = 40.7436f * atan2f((y - C_Y), (x - C_X)); // avoid 128*atan2()/PI
rMap[XY(x, y)].angle = int(40.7436f * atan2f((y - C_Y), (x - C_X))); // avoid 128*atan2()/PI
rMap[XY(x, y)].radius = hypotf((x - C_X), (y - C_Y)) * mapp; //thanks Sutaburosu
}
}

View File

@@ -2,24 +2,10 @@
WS2812FX.h - Library for WS2812 LED effects.
Harm Aldick - 2016
www.aldick.org
LICENSE
The MIT License (MIT)
Copyright (c) 2016 Harm Aldick
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Licensed under the EUPL v. 1.2 or later
Adapted from code originally licensed under the MIT license
Modified for WLED
*/
@@ -539,12 +525,12 @@ typedef struct Segment {
inline static const CRGBPalette16 &getCurrentPalette() { return Segment::_currentPalette; }
void setUp(uint16_t i1, uint16_t i2, uint8_t grp=1, uint8_t spc=0, uint16_t ofs=UINT16_MAX, uint16_t i1Y=0, uint16_t i2Y=1);
bool setColor(uint8_t slot, uint32_t c); //returns true if changed
void setCCT(uint16_t k);
void setOpacity(uint8_t o);
void setOption(uint8_t n, bool val);
void setMode(uint8_t fx, bool loadDefaults = false);
void setPalette(uint8_t pal);
Segment &setColor(uint8_t slot, uint32_t c);
Segment &setCCT(uint16_t k);
Segment &setOpacity(uint8_t o);
Segment &setOption(uint8_t n, bool val);
Segment &setMode(uint8_t fx, bool loadDefaults = false);
Segment &setPalette(uint8_t pal);
uint8_t differs(Segment& b) const;
void refreshLightCapabilities();
@@ -559,7 +545,7 @@ typedef struct Segment {
* Call resetIfRequired before calling the next effect function.
* Safe to call from interrupts and network requests.
*/
inline void markForReset() { reset = true; } // setOption(SEG_OPTION_RESET, true)
inline Segment &markForReset() { reset = true; return *this; } // setOption(SEG_OPTION_RESET, true)
// transition functions
void startTransition(uint16_t dur); // transition has to start before actual segment values change
@@ -613,9 +599,15 @@ typedef struct Segment {
}
// 2D matrix
[[gnu::hot]] uint16_t virtualWidth() const; // segment width in virtual pixels (accounts for groupping and spacing)
[[gnu::hot]] uint16_t virtualHeight() const; // segment height in virtual pixels (accounts for groupping and spacing)
uint16_t nrOfVStrips() const; // returns number of virtual vertical strips in 2D matrix (used to expand 1D effects into 2D)
[[gnu::hot]] unsigned virtualWidth() const; // segment width in virtual pixels (accounts for groupping and spacing)
[[gnu::hot]] unsigned virtualHeight() const; // segment height in virtual pixels (accounts for groupping and spacing)
inline unsigned nrOfVStrips() const { // returns number of virtual vertical strips in 2D matrix (used to expand 1D effects into 2D)
#ifndef WLED_DISABLE_2D
return (is2D() && map1D2D == M12_pBar) ? virtualWidth() : 1;
#else
return 1;
#endif
}
#ifndef WLED_DISABLE_2D
[[gnu::hot]] uint16_t XY(int x, int y); // support function to get relative index within segment
[[gnu::hot]] void setPixelColorXY(int x, int y, uint32_t c); // set relative pixel within segment with color
@@ -792,7 +784,8 @@ class WS2812FX { // 96 bytes
setTargetFps(uint8_t fps),
setupEffectData(); // add default effects to the list; defined in FX.cpp
inline void restartRuntime() { for (Segment &seg : _segments) seg.markForReset(); }
inline void resetTimebase() { timebase = 0UL - millis(); }
inline void restartRuntime() { for (Segment &seg : _segments) { seg.markForReset().resetIfRequired(); } }
inline void setTransitionMode(bool t) { for (Segment &seg : _segments) seg.startTransition(t ? _transitionDur : 0); }
inline void setColor(uint8_t slot, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0) { setColor(slot, RGBW32(r,g,b,w)); }
inline void setPixelColor(unsigned n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0) { setPixelColor(n, RGBW32(r,g,b,w)); }
@@ -848,10 +841,8 @@ class WS2812FX { // 96 bytes
inline uint16_t getLength() const { return _length; } // returns actual amount of LEDs on a strip (2D matrix may have less LEDs than W*H)
inline uint16_t getTransition() const { return _transitionDur; } // returns currently set transition time (in ms)
uint32_t
now,
timebase,
getPixelColor(uint16_t) const;
unsigned long now, timebase;
uint32_t getPixelColor(unsigned) const;
inline uint32_t getLastShow() const { return _lastShow; } // returns millis() timestamp of last strip.show() call
inline uint32_t segColor(uint8_t i) const { return _colors_t[i]; } // returns currently valid color (for slot i) AKA SEGCOLOR(); may be blended between two colors while in transition

View File

@@ -1,24 +1,9 @@
/*
FX_2Dfcn.cpp contains all 2D utility functions
LICENSE
The MIT License (MIT)
Copyright (c) 2022 Blaz Kristan (https://blaz.at/home)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Licensed under the EUPL v. 1.2 or later
Adapted from code originally licensed under the MIT license
Parts of the code adapted from WLED Sound Reactive
*/
@@ -171,7 +156,7 @@ uint16_t IRAM_ATTR_YN Segment::XY(int x, int y)
void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col)
{
if (!isActive()) return; // not active
if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit
if ((unsigned)x >= virtualWidth() || (unsigned)y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit
uint8_t _bri_t = currentBri();
if (_bri_t < 255) {
@@ -266,7 +251,7 @@ void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa)
// returns RGBW values of pixel
uint32_t IRAM_ATTR_YN Segment::getPixelColorXY(int x, int y) const {
if (!isActive()) return 0; // not active
if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return 0; // if pixel would fall out of virtual segment just exit
if ((unsigned)x >= virtualWidth() || (unsigned)y >= virtualHeight() || x<0 || y<0) return 0; // if pixel would fall out of virtual segment just exit
if (reverse ) x = virtualWidth() - x - 1;
if (reverse_y) y = virtualHeight() - y - 1;
if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed

View File

@@ -2,24 +2,10 @@
WS2812FX_fcn.cpp contains all utility functions
Harm Aldick - 2016
www.aldick.org
LICENSE
The MIT License (MIT)
Copyright (c) 2016 Harm Aldick
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Licensed under the EUPL v. 1.2 or later
Adapted from code originally licensed under the MIT license
Modified heavily for WLED
*/
@@ -523,46 +509,53 @@ void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t
}
bool Segment::setColor(uint8_t slot, uint32_t c) { //returns true if changed
if (slot >= NUM_COLORS || c == colors[slot]) return false;
Segment &Segment::setColor(uint8_t slot, uint32_t c) {
if (slot >= NUM_COLORS || c == colors[slot]) return *this;
if (!_isRGB && !_hasW) {
if (slot == 0 && c == BLACK) return false; // on/off segment cannot have primary color black
if (slot == 1 && c != BLACK) return false; // on/off segment cannot have secondary color non black
if (slot == 0 && c == BLACK) return *this; // on/off segment cannot have primary color black
if (slot == 1 && c != BLACK) return *this; // on/off segment cannot have secondary color non black
}
if (fadeTransition) startTransition(strip.getTransition()); // start transition prior to change
colors[slot] = c;
stateChanged = true; // send UDP/WS broadcast
return true;
return *this;
}
void Segment::setCCT(uint16_t k) {
Segment &Segment::setCCT(uint16_t k) {
if (k > 255) { //kelvin value, convert to 0-255
if (k < 1900) k = 1900;
if (k > 10091) k = 10091;
k = (k - 1900) >> 5;
}
if (cct == k) return;
if (fadeTransition) startTransition(strip.getTransition()); // start transition prior to change
cct = k;
stateChanged = true; // send UDP/WS broadcast
if (cct != k) {
//DEBUGFX_PRINTF_P(PSTR("- Starting CCT transition: %d\n"), k);
startTransition(strip.getTransition()); // start transition prior to change
cct = k;
stateChanged = true; // send UDP/WS broadcast
}
return *this;
}
void Segment::setOpacity(uint8_t o) {
if (opacity == o) return;
if (fadeTransition) startTransition(strip.getTransition()); // start transition prior to change
opacity = o;
stateChanged = true; // send UDP/WS broadcast
Segment &Segment::setOpacity(uint8_t o) {
if (opacity != o) {
//DEBUGFX_PRINTF_P(PSTR("- Starting opacity transition: %d\n"), o);
startTransition(strip.getTransition()); // start transition prior to change
opacity = o;
stateChanged = true; // send UDP/WS broadcast
}
return *this;
}
void Segment::setOption(uint8_t n, bool val) {
Segment &Segment::setOption(uint8_t n, bool val) {
bool prevOn = on;
if (fadeTransition && n == SEG_OPTION_ON && val != prevOn) startTransition(strip.getTransition()); // start transition prior to change
if (val) options |= 0x01 << n;
else options &= ~(0x01 << n);
if (!(n == SEG_OPTION_SELECTED || n == SEG_OPTION_RESET)) stateChanged = true; // send UDP/WS broadcast
return *this;
}
void Segment::setMode(uint8_t fx, bool loadDefaults) {
Segment &Segment::setMode(uint8_t fx, bool loadDefaults) {
// skip reserved
while (fx < strip.getModeCount() && strncmp_P("RSVD", strip.getModeData(fx), 4) == 0) fx++;
if (fx >= strip.getModeCount()) fx = 0; // set solid mode
@@ -594,9 +587,10 @@ void Segment::setMode(uint8_t fx, bool loadDefaults) {
markForReset();
stateChanged = true; // send UDP/WS broadcast
}
return *this;
}
void Segment::setPalette(uint8_t pal) {
Segment &Segment::setPalette(uint8_t pal) {
if (pal < 245 && pal > GRADIENT_PALETTE_COUNT+13) pal = 0; // built in palettes
if (pal > 245 && (strip.customPalettes.size() == 0 || 255U-pal > strip.customPalettes.size()-1)) pal = 0; // custom palettes
if (pal != palette) {
@@ -604,37 +598,24 @@ void Segment::setPalette(uint8_t pal) {
palette = pal;
stateChanged = true; // send UDP/WS broadcast
}
return *this;
}
// 2D matrix
uint16_t IRAM_ATTR Segment::virtualWidth() const {
unsigned IRAM_ATTR Segment::virtualWidth() const {
unsigned groupLen = groupLength();
unsigned vWidth = ((transpose ? height() : width()) + groupLen - 1) / groupLen;
if (mirror) vWidth = (vWidth + 1) /2; // divide by 2 if mirror, leave at least a single LED
return vWidth;
}
uint16_t IRAM_ATTR Segment::virtualHeight() const {
unsigned IRAM_ATTR Segment::virtualHeight() const {
unsigned groupLen = groupLength();
unsigned vHeight = ((transpose ? width() : height()) + groupLen - 1) / groupLen;
if (mirror_y) vHeight = (vHeight + 1) /2; // divide by 2 if mirror, leave at least a single LED
return vHeight;
}
uint16_t IRAM_ATTR_YN Segment::nrOfVStrips() const {
unsigned vLen = 1;
#ifndef WLED_DISABLE_2D
if (is2D()) {
switch (map1D2D) {
case M12_pBar:
vLen = virtualWidth();
break;
}
}
#endif
return vLen;
}
// Constants for mapping mode "Pinwheel"
#ifndef WLED_DISABLE_2D
constexpr int Pinwheel_Steps_Small = 72; // no holes up to 16x16
@@ -1201,10 +1182,7 @@ uint32_t Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_
//do not call this method from system context (network callback)
void WS2812FX::finalizeInit() {
//reset segment runtimes
for (segment &seg : _segments) {
seg.markForReset();
seg.resetIfRequired();
}
restartRuntime();
// for the lack of better place enumerate ledmaps here
// if we do it in json.cpp (serializeInfo()) we are getting flashes on LEDs
@@ -1351,7 +1329,7 @@ void WS2812FX::service() {
if (nowUp > seg.next_time || _triggered || (doShow && seg.mode == FX_MODE_STATIC))
{
doShow = true;
unsigned delay = FRAMETIME;
unsigned frameDelay = FRAMETIME;
if (!seg.freeze) { //only run effect function if not frozen
int oldCCT = BusManager::getSegmentCCT(); // store original CCT value (actually it is not Segment based)
@@ -1371,7 +1349,7 @@ void WS2812FX::service() {
// overwritten by later effect. To enable seamless blending for every effect, additional LED buffer
// would need to be allocated for each effect and then blended together for each pixel.
[[maybe_unused]] uint8_t tmpMode = seg.currentMode(); // this will return old mode while in transition
delay = (*_mode[seg.mode])(); // run new/current mode
frameDelay = (*_mode[seg.mode])(); // run new/current mode
#ifndef WLED_DISABLE_MODE_BLEND
if (modeBlending && seg.mode != tmpMode) {
Segment::tmpsegd_t _tmpSegData;
@@ -1380,16 +1358,16 @@ void WS2812FX::service() {
_virtualSegmentLength = seg.virtualLength(); // update SEGLEN (mapping may have changed)
unsigned d2 = (*_mode[tmpMode])(); // run old mode
seg.restoreSegenv(_tmpSegData); // restore mode state (will also update transitional state)
delay = MIN(delay,d2); // use shortest delay
frameDelay = min(frameDelay,d2); // use shortest delay
Segment::modeBlend(false); // unset semaphore
}
#endif
seg.call++;
if (seg.isInTransition() && delay > FRAMETIME) delay = FRAMETIME; // force faster updates during transition
if (seg.isInTransition() && frameDelay > FRAMETIME) frameDelay = FRAMETIME; // force faster updates during transition
BusManager::setSegmentCCT(oldCCT); // restore old CCT for ABL adjustments
}
seg.next_time = nowUp + delay;
seg.next_time = nowUp + frameDelay;
}
_segment_index++;
}
@@ -1416,7 +1394,7 @@ void IRAM_ATTR WS2812FX::setPixelColor(unsigned i, uint32_t col) {
BusManager::setPixelColor(i, col);
}
uint32_t IRAM_ATTR WS2812FX::getPixelColor(uint16_t i) const {
uint32_t IRAM_ATTR WS2812FX::getPixelColor(unsigned i) const {
i = getMappedPixelIndex(i);
if (i >= _length) return 0;
return BusManager::getPixelColor(i);

View File

@@ -215,6 +215,7 @@ void handleAnalog(uint8_t b)
briLast = bri;
bri = 0;
} else {
if (bri == 0) strip.restartRuntime();
bri = aRead;
}
} else if (macroDoublePress[b] == 249) {

View File

@@ -53,7 +53,7 @@
#else
#define WLED_MAX_ANALOG_CHANNELS (LEDC_CHANNEL_MAX*LEDC_SPEED_MODE_MAX)
#if defined(CONFIG_IDF_TARGET_ESP32C3) // 2 RMT, 6 LEDC, only has 1 I2S but NPB does not support it ATM
#define WLED_MAX_BUSSES 4 // will allow 2 digital & 2 analog RGB
#define WLED_MAX_BUSSES 6 // will allow 2 digital & 2 analog RGB or 6 PWM white
#define WLED_MAX_DIGITAL_CHANNELS 2
//#define WLED_MAX_ANALOG_CHANNELS 6
#define WLED_MIN_VIRTUAL_BUSSES 3

View File

@@ -1040,7 +1040,7 @@ textarea {
.segname .flr, .pname .flr {
transform: rotate(0deg);
right: -6px;
/*right: -6px;*/
}
/* segment power wrapper */
@@ -1335,6 +1335,11 @@ TD .checkmark, TD .radiomark {
box-shadow: 0 0 10px 4px var(--c-1);
}
.lstI .flr:hover {
background: var(--c-6);
border-radius: 100%;
}
#pcont .selected:not([class*="expanded"]) {
bottom: 52px;
top: 42px;

View File

@@ -72,7 +72,7 @@
<a href="https://github.com/Aircoookie/WLED/wiki/Contributors-and-credits" target="_blank">Contributors, dependencies and special thanks</a><br>
A huge thank you to everyone who helped me create WLED!<br><br>
(c) 2016-2024 Christian Schwinne <br>
<i>Licensed under the <a href="https://github.com/Aircoookie/WLED/blob/master/LICENSE" target="_blank">MIT license</a></i><br><br>
<i>Licensed under the <a href="https://github.com/Aircoookie/WLED/blob/master/LICENSE" target="_blank">EUPL v1.2 license</a></i><br><br>
Server message: <span class="sip"> Response error! </span><hr>
<div id="toast"></div>
<button type="button" onclick="B()">Back</button><button type="submit">Save</button>

View File

@@ -169,7 +169,6 @@ bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient = 0);
void setValuesFromSegment(uint8_t s);
void setValuesFromMainSeg();
void setValuesFromFirstSelectedSeg();
void resetTimebase();
void toggleOnOff();
void applyBri();
void applyFinalBri();
@@ -236,7 +235,7 @@ void handleRemote(uint8_t *data, size_t len);
//set.cpp
bool isAsterisksOnly(const char* str, byte maxLen);
void handleSettingsSet(AsyncWebServerRequest *request, byte subPage);
bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply=true);
bool handleHttpApi(const String& req, bool apply=true);
//udp.cpp
void notify(byte callMode, bool followUp=false);
@@ -324,6 +323,10 @@ class Usermod {
protected:
// Shim for oappend(), which used to exist in utils.cpp
template<typename T> static inline void oappend(const T& t) { oappend_shim->print(t); };
#ifdef ESP8266
// Handle print(PSTR()) without crashing by detecting PROGMEM strings
static void oappend(const char* c) { if ((intptr_t) c >= 0x40000000) oappend_shim->print(FPSTR(c)); else oappend_shim->print(c); };
#endif
};
class UsermodManager {

View File

@@ -599,16 +599,14 @@ static void decodeIRJson(uint32_t code)
}
} else {
// HTTP API command
String apireq = "win"; apireq += '&'; // reduce flash string usage
if (cmdStr.indexOf("~") > 0 || fdo["rpt"]) lastValidCode = code; // repeatable action
if (!cmdStr.startsWith(apireq)) cmdStr = apireq + cmdStr; // if no "win&" prefix
if (!irApplyToAllSelected && cmdStr.indexOf(F("SS="))<0) {
char tmp[10];
sprintf_P(tmp, PSTR("&SS=%d"), strip.getMainSegmentId());
cmdStr += tmp;
}
fdo.clear(); // clear JSON buffer (it is no longer needed)
handleSet(nullptr, cmdStr, false); // no stateUpdated() call here
handleHttpApi(cmdStr, false); // no stateUpdated() call here
}
} else {
// command is JSON object (TODO: currently will not handle irApplyToAllSelected correctly)

View File

@@ -346,7 +346,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
}
}
int tr = -1;
long tr = -1;
if (!presetId || currentPlaylist < 0) { //do not apply transition time from preset if playlist active, as it would override playlist transition times
tr = root[F("transition")] | -1;
if (tr >= 0) {
@@ -363,7 +363,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
}
tr = root[F("tb")] | -1;
if (tr >= 0) strip.timebase = ((uint32_t)tr) - millis();
if (tr >= 0) strip.timebase = (unsigned long)tr - millis();
JsonObject nl = root["nl"];
nightlightActive = getBoolVal(nl["on"], nightlightActive);
@@ -449,9 +449,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
// HTTP API commands (must be handled before "ps")
const char* httpwin = root["win"];
if (httpwin) {
String apireq = "win"; apireq += '&'; // reduce flash string usage
apireq += httpwin;
handleSet(nullptr, apireq, false); // may set stateChanged
handleHttpApi(httpwin, false); // may set stateChanged
}
// Applying preset from JSON API has 2 cases: a) "pd" AKA "preset direct" and b) "ps" AKA "preset select"
@@ -462,7 +460,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
if (!root[F("pd")].isNull() && stateChanged) {
// a) already applied preset content (requires "seg" or "win" but will ignore the rest)
currentPreset = root[F("pd")] | currentPreset;
if (root["win"].isNull()) presetCycCurr = currentPreset; // otherwise presetCycCurr was set in handleSet() [set.cpp]
if (root["win"].isNull()) presetCycCurr = currentPreset; // otherwise presetCycCurr was set in handleHttpApi() [set.cpp]
presetToRestore = currentPreset; // stateUpdated() will clear the preset, so we need to restore it after
DEBUG_PRINTF_P(PSTR("Preset direct: %d\n"), currentPreset);
} else if (!root["ps"].isNull()) {

View File

@@ -47,17 +47,12 @@ void applyValuesToSelectedSegs()
}
void resetTimebase()
{
strip.timebase = 0 - millis();
}
void toggleOnOff()
{
if (bri == 0)
{
bri = briLast;
strip.restartRuntime();
} else
{
briLast = bri;
@@ -122,7 +117,7 @@ void stateUpdated(byte callMode) {
nightlightStartTime = millis();
}
if (briT == 0) {
if (callMode != CALL_MODE_NOTIFICATION) resetTimebase(); //effect start from beginning
if (callMode != CALL_MODE_NOTIFICATION) strip.resetTimebase(); //effect start from beginning
}
if (bri > 0) briLast = bri;

View File

@@ -107,9 +107,7 @@ static void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProp
deserializeJson(*pDoc, payloadStr);
deserializeState(pDoc->as<JsonObject>());
} else { //HTTP API
String apireq = "win"; apireq += '&'; // reduce flash string usage
apireq += payloadStr;
handleSet(nullptr, apireq);
handleHttpApi(payloadStr);
}
releaseJSONBufferLock();
}

View File

@@ -201,7 +201,12 @@ bool PinManager::isPinOk(byte gpio, bool output)
if (gpio > 18 && gpio < 21) return false; // 19 + 20 = USB-JTAG. Not recommended for other uses.
#endif
if (gpio > 21 && gpio < 33) return false; // 22 to 32: not connected + SPI FLASH
if (gpio > 32 && gpio < 38) return !psramFound(); // 33 to 37: not available if using _octal_ SPI Flash or _octal_ PSRAM
#if CONFIG_ESPTOOLPY_FLASHMODE_OPI // 33-37: never available if using _octal_ Flash (opi_opi)
if (gpio > 32 && gpio < 38) return false;
#endif
#if CONFIG_SPIRAM_MODE_OCT // 33-37: not available if using _octal_ PSRAM (qio_opi), but free to use on _quad_ PSRAM (qio_qspi)
if (gpio > 32 && gpio < 38) return !psramFound();
#endif
// 38 to 48 are for general use. Be careful about straping pins GPIO45 and GPIO46 - these may be pull-up or pulled-down on your board.
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
// strapping pins: 0, 45 & 46

View File

@@ -143,6 +143,7 @@ void applyPresetWithFallback(uint8_t index, uint8_t callMode, uint8_t effectID,
void handlePresets()
{
byte presetErrFlag = ERR_NONE;
if (presetToSave) {
strip.suspend();
doSaveState();
@@ -166,21 +167,20 @@ void handlePresets()
#ifdef ARDUINO_ARCH_ESP32
if (tmpPreset==255 && tmpRAMbuffer!=nullptr) {
deserializeJson(*pDoc,tmpRAMbuffer);
errorFlag = ERR_NONE;
} else
#endif
{
errorFlag = readObjectFromFileUsingId(getPresetsFileName(tmpPreset < 255), tmpPreset, pDoc) ? ERR_NONE : ERR_FS_PLOAD;
presetErrFlag = readObjectFromFileUsingId(getPresetsFileName(tmpPreset < 255), tmpPreset, pDoc) ? ERR_NONE : ERR_FS_PLOAD;
}
fdo = pDoc->as<JsonObject>();
// only reset errorflag if previous error was preset-related
if ((errorFlag == ERR_NONE) || (errorFlag == ERR_FS_PLOAD)) errorFlag = presetErrFlag;
//HTTP API commands
const char* httpwin = fdo["win"];
if (httpwin) {
String apireq = "win"; // reduce flash string usage
apireq += F("&IN&"); // internal call
apireq += httpwin;
handleSet(nullptr, apireq, false); // may call applyPreset() via PL=
handleHttpApi(httpwin, false); // may call applyPreset() via PL=
setValuesFromFirstSelectedSeg(); // fills legacy values
changePreset = true;
} else {
@@ -205,7 +205,7 @@ void handlePresets()
updateInterfaces(tmpMode);
}
//called from handleSet(PS=) [network callback (sObj is empty), IR (irrational), deserializeState, UDP] and deserializeState() [network callback (filedoc!=nullptr)]
//called from handleHttpApi(PS=) [network callback (sObj is empty), IR (irrational), deserializeState, UDP] and deserializeState() [network callback (filedoc!=nullptr)]
void savePreset(byte index, const char* pname, JsonObject sObj)
{
if (!saveName) saveName = new char[33];

View File

@@ -153,16 +153,14 @@ static bool remoteJson(int button)
}
} else {
// HTTP API command
String apireq = "win"; apireq += '&'; // reduce flash string usage
//if (cmdStr.indexOf("~") || fdo["rpt"]) lastValidCode = code; // repeatable action
if (!cmdStr.startsWith(apireq)) cmdStr = apireq + cmdStr; // if no "win&" prefix
if (!irApplyToAllSelected && cmdStr.indexOf(F("SS="))<0) {
char tmp[10];
sprintf_P(tmp, PSTR("&SS=%d"), strip.getMainSegmentId());
cmdStr += tmp;
}
fdo.clear(); // clear JSON buffer (it is no longer needed)
handleSet(nullptr, cmdStr, false); // no stateUpdated() call here
handleHttpApi(cmdStr, false); // no stateUpdated() call here
stateUpdated(CALL_MODE_BUTTON);
parsed = true;
}

View File

@@ -803,16 +803,14 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
//HTTP API request parser
bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
bool handleHttpApi(const String& req, bool apply)
{
if (!(req.indexOf("win") >= 0)) return false;
int pos = 0;
DEBUG_PRINTF_P(PSTR("API req: %s\n"), req.c_str());
//segment select (sets main segment)
pos = req.indexOf(F("SM="));
if (pos > 0 && !realtimeMode) {
if (pos >= 0 && !realtimeMode) {
strip.setMainSegmentId(getNumVal(&req, pos));
}
@@ -821,7 +819,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
bool singleSegment = false;
pos = req.indexOf(F("SS="));
if (pos > 0) {
if (pos >= 0) {
unsigned t = getNumVal(&req, pos);
if (t < strip.getSegmentsNum()) {
selectedSeg = t;
@@ -831,7 +829,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
Segment& selseg = strip.getSegment(selectedSeg);
pos = req.indexOf(F("SV=")); //segment selected
if (pos > 0) {
if (pos >= 0) {
unsigned t = getNumVal(&req, pos);
if (t == 2) for (unsigned i = 0; i < strip.getSegmentsNum(); i++) strip.getSegment(i).selected = false; // unselect other segments
selseg.selected = t;
@@ -859,31 +857,31 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
uint8_t grpI = selseg.grouping;
uint16_t spcI = selseg.spacing;
pos = req.indexOf(F("&S=")); //segment start
if (pos > 0) {
if (pos >= 0) {
startI = std::abs(getNumVal(&req, pos));
}
pos = req.indexOf(F("S2=")); //segment stop
if (pos > 0) {
if (pos >= 0) {
stopI = std::abs(getNumVal(&req, pos));
}
pos = req.indexOf(F("GP=")); //segment grouping
if (pos > 0) {
if (pos >= 0) {
grpI = std::max(1,getNumVal(&req, pos));
}
pos = req.indexOf(F("SP=")); //segment spacing
if (pos > 0) {
if (pos >= 0) {
spcI = std::max(0,getNumVal(&req, pos));
}
strip.setSegment(selectedSeg, startI, stopI, grpI, spcI, UINT16_MAX, startY, stopY);
pos = req.indexOf(F("RV=")); //Segment reverse
if (pos > 0) selseg.reverse = req.charAt(pos+3) != '0';
if (pos >= 0) selseg.reverse = req.charAt(pos+3) != '0';
pos = req.indexOf(F("MI=")); //Segment mirror
if (pos > 0) selseg.mirror = req.charAt(pos+3) != '0';
if (pos >= 0) selseg.mirror = req.charAt(pos+3) != '0';
pos = req.indexOf(F("SB=")); //Segment brightness/opacity
if (pos > 0) {
if (pos >= 0) {
byte segbri = getNumVal(&req, pos);
selseg.setOption(SEG_OPTION_ON, segbri); // use transition
if (segbri) {
@@ -892,7 +890,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
}
pos = req.indexOf(F("SW=")); //segment power
if (pos > 0) {
if (pos >= 0) {
switch (getNumVal(&req, pos)) {
case 0: selseg.setOption(SEG_OPTION_ON, false); break; // use transition
case 1: selseg.setOption(SEG_OPTION_ON, true); break; // use transition
@@ -901,13 +899,13 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
}
pos = req.indexOf(F("PS=")); //saves current in preset
if (pos > 0) savePreset(getNumVal(&req, pos));
if (pos >= 0) savePreset(getNumVal(&req, pos));
pos = req.indexOf(F("P1=")); //sets first preset for cycle
if (pos > 0) presetCycMin = getNumVal(&req, pos);
if (pos >= 0) presetCycMin = getNumVal(&req, pos);
pos = req.indexOf(F("P2=")); //sets last preset for cycle
if (pos > 0) presetCycMax = getNumVal(&req, pos);
if (pos >= 0) presetCycMax = getNumVal(&req, pos);
//apply preset
if (updateVal(req.c_str(), "PL=", &presetCycCurr, presetCycMin, presetCycMax)) {
@@ -915,7 +913,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
}
pos = req.indexOf(F("NP")); //advances to next preset in a playlist
if (pos > 0) doAdvancePlaylist = true;
if (pos >= 0) doAdvancePlaylist = true;
//set brightness
updateVal(req.c_str(), "&A=", &bri);
@@ -935,7 +933,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
#ifdef WLED_ENABLE_LOXONE
//lox parser
pos = req.indexOf(F("LX=")); // Lox primary color
if (pos > 0) {
if (pos >= 0) {
int lxValue = getNumVal(&req, pos);
if (parseLx(lxValue, colIn)) {
bri = 255;
@@ -944,7 +942,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
}
}
pos = req.indexOf(F("LY=")); // Lox secondary color
if (pos > 0) {
if (pos >= 0) {
int lxValue = getNumVal(&req, pos);
if(parseLx(lxValue, colInSec)) {
bri = 255;
@@ -956,11 +954,11 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
//set hue
pos = req.indexOf(F("HU="));
if (pos > 0) {
if (pos >= 0) {
uint16_t temphue = getNumVal(&req, pos);
byte tempsat = 255;
pos = req.indexOf(F("SA="));
if (pos > 0) {
if (pos >= 0) {
tempsat = getNumVal(&req, pos);
}
byte sec = req.indexOf(F("H2"));
@@ -970,7 +968,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
//set white spectrum (kelvin)
pos = req.indexOf(F("&K="));
if (pos > 0) {
if (pos >= 0) {
byte sec = req.indexOf(F("K2"));
colorKtoRGB(getNumVal(&req, pos), (sec>0) ? colInSec : colIn);
col0Changed |= (!sec); col1Changed |= sec;
@@ -979,17 +977,17 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
//set color from HEX or 32bit DEC
byte tmpCol[4];
pos = req.indexOf(F("CL="));
if (pos > 0) {
if (pos >= 0) {
colorFromDecOrHexString(colIn, (char*)req.substring(pos + 3).c_str());
col0Changed = true;
}
pos = req.indexOf(F("C2="));
if (pos > 0) {
if (pos >= 0) {
colorFromDecOrHexString(colInSec, (char*)req.substring(pos + 3).c_str());
col1Changed = true;
}
pos = req.indexOf(F("C3="));
if (pos > 0) {
if (pos >= 0) {
colorFromDecOrHexString(tmpCol, (char*)req.substring(pos + 3).c_str());
uint32_t col2 = RGBW32(tmpCol[0], tmpCol[1], tmpCol[2], tmpCol[3]);
selseg.setColor(2, col2); // defined above (SS= or main)
@@ -998,7 +996,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
//set to random hue SR=0->1st SR=1->2nd
pos = req.indexOf(F("SR"));
if (pos > 0) {
if (pos >= 0) {
byte sec = getNumVal(&req, pos);
setRandomColor(sec? colInSec : colIn);
col0Changed |= (!sec); col1Changed |= sec;
@@ -1006,7 +1004,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
//swap 2nd & 1st
pos = req.indexOf(F("SC"));
if (pos > 0) {
if (pos >= 0) {
byte temp;
for (unsigned i=0; i<4; i++) {
temp = colIn[i];
@@ -1032,10 +1030,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
bool fxModeChanged = false, speedChanged = false, intensityChanged = false, paletteChanged = false;
bool custom1Changed = false, custom2Changed = false, custom3Changed = false, check1Changed = false, check2Changed = false, check3Changed = false;
// set effect parameters
if (updateVal(req.c_str(), "FX=", &effectIn, 0, strip.getModeCount()-1)) {
if (request != nullptr) unloadPlaylist(); // unload playlist if changing FX using web request
fxModeChanged = true;
}
fxModeChanged = updateVal(req.c_str(), "FX=", &effectIn, 0, strip.getModeCount()-1);
speedChanged = updateVal(req.c_str(), "SX=", &speedIn);
intensityChanged = updateVal(req.c_str(), "IX=", &intensityIn);
paletteChanged = updateVal(req.c_str(), "FP=", &paletteIn, 0, strip.getPaletteCount()-1);
@@ -1066,31 +1061,31 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
//set advanced overlay
pos = req.indexOf(F("OL="));
if (pos > 0) {
if (pos >= 0) {
overlayCurrent = getNumVal(&req, pos);
}
//apply macro (deprecated, added for compatibility with pre-0.11 automations)
pos = req.indexOf(F("&M="));
if (pos > 0) {
if (pos >= 0) {
applyPreset(getNumVal(&req, pos) + 16);
}
//toggle send UDP direct notifications
pos = req.indexOf(F("SN="));
if (pos > 0) notifyDirect = (req.charAt(pos+3) != '0');
if (pos >= 0) notifyDirect = (req.charAt(pos+3) != '0');
//toggle receive UDP direct notifications
pos = req.indexOf(F("RN="));
if (pos > 0) receiveGroups = (req.charAt(pos+3) != '0') ? receiveGroups | 1 : receiveGroups & 0xFE;
if (pos >= 0) receiveGroups = (req.charAt(pos+3) != '0') ? receiveGroups | 1 : receiveGroups & 0xFE;
//receive live data via UDP/Hyperion
pos = req.indexOf(F("RD="));
if (pos > 0) receiveDirect = (req.charAt(pos+3) != '0');
if (pos >= 0) receiveDirect = (req.charAt(pos+3) != '0');
//main toggle on/off (parse before nightlight, #1214)
pos = req.indexOf(F("&T="));
if (pos > 0) {
if (pos >= 0) {
nightlightActive = false; //always disable nightlight when toggling
switch (getNumVal(&req, pos))
{
@@ -1102,9 +1097,9 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
//toggle nightlight mode
bool aNlDef = false;
if (req.indexOf(F("&ND")) > 0) aNlDef = true;
if (req.indexOf(F("&ND")) >= 0) aNlDef = true;
pos = req.indexOf(F("NL="));
if (pos > 0)
if (pos >= 0)
{
if (req.charAt(pos+3) == '0')
{
@@ -1124,14 +1119,14 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
//set nightlight target brightness
pos = req.indexOf(F("NT="));
if (pos > 0) {
if (pos >= 0) {
nightlightTargetBri = getNumVal(&req, pos);
nightlightActiveOld = false; //re-init
}
//toggle nightlight fade
pos = req.indexOf(F("NF="));
if (pos > 0)
if (pos >= 0)
{
nightlightMode = getNumVal(&req, pos);
@@ -1140,24 +1135,24 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
if (nightlightMode > NL_MODE_SUN) nightlightMode = NL_MODE_SUN;
pos = req.indexOf(F("TT="));
if (pos > 0) transitionDelay = getNumVal(&req, pos);
if (pos >= 0) transitionDelay = getNumVal(&req, pos);
if (fadeTransition) strip.setTransition(transitionDelay);
//set time (unix timestamp)
pos = req.indexOf(F("ST="));
if (pos > 0) {
if (pos >= 0) {
setTimeFromAPI(getNumVal(&req, pos));
}
//set countdown goal (unix timestamp)
pos = req.indexOf(F("CT="));
if (pos > 0) {
if (pos >= 0) {
countdownTime = getNumVal(&req, pos);
if (countdownTime - toki.second() > 0) countdownOverTriggered = false;
}
pos = req.indexOf(F("LO="));
if (pos > 0) {
if (pos >= 0) {
realtimeOverride = getNumVal(&req, pos);
if (realtimeOverride > 2) realtimeOverride = REALTIME_OVERRIDE_ALWAYS;
if (realtimeMode && useMainSegmentOnly) {
@@ -1166,19 +1161,19 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
}
pos = req.indexOf(F("RB"));
if (pos > 0) doReboot = true;
if (pos >= 0) doReboot = true;
// clock mode, 0: normal, 1: countdown
pos = req.indexOf(F("NM="));
if (pos > 0) countdownMode = (req.charAt(pos+3) != '0');
if (pos >= 0) countdownMode = (req.charAt(pos+3) != '0');
pos = req.indexOf(F("U0=")); //user var 0
if (pos > 0) {
if (pos >= 0) {
userVar0 = getNumVal(&req, pos);
}
pos = req.indexOf(F("U1=")); //user var 1
if (pos > 0) {
if (pos >= 0) {
userVar1 = getNumVal(&req, pos);
}
// you can add more if you need
@@ -1187,15 +1182,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
if (!apply) return true; // when called by JSON API, do not call colorUpdated() here
pos = req.indexOf(F("&NN")); //do not send UDP notifications this time
stateUpdated((pos > 0) ? CALL_MODE_NO_NOTIFY : CALL_MODE_DIRECT_CHANGE);
// internal call, does not send XML response
pos = req.indexOf(F("IN"));
if (pos < 1) {
auto response = request->beginResponseStream("text/xml");
XML_response(*response);
request->send(response);
}
stateUpdated((pos >= 0) ? CALL_MODE_NO_NOTIFY : CALL_MODE_DIRECT_CHANGE);
return true;
}

View File

@@ -120,10 +120,8 @@ private:
void encodeLightId(uint8_t idx, char* out)
{
uint8_t mac[6];
WiFi.macAddress(mac);
sprintf_P(out, PSTR("%02X:%02X:%02X:%02X:%02X:%02X:00:11-%02X"), mac[0],mac[1],mac[2],mac[3],mac[4],mac[5], idx);
String mymac = WiFi.macAddress();
sprintf_P(out, PSTR("%02X:%s:AB-%02X"), idx, mymac.c_str(), idx);
}
// construct 'globally unique' Json dict key fitting into signed int

View File

@@ -681,9 +681,7 @@ void handleNotifications()
if (requestJSONBufferLock(18)) {
if (udpIn[0] >= 'A' && udpIn[0] <= 'Z') { //HTTP API
String apireq = "win"; apireq += '&'; // reduce flash string usage
apireq += (char*)udpIn;
handleSet(nullptr, apireq);
handleHttpApi((char*)udpIn);
} else if (udpIn[0] == '{') { //JSON API
DeserializationError error = deserializeJson(*pDoc, udpIn);
JsonObject root = pDoc->as<JsonObject>();

View File

@@ -380,6 +380,12 @@ void WLED::setup()
case FM_QOUT: DEBUG_PRINT(F("(QOUT)"));break;
case FM_DIO: DEBUG_PRINT(F("(DIO)")); break;
case FM_DOUT: DEBUG_PRINT(F("(DOUT)"));break;
#if defined(CONFIG_IDF_TARGET_ESP32S3) && CONFIG_ESPTOOLPY_FLASHMODE_OPI
case FM_FAST_READ: DEBUG_PRINT(F("(OPI)")); break;
#else
case FM_FAST_READ: DEBUG_PRINT(F("(fast_read)")); break;
#endif
case FM_SLOW_READ: DEBUG_PRINT(F("(slow_read)")); break;
default: break;
}
#endif

View File

@@ -3,12 +3,12 @@
/*
Main sketch, global variable declarations
@title WLED project sketch
@version 0.15.0-b6
@version 0.15.0-b7
@author Christian Schwinne
*/
// version code in format yymmddb (b = daily build)
#define VERSION 2410140
#define VERSION 2410270
//uncomment this if you have a "my_config.h" file you'd like to use
//#define WLED_USE_MY_CONFIG
@@ -36,12 +36,13 @@
#undef WLED_ENABLE_ADALIGHT // disable has priority over enable
#endif
//#define WLED_ENABLE_DMX // uses 3.5kb
//#define WLED_ENABLE_JSONLIVE // peek LED output via /json/live (WS binary peek is always enabled)
#ifndef WLED_DISABLE_LOXONE
#define WLED_ENABLE_LOXONE // uses 1.2kb
#endif
#ifndef WLED_DISABLE_WEBSOCKETS
#define WLED_ENABLE_WEBSOCKETS
#else
#define WLED_ENABLE_JSONLIVE // peek LED output via /json/live (WS binary peek is always enabled)
#endif
//#define WLED_DISABLE_ESPNOW // Removes dependence on esp now

View File

@@ -193,12 +193,12 @@ void createEditHandler(bool enable) {
editHandler = &server.addHandler(new SPIFFSEditor("","",WLED_FS));//http_username,http_password));
#endif
#else
editHandler = &server.on(SET_F("/edit"), HTTP_GET, [](AsyncWebServerRequest *request){
editHandler = &server.on(F("/edit"), HTTP_GET, [](AsyncWebServerRequest *request){
serveMessage(request, 501, FPSTR(s_notimplemented), F("The FS editor is disabled in this build."), 254);
});
#endif
} else {
editHandler = &server.on(SET_F("/edit"), HTTP_ANY, [](AsyncWebServerRequest *request){
editHandler = &server.on(F("/edit"), HTTP_ANY, [](AsyncWebServerRequest *request){
serveMessage(request, 401, FPSTR(s_accessdenied), FPSTR(s_unlock_cfg), 254);
});
}
@@ -427,11 +427,11 @@ void initServer()
#ifdef WLED_ENABLE_DMX
server.on(SET_F("/dmxmap"), HTTP_GET, [](AsyncWebServerRequest *request){
server.on(F("/dmxmap"), HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, FPSTR(CONTENT_TYPE_HTML), PAGE_dmxmap , dmxProcessor);
});
#else
server.on(SET_F("/dmxmap"), HTTP_GET, [](AsyncWebServerRequest *request){
server.on(F("/dmxmap"), HTTP_GET, [](AsyncWebServerRequest *request){
serveMessage(request, 501, FPSTR(s_notimplemented), F("DMX support is not enabled in this build."), 254);
});
#endif
@@ -482,7 +482,17 @@ void initServer()
return;
}
if(handleSet(request, request->url())) return;
if (request->url().indexOf("win") == 0) {
if (handleHttpApi(request->url().substring(3))) {
if (request->url().indexOf(F("&FX=")) > 0) {
unloadPlaylist(); // Setting an FX via HTTP disables any active playlist.
}
auto response = request->beginResponseStream(CONTENT_TYPE_XML);
XML_response(*response);
request->send(response);
return;
}
}
#ifndef WLED_DISABLE_ALEXA
if(espalexa.handleAlexaApiCall(request)) return;
#endif

View File

@@ -227,7 +227,7 @@ void getSettingsJS(byte subPage, Print& settingsScript)
sprintf(s, "%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]);
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET)
if (Network.isEthernet()) strcat_P(s ,SET_F(" (Ethernet)"));
if (Network.isEthernet()) strcat_P(s ,PSTR(" (Ethernet)"));
#endif
printSetClassElementHTML(settingsScript,PSTR("sip"),0,s);
} else
@@ -501,7 +501,7 @@ void getSettingsJS(byte subPage, Print& settingsScript)
#endif
printSetFormValue(settingsScript,PSTR("BD"),serialBaud);
#ifndef WLED_ENABLE_ADALIGHT
settingsScript.print(F("toggle('Serial);"));
settingsScript.print(F("toggle('Serial');"));
#endif
}