Compare commits

..

107 Commits

Author SHA1 Message Date
cb267a20c7 readme.md aktualisiert 2023-11-21 17:27:11 +01:00
24cb3ae8e0 readme.md aktualisiert 2023-11-21 17:26:41 +01:00
16a3148235 readme.md aktualisiert 2023-11-21 17:25:59 +01:00
Christian Schwinne
1dab26bcbc
Update Discord invite links to point to guidelines channel 2023-10-19 13:29:46 +02:00
Frank
3847bfc41a npm run build
plus fixing a small typo in VERSION
2023-10-13 13:55:13 +02:00
Frank
783424dd26 version bump 0.14.0 (release) 2023-10-13 13:45:25 +02:00
Frank
5dadf92a62
also change second discord link in readme
seems this was missing in the previous PR.
2023-10-11 21:09:56 +02:00
Frank
76821addd7
Merge pull request #3437 from chrishultin/fix_discord_invite
Updating "Discord" invite to point to #general
2023-10-11 21:07:22 +02:00
Christopher
a769c55c72 Updating "Discord" invite to point to #general 2023-10-11 09:58:58 -06:00
Frank
4245767357
fix for partly uninitialized sound sync packets (audioreactive)
audioSyncPacket contains four "invisible" padding bytes added by the compiler. These need to be initialized to zero, as future versions of the protocol will make use of these fields.
2023-10-08 19:54:14 +02:00
Frank
74d196ad50 npm run build
chores
2023-10-06 16:37:12 +02:00
Frank
3c4649748d
Merge pull request #3420 from mountainash/fix/duplicate-viewport-declaration
Remove duplicate `viewport` declaration, put lang=en into the right place
2023-10-06 16:27:25 +02:00
Frank
22985900a8
Merge pull request #3425 from mountainash/fix/git-ignore
.gitignore Reordered & grouped
2023-10-06 16:26:04 +02:00
Mountain/\Ash
32ab2ae201 Allow /wled00/html_*.h files 2023-10-05 11:55:48 +02:00
Mountain/\Ash
23e4a2e28e Reordered & grouped 2023-10-05 10:26:51 +02:00
Mountain/\Ash
40515e62ac Ignoring HTML build output 2023-10-05 10:21:24 +02:00
Mountain/\Ash
b5751795b5 Fix: lang moved to the correct HTML element 2023-10-04 21:42:15 +02:00
Mountain/\Ash
43d6151506 Fix: removing duplicate viewport declaration
- removed unneeded self-closing slash
2023-10-04 21:37:10 +02:00
Frank
26e766ee19
Merge pull request #3406 from Aircoookie/sunset_accuracy_fix
fix for #3400 - wrong sunset time 00:00
2023-10-02 19:58:06 +02:00
Frank
1c3fdb73fb optimization: only use "float" math functions
- saves 5KB flash and some RAM
-allow to build with -D WLED_USE_UNREAL_MATH, to restore old behaviour and save another 6KB flash
2023-10-01 19:04:30 +02:00
Blaz Kristan
332be7edd6 Build bump. 2023-10-01 13:38:10 +02:00
Blaz Kristan
7e6eb65950 Fix for #3403 2023-10-01 13:26:31 +02:00
Blaz Kristan
b0a56a431b Fix for #3405 2023-10-01 13:04:05 +02:00
Frank
166316e0c5 fix for #3400
replace low_accuracy math functions (sint_t, cos_t, atan_t, ...) with standard libm functions that have higher accuracy.
2023-09-30 23:34:02 +02:00
Blaz Kristan
5eadbe7ecd FX update
- Meteor: trail & 0.13 behaviour
- Meteor Smooth: train & 0.13 behaviour
- Scrolling Text: rotation
2023-09-24 16:48:59 +02:00
Frank
ea7e0c6204 npm run build
regenerate UI files from latest sources.
2023-09-23 21:22:14 +02:00
Frank
2dcb126e6d version bump 0.14.0-b6
beta release preparation.
2023-09-23 21:08:11 +02:00
Frank
438525e8ec
AR: use bandpass filter for analog input
Many bad quality analog mics are not centered properly at 1.6V, but stuck at 0V or stuck at 3.3V in silence. The bandpass filter removes DC offsets and improve signal quality.
2023-09-23 16:48:45 +02:00
Frank
eb66a403d9
Merge pull request #3377 from christianpatterson/audioreactive-initialize-i2ssource-bugfix
Fix ES8388Source & ES7243 initialization.
2023-09-19 16:32:10 +02:00
Frank
26ac612474 fix wrong signature of SPH0654::initialize()
* debug messages added to different initializers
* SPH0654::initialize() was having a wrong signature: uint8 instead of int8.

C++ can be a real bastard ;-)
2023-09-19 15:27:41 +02:00
Frank
43613e3b10
Matrix effect speedup
Typically, more than 50% of pixels are black. 
This optimization avoids to fade and rewrite already black pixels.
2023-09-18 15:56:50 +02:00
Frank
555dd2e726
matrix: fix for a corner case (e.g. gapmaps)
workaround for a corner case; if the reference pixels falls into a "gap" then gPC returns BLACK. Solutions is to reject BLACK.
2023-09-18 15:34:53 +02:00
Frank
3260f46543 bugfix for #3375
* improves robustness of the Matrix effect, by dynamically adjusting the "reference color" used to identify "falling code" head pixels.
* a bit faster, as I've removed the need to scan all pixels a second time for "black screen" detection.

Its still not perfect, and the main loop could be simplified a lot by leveraging on the fact that all changes actually happen in the top row, and "falling" is actually just moving everything down by one pixel.
2023-09-18 14:57:15 +02:00
Christian Patterson
f9de23402a Remove obsolete I2C parameters from AudioSource::initialize and all overriding methods. 2023-09-17 19:10:18 -05:00
Christian Patterson
9e155cf94a Fix ES8388Source & ES7243 initialization.
Update ES8388Source::initialize and ES7243::initialize method signatures to match I2SSource::initialize so that when initialize is called on a AudioSource pointer the child class's method is used.
2023-09-17 14:12:20 -05:00
Frank
527e3d6cd0
Merge pull request #3373 from Aircoookie/ripple-tweak
2D Ripple and Meteor effect tweak
2023-09-17 18:48:43 +02:00
Blaz Kristan
c7d45c28cf Meteor effect change
- remedy for #3374
2023-09-16 12:30:57 +02:00
Blaz Kristan
87cc3fd714 2D Ripple effect tweak
for #3370
2023-09-16 00:21:10 +02:00
Frank
282d58a6fe
audioreactive: stack size tuning
This gives ~3KB extra free heap on -S2.
2023-09-14 18:26:57 +02:00
Blaz Kristan
fc4ed1c50b Fix for #3369 2023-09-12 16:48:32 +02:00
Frank
60c47cfca1 npm run build
regenerated UI files
2023-09-10 16:59:31 +02:00
Frank
720abd4e04 version bump 0.14.0-b5
preparations for releasing -beta5
2023-09-10 16:54:59 +02:00
Frank
b4fe694d1b esp32 buildenv with audioreactive
To make it better readable and prevent copy&paste errors, all needed flags can be referenced from the "esp32" buildenv:
  ${esp32.AR_build_flags}
  ${esp32.AR_lib_deps}
2023-09-10 16:30:04 +02:00
Frank
c117785554 8266 optional build flags to increase IRAM
related to #3364
2023-09-10 02:00:09 +02:00
Frank
e9723de6c3 minor updates for audioreactive
* remove "not supported" warning on -S2
* minor tweaking of beat detector
* optimized parameters for arduinoFFT
* fixed a few implicit "double" promotions
* minor UDP protocol optimizations
* small optimization for fft task create / suspend
* completely remove analogmic settings for -S3/-S2/-C3 where analog is not supported

changes were already tested extensively in the MM fork.
2023-09-09 21:07:20 +02:00
Frank
da0cf01eee fixing a few implicit promotions to double
any expression with at least on "double" is evaluated as double, which is slow.
2023-09-09 20:48:17 +02:00
Blaz Kristan
e40f266042 Better bugfix in mode blending when _t is unallocated 2023-09-08 16:01:11 +02:00
Frank
69fb15d3cb debug message optimizations for 8266
as discussed in previous commit.
2023-09-08 14:06:57 +02:00
Frank
188956a4af bugfix for random crash when switching between presets
this is a band-aid fix for random crashes when switching between presets with multiple segments - crossfade disabled.

!! adding type initializers fixed it for me on -S3, however I still see (less frequent) crashes on esp32, due to heap corruption.

It took me hours to get a meaningful stackdump:

assert failed: heap_caps_free heap_caps.c:360 (heap != NULL && "free() target pointer is outside heap areas")

Backtrace: 0x40084ee1:0x3ffb2570 0x4008e341:0x3ffb2590 0x40094709:0x3ffb25b0 0x4008534a:0x3ffb26e0 0x40094739:0x3ffb2700 0x400e9037:0x3ffb2720 0x400e917c:0x3ffb2740 0x400eaeeb:0x3ffb2760 0x40117ec5:0x3ffb27c0 0x401184ea:0x3ffb2800 0x4013509d:0x3ffb2820

  #0  0x40084ee1:0x3ffb2570 in panic_abort at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/esp_system/panic.c:402
  #1  0x4008e341:0x3ffb2590 in esp_system_abort at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/esp_system/esp_system.c:128
  #2  0x40094709:0x3ffb25b0 in __assert_func at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/newlib/assert.c:85
  #3  0x4008534a:0x3ffb26e0 in heap_caps_free at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/heap/heap_caps.c:360
      (inlined by) heap_caps_free at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/heap/heap_caps.c:345
  #4  0x40094739:0x3ffb2700 in free at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/newlib/heap.c:39
  #5  0x400e9037:0x3ffb2720 in Segment::deallocateData() at wled00/FX_fcn.cpp:189
  #6  0x400e917c:0x3ffb2740 in Segment::resetIfRequired() at wled00/FX_fcn.cpp:206
      (inlined by) Segment::resetIfRequired() at wled00/FX_fcn.cpp:203
  #7  0x400eaeeb:0x3ffb2760 in WS2812FX::service() at wled00/FX_fcn.cpp:1216 (discriminator 2)
  #8  0x40117ec5:0x3ffb27c0 in WLED::loop() at wled00/wled.cpp:115 (discriminator 3)
  #9  0x401184ea:0x3ffb2800 in loop() at C:/src/wled00/wled00.ino:20
  #10 0x4013509d:0x3ffb2820 in loopTask(void*) at C:/Users/user/.platformio/packages/framework-arduinoespressif32/cores/esp32/main.cpp:50

ELF file SHA256: 18c20b536f4c6ef4
2023-09-08 12:06:23 +02:00
Frank
c7dd4a7f2b potentiometer: check that pin supports ananlogread
newer esp32 frameworks will throw lots of warnings when trying to read from a non-analog pin.
2023-09-07 18:55:13 +02:00
Frank
111f1729c9
Update CHANGELOG.md
small correction
2023-09-07 17:51:28 +02:00
Blaz Kristan
164372b46a Update changelog 2023-09-07 16:32:59 +02:00
Frank
1af3794fed
Merge pull request #1039 from pjhatch/PJH_ADD_Linearbounce
Pjh add linearbounce
2023-09-06 11:14:43 +02:00
Blaz Kristan
885f4ded0c Merge branch 'main' into PJH_ADD_Linearbounce 2023-09-05 21:20:55 +02:00
Frank
9bb018d8d9 bump to build 2309050 2023-09-05 19:15:22 +02:00
Frank
58187e00e6 optional ball trails (rolling balls) 2023-09-05 19:11:44 +02:00
Frank
5110a8c636 Squashed commit of the following:
commit 84148ad07a
Author: Blaz Kristan <blaz@kristan-sp.si>
Date:   Sun Sep 3 12:34:17 2023 +0200

    Implement palette colors

commit af3c8f66f7
Author: Blaz Kristan <blaz@kristan-sp.si>
Date:   Tue Aug 1 18:18:41 2023 +0200

    revert wled00.ino

commit 3097a1b17e
Author: Blaz Kristan <blaz@kristan-sp.si>
Date:   Tue Aug 1 18:13:37 2023 +0200

    minor aesthetic fixes

commit 54b80f74b2
Author: Blaz Kristan <blaz@kristan-sp.si>
Date:   Tue Aug 1 18:09:32 2023 +0200

    remove unused variable

commit 9a78d28cd7
Merge: 56a74bc5 1ed81793
Author: Blaz Kristan <blaz@kristan-sp.si>
Date:   Tue Aug 1 18:08:29 2023 +0200

    Merge branch 'main' into PJH_ADD_Linearbounce

commit 56a74bc54c
Author: pjhatch <66844564+pjhatch@users.noreply.github.com>
Date:   Sat Aug 15 12:34:13 2020 -0500

    Update FX.cpp

    Added the improvements suggested by Gregor Hartmann

commit a20358b61b
Author: pjhatch <66844564+pjhatch@users.noreply.github.com>
Date:   Sun Jul 12 08:33:48 2020 -0500

    Adding 2 ball track modes

    With and without collisions

commit 341d9d1697
Author: pjhatch <66844564+pjhatch@users.noreply.github.com>
Date:   Sun Jul 5 14:55:14 2020 -0500

    Update FX.cpp

    Still 1 bug to fix - this was a test.

commit 9cee424383
Author: pjhatch <66844564+pjhatch@users.noreply.github.com>
Date:   Sun Jul 5 14:53:14 2020 -0500

    Update FX.cpp

commit 37cb51cfd6
Author: pjhatch <66844564+pjhatch@users.noreply.github.com>
Date:   Thu Jul 2 14:16:25 2020 -0500

    Adding Collision

    A couple of bugs still need sorting

commit 84b7bfb989
Author: pjhatch <66844564+pjhatch@users.noreply.github.com>
Date:   Sun Jun 28 19:59:46 2020 -0500

    update for lost balls

    Added some protection - so that when intensity is lowered and raised some time later balls that have moved way off the track are recovered.

commit 04d17e4839
Author: pjhatch <66844564+pjhatch@users.noreply.github.com>
Date:   Sun Jun 28 19:43:56 2020 -0500

    Added Ball Track V1

    In this version the balls bounce of the edges and do not interact with one another.
2023-09-05 18:39:51 +02:00
Frank
ddbe883d47 Merge branch 'fx-blending' 2023-09-05 18:37:55 +02:00
Frank
945ac82b6a
fix small typo in MQTT override code
bracket was on wrong position, resulting in this warning:

wled00/set.cpp:357:79: warning: value computed is not used [-Wunused-value]
     strlcpy(mqttGroupTopic, request->arg(F("MG")).c_str(), MQTT_MAX_TOPIC_LEN)+1;
2023-09-05 17:15:12 +02:00
Blaz Kristan
84148ad07a Implement palette colors 2023-09-03 12:34:17 +02:00
Blaž Kristan
25553a28a1
Merge pull request #3351 from PSandro/pr_info_time
show current local time in info page ⏲️
2023-09-02 20:52:33 +02:00
Blaz Kristan
c2f5846a8e Add optional compile flag 2023-09-02 20:20:51 +02:00
Blaž Kristan
3f98e9451a
Merge pull request #3348 from djasonic/staircase-toggle-pr 2023-09-02 18:52:16 +02:00
Blaž Kristan
6c72194346
Add compile time MQTT override (#3354)
- for max server name length
- for max topic length

Fix for #3353
2023-09-02 01:05:45 +02:00
Dimitry
822dd24756
Add Internal Temperature usermod (#3246)
* Add Internal Temperature usermod

* Fix line endings

* Update readme

* Format readme
2023-09-01 19:43:21 +02:00
Blaz Kristan
262ed38429 Fix for #3352 2023-08-31 19:10:22 +02:00
Sandro Pischinger
5ff66ce4dd recreate html_ui.h & html_simple.h 2023-08-30 20:58:32 +02:00
Sandro Pischinger
ca73b8e0b8 rename 'Current local time' -> 'Time' 2023-08-30 20:57:54 +02:00
Sandro Pischinger
2d49ace0e3 recreate html_ui.h & html_simple.h 2023-08-30 20:45:05 +02:00
Sandro Pischinger
d52f22044e Revert "recreate web ui files"
This reverts commit 2bf052aac9.
2023-08-30 20:43:22 +02:00
Sandro Pischinger
2bf052aac9 recreate web ui files 2023-08-29 23:52:32 +02:00
Sandro Pischinger
a79c9d5f4f info page: add time 2023-08-29 23:44:08 +02:00
Blaz Kristan
6f9bcf1858 Merge branch 'main' into fx-blending 2023-08-28 17:59:02 +02:00
Blaz Kristan
d1b00ba95d Bugfix.
- feed WDT even if strip is updating
- provide custom palette names
- handle interface cooldown properly
- rotary encoder ALT fix for custom palettes
2023-08-28 17:58:30 +02:00
Frank
bb45bee7f8 oappend() debug message when buffer is full
oappend() silently discards strings when the buffer is full, leading to strange effects like half-working UI pages.

The new debug message will help developers to understand what could be wrong.
2023-08-27 23:01:55 +02:00
Jason Cobb
246f0b21fd staircase toggle power on/off option bool 2023-08-26 22:19:52 -05:00
Blaz Kristan
394443b6d1 Merge branch 'main' into fx-blending 2023-08-25 18:34:56 +02:00
Blaz Kristan
fc1dd2daac Fix for #3346 2023-08-25 18:34:11 +02:00
Blaz Kristan
ba1b6f321e Button bugfix. 2023-08-23 14:50:46 +02:00
Blaz Kristan
06402cf1c6 Making buffer fix easy to maintain and portable.
Thanks to @softhack007
2023-08-17 17:10:29 +02:00
Blaz Kristan
dfc33389d8 Optimisation. 2023-08-17 16:46:31 +02:00
Blaz Kristan
4e83752655 Merge branch 'main' into fx-blending 2023-08-17 16:24:47 +02:00
Blaz Kristan
7e28718681 Too long metadata string bugfix. 2023-08-17 16:24:16 +02:00
Blaz Kristan
bf452e922a Playlist saving bugfix.
Fixes #3324
2023-08-16 22:11:16 +02:00
Blaz Kristan
4911a74cac Scrolling text enhancement.
- breaking change
- remove leading 0 checkmark
- add reverse scroll checkmark
- add vertical scroll if text fits into segment (intensity ==0 or ==255)
- rotated characters
- leading 0 check added to short texts (i.e. #DDMM0)
Fixes #3322
2023-08-16 21:02:00 +02:00
Blaz Kristan
ac83b67632 Cleaner transition code.
Fixed skipped pixel flashing.
2023-08-12 12:45:11 +02:00
Blaz Kristan
00bc7dccb9 Merge branch 'main' into fx-blending 2023-08-12 11:36:40 +02:00
Blaz Kristan
353e97a4c1 Clear status pixels 2023-08-11 00:48:32 +02:00
Blaz Kristan
7b28387bb4 Comments from Aircoookie addressed 2023-08-09 17:23:21 +02:00
Christian Schwinne
1889fe23c5
Merge branch 'main' into fx-blending 2023-08-09 16:58:21 +02:00
Blaz Kristan
9832fbe042 Segment reset 2023-08-08 20:40:19 +02:00
Blaz Kristan
084070475d Chasing memory corruption/leaks. 2023-08-07 16:50:18 +02:00
Blaz Kristan
cb42ca8765 FX optimisation 2023-08-06 19:11:44 +02:00
Blaz Kristan
93a1616933 Blend tweaking. 2023-08-05 21:01:06 +02:00
Blaz Kristan
9a87a2ff0d Blending 2023-08-05 17:35:14 +02:00
Blaz Kristan
937e3d0b94 FX blending POC 2023-08-05 13:50:08 +02:00
Blaz Kristan
af3c8f66f7 revert wled00.ino 2023-08-01 18:18:41 +02:00
Blaz Kristan
3097a1b17e minor aesthetic fixes 2023-08-01 18:13:37 +02:00
Blaz Kristan
54b80f74b2 remove unused variable 2023-08-01 18:09:32 +02:00
Blaz Kristan
9a78d28cd7 Merge branch 'main' into PJH_ADD_Linearbounce 2023-08-01 18:08:29 +02:00
pjhatch
56a74bc54c Update FX.cpp
Added the improvements suggested by Gregor Hartmann
2020-08-15 12:34:13 -05:00
pjhatch
a20358b61b Adding 2 ball track modes
With and without collisions
2020-07-12 08:33:48 -05:00
pjhatch
341d9d1697 Update FX.cpp
Still 1 bug to fix - this was a test.
2020-07-05 14:55:14 -05:00
pjhatch
9cee424383 Update FX.cpp 2020-07-05 14:53:14 -05:00
pjhatch
37cb51cfd6 Adding Collision
A couple of bugs still need sorting
2020-07-02 14:16:25 -05:00
pjhatch
84b7bfb989 update for lost balls
Added some protection - so that when intensity is lowered and raised some time later balls that have moved way off the track are recovered.
2020-06-28 19:59:46 -05:00
pjhatch
04d17e4839 Added Ball Track V1
In this version the balls bounce of the edges and do not interact with one another.
2020-06-28 19:43:56 -05:00
54 changed files with 6790 additions and 6278 deletions

33
.gitignore vendored
View File

@ -1,21 +1,24 @@
.pio
.cache .cache
.clang-format
.direnv
.DS_Store
.gitignore
.idea
.pio
.pioenvs .pioenvs
.piolibdeps .piolibdeps
.vscode .vscode
/wled00/Release
/wled00/extLibs
/platformio_override.ini
/wled00/my_config.h
/build_output
.DS_Store
.gitignore
.clang-format
node_modules
.idea
.direnv
wled-update.sh
esp01-update.sh esp01-update.sh
/wled00/LittleFS platformio_override.ini
replace_fs.py replace_fs.py
wled00/wled00.ino.cpp wled-update.sh
/build_output/
/node_modules/
/wled00/extLibs
/wled00/LittleFS
/wled00/my_config.h
/wled00/Release
/wled00/wled00.ino.cpp

View File

@ -1,5 +1,32 @@
## WLED changelog ## WLED changelog
#### Build 2310010, build 2310130
- Release of WLED version 0.14.0 "Hoshi"
- Bugfixes for #3400, #3403, #3405
- minor HTML optimizations
- audioreactive: bugfix for UDP sound sync (partly initialized packets)
#### Build 2309240
- Release of WLED beta version 0.14.0-b6 "Hoshi"
- Effect bugfixes and improvements (Meteor, Meteor Smooth, Scrolling Text)
- audioreactive: bugfixes for ES8388 and ES7243 init; minor improvements for analog inputs
#### Build 2309100
- Release of WLED beta version 0.14.0-b5 "Hoshi"
- New standard esp32 build with audioreactive
- Effect blending bugfixes, and minor optimizations
#### Build 2309050
- Effect blending (#3311) (finally effect transitions!)
*WARNING*: May not work well with ESP8266, with plenty of segments or usermods (low RAM condition)!!!
- Added receive and send sync groups to JSON API (#3317) (you can change sync groups using preset)
- Internal temperature usermod (#3246)
- MQTT server and topic length overrides (#3354) (new build flags)
- Animated Staircase usermod enhancement (#3348) (on/off toggle/relay control)
- Added local time info to Info page (#3351)
- New effect: Rolling Balls (a.k.a. linear bounce) (#1039)
- Various bug fixes and enhancements.
#### Build 2308110 #### Build 2308110
- Release of WLED beta version 0.14.0-b4 "Hoshi" - Release of WLED beta version 0.14.0-b4 "Hoshi"
- Reset effect data immediately upon mode change - Reset effect data immediately upon mode change
@ -19,7 +46,7 @@
- Preset cycle bugfix (#3262) - Preset cycle bugfix (#3262)
- Rotary encoder ALT fix for large LED count (#3276) - Rotary encoder ALT fix for large LED count (#3276)
- effect updates (2D Plasmaball), `blur()` speedup - effect updates (2D Plasmaball), `blur()` speedup
- On/Off toggle from nodes view (may show unknow device type on older versions) (#3291) - On/Off toggle from nodes view (may show unknown device type on older versions) (#3291)
- various fixes and improvements (ABL, crashes when changing presets with different segments) - various fixes and improvements (ABL, crashes when changing presets with different segments)
#### Build 2306270 #### Build 2306270
@ -32,7 +59,7 @@
#### Build 2306210 #### Build 2306210
- 0.14.0-b3 release - 0.14.0-b3 release
- respect global I2C in all usermods (no local initilaisation of I2C bus) - respect global I2C in all usermods (no local initialization of I2C bus)
- Multi relay usermod compile-time enabled option (-D MULTI_RELAY_ENABLED=true|false) - Multi relay usermod compile-time enabled option (-D MULTI_RELAY_ENABLED=true|false)
#### Build 2306180 #### Build 2306180
@ -58,7 +85,7 @@
#### Build 2306020 #### Build 2306020
- Support for segment sets (PR #3171) - Support for segment sets (PR #3171)
- Reduce sound simulation modes to 2 to facilitiate segment sets - Reduce sound simulation modes to 2 to facilitate segment sets
- Trigger button immediately on press if all configured presets are the same (PR #3226) - Trigger button immediately on press if all configured presets are the same (PR #3226)
- Changes for allowing Alexa to change light color to White when auto-calculating from RGB (PR #3211) - Changes for allowing Alexa to change light color to White when auto-calculating from RGB (PR #3211)

2
package-lock.json generated
View File

@ -1,6 +1,6 @@
{ {
"name": "wled", "name": "wled",
"version": "0.14.0-b4", "version": "0.14.0",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {

View File

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

View File

@ -11,7 +11,7 @@
# CI binaries # CI binaries
; default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth # ESP32 variant builds are temporarily excluded from CI due to toolchain issues on the GitHub Actions Linux environment ; default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth # ESP32 variant builds are temporarily excluded from CI due to toolchain issues on the GitHub Actions Linux environment
default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_8MB, esp32s3dev_8MB_PSRAM_opi default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth, esp32dev_audioreactive, lolin_s2_mini, esp32c3dev, esp32s3dev_8MB, esp32s3dev_8MB_PSRAM_opi
# Release binaries # Release binaries
; default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_8MB ; default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_8MB
@ -87,11 +87,13 @@ platform_packages = platformio/framework-arduinoespressif8266
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# FLAGS: DEBUG # FLAGS: DEBUG
# # esp8266 : see https://docs.platformio.org/en/latest/platforms/espressif8266.html#debug-level
# esp32 : see https://docs.platformio.org/en/latest/platforms/espressif32.html#debug-level
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
debug_flags = -D DEBUG=1 -D WLED_DEBUG -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_UPDATE -DDEBUG_ESP_HTTP_SERVER -DDEBUG_ESP_UPDATER -DDEBUG_ESP_OTA -DDEBUG_TLS_MEM debug_flags = -D DEBUG=1 -D WLED_DEBUG
#if needed (for memleaks etc) also add; -DDEBUG_ESP_OOM -include "umm_malloc/umm_malloc_cfg.h" -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_UPDATE -DDEBUG_ESP_HTTP_SERVER -DDEBUG_ESP_UPDATER -DDEBUG_ESP_OTA -DDEBUG_TLS_MEM ;; for esp8266
#-DDEBUG_ESP_CORE is not working right now # if needed (for memleaks etc) also add; -DDEBUG_ESP_OOM -include "umm_malloc/umm_malloc_cfg.h"
# -DDEBUG_ESP_CORE is not working right now
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# FLAGS: ldscript (available ldscripts at https://github.com/esp8266/Arduino/tree/master/tools/sdk/ld) # FLAGS: ldscript (available ldscripts at https://github.com/esp8266/Arduino/tree/master/tools/sdk/ld)
@ -214,6 +216,9 @@ build_flags =
-DVTABLES_IN_FLASH -DVTABLES_IN_FLASH
; restrict to minimal mime-types ; restrict to minimal mime-types
-DMIMETYPE_MINIMAL -DMIMETYPE_MINIMAL
; other special-purpose framework flags (see https://docs.platformio.org/en/latest/platforms/espressif8266.html)
; -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
lib_deps = lib_deps =
#https://github.com/lorol/LITTLEFS.git #https://github.com/lorol/LITTLEFS.git
@ -224,9 +229,7 @@ lib_deps =
[esp32] [esp32]
#platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.2.3/platform-espressif32-2.0.2.3.zip #platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.2.3/platform-espressif32-2.0.2.3.zip
platform = espressif32@3.5.0 platform = espressif32@3.5.0
platform_packages = framework-arduinoespressif32 @ https://github.com/Aircoookie/arduino-esp32.git#1.0.6.4 platform_packages = framework-arduinoespressif32 @ https://github.com/Aircoookie/arduino-esp32.git#1.0.6.4
build_flags = -g build_flags = -g
-DARDUINO_ARCH_ESP32 -DARDUINO_ARCH_ESP32
#-DCONFIG_LITTLEFS_FOR_IDF_3_2 #-DCONFIG_LITTLEFS_FOR_IDF_3_2
@ -234,14 +237,14 @@ build_flags = -g
#use LITTLEFS library by lorol in ESP32 core 1.x.x instead of built-in in 2.x.x #use LITTLEFS library by lorol in ESP32 core 1.x.x instead of built-in in 2.x.x
-D LOROL_LITTLEFS -D LOROL_LITTLEFS
; -DARDUINO_USB_CDC_ON_BOOT=0 ;; this flag is mandatory for "classic ESP32" when building with arduino-esp32 >=2.0.3 ; -DARDUINO_USB_CDC_ON_BOOT=0 ;; this flag is mandatory for "classic ESP32" when building with arduino-esp32 >=2.0.3
default_partitions = tools/WLED_ESP32_4MB_1MB_FS.csv default_partitions = tools/WLED_ESP32_4MB_1MB_FS.csv
lib_deps = lib_deps =
https://github.com/lorol/LITTLEFS.git https://github.com/lorol/LITTLEFS.git
https://github.com/pbolduc/AsyncTCP.git @ 1.2.0 https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
${env.lib_deps} ${env.lib_deps}
# additional build flags for audioreactive
AR_build_flags = -D USERMOD_AUDIOREACTIVE -D UM_AUDIOREACTIVE_USE_NEW_FFT
AR_lib_deps = https://github.com/kosme/arduinoFFT#develop @ ^1.9.2
[esp32_idf_V4] [esp32_idf_V4]
;; experimental build environment for ESP32 using ESP-IDF 4.4.x / arduino-esp32 v2.0.5 ;; experimental build environment for ESP32 using ESP-IDF 4.4.x / arduino-esp32 v2.0.5
@ -349,6 +352,7 @@ platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_1m128k} board_build.ldscript = ${common.ldscript_1m128k}
build_unflags = ${common.build_unflags} build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=ESP01 -D WLED_DISABLE_OTA build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=ESP01 -D WLED_DISABLE_OTA
; -D WLED_USE_UNREAL_MATH ;; may cause wrong sunset/sunrise times, but saves 7064 bytes FLASH and 975 bytes RAM
lib_deps = ${esp8266.lib_deps} lib_deps = ${esp8266.lib_deps}
[env:esp07] [env:esp07]
@ -399,6 +403,20 @@ lib_deps = ${esp32.lib_deps}
monitor_filters = esp32_exception_decoder monitor_filters = esp32_exception_decoder
board_build.partitions = ${esp32.default_partitions} board_build.partitions = ${esp32.default_partitions}
[env:esp32dev_audioreactive]
board = esp32dev
platform = ${esp32.platform}
platform_packages = ${esp32.platform_packages}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32_audioreactive #-D WLED_DISABLE_BROWNOUT_DET
${esp32.AR_build_flags}
lib_deps = ${esp32.lib_deps}
${esp32.AR_lib_deps}
monitor_filters = esp32_exception_decoder
board_build.partitions = ${esp32.default_partitions}
; board_build.f_flash = 80000000L
; board_build.flash_mode = dio
[env:esp32dev_qio80] [env:esp32dev_qio80]
board = esp32dev board = esp32dev
platform = ${esp32.platform} platform = ${esp32.platform}
@ -588,6 +606,7 @@ build_flags = ${common.build_flags} ${esp32s2.build_flags} -D WLED_RELEASE_NAME=
-DARDUINO_USB_DFU_ON_BOOT=0 -DARDUINO_USB_DFU_ON_BOOT=0
-DLOLIN_WIFI_FIX ; seems to work much better with this -DLOLIN_WIFI_FIX ; seems to work much better with this
-D WLED_USE_PSRAM -D WLED_USE_PSRAM
; -D WLED_USE_UNREAL_MATH ;; may cause wrong sunset/sunrise times, but saves 6792 bytes FLASH
-D WLED_WATCHDOG_TIMEOUT=0 -D WLED_WATCHDOG_TIMEOUT=0
-D CONFIG_ASYNC_TCP_USE_WDT=0 -D CONFIG_ASYNC_TCP_USE_WDT=0
-D LEDPIN=16 -D LEDPIN=16

168
readme.md
View File

@ -1,84 +1,84 @@
<p align="center"> <p align="center">
<img src="/images/wled_logo_akemi.png"> <img src="/images/wled_logo_akemi.png">
<a href="https://github.com/Aircoookie/WLED/releases"><img src="https://img.shields.io/github/release/Aircoookie/WLED.svg?style=flat-square"></a> <a href="https://github.com/Aircoookie/WLED/releases"><img src="https://img.shields.io/github/release/Aircoookie/WLED.svg?style=flat-square"></a>
<a href="https://raw.githubusercontent.com/Aircoookie/WLED/master/LICENSE"><img src="https://img.shields.io/github/license/Aircoookie/wled?color=blue&style=flat-square"></a> <a href="https://raw.githubusercontent.com/Aircoookie/WLED/master/LICENSE"><img src="https://img.shields.io/github/license/Aircoookie/wled?color=blue&style=flat-square"></a>
<a href="https://wled.discourse.group"><img src="https://img.shields.io/discourse/topics?colorB=blue&label=forum&server=https%3A%2F%2Fwled.discourse.group%2F&style=flat-square"></a> <a href="https://wled.discourse.group"><img src="https://img.shields.io/discourse/topics?colorB=blue&label=forum&server=https%3A%2F%2Fwled.discourse.group%2F&style=flat-square"></a>
<a href="https://discord.gg/KuqP7NE"><img src="https://img.shields.io/discord/473448917040758787.svg?colorB=blue&label=discord&style=flat-square"></a> <a href="https://discord.gg/QAh7wJHrRM"><img src="https://img.shields.io/discord/473448917040758787.svg?colorB=blue&label=discord&style=flat-square"></a>
<a href="https://kno.wled.ge"><img src="https://img.shields.io/badge/quick_start-wiki-blue.svg?style=flat-square"></a> <a href="https://kno.wled.ge"><img src="https://img.shields.io/badge/quick_start-wiki-blue.svg?style=flat-square"></a>
<a href="https://github.com/Aircoookie/WLED-App"><img src="https://img.shields.io/badge/app-wled-blue.svg?style=flat-square"></a> <a href="https://github.com/Aircoookie/WLED-App"><img src="https://img.shields.io/badge/app-wled-blue.svg?style=flat-square"></a>
<a href="https://gitpod.io/#https://github.com/Aircoookie/WLED"><img src="https://img.shields.io/badge/Gitpod-ready--to--code-blue?style=flat-square&logo=gitpod"></a> <a href="https://gitpod.io/#https://github.com/Aircoookie/WLED"><img src="https://img.shields.io/badge/Gitpod-ready--to--code-blue?style=flat-square&logo=gitpod"></a>
</p> </p>
# Welcome to my project WLED! ✨ # Welcome to my project WLED! ✨
A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control NeoPixel (WS2812B, WS2811, SK6812) LEDs or also SPI based chipsets like the WS2801 and APA102! A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control NeoPixel (WS2812B, WS2811, SK6812) LEDs or also SPI based chipsets like the WS2801 and APA102!
## ⚙️ Features ## ⚙️ Features
- WS2812FX library with more than 100 special effects - WS2812FX library with more than 100 special effects
- FastLED noise effects and 50 palettes - FastLED noise effects and 50 palettes
- Modern UI with color, effect and segment controls - Modern UI with color, effect and segment controls
- Segments to set different effects and colors to user defined parts of the LED string - Segments to set different effects and colors to user defined parts of the LED string
- Settings page - configuration via the network - Settings page - configuration via the network
- Access Point and station mode - automatic failsafe AP - Access Point and station mode - automatic failsafe AP
- Up to 10 LED outputs per instance - Up to 10 LED outputs per instance
- Support for RGBW strips - Support for RGBW strips
- Up to 250 user presets to save and load colors/effects easily, supports cycling through them. - Up to 250 user presets to save and load colors/effects easily, supports cycling through them.
- Presets can be used to automatically execute API calls - Presets can be used to automatically execute API calls
- Nightlight function (gradually dims down) - Nightlight function (gradually dims down)
- Full OTA software updatability (HTTP + ArduinoOTA), password protectable - Full OTA software updatability (HTTP + ArduinoOTA), password protectable
- Configurable analog clock (Cronixie, 7-segment and EleksTube IPS clock support via usermods) - Configurable analog clock (Cronixie, 7-segment and EleksTube IPS clock support via usermods)
- Configurable Auto Brightness limit for safe operation - Configurable Auto Brightness limit for safe operation
- Filesystem-based config for easier backup of presets and settings - Filesystem-based config for easier backup of presets and settings
## 💡 Supported light control interfaces ## 💡 Supported light control interfaces
- WLED app for [Android](https://play.google.com/store/apps/details?id=com.aircoookie.WLED) and [iOS](https://apps.apple.com/us/app/wled/id1475695033) - WLED app for [Android](https://play.google.com/store/apps/details?id=com.aircoookie.WLED) and [iOS](https://apps.apple.com/us/app/wled/id1475695033)
- JSON and HTTP request APIs - JSON and HTTP request APIs
- MQTT - MQTT
- E1.31, Art-Net, DDP and TPM2.net - E1.31, Art-Net, DDP and TPM2.net
- [diyHue](https://github.com/diyhue/diyHue) (Wled is supported by diyHue, including Hue Sync Entertainment under udp. Thanks to [Gregory Mallios](https://github.com/gmallios)) - [diyHue](https://github.com/diyhue/diyHue) (Wled is supported by diyHue, including Hue Sync Entertainment under udp. Thanks to [Gregory Mallios](https://github.com/gmallios))
- [Hyperion](https://github.com/hyperion-project/hyperion.ng) - [Hyperion](https://github.com/hyperion-project/hyperion.ng)
- UDP realtime - UDP realtime
- Alexa voice control (including dimming and color) - Alexa voice control (including dimming and color)
- Sync to Philips hue lights - Sync to Philips hue lights
- Adalight (PC ambilight via serial) and TPM2 - Adalight (PC ambilight via serial) and TPM2
- Sync color of multiple WLED devices (UDP notifier) - Sync color of multiple WLED devices (UDP notifier)
- Infrared remotes (24-key RGB, receiver required) - Infrared remotes (24-key RGB, receiver required)
- Simple timers/schedules (time from NTP, timezones/DST supported) - Simple timers/schedules (time from NTP, timezones/DST supported)
## 📲 Quick start guide and documentation ## 📲 Quick start guide and documentation
See the [documentation on our official site](https://kno.wled.ge)! See the [documentation on our official site](https://kno.wled.ge)!
[On this page](https://kno.wled.ge/basics/tutorials/) you can find excellent tutorials and tools to help you get your new project up and running! [On this page](https://kno.wled.ge/basics/tutorials/) you can find excellent tutorials and tools to help you get your new project up and running!
## 🖼️ User interface ## 🖼️ User interface
<img src="/images/macbook-pro-space-gray-on-the-wooden-table.jpg" width="50%"><img src="/images/walking-with-iphone-x.jpg" width="50%"> <img src="images/macbook-pro-space-gray-on-the-wooden-table.jpg" width="50%"><img src="images/walking-with-iphone-x.jpg" width="50%">
## 💾 Compatible hardware ## 💾 Compatible hardware
See [here](https://kno.wled.ge/basics/compatible-hardware)! See [here](https://kno.wled.ge/basics/compatible-hardware)!
## ✌️ Other ## ✌️ Other
Licensed under the MIT license Licensed under the MIT license
Credits [here](https://kno.wled.ge/about/contributors/)! Credits [here](https://kno.wled.ge/about/contributors/)!
Join the Discord server to discuss everything about WLED! Join the Discord server to discuss everything about WLED!
<a href="https://discord.gg/KuqP7NE"><img src="https://discordapp.com/api/guilds/473448917040758787/widget.png?style=banner2" width="25%"></a> <a href="https://discord.gg/QAh7wJHrRM"><img src="https://discordapp.com/api/guilds/473448917040758787/widget.png?style=banner2" width="25%"></a>
Check out the WLED [Discourse forum](https://wled.discourse.group)! Check out the WLED [Discourse forum](https://wled.discourse.group)!
You can also send me mails to [dev.aircoookie@gmail.com](mailto:dev.aircoookie@gmail.com), but please, only do so if you want to talk to me privately. You can also send me mails to [dev.aircoookie@gmail.com](mailto:dev.aircoookie@gmail.com), but please, only do so if you want to talk to me privately.
If WLED really brightens up your day, you can [![](https://img.shields.io/badge/send%20me%20a%20small%20gift-paypal-blue.svg?style=flat-square)](https://paypal.me/aircoookie) If WLED really brightens up your day, you can [![](https://img.shields.io/badge/send%20me%20a%20small%20gift-paypal-blue.svg?style=flat-square)](https://paypal.me/aircoookie)
*Disclaimer:* *Disclaimer:*
If you are prone to photosensitive epilepsy, we recommended you do **not** use this software. 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. 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 MIT license, I assume no liability for any damage to you or any other person or equipment.

View File

@ -25,6 +25,7 @@ class Animated_Staircase : public Usermod {
bool useUSSensorBottom = false; // using PIR or UltraSound sensor? bool useUSSensorBottom = false; // using PIR or UltraSound sensor?
unsigned int topMaxDist = 50; // default maximum measured distance in cm, top unsigned int topMaxDist = 50; // default maximum measured distance in cm, top
unsigned int bottomMaxDist = 50; // default maximum measured distance in cm, bottom unsigned int bottomMaxDist = 50; // default maximum measured distance in cm, bottom
bool togglePower = false; // toggle power on/off with staircase on/off
/* runtime variables */ /* runtime variables */
bool initDone = false; bool initDone = false;
@ -90,7 +91,8 @@ class Animated_Staircase : public Usermod {
static const char _bottomEcho_pin[]; static const char _bottomEcho_pin[];
static const char _topEchoCm[]; static const char _topEchoCm[];
static const char _bottomEchoCm[]; static const char _bottomEchoCm[];
static const char _togglePower[];
void publishMqtt(bool bottom, const char* state) { void publishMqtt(bool bottom, const char* state) {
#ifndef WLED_DISABLE_MQTT #ifndef WLED_DISABLE_MQTT
//Check if MQTT Connected, otherwise it will crash the 8266 //Check if MQTT Connected, otherwise it will crash the 8266
@ -196,6 +198,7 @@ class Animated_Staircase : public Usermod {
if (on) { if (on) {
lastSensor = topSensorRead; lastSensor = topSensorRead;
} else { } else {
if (togglePower && onIndex == offIndex && offMode) toggleOnOff(); // toggle power on if off
// If the bottom sensor triggered, we need to swipe up, ON // If the bottom sensor triggered, we need to swipe up, ON
swipe = bottomSensorRead; swipe = bottomSensorRead;
@ -249,7 +252,10 @@ class Animated_Staircase : public Usermod {
offIndex = MAX(onIndex, offIndex - 1); offIndex = MAX(onIndex, offIndex - 1);
} }
} }
if (oldOn != onIndex || oldOff != offIndex) updateSegments(); // reduce the number of updates to necessary ones if (oldOn != onIndex || oldOff != offIndex) {
updateSegments(); // reduce the number of updates to necessary ones
if (togglePower && onIndex == offIndex && !offMode && !on) toggleOnOff(); // toggle power off for all segments off
}
} }
} }
@ -295,6 +301,7 @@ class Animated_Staircase : public Usermod {
strip.setTransition(segment_delay_ms/100); strip.setTransition(segment_delay_ms/100);
strip.trigger(); strip.trigger();
} else { } else {
if (togglePower && !on && offMode) toggleOnOff(); // toggle power on if off
// Restore segment options // Restore segment options
for (int i = 0; i <= strip.getLastActiveSegmentId(); i++) { for (int i = 0; i <= strip.getLastActiveSegmentId(); i++) {
Segment &seg = strip.getSegment(i); Segment &seg = strip.getSegment(i);
@ -444,6 +451,7 @@ class Animated_Staircase : public Usermod {
staircase[FPSTR(_bottomEcho_pin)] = useUSSensorBottom ? bottomEchoPin : -1; staircase[FPSTR(_bottomEcho_pin)] = useUSSensorBottom ? bottomEchoPin : -1;
staircase[FPSTR(_topEchoCm)] = topMaxDist; staircase[FPSTR(_topEchoCm)] = topMaxDist;
staircase[FPSTR(_bottomEchoCm)] = bottomMaxDist; staircase[FPSTR(_bottomEchoCm)] = bottomMaxDist;
staircase[FPSTR(_togglePower)] = togglePower;
DEBUG_PRINTLN(F("Staircase config saved.")); DEBUG_PRINTLN(F("Staircase config saved."));
} }
@ -488,6 +496,8 @@ class Animated_Staircase : public Usermod {
bottomMaxDist = top[FPSTR(_bottomEchoCm)] | bottomMaxDist; bottomMaxDist = top[FPSTR(_bottomEchoCm)] | bottomMaxDist;
bottomMaxDist = min(150,max(30,(int)bottomMaxDist)); // max distance ~1.5m (a lag of 9ms may be expected) bottomMaxDist = min(150,max(30,(int)bottomMaxDist)); // max distance ~1.5m (a lag of 9ms may be expected)
togglePower = top[FPSTR(_togglePower)] | togglePower; // staircase toggles power on/off
DEBUG_PRINT(FPSTR(_name)); DEBUG_PRINT(FPSTR(_name));
if (!initDone) { if (!initDone) {
// first run: reading from cfg.json // first run: reading from cfg.json
@ -511,7 +521,7 @@ class Animated_Staircase : public Usermod {
if (changed) setup(); if (changed) setup();
} }
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features // use "return !top["newestParameter"].isNull();" when updating Usermod with new features
return true; return !top[FPSTR(_togglePower)].isNull();
} }
/* /*
@ -551,3 +561,4 @@ const char Animated_Staircase::_bottomPIRorTrigger_pin[] PROGMEM = "bottomPIR
const char Animated_Staircase::_bottomEcho_pin[] PROGMEM = "bottomEcho_pin"; const char Animated_Staircase::_bottomEcho_pin[] PROGMEM = "bottomEcho_pin";
const char Animated_Staircase::_topEchoCm[] PROGMEM = "top-dist-cm"; const char Animated_Staircase::_topEchoCm[] PROGMEM = "top-dist-cm";
const char Animated_Staircase::_bottomEchoCm[] PROGMEM = "bottom-dist-cm"; const char Animated_Staircase::_bottomEchoCm[] PROGMEM = "bottom-dist-cm";
const char Animated_Staircase::_togglePower[] PROGMEM = "toggle-on-off";

View File

@ -0,0 +1,17 @@
# Internal Temperature Usermod
This usermod adds the temperature readout to the Info tab and also publishes that over the topic `mcutemp` topic.
## Important
A shown temp of 53,33°C might indicate that the internal temp is not supported.
ESP8266 does not have a internal temp sensor
ESP32S2 seems to crash on reading the sensor -> disabled
## Installation
Add a build flag `-D USERMOD_INTERNAL_TEMPERATURE` to your `platformio.ini` (or `platformio_override.ini`).
## Authors
Soeren Willrodt [@lost-hope](https://github.com/lost-hope)
Dimitry Zhemkov [@dima-zhemkov](https://github.com/dima-zhemkov)

View File

@ -0,0 +1,117 @@
#pragma once
#include "wled.h"
class InternalTemperatureUsermod : public Usermod
{
private:
unsigned long loopInterval = 10000;
unsigned long lastTime = 0;
bool isEnabled = false;
float temperature = 0;
static const char _name[];
static const char _enabled[];
static const char _loopInterval[];
// any private methods should go here (non-inline methosd should be defined out of class)
void publishMqtt(const char *state, bool retain = false); // example for publishing MQTT message
public:
void setup()
{
}
void loop()
{
// if usermod is disabled or called during strip updating just exit
// NOTE: on very long strips strip.isUpdating() may always return true so update accordingly
if (!isEnabled || strip.isUpdating() || millis() - lastTime <= loopInterval)
return;
lastTime = millis();
#ifdef ESP8266 // ESP8266
// does not seem possible
temperature = -1;
#elif defined(CONFIG_IDF_TARGET_ESP32S2) // ESP32S2
temperature = -1;
#else // ESP32 ESP32S3 and ESP32C3
temperature = roundf(temperatureRead() * 10) / 10;
#endif
#ifndef WLED_DISABLE_MQTT
if (WLED_MQTT_CONNECTED)
{
char array[10];
snprintf(array, sizeof(array), "%f", temperature);
publishMqtt(array);
}
#endif
}
void addToJsonInfo(JsonObject &root)
{
if (!isEnabled)
return;
// if "u" object does not exist yet wee need to create it
JsonObject user = root["u"];
if (user.isNull())
user = root.createNestedObject("u");
JsonArray userTempArr = user.createNestedArray(FPSTR(_name));
userTempArr.add(temperature);
userTempArr.add(F(" °C"));
// if "sensor" object does not exist yet wee need to create it
JsonObject sensor = root[F("sensor")];
if (sensor.isNull())
sensor = root.createNestedObject(F("sensor"));
JsonArray sensorTempArr = sensor.createNestedArray(FPSTR(_name));
sensorTempArr.add(temperature);
sensorTempArr.add(F("°C"));
}
void addToConfig(JsonObject &root)
{
JsonObject top = root.createNestedObject(FPSTR(_name));
top[FPSTR(_enabled)] = isEnabled;
top[FPSTR(_loopInterval)] = loopInterval;
}
bool readFromConfig(JsonObject &root)
{
JsonObject top = root[FPSTR(_name)];
bool configComplete = !top.isNull();
configComplete &= getJsonValue(top[FPSTR(_enabled)], isEnabled);
configComplete &= getJsonValue(top[FPSTR(_loopInterval)], loopInterval);
return configComplete;
}
uint16_t getId()
{
return USERMOD_ID_INTERNAL_TEMPERATURE;
}
};
const char InternalTemperatureUsermod::_name[] PROGMEM = "Internal Temperature";
const char InternalTemperatureUsermod::_enabled[] PROGMEM = "Enabled";
const char InternalTemperatureUsermod::_loopInterval[] PROGMEM = "Loop Interval";
void InternalTemperatureUsermod::publishMqtt(const char *state, bool retain)
{
#ifndef WLED_DISABLE_MQTT
// Check if MQTT Connected, otherwise it will crash the 8266
if (WLED_MQTT_CONNECTED)
{
char subuf[64];
strcpy(subuf, mqttDeviceTopic);
strcat_P(subuf, PSTR("/mcutemp"));
mqtt->publish(subuf, 0, retain, state);
}
#endif
}

View File

@ -20,6 +20,12 @@
* .... * ....
*/ */
#if !defined(FFTTASK_PRIORITY)
#define FFTTASK_PRIORITY 1 // standard: looptask prio
//#define FFTTASK_PRIORITY 2 // above looptask, below asyc_tcp
//#define FFTTASK_PRIORITY 4 // above asyc_tcp
#endif
// Comment/Uncomment to toggle usb serial debugging // Comment/Uncomment to toggle usb serial debugging
// #define MIC_LOGGER // MIC sampling & sound input debugging (serial plotter) // #define MIC_LOGGER // MIC sampling & sound input debugging (serial plotter)
// #define FFT_SAMPLING_LOG // FFT result debugging // #define FFT_SAMPLING_LOG // FFT result debugging
@ -104,7 +110,7 @@ static float sampleAgc = 0.0f; // Smoothed AGC sample
// peak detection // peak detection
static bool samplePeak = false; // Boolean flag for peak - used in effects. Responding routine may reset this flag. Auto-reset after strip.getMinShowDelay() static bool samplePeak = false; // Boolean flag for peak - used in effects. Responding routine may reset this flag. Auto-reset after strip.getMinShowDelay()
static uint8_t maxVol = 10; // Reasonable value for constant volume for 'peak detector', as it won't always trigger (deprecated) static uint8_t maxVol = 31; // Reasonable value for constant volume for 'peak detector', as it won't always trigger (deprecated)
static uint8_t binNum = 8; // Used to select the bin for FFT based beat detection (deprecated) static uint8_t binNum = 8; // Used to select the bin for FFT based beat detection (deprecated)
static bool udpSamplePeak = false; // Boolean flag for peak. Set at the same tiem as samplePeak, but reset by transmitAudioData static bool udpSamplePeak = false; // Boolean flag for peak. Set at the same tiem as samplePeak, but reset by transmitAudioData
static unsigned long timeOfPeak = 0; // time of last sample peak detection. static unsigned long timeOfPeak = 0; // time of last sample peak detection.
@ -173,13 +179,18 @@ static float windowWeighingFactors[samplesFFT] = {0.0f};
// Create FFT object // Create FFT object
#ifdef UM_AUDIOREACTIVE_USE_NEW_FFT #ifdef UM_AUDIOREACTIVE_USE_NEW_FFT
// lib_deps += https://github.com/kosme/arduinoFFT#develop @ 1.9.2 // lib_deps += https://github.com/kosme/arduinoFFT#develop @ 1.9.2
#define FFT_SPEED_OVER_PRECISION // enables use of reciprocals (1/x etc), and an a few other speedups // these options actually cause slow-downs on all esp32 processors, don't use them.
#define FFT_SQRT_APPROXIMATION // enables "quake3" style inverse sqrt // #define FFT_SPEED_OVER_PRECISION // enables use of reciprocals (1/x etc) - not faster on ESP32
#define sqrt(x) sqrtf(x) // little hack that reduces FFT time by 50% on ESP32 (as alternative to FFT_SQRT_APPROXIMATION) // #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
#else #else
// lib_deps += https://github.com/blazoncek/arduinoFFT.git // around 40% slower on -S2
// lib_deps += https://github.com/blazoncek/arduinoFFT.git
#endif #endif
#include <arduinoFFT.h> #include <arduinoFFT.h>
#ifdef UM_AUDIOREACTIVE_USE_NEW_FFT #ifdef UM_AUDIOREACTIVE_USE_NEW_FFT
@ -411,7 +422,7 @@ static void runMicFilter(uint16_t numSamples, float *sampleBuffer) // p
//constexpr float beta1 = 0.8285f; // 18Khz //constexpr float beta1 = 0.8285f; // 18Khz
constexpr float beta1 = 0.85f; // 20Khz constexpr float beta1 = 0.85f; // 20Khz
constexpr float beta2 = (1.0f - beta1) / 2.0; constexpr float beta2 = (1.0f - beta1) / 2.0f;
static float last_vals[2] = { 0.0f }; // FIR high freq cutoff filter static float last_vals[2] = { 0.0f }; // FIR high freq cutoff filter
static float lowfilt = 0.0f; // IIR low frequency cutoff filter static float lowfilt = 0.0f; // IIR low frequency cutoff filter
@ -464,17 +475,17 @@ static void postProcessFFTResults(bool noiseGateOpen, int numberOfChannels) // p
switch (FFTScalingMode) { switch (FFTScalingMode) {
case 1: case 1:
// Logarithmic scaling // Logarithmic scaling
currentResult *= 0.42; // 42 is the answer ;-) currentResult *= 0.42f; // 42 is the answer ;-)
currentResult -= 8.0; // this skips the lowest row, giving some room for peaks currentResult -= 8.0f; // this skips the lowest row, giving some room for peaks
if (currentResult > 1.0) currentResult = logf(currentResult); // log to base "e", which is the fastest log() function if (currentResult > 1.0f) currentResult = logf(currentResult); // log to base "e", which is the fastest log() function
else currentResult = 0.0; // special handling, because log(1) = 0; log(0) = undefined else currentResult = 0.0f; // special handling, because log(1) = 0; log(0) = undefined
currentResult *= 0.85f + (float(i)/18.0f); // extra up-scaling for high frequencies currentResult *= 0.85f + (float(i)/18.0f); // extra up-scaling for high frequencies
currentResult = mapf(currentResult, 0, LOG_256, 0, 255); // map [log(1) ... log(255)] to [0 ... 255] currentResult = mapf(currentResult, 0, LOG_256, 0, 255); // map [log(1) ... log(255)] to [0 ... 255]
break; break;
case 2: case 2:
// Linear scaling // Linear scaling
currentResult *= 0.30f; // needs a bit more damping, get stay below 255 currentResult *= 0.30f; // needs a bit more damping, get stay below 255
currentResult -= 4.0; // giving a bit more room for peaks currentResult -= 4.0f; // giving a bit more room for peaks
if (currentResult < 1.0f) currentResult = 0.0f; if (currentResult < 1.0f) currentResult = 0.0f;
currentResult *= 0.85f + (float(i)/1.8f); // extra up-scaling for high frequencies currentResult *= 0.85f + (float(i)/1.8f); // extra up-scaling for high frequencies
break; break;
@ -482,8 +493,8 @@ static void postProcessFFTResults(bool noiseGateOpen, int numberOfChannels) // p
// square root scaling // square root scaling
currentResult *= 0.38f; currentResult *= 0.38f;
currentResult -= 6.0f; currentResult -= 6.0f;
if (currentResult > 1.0) currentResult = sqrtf(currentResult); if (currentResult > 1.0f) currentResult = sqrtf(currentResult);
else currentResult = 0.0; // special handling, because sqrt(0) = undefined else currentResult = 0.0f; // special handling, because sqrt(0) = undefined
currentResult *= 0.85f + (float(i)/4.5f); // extra up-scaling for high frequencies currentResult *= 0.85f + (float(i)/4.5f); // extra up-scaling for high frequencies
currentResult = mapf(currentResult, 0.0, 16.0, 0.0, 255.0); // map [sqrt(1) ... sqrt(256)] to [0 ... 255] currentResult = mapf(currentResult, 0.0, 16.0, 0.0, 255.0); // map [sqrt(1) ... sqrt(256)] to [0 ... 255]
break; break;
@ -511,11 +522,11 @@ static void postProcessFFTResults(bool noiseGateOpen, int numberOfChannels) // p
// peak detection is called from FFT task when vReal[] contains valid FFT results // peak detection is called from FFT task when vReal[] contains valid FFT results
static void detectSamplePeak(void) { static void detectSamplePeak(void) {
bool havePeak = false; bool havePeak = false;
// softhack007: this code continuously triggers while amplitude in the selected bin is above a certain threshold. So it does not detect peaks - it detects high activity in a frequency bin.
// Poor man's beat detection by seeing if sample > Average + some value. // Poor man's beat detection by seeing if sample > Average + some value.
// This goes through ALL of the 255 bins - but ignores stupid settings // This goes through ALL of the 255 bins - but ignores stupid settings
// Then we got a peak, else we don't. The peak has to time out on its own in order to support UDP sound sync. // Then we got a peak, else we don't. The peak has to time out on its own in order to support UDP sound sync.
if ((sampleAvg > 1) && (maxVol > 0) && (binNum > 1) && (vReal[binNum] > maxVol) && ((millis() - timeOfPeak) > 100)) { if ((sampleAvg > 1) && (maxVol > 0) && (binNum > 4) && (vReal[binNum] > maxVol) && ((millis() - timeOfPeak) > 100)) {
havePeak = true; havePeak = true;
} }
@ -758,7 +769,7 @@ class AudioReactive : public Usermod {
if (time_now - last_time > 2) { if (time_now - last_time > 2) {
last_time = time_now; last_time = time_now;
if((fabsf(sampleReal) < 2.0f) || (sampleMax < 1.0f)) { if((fabsf(sampleReal) < 2.0f) || (sampleMax < 1.0)) {
// MIC signal is "squelched" - deliver silence // MIC signal is "squelched" - deliver silence
tmpAgc = 0; tmpAgc = 0;
// we need to "spin down" the intgrated error buffer // we need to "spin down" the intgrated error buffer
@ -873,8 +884,8 @@ class AudioReactive : public Usermod {
// keep "peak" sample, but decay value if current sample is below peak // keep "peak" sample, but decay value if current sample is below peak
if ((sampleMax < sampleReal) && (sampleReal > 0.5f)) { if ((sampleMax < sampleReal) && (sampleReal > 0.5f)) {
sampleMax = sampleMax + 0.5f * (sampleReal - sampleMax); // new peak - with some filtering sampleMax = sampleMax + 0.5f * (sampleReal - sampleMax); // new peak - with some filtering
// another simple way to detect samplePeak // another simple way to detect samplePeak - cannot detect beats, but reacts on peak volume
if ((binNum < 10) && (millis() - timeOfPeak > 80) && (sampleAvg > 1)) { if (((binNum < 12) || ((maxVol < 1))) && (millis() - timeOfPeak > 80) && (sampleAvg > 1)) {
samplePeak = true; samplePeak = true;
timeOfPeak = millis(); timeOfPeak = millis();
udpSamplePeak = true; udpSamplePeak = true;
@ -949,6 +960,8 @@ class AudioReactive : public Usermod {
//DEBUGSR_PRINTLN("Transmitting UDP Mic Packet"); //DEBUGSR_PRINTLN("Transmitting UDP Mic Packet");
audioSyncPacket transmitData; audioSyncPacket transmitData;
memset(reinterpret_cast<void *>(&transmitData), 0, sizeof(transmitData)); // make sure that the packet - including "invisible" padding bytes added by the compiler - is fully initialized
strncpy_P(transmitData.header, PSTR(UDP_SYNC_HEADER), 6); strncpy_P(transmitData.header, PSTR(UDP_SYNC_HEADER), 6);
// transmit samples that were not modified by limitSampleDynamics() // transmit samples that were not modified by limitSampleDynamics()
transmitData.sampleRaw = (soundAgc) ? rawSampleAgc: sampleRaw; transmitData.sampleRaw = (soundAgc) ? rawSampleAgc: sampleRaw;
@ -964,9 +977,10 @@ class AudioReactive : public Usermod {
transmitData.FFT_Magnitude = my_magnitude; transmitData.FFT_Magnitude = my_magnitude;
transmitData.FFT_MajorPeak = FFT_MajorPeak; transmitData.FFT_MajorPeak = FFT_MajorPeak;
fftUdp.beginMulticastPacket(); if (fftUdp.beginMulticastPacket() != 0) { // beginMulticastPacket returns 0 in case of error
fftUdp.write(reinterpret_cast<uint8_t *>(&transmitData), sizeof(transmitData)); fftUdp.write(reinterpret_cast<uint8_t *>(&transmitData), sizeof(transmitData));
fftUdp.endPacket(); fftUdp.endPacket();
}
return; return;
} // transmitAudioData() } // transmitAudioData()
@ -1163,6 +1177,7 @@ class AudioReactive : public Usermod {
DEBUGSR_PRINTLN(F("AR: Analog Microphone (left channel only).")); DEBUGSR_PRINTLN(F("AR: Analog Microphone (left channel only)."));
audioSource = new I2SAdcSource(SAMPLE_RATE, BLOCK_SIZE); audioSource = new I2SAdcSource(SAMPLE_RATE, BLOCK_SIZE);
delay(100); delay(100);
useBandPassFilter = true; // PDM bandpass filter seems to help for bad quality analog
if (audioSource) audioSource->initialize(audioPin); if (audioSource) audioSource->initialize(audioPin);
break; break;
#endif #endif
@ -1272,9 +1287,10 @@ class AudioReactive : public Usermod {
#ifdef WLED_DEBUG #ifdef WLED_DEBUG
// complain when audio userloop has been delayed for long time. Currently we need userloop running between 500 and 1500 times per second. // complain when audio userloop has been delayed for long time. Currently we need userloop running between 500 and 1500 times per second.
if ((userloopDelay > 23) && !disableSoundProcessing && (audioSyncEnabled == 0)) { // softhack007 disabled temporarily - avoid serial console spam with MANY leds and low FPS
DEBUG_PRINTF("[AR userLoop] hickup detected -> was inactive for last %d millis!\n", userloopDelay); //if ((userloopDelay > 65) && !disableSoundProcessing && (audioSyncEnabled == 0)) {
} //DEBUG_PRINTF("[AR userLoop] hickup detected -> was inactive for last %d millis!\n", userloopDelay);
//}
#endif #endif
// run filters, and repeat in case of loop delays (hick-up compensation) // run filters, and repeat in case of loop delays (hick-up compensation)
@ -1311,6 +1327,9 @@ class AudioReactive : public Usermod {
if (millis() - lastTime > delayMs) { if (millis() - lastTime > delayMs) {
have_new_sample = receiveAudioData(); have_new_sample = receiveAudioData();
if (have_new_sample) last_UDPTime = millis(); if (have_new_sample) last_UDPTime = millis();
#ifdef ARDUINO_ARCH_ESP32
else fftUdp.flush(); // Flush udp input buffers if we haven't read it - avoids hickups in receive mode. Does not work on 8266.
#endif
lastTime = millis(); lastTime = millis();
} }
if (have_new_sample) syncVolumeSmth = volumeSmth; // remember received sample if (have_new_sample) syncVolumeSmth = volumeSmth; // remember received sample
@ -1329,7 +1348,7 @@ class AudioReactive : public Usermod {
// Info Page: keep max sample from last 5 seconds // Info Page: keep max sample from last 5 seconds
if ((millis() - sampleMaxTimer) > CYCLE_SAMPLEMAX) { if ((millis() - sampleMaxTimer) > CYCLE_SAMPLEMAX) {
sampleMaxTimer = millis(); sampleMaxTimer = millis();
maxSample5sec = (0.15 * maxSample5sec) + 0.85 *((soundAgc) ? sampleAgc : sampleAvg); // reset, and start with some smoothing maxSample5sec = (0.15f * maxSample5sec) + 0.85f *((soundAgc) ? sampleAgc : sampleAvg); // reset, and start with some smoothing
if (sampleAvg < 1) maxSample5sec = 0; // noise gate if (sampleAvg < 1) maxSample5sec = 0; // noise gate
} else { } else {
if ((sampleAvg >= 1)) maxSample5sec = fmaxf(maxSample5sec, (soundAgc) ? rawSampleAgc : sampleRaw); // follow maximum volume if ((sampleAvg >= 1)) maxSample5sec = fmaxf(maxSample5sec, (soundAgc) ? rawSampleAgc : sampleRaw); // follow maximum volume
@ -1373,10 +1392,11 @@ class AudioReactive : public Usermod {
memset(fftAvg, 0, sizeof(fftAvg)); memset(fftAvg, 0, sizeof(fftAvg));
memset(fftResult, 0, sizeof(fftResult)); memset(fftResult, 0, sizeof(fftResult));
for(int i=(init?0:1); i<NUM_GEQ_CHANNELS; i+=2) fftResult[i] = 16; // make a tiny pattern for(int i=(init?0:1); i<NUM_GEQ_CHANNELS; i+=2) fftResult[i] = 16; // make a tiny pattern
inputLevel = 128; // resset level slider to default inputLevel = 128; // reset level slider to default
autoResetPeak(); autoResetPeak();
if (init && FFT_Task) { if (init && FFT_Task) {
delay(25); // give some time for I2S driver to finish sampling before we suspend it
vTaskSuspend(FFT_Task); // update is about to begin, disable task to prevent crash vTaskSuspend(FFT_Task); // update is about to begin, disable task to prevent crash
if (udpSyncConnected) { // close UDP sync connection (if open) if (udpSyncConnected) { // close UDP sync connection (if open)
udpSyncConnected = false; udpSyncConnected = false;
@ -1388,15 +1408,14 @@ class AudioReactive : public Usermod {
vTaskResume(FFT_Task); vTaskResume(FFT_Task);
connected(); // resume UDP connected(); // resume UDP
} else } else
// xTaskCreatePinnedToCore( xTaskCreateUniversal( // xTaskCreateUniversal also works on -S2 and -C3 with single core
xTaskCreate( // no need to "pin" this task to core #0
FFTcode, // Function to implement the task FFTcode, // Function to implement the task
"FFT", // Name of the task "FFT", // Name of the task
5000, // Stack size in words 3592, // Stack size in words // 3592 leaves 800-1024 bytes of task stack free
NULL, // Task input parameter NULL, // Task input parameter
1, // Priority of the task FFTTASK_PRIORITY, // Priority of the task
&FFT_Task // Task handle &FFT_Task // Task handle
// , 0 // Core where the task should run , 0 // Core where the task should run
); );
} }
micDataReal = 0.0f; // just to be sure micDataReal = 0.0f; // just to be sure
@ -1493,7 +1512,7 @@ class AudioReactive : public Usermod {
infoArr.add(F("I2S digital")); infoArr.add(F("I2S digital"));
} }
// input level or "silence" // input level or "silence"
if (maxSample5sec > 1.0) { if (maxSample5sec > 1.0f) {
float my_usage = 100.0f * (maxSample5sec / 255.0f); float my_usage = 100.0f * (maxSample5sec / 255.0f);
snprintf_P(myStringBuffer, 15, PSTR(" - peak %3d%%"), int(my_usage)); snprintf_P(myStringBuffer, 15, PSTR(" - peak %3d%%"), int(my_usage));
infoArr.add(myStringBuffer); infoArr.add(myStringBuffer);
@ -1503,7 +1522,7 @@ class AudioReactive : public Usermod {
} else { } else {
// error during audio source setup // error during audio source setup
infoArr.add(F("not initialized")); infoArr.add(F("not initialized"));
infoArr.add(F(" - check GPIO config")); infoArr.add(F(" - check pin settings"));
} }
} }
@ -1807,7 +1826,9 @@ class AudioReactive : public Usermod {
const char AudioReactive::_name[] PROGMEM = "AudioReactive"; const char AudioReactive::_name[] PROGMEM = "AudioReactive";
const char AudioReactive::_enabled[] PROGMEM = "enabled"; const char AudioReactive::_enabled[] PROGMEM = "enabled";
const char AudioReactive::_inputLvl[] PROGMEM = "inputLevel"; const char AudioReactive::_inputLvl[] PROGMEM = "inputLevel";
#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3)
const char AudioReactive::_analogmic[] PROGMEM = "analogmic"; const char AudioReactive::_analogmic[] PROGMEM = "analogmic";
#endif
const char AudioReactive::_digitalmic[] PROGMEM = "digitalmic"; const char AudioReactive::_digitalmic[] PROGMEM = "digitalmic";
const char AudioReactive::UDP_SYNC_HEADER[] PROGMEM = "00002"; // new sync header version, as format no longer compatible with previous structure const char AudioReactive::UDP_SYNC_HEADER[] PROGMEM = "00002"; // new sync header version, as format no longer compatible with previous structure
const char AudioReactive::UDP_SYNC_HEADER_v1[] PROGMEM = "00001"; // old sync header version - need to add backwards-compatibility feature const char AudioReactive::UDP_SYNC_HEADER_v1[] PROGMEM = "00001"; // old sync header version - need to add backwards-compatibility feature

View File

@ -1,5 +1,5 @@
#pragma once #pragma once
#ifdef ARDUINO_ARCH_ESP32
#include "wled.h" #include "wled.h"
#include <driver/i2s.h> #include <driver/i2s.h>
#include <driver/adc.h> #include <driver/adc.h>
@ -22,14 +22,14 @@
// see https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/hw-reference/chip-series-comparison.html#related-documents // see https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/hw-reference/chip-series-comparison.html#related-documents
// and https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-reference/peripherals/i2s.html#overview-of-all-modes // and https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-reference/peripherals/i2s.html#overview-of-all-modes
#if defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32H2) || defined(ESP8266) || defined(ESP8265) #if defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32H2) || defined(ESP8266) || defined(ESP8265)
// there are two things in these MCUs that could lead to problems with audio processing: // there are two things in these MCUs that could lead to problems with audio processing:
// * no floating point hardware (FPU) support - FFT uses float calculations. If done in software, a strong slow-down can be expected (between 8x and 20x) // * no floating point hardware (FPU) support - FFT uses float calculations. If done in software, a strong slow-down can be expected (between 8x and 20x)
// * single core, so FFT task might slow down other things like LED updates // * single core, so FFT task might slow down other things like LED updates
#if !defined(SOC_I2S_NUM) || (SOC_I2S_NUM < 1) #if !defined(SOC_I2S_NUM) || (SOC_I2S_NUM < 1)
#error This audio reactive usermod does not support ESP32-C2, ESP32-C3 or ESP32-S2. #error This audio reactive usermod does not support ESP32-C2 or ESP32-C3.
#else #else
#warning This audio reactive usermod does not support ESP32-C2, ESP32-C3 or ESP32-S2. #warning This audio reactive usermod does not support ESP32-C2 and ESP32-C3.
#endif #endif
#endif #endif
@ -71,7 +71,7 @@
* if you want to receive two channels, one is the actual data from microphone and another channel is suppose to receive 0, it's different data in two channels, you need to choose I2S_CHANNEL_FMT_RIGHT_LEFT in this case. * if you want to receive two channels, one is the actual data from microphone and another channel is suppose to receive 0, it's different data in two channels, you need to choose I2S_CHANNEL_FMT_RIGHT_LEFT in this case.
*/ */
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0)) && (ESP_IDF_VERSION <= ESP_IDF_VERSION_VAL(4, 4, 3)) #if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0)) && (ESP_IDF_VERSION <= ESP_IDF_VERSION_VAL(4, 4, 4))
// espressif bug: only_left has no sound, left and right are swapped // espressif bug: only_left has no sound, left and right are swapped
// https://github.com/espressif/esp-idf/issues/9635 I2S mic not working since 4.4 (IDFGH-8138) // https://github.com/espressif/esp-idf/issues/9635 I2S mic not working since 4.4 (IDFGH-8138)
// https://github.com/espressif/esp-idf/issues/8538 I2S channel selection issue? (IDFGH-6918) // https://github.com/espressif/esp-idf/issues/8538 I2S channel selection issue? (IDFGH-6918)
@ -122,7 +122,7 @@ class AudioSource {
This function needs to take care of anything that needs to be done This function needs to take care of anything that needs to be done
before samples can be obtained from the microphone. before samples can be obtained from the microphone.
*/ */
virtual void initialize(int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE) = 0; virtual void initialize(int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE) = 0;
/* Deinitialize /* Deinitialize
Release all resources and deactivate any functionality that is used Release all resources and deactivate any functionality that is used
@ -191,7 +191,8 @@ class I2SSource : public AudioSource {
}; };
} }
virtual void initialize(int8_t i2swsPin = I2S_PIN_NO_CHANGE, int8_t i2ssdPin = I2S_PIN_NO_CHANGE, int8_t i2sckPin = I2S_PIN_NO_CHANGE, int8_t mclkPin = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE) { virtual void initialize(int8_t i2swsPin = I2S_PIN_NO_CHANGE, int8_t i2ssdPin = I2S_PIN_NO_CHANGE, int8_t i2sckPin = I2S_PIN_NO_CHANGE, int8_t mclkPin = I2S_PIN_NO_CHANGE) {
DEBUGSR_PRINTLN("I2SSource:: initialize().");
if (i2swsPin != I2S_PIN_NO_CHANGE && i2ssdPin != I2S_PIN_NO_CHANGE) { if (i2swsPin != I2S_PIN_NO_CHANGE && i2ssdPin != I2S_PIN_NO_CHANGE) {
if (!pinManager.allocatePin(i2swsPin, true, PinOwner::UM_Audioreactive) || if (!pinManager.allocatePin(i2swsPin, true, PinOwner::UM_Audioreactive) ||
!pinManager.allocatePin(i2ssdPin, false, PinOwner::UM_Audioreactive)) { // #206 !pinManager.allocatePin(i2ssdPin, false, PinOwner::UM_Audioreactive)) { // #206
@ -412,6 +413,7 @@ public:
}; };
void initialize(int8_t i2swsPin, int8_t i2ssdPin, int8_t i2sckPin, int8_t mclkPin) { void initialize(int8_t i2swsPin, int8_t i2ssdPin, int8_t i2sckPin, int8_t mclkPin) {
DEBUGSR_PRINTLN("ES7243:: initialize();");
if ((i2sckPin < 0) || (mclkPin < 0)) { if ((i2sckPin < 0) || (mclkPin < 0)) {
DEBUGSR_PRINTF("\nAR: invalid I2S pin: SCK=%d, MCLK=%d\n", i2sckPin, mclkPin); DEBUGSR_PRINTF("\nAR: invalid I2S pin: SCK=%d, MCLK=%d\n", i2sckPin, mclkPin);
return; return;
@ -527,7 +529,7 @@ class ES8388Source : public I2SSource {
}; };
void initialize(int8_t i2swsPin, int8_t i2ssdPin, int8_t i2sckPin, int8_t mclkPin) { void initialize(int8_t i2swsPin, int8_t i2ssdPin, int8_t i2sckPin, int8_t mclkPin) {
DEBUGSR_PRINTLN("ES8388Source:: initialize();");
if ((i2sckPin < 0) || (mclkPin < 0)) { if ((i2sckPin < 0) || (mclkPin < 0)) {
DEBUGSR_PRINTF("\nAR: invalid I2S pin: SCK=%d, MCLK=%d\n", i2sckPin, mclkPin); DEBUGSR_PRINTF("\nAR: invalid I2S pin: SCK=%d, MCLK=%d\n", i2sckPin, mclkPin);
return; return;
@ -584,7 +586,8 @@ class I2SAdcSource : public I2SSource {
/* identify Audiosource type - I2S-ADC*/ /* identify Audiosource type - I2S-ADC*/
AudioSourceType getType(void) {return(Type_I2SAdc);} AudioSourceType getType(void) {return(Type_I2SAdc);}
void initialize(int8_t audioPin, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE) { void initialize(int8_t audioPin, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE) {
DEBUGSR_PRINTLN("I2SAdcSource:: initialize().");
_myADCchannel = 0x0F; _myADCchannel = 0x0F;
if(!pinManager.allocatePin(audioPin, false, PinOwner::UM_Audioreactive)) { if(!pinManager.allocatePin(audioPin, false, PinOwner::UM_Audioreactive)) {
DEBUGSR_PRINTF("failed to allocate GPIO for audio analog input: %d\n", audioPin); DEBUGSR_PRINTF("failed to allocate GPIO for audio analog input: %d\n", audioPin);
@ -755,7 +758,8 @@ class SPH0654 : public I2SSource {
I2SSource(sampleRate, blockSize, sampleScale) I2SSource(sampleRate, blockSize, sampleScale)
{} {}
void initialize(uint8_t i2swsPin, uint8_t i2ssdPin, uint8_t i2sckPin, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE) { void initialize(int8_t i2swsPin, int8_t i2ssdPin, int8_t i2sckPin, int8_t = I2S_PIN_NO_CHANGE) {
DEBUGSR_PRINTLN("SPH0654:: initialize();");
I2SSource::initialize(i2swsPin, i2ssdPin, i2sckPin); I2SSource::initialize(i2swsPin, i2ssdPin, i2sckPin);
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3)
// these registers are only existing in "classic" ESP32 // these registers are only existing in "classic" ESP32
@ -766,3 +770,4 @@ class SPH0654 : public I2SSource {
#endif #endif
} }
}; };
#endif

View File

@ -1081,7 +1081,7 @@ bool FourLineDisplayUsermod::handleButton(uint8_t b) {
static bool buttonLongPressed = false; static bool buttonLongPressed = false;
static unsigned long buttonPressedTime = 0; static unsigned long buttonPressedTime = 0;
static unsigned long buttonWaitTime = 0; static unsigned long buttonWaitTime = 0;
bool handled = true; bool handled = false;
//momentary button logic //momentary button logic
if (isButtonPressed(b)) { //pressed if (isButtonPressed(b)) { //pressed
@ -1090,11 +1090,12 @@ bool FourLineDisplayUsermod::handleButton(uint8_t b) {
buttonPressedBefore = true; buttonPressedBefore = true;
if (now - buttonPressedTime > 600) { //long press if (now - buttonPressedTime > 600) { //long press
buttonLongPressed = true;
//TODO: handleButton() handles button 0 without preset in a different way for double click //TODO: handleButton() handles button 0 without preset in a different way for double click
//so we need to override with same behaviour //so we need to override with same behaviour
longPressAction(0); //DEBUG_PRINTLN(F("4LD action."));
//handled = false; //if (!buttonLongPressed) longPressAction(0);
buttonLongPressed = true;
return false;
} }
} else if (!isButtonPressed(b) && buttonPressedBefore) { //released } else if (!isButtonPressed(b) && buttonPressedBefore) { //released
@ -1126,7 +1127,7 @@ bool FourLineDisplayUsermod::handleButton(uint8_t b) {
buttonWaitTime = 0; buttonWaitTime = 0;
//TODO: handleButton() handles button 0 without preset in a different way for double click //TODO: handleButton() handles button 0 without preset in a different way for double click
//so we need to override with same behaviour //so we need to override with same behaviour
shortPressAction(0); //shortPressAction(0);
//handled = false; //handled = false;
} }
return handled; return handled;

View File

@ -398,8 +398,14 @@ void RotaryEncoderUIUsermod::sortModesAndPalettes() {
modes_alpha_indexes = re_initIndexArray(strip.getModeCount()); modes_alpha_indexes = re_initIndexArray(strip.getModeCount());
re_sortModes(modes_qstrings, modes_alpha_indexes, strip.getModeCount(), MODE_SORT_SKIP_COUNT); re_sortModes(modes_qstrings, modes_alpha_indexes, strip.getModeCount(), MODE_SORT_SKIP_COUNT);
palettes_qstrings = re_findModeStrings(JSON_palette_names, strip.getPaletteCount()); palettes_qstrings = re_findModeStrings(JSON_palette_names, strip.getPaletteCount()+strip.customPalettes.size());
palettes_alpha_indexes = re_initIndexArray(strip.getPaletteCount()); // only use internal palettes palettes_alpha_indexes = re_initIndexArray(strip.getPaletteCount()+strip.customPalettes.size());
if (strip.customPalettes.size()) {
for (int i=0; i<strip.customPalettes.size(); i++) {
palettes_alpha_indexes[strip.getPaletteCount()+i] = 255-i;
palettes_qstrings[strip.getPaletteCount()+i] = PSTR("~Custom~");
}
}
// How many palette names start with '*' and should not be sorted? // How many palette names start with '*' and should not be sorted?
// (Also skipping the first one, 'Default'). // (Also skipping the first one, 'Default').
@ -496,7 +502,7 @@ void RotaryEncoderUIUsermod::setup()
} }
} else { } else {
PinManagerPinType pins[3] = { { pinA, false }, { pinB, false }, { pinC, false } }; PinManagerPinType pins[3] = { { pinA, false }, { pinB, false }, { pinC, false } };
if (!pinManager.allocateMultiplePins(pins, 3, PinOwner::UM_RotaryEncoderUI)) { if (pinA<0 || pinB<0 || !pinManager.allocateMultiplePins(pins, 3, PinOwner::UM_RotaryEncoderUI)) {
pinA = pinB = pinC = -1; pinA = pinB = pinC = -1;
enabled = false; enabled = false;
return; return;
@ -507,7 +513,7 @@ void RotaryEncoderUIUsermod::setup()
#endif #endif
pinMode(pinA, USERMOD_ROTARY_ENCODER_GPIO); pinMode(pinA, USERMOD_ROTARY_ENCODER_GPIO);
pinMode(pinB, USERMOD_ROTARY_ENCODER_GPIO); pinMode(pinB, USERMOD_ROTARY_ENCODER_GPIO);
pinMode(pinC, USERMOD_ROTARY_ENCODER_GPIO); if (pinC>=0) pinMode(pinC, USERMOD_ROTARY_ENCODER_GPIO);
} }
loopTime = millis(); loopTime = millis();
@ -682,21 +688,25 @@ void RotaryEncoderUIUsermod::displayNetworkInfo() {
void RotaryEncoderUIUsermod::findCurrentEffectAndPalette() { void RotaryEncoderUIUsermod::findCurrentEffectAndPalette() {
DEBUG_PRINTLN(F("Finding current mode and palette.")); DEBUG_PRINTLN(F("Finding current mode and palette."));
currentEffectAndPaletteInitialized = true; currentEffectAndPaletteInitialized = true;
for (uint8_t i = 0; i < strip.getModeCount(); i++) {
effectCurrentIndex = 0;
for (int i = 0; i < strip.getModeCount(); i++) {
if (modes_alpha_indexes[i] == effectCurrent) { if (modes_alpha_indexes[i] == effectCurrent) {
effectCurrentIndex = i; effectCurrentIndex = i;
DEBUG_PRINTLN(F("Found current mode."));
break; break;
} }
} }
DEBUG_PRINTLN(F("Found current mode."));
for (uint8_t i = 0; i < strip.getPaletteCount(); i++) { effectPaletteIndex = 0;
DEBUG_PRINTLN(effectPalette);
for (uint8_t i = 0; i < strip.getPaletteCount()+strip.customPalettes.size(); i++) {
if (palettes_alpha_indexes[i] == effectPalette) { if (palettes_alpha_indexes[i] == effectPalette) {
effectPaletteIndex = i; effectPaletteIndex = i;
DEBUG_PRINTLN(F("Found palette."));
break; break;
} }
} }
DEBUG_PRINTLN(F("Found palette."));
} }
bool RotaryEncoderUIUsermod::changeState(const char *stateName, byte markedLine, byte markedCol, byte glyph) { bool RotaryEncoderUIUsermod::changeState(const char *stateName, byte markedLine, byte markedCol, byte glyph) {
@ -731,7 +741,9 @@ void RotaryEncoderUIUsermod::changeBrightness(bool increase) {
} }
display->updateRedrawTime(); display->updateRedrawTime();
#endif #endif
bri = max(min((increase ? bri+fadeAmount : bri-fadeAmount), 255), 0); //bri = max(min((increase ? bri+fadeAmount : bri-fadeAmount), 255), 0);
if (bri < 40) bri = max(min((increase ? bri+fadeAmount/2 : bri-fadeAmount/2), 255), 0); // slower steps when brightness < 16%
else bri = max(min((increase ? bri+fadeAmount : bri-fadeAmount), 255), 0);
lampUdated(); lampUdated();
#ifdef USERMOD_FOUR_LINE_DISPLAY #ifdef USERMOD_FOUR_LINE_DISPLAY
display->updateBrightness(); display->updateBrightness();
@ -878,7 +890,7 @@ void RotaryEncoderUIUsermod::changePalette(bool increase) {
} }
display->updateRedrawTime(); display->updateRedrawTime();
#endif #endif
effectPaletteIndex = max(min((increase ? effectPaletteIndex+1 : effectPaletteIndex-1), strip.getPaletteCount()-1), 0); effectPaletteIndex = max(min((unsigned)(increase ? effectPaletteIndex+1 : effectPaletteIndex-1), strip.getPaletteCount()+strip.customPalettes.size()-1), 0U);
effectPalette = palettes_alpha_indexes[effectPaletteIndex]; effectPalette = palettes_alpha_indexes[effectPaletteIndex];
stateChanged = true; stateChanged = true;
if (applyToAll) { if (applyToAll) {

File diff suppressed because it is too large Load Diff

View File

@ -176,7 +176,7 @@
#define FX_MODE_FIRE_FLICKER 45 #define FX_MODE_FIRE_FLICKER 45
#define FX_MODE_GRADIENT 46 #define FX_MODE_GRADIENT 46
#define FX_MODE_LOADING 47 #define FX_MODE_LOADING 47
// #define FX_MODE_POLICE 48 // removed in 0.14! #define FX_MODE_ROLLINGBALLS 48 //was Police before 0.14
#define FX_MODE_FAIRY 49 //was Police All prior to 0.13.0-b6 (use "Two Dots" with Red/Blue and full intensity) #define FX_MODE_FAIRY 49 //was Police All prior to 0.13.0-b6 (use "Two Dots" with Red/Blue and full intensity)
#define FX_MODE_TWO_DOTS 50 #define FX_MODE_TWO_DOTS 50
#define FX_MODE_FAIRYTWINKLE 51 //was Two Areas prior to 0.13.0-b6 (use "Two Dots" with full intensity) #define FX_MODE_FAIRYTWINKLE 51 //was Two Areas prior to 0.13.0-b6 (use "Two Dots" with full intensity)
@ -381,6 +381,30 @@ typedef struct Segment {
byte *data; // effect data pointer byte *data; // effect data pointer
static uint16_t maxWidth, maxHeight; // these define matrix width & height (max. segment dimensions) static uint16_t maxWidth, maxHeight; // these define matrix width & height (max. segment dimensions)
typedef struct TemporarySegmentData {
uint16_t _optionsT;
uint32_t _colorT[NUM_COLORS];
uint8_t _speedT;
uint8_t _intensityT;
uint8_t _custom1T, _custom2T; // custom FX parameters/sliders
struct {
uint8_t _custom3T : 5; // reduced range slider (0-31)
bool _check1T : 1; // checkmark 1
bool _check2T : 1; // checkmark 2
bool _check3T : 1; // checkmark 3
};
uint16_t _aux0T;
uint16_t _aux1T;
uint32_t _stepT;
uint32_t _callT;
uint8_t *_dataT;
uint16_t _dataLenT;
TemporarySegmentData()
: _dataT(nullptr) // just in case...
, _dataLenT(0)
{}
} tmpsegd_t;
private: private:
union { union {
uint8_t _capabilities; uint8_t _capabilities;
@ -396,43 +420,33 @@ typedef struct Segment {
static uint16_t _usedSegmentData; static uint16_t _usedSegmentData;
// perhaps this should be per segment, not static // perhaps this should be per segment, not static
static CRGBPalette16 _randomPalette; static CRGBPalette16 _randomPalette; // actual random palette
static CRGBPalette16 _newRandomPalette; static CRGBPalette16 _newRandomPalette; // target random palette
static unsigned long _lastPaletteChange; static unsigned long _lastPaletteChange; // last random palette change time in millis()
#ifndef WLED_DISABLE_MODE_BLEND
static bool _modeBlend; // mode/effect blending semaphore
#endif
// transition data, valid only if transitional==true, holds values during transition (72 bytes) // transition data, valid only if transitional==true, holds values during transition (72 bytes)
struct Transition { struct Transition {
#ifndef WLED_DISABLE_MODE_BLEND
tmpsegd_t _segT; // previous segment environment
uint8_t _modeT; // previous mode/effect
#else
uint32_t _colorT[NUM_COLORS]; uint32_t _colorT[NUM_COLORS];
#endif
uint8_t _briT; // temporary brightness uint8_t _briT; // temporary brightness
uint8_t _cctT; // temporary CCT uint8_t _cctT; // temporary CCT
CRGBPalette16 _palT; // temporary palette CRGBPalette16 _palT; // temporary palette
uint8_t _prevPaletteBlends; // number of previous palette blends (there are max 255 belnds possible) uint8_t _prevPaletteBlends; // number of previous palette blends (there are max 255 belnds possible)
uint8_t _modeP; // previous mode/effect unsigned long _start; // must accommodate millis()
//uint16_t _aux0, _aux1; // previous mode/effect runtime data
//uint32_t _step, _call; // previous mode/effect runtime data
//byte *_data; // previous mode/effect runtime data
unsigned long _start; // must accommodate millis()
uint16_t _dur; uint16_t _dur;
Transition(uint16_t dur=750) Transition(uint16_t dur=750)
: _briT(255) : _palT(CRGBPalette16(CRGB::Black))
, _cctT(127)
, _palT(CRGBPalette16(CRGB::Black))
, _prevPaletteBlends(0) , _prevPaletteBlends(0)
, _modeP(FX_MODE_STATIC)
, _start(millis()) , _start(millis())
, _dur(dur) , _dur(dur)
{} {}
Transition(uint16_t d, uint8_t b, uint8_t c, const uint32_t *o)
: _briT(b)
, _cctT(c)
, _palT(CRGBPalette16(CRGB::Black))
, _prevPaletteBlends(0)
, _modeP(FX_MODE_STATIC)
, _start(millis())
, _dur(d)
{
for (size_t i=0; i<NUM_COLORS; i++) _colorT[i] = o[i];
}
} *_t; } *_t;
public: public:
@ -471,6 +485,9 @@ typedef struct Segment {
_t(nullptr) _t(nullptr)
{ {
//refreshLightCapabilities(); //refreshLightCapabilities();
#ifdef WLED_DEBUG
//Serial.printf("-- Creating segment: %p\n", this);
#endif
} }
Segment(uint16_t sStartX, uint16_t sStopX, uint16_t sStartY, uint16_t sStopY) : Segment(sStartX, sStopX) { Segment(uint16_t sStartX, uint16_t sStopX, uint16_t sStartY, uint16_t sStopY) : Segment(sStartX, sStopX) {
@ -482,14 +499,14 @@ typedef struct Segment {
Segment(Segment &&orig) noexcept; // move constructor Segment(Segment &&orig) noexcept; // move constructor
~Segment() { ~Segment() {
//#ifdef WLED_DEBUG #ifdef WLED_DEBUG
//Serial.print(F("Destroying segment:")); //Serial.printf("-- Destroying segment: %p\n", this);
//if (name) Serial.printf(" %s (%p)", name, name); //if (name) Serial.printf(" %s (%p)", name, name);
//if (data) Serial.printf(" %d (%p)", (int)_dataLen, data); //if (data) Serial.printf(" %d (%p)", (int)_dataLen, data);
//Serial.println(); //Serial.println();
//#endif #endif
if (name) { delete[] name; name = nullptr; } if (name) { delete[] name; name = nullptr; }
if (_t) { transitional = false; delete _t; _t = nullptr; } stopTransition();
deallocateData(); deallocateData();
} }
@ -515,6 +532,9 @@ typedef struct Segment {
static uint16_t getUsedSegmentData(void) { return _usedSegmentData; } static uint16_t getUsedSegmentData(void) { return _usedSegmentData; }
static void addUsedSegmentData(int len) { _usedSegmentData += len; } static void addUsedSegmentData(int len) { _usedSegmentData += len; }
#ifndef WLED_DISABLE_MODE_BLEND
static void modeBlend(bool blend) { _modeBlend = blend; }
#endif
static void handleRandomPalette(); static void handleRandomPalette();
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, uint8_t segId = 255); 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, uint8_t segId = 255);
@ -542,7 +562,12 @@ typedef struct Segment {
// transition functions // transition functions
void startTransition(uint16_t dur); // transition has to start before actual segment values change void startTransition(uint16_t dur); // transition has to start before actual segment values change
void stopTransition(void);
void handleTransition(void); void handleTransition(void);
#ifndef WLED_DISABLE_MODE_BLEND
void swapSegenv(tmpsegd_t &tmpSegD);
void restoreSegenv(tmpsegd_t &tmpSegD);
#endif
uint16_t progress(void); //transition progression between 0-65535 uint16_t progress(void); //transition progression between 0-65535
uint8_t currentBri(uint8_t briNew, bool useCct = false); uint8_t currentBri(uint8_t briNew, bool useCct = false);
uint8_t currentMode(uint8_t modeNew); uint8_t currentMode(uint8_t modeNew);
@ -604,9 +629,9 @@ typedef struct Segment {
void fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c); void fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c);
void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c); void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c);
void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c) { drawLine(x0, y0, x1, y1, RGBW32(c.r,c.g,c.b,0)); } // automatic inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c) { drawLine(x0, y0, x1, y1, RGBW32(c.r,c.g,c.b,0)); } // automatic inline
void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2 = 0); void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2 = 0, int8_t rotate = 0);
void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0)); } // automatic inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0)); } // automatic inline
void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0), RGBW32(c2.r,c2.g,c2.b,0)); } // automatic inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2, int8_t rotate = 0) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0), RGBW32(c2.r,c2.g,c2.b,0), rotate); } // automatic inline
void wu_pixel(uint32_t x, uint32_t y, CRGB c); void wu_pixel(uint32_t x, uint32_t y, CRGB c);
void blur1d(fract8 blur_amount); // blur all rows in 1 dimension void blur1d(fract8 blur_amount); // blur all rows in 1 dimension
void blur2d(fract8 blur_amount) { blur(blur_amount); } void blur2d(fract8 blur_amount) { blur(blur_amount); }
@ -636,8 +661,9 @@ typedef struct Segment {
void fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c) {} void fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c) {}
void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c) {} void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c) {}
void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c) {} void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c) {}
void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color) {} void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t = 0, int8_t = 0) {}
void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB color) {} void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB color) {}
void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2, int8_t rotate = 0) {}
void wu_pixel(uint32_t x, uint32_t y, CRGB c) {} void wu_pixel(uint32_t x, uint32_t y, CRGB c) {}
#endif #endif
} segment; } segment;

View File

@ -216,23 +216,29 @@ void /*IRAM_ATTR*/ Segment::setPixelColorXY(int x, int y, uint32_t col)
y *= groupLength(); // expand to physical pixels y *= groupLength(); // expand to physical pixels
if (x >= width() || y >= height()) return; // if pixel would fall out of segment just exit if (x >= width() || y >= height()) return; // if pixel would fall out of segment just exit
uint32_t tmpCol = col;
for (int j = 0; j < grouping; j++) { // groupping vertically for (int j = 0; j < grouping; j++) { // groupping vertically
for (int g = 0; g < grouping; g++) { // groupping horizontally for (int g = 0; g < grouping; g++) { // groupping horizontally
uint16_t xX = (x+g), yY = (y+j); uint16_t xX = (x+g), yY = (y+j);
if (xX >= width() || yY >= height()) continue; // we have reached one dimension's end if (xX >= width() || yY >= height()) continue; // we have reached one dimension's end
strip.setPixelColorXY(start + xX, startY + yY, col); #ifndef WLED_DISABLE_MODE_BLEND
// if blending modes, blend with underlying pixel
if (_modeBlend) tmpCol = color_blend(strip.getPixelColorXY(start + xX, startY + yY), col, 0xFFFFU - progress(), true);
#endif
strip.setPixelColorXY(start + xX, startY + yY, tmpCol);
if (mirror) { //set the corresponding horizontally mirrored pixel if (mirror) { //set the corresponding horizontally mirrored pixel
if (transpose) strip.setPixelColorXY(start + xX, startY + height() - yY - 1, col); if (transpose) strip.setPixelColorXY(start + xX, startY + height() - yY - 1, tmpCol);
else strip.setPixelColorXY(start + width() - xX - 1, startY + yY, col); else strip.setPixelColorXY(start + width() - xX - 1, startY + yY, tmpCol);
} }
if (mirror_y) { //set the corresponding vertically mirrored pixel if (mirror_y) { //set the corresponding vertically mirrored pixel
if (transpose) strip.setPixelColorXY(start + width() - xX - 1, startY + yY, col); if (transpose) strip.setPixelColorXY(start + width() - xX - 1, startY + yY, tmpCol);
else strip.setPixelColorXY(start + xX, startY + height() - yY - 1, col); else strip.setPixelColorXY(start + xX, startY + height() - yY - 1, tmpCol);
} }
if (mirror_y && mirror) { //set the corresponding vertically AND horizontally mirrored pixel if (mirror_y && mirror) { //set the corresponding vertically AND horizontally mirrored pixel
strip.setPixelColorXY(width() - xX - 1, height() - yY - 1, col); strip.setPixelColorXY(width() - xX - 1, height() - yY - 1, tmpCol);
} }
} }
} }
@ -565,7 +571,7 @@ void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint3
// draws a raster font character on canvas // draws a raster font character on canvas
// only supports: 4x6=24, 5x8=40, 5x12=60, 6x8=48 and 7x9=63 fonts ATM // only supports: 4x6=24, 5x8=40, 5x12=60, 6x8=48 and 7x9=63 fonts ATM
void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2) { void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2, int8_t rotate) {
if (!isActive()) return; // not active if (!isActive()) return; // not active
if (chr < 32 || chr > 126) return; // only ASCII 32-126 supported if (chr < 32 || chr > 126) return; // only ASCII 32-126 supported
chr -= 32; // align with font table entries chr -= 32; // align with font table entries
@ -578,9 +584,6 @@ void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w,
//if (w<5 || w>6 || h!=8) return; //if (w<5 || w>6 || h!=8) return;
for (int i = 0; i<h; i++) { // character height for (int i = 0; i<h; i++) { // character height
int16_t y0 = y + i;
if (y0 < 0) continue; // drawing off-screen
if (y0 >= rows) break; // drawing off-screen
uint8_t bits = 0; uint8_t bits = 0;
switch (font) { switch (font) {
case 24: bits = pgm_read_byte_near(&console_font_4x6[(chr * h) + i]); break; // 5x8 font case 24: bits = pgm_read_byte_near(&console_font_4x6[(chr * h) + i]); break; // 5x8 font
@ -592,8 +595,16 @@ void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w,
} }
col = ColorFromPalette(grad, (i+1)*255/h, 255, NOBLEND); col = ColorFromPalette(grad, (i+1)*255/h, 255, NOBLEND);
for (int j = 0; j<w; j++) { // character width for (int j = 0; j<w; j++) { // character width
int16_t x0 = x + (w-1) - j; int x0, y0;
if ((x0 >= 0 || x0 < cols) && ((bits>>(j+(8-w))) & 0x01)) { // bit set & drawing on-screen switch (rotate) {
case -1: x0 = x + (h-1) - i; y0 = y + (w-1) - j; break; // -90 deg
case -2:
case 2: x0 = x + j; y0 = y + (h-1) - i; break; // 180 deg
case 1: x0 = x + i; y0 = y + j; break; // +90 deg
default: x0 = x + (w-1) - j; y0 = y + i; break; // no rotation
}
if (x0 < 0 || x0 >= cols || y0 < 0 || y0 >= rows) continue; // drawing off-screen
if (((bits>>(j+(8-w))) & 0x01)) { // bit set
setPixelColorXY(x0, y0, col); setPixelColorXY(x0, y0, col);
} }
} }

View File

@ -81,9 +81,13 @@ CRGBPalette16 Segment::_randomPalette = CRGBPalette16(DEFAULT_COLOR);
CRGBPalette16 Segment::_newRandomPalette = CRGBPalette16(DEFAULT_COLOR); CRGBPalette16 Segment::_newRandomPalette = CRGBPalette16(DEFAULT_COLOR);
unsigned long Segment::_lastPaletteChange = 0; // perhaps it should be per segment unsigned long Segment::_lastPaletteChange = 0; // perhaps it should be per segment
#ifndef WLED_DISABLE_MODE_BLEND
bool Segment::_modeBlend = false;
#endif
// copy constructor // copy constructor
Segment::Segment(const Segment &orig) { Segment::Segment(const Segment &orig) {
//DEBUG_PRINTLN(F("-- Copy segment constructor --")); //DEBUG_PRINTF("-- Copy segment constructor: %p -> %p\n", &orig, this);
memcpy((void*)this, (void*)&orig, sizeof(Segment)); memcpy((void*)this, (void*)&orig, sizeof(Segment));
transitional = false; // copied segment cannot be in transition transitional = false; // copied segment cannot be in transition
name = nullptr; name = nullptr;
@ -92,12 +96,12 @@ Segment::Segment(const Segment &orig) {
_t = nullptr; _t = nullptr;
if (orig.name) { name = new char[strlen(orig.name)+1]; if (name) strcpy(name, orig.name); } if (orig.name) { name = new char[strlen(orig.name)+1]; if (name) strcpy(name, orig.name); }
if (orig.data) { if (allocateData(orig._dataLen)) memcpy(data, orig.data, orig._dataLen); } if (orig.data) { if (allocateData(orig._dataLen)) memcpy(data, orig.data, orig._dataLen); }
//if (orig._t) { _t = new Transition(orig._t->_dur, orig._t->_briT, orig._t->_cctT, orig._t->_colorT); } //if (orig._t) { _t = new Transition(orig._t->_dur); }
} }
// move constructor // move constructor
Segment::Segment(Segment &&orig) noexcept { Segment::Segment(Segment &&orig) noexcept {
//DEBUG_PRINTLN(F("-- Move segment constructor --")); //DEBUG_PRINTF("-- Move segment constructor: %p -> %p\n", &orig, this);
memcpy((void*)this, (void*)&orig, sizeof(Segment)); memcpy((void*)this, (void*)&orig, sizeof(Segment));
orig.transitional = false; // old segment cannot be in transition any more orig.transitional = false; // old segment cannot be in transition any more
orig.name = nullptr; orig.name = nullptr;
@ -108,12 +112,17 @@ Segment::Segment(Segment &&orig) noexcept {
// copy assignment // copy assignment
Segment& Segment::operator= (const Segment &orig) { Segment& Segment::operator= (const Segment &orig) {
//DEBUG_PRINTLN(F("-- Copying segment --")); //DEBUG_PRINTF("-- Copying segment: %p -> %p\n", &orig, this);
if (this != &orig) { if (this != &orig) {
// clean destination // clean destination
transitional = false; // copied segment cannot be in transition transitional = false; // copied segment cannot be in transition
if (name) delete[] name; if (name) delete[] name;
if (_t) delete _t; if (_t) {
#ifndef WLED_DISABLE_MODE_BLEND
if (_t->_segT._dataT) free(_t->_segT._dataT);
#endif
delete _t;
}
deallocateData(); deallocateData();
// copy source // copy source
memcpy((void*)this, (void*)&orig, sizeof(Segment)); memcpy((void*)this, (void*)&orig, sizeof(Segment));
@ -133,12 +142,18 @@ Segment& Segment::operator= (const Segment &orig) {
// move assignment // move assignment
Segment& Segment::operator= (Segment &&orig) noexcept { Segment& Segment::operator= (Segment &&orig) noexcept {
//DEBUG_PRINTLN(F("-- Moving segment --")); //DEBUG_PRINTF("-- Moving segment: %p -> %p\n", &orig, this);
if (this != &orig) { if (this != &orig) {
transitional = false; // just temporary transitional = false; // just temporary
if (name) { delete[] name; name = nullptr; } // free old name if (name) { delete[] name; name = nullptr; } // free old name
deallocateData(); // free old runtime data deallocateData(); // free old runtime data
if (_t) { delete _t; _t = nullptr; } if (_t) {
#ifndef WLED_DISABLE_MODE_BLEND
if (_t->_segT._dataT) free(_t->_segT._dataT);
#endif
delete _t;
_t = nullptr;
}
memcpy((void*)this, (void*)&orig, sizeof(Segment)); memcpy((void*)this, (void*)&orig, sizeof(Segment));
orig.transitional = false; // old segment cannot be in transition orig.transitional = false; // old segment cannot be in transition
orig.name = nullptr; orig.name = nullptr;
@ -151,22 +166,39 @@ Segment& Segment::operator= (Segment &&orig) noexcept {
bool Segment::allocateData(size_t len) { bool Segment::allocateData(size_t len) {
if (data && _dataLen == len) return true; //already allocated if (data && _dataLen == len) return true; //already allocated
//DEBUG_PRINTF("-- Allocating data (%d): %p\n", len, this);
deallocateData(); deallocateData();
if (Segment::getUsedSegmentData() + len > MAX_SEGMENT_DATA) return false; //not enough memory if (len == 0) return(false); // nothing to do
if (Segment::getUsedSegmentData() + len > MAX_SEGMENT_DATA) {
// not enough memory
DEBUG_PRINT(F("!!! Effect RAM depleted: "));
DEBUG_PRINTF("%d/%d !!!\n", len, Segment::getUsedSegmentData());
return false;
}
// do not use SPI RAM on ESP32 since it is slow // do not use SPI RAM on ESP32 since it is slow
data = (byte*) malloc(len); data = (byte*) malloc(len);
if (!data) return false; //allocation failed if (!data) { DEBUG_PRINTLN(F("!!! Allocation failed. !!!")); return false; } //allocation failed
Segment::addUsedSegmentData(len); Segment::addUsedSegmentData(len);
//DEBUG_PRINTF("--- Allocated data (%p): %d/%d -> %p\n", this, len, Segment::getUsedSegmentData(), data);
_dataLen = len; _dataLen = len;
memset(data, 0, len); memset(data, 0, len);
return true; return true;
} }
void Segment::deallocateData() { void Segment::deallocateData() {
if (!data) return; if (!data) { _dataLen = 0; return; }
free(data); //DEBUG_PRINTF("--- Released data (%p): %d/%d -> %p\n", this, _dataLen, Segment::getUsedSegmentData(), data);
if ((Segment::getUsedSegmentData() > 0) && (_dataLen > 0)) { // check that we don't have a dangling / inconsistent data pointer
free(data);
} else {
DEBUG_PRINT(F("---- Released data "));
DEBUG_PRINTF("(%p): ", this);
DEBUG_PRINT(F("inconsistent UsedSegmentData "));
DEBUG_PRINTF("(%d/%d)", _dataLen, Segment::getUsedSegmentData());
DEBUG_PRINTLN(F(", cowardly refusing to free nothing."));
}
data = nullptr; data = nullptr;
Segment::addUsedSegmentData(-_dataLen); Segment::addUsedSegmentData(_dataLen <= Segment::getUsedSegmentData() ? -_dataLen : -Segment::getUsedSegmentData());
_dataLen = 0; _dataLen = 0;
} }
@ -179,7 +211,7 @@ void Segment::deallocateData() {
*/ */
void Segment::resetIfRequired() { void Segment::resetIfRequired() {
if (!reset) return; if (!reset) return;
//DEBUG_PRINTF("-- Segment reset: %p\n", this);
deallocateData(); deallocateData();
next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0; next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0;
reset = false; reset = false;
@ -215,7 +247,7 @@ CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) {
CHSV(random8(), random8(160, 255), random8(128, 255)), CHSV(random8(), random8(160, 255), random8(128, 255)),
CHSV(random8(), random8(160, 255), random8(128, 255))); CHSV(random8(), random8(160, 255), random8(128, 255)));
_lastPaletteChange = millis(); _lastPaletteChange = millis();
handleRandomPalette(); // do initial blend handleRandomPalette(); // do a 1st pass of blend
} }
targetPalette = _randomPalette; targetPalette = _randomPalette;
break;} break;}
@ -270,11 +302,8 @@ CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) {
void Segment::startTransition(uint16_t dur) { void Segment::startTransition(uint16_t dur) {
if (!dur) { if (!dur) {
transitional = false; if (_t) _t->_dur = dur; // this will stop transition in next handleTransisiton()
if (_t) { else transitional = false;
delete _t;
_t = nullptr;
}
return; return;
} }
if (transitional && _t) return; // already in transition no need to store anything if (transitional && _t) return; // already in transition no need to store anything
@ -283,44 +312,165 @@ void Segment::startTransition(uint16_t dur) {
_t = new Transition(dur); // no previous transition running _t = new Transition(dur); // no previous transition running
if (!_t) return; // failed to allocate data if (!_t) return; // failed to allocate data
//DEBUG_PRINTF("-- Started transition: %p\n", this);
CRGBPalette16 _palT = CRGBPalette16(DEFAULT_COLOR); loadPalette(_palT, palette); CRGBPalette16 _palT = CRGBPalette16(DEFAULT_COLOR); loadPalette(_palT, palette);
_t->_briT = on ? opacity : 0; _t->_palT = _palT;
_t->_cctT = cct; _t->_briT = on ? opacity : 0;
_t->_palT = _palT; _t->_cctT = cct;
_t->_modeP = mode; #ifndef WLED_DISABLE_MODE_BLEND
swapSegenv(_t->_segT);
_t->_modeT = mode;
_t->_segT._optionsT |= 0b0000000001000000; // mark old segment transitional
_t->_segT._dataLenT = 0;
_t->_segT._dataT = nullptr;
if (_dataLen > 0 && data) {
_t->_segT._dataT = (byte *)malloc(_dataLen);
if (_t->_segT._dataT) {
//DEBUG_PRINTF("-- Allocated duplicate data (%d): %p\n", _dataLen, _t->_segT._dataT);
memcpy(_t->_segT._dataT, data, _dataLen);
_t->_segT._dataLenT = _dataLen;
}
}
#else
for (size_t i=0; i<NUM_COLORS; i++) _t->_colorT[i] = colors[i]; for (size_t i=0; i<NUM_COLORS; i++) _t->_colorT[i] = colors[i];
#endif
transitional = true; // setOption(SEG_OPTION_TRANSITIONAL, true); transitional = true; // setOption(SEG_OPTION_TRANSITIONAL, true);
} }
void Segment::stopTransition() {
if (!transitional) return;
transitional = false; // finish transitioning segment
//DEBUG_PRINTF("-- Stopping transition: %p\n", this);
if (_t) {
#ifndef WLED_DISABLE_MODE_BLEND
if (_t->_segT._dataT && _t->_segT._dataLenT > 0) {
//DEBUG_PRINTF("-- Released duplicate data (%d): %p\n", _t->_segT._dataLenT, _t->_segT._dataT);
free(_t->_segT._dataT);
_t->_segT._dataT = nullptr;
_t->_segT._dataLenT = 0;
}
#endif
delete _t;
_t = nullptr;
}
}
void Segment::handleTransition() {
if (!transitional) return;
uint16_t _progress = progress();
if (_progress == 0xFFFFU) stopTransition();
}
// transition progression between 0-65535 // transition progression between 0-65535
uint16_t Segment::progress() { uint16_t Segment::progress() {
if (!transitional || !_t) return 0xFFFFU; if (transitional && _t) {
unsigned long timeNow = millis(); unsigned long timeNow = millis();
if (timeNow - _t->_start > _t->_dur || _t->_dur == 0) return 0xFFFFU; if (_t->_dur > 0 && timeNow - _t->_start < _t->_dur) return (timeNow - _t->_start) * 0xFFFFU / _t->_dur;
return (timeNow - _t->_start) * 0xFFFFU / _t->_dur; }
return 0xFFFFU;
} }
#ifndef WLED_DISABLE_MODE_BLEND
void Segment::swapSegenv(tmpsegd_t &tmpSeg) {
//DEBUG_PRINTF("-- Saving temp seg: %p (%p)\n", this, tmpSeg);
tmpSeg._optionsT = options;
for (size_t i=0; i<NUM_COLORS; i++) tmpSeg._colorT[i] = colors[i];
tmpSeg._speedT = speed;
tmpSeg._intensityT = intensity;
tmpSeg._custom1T = custom1;
tmpSeg._custom2T = custom2;
tmpSeg._custom3T = custom3;
tmpSeg._check1T = check1;
tmpSeg._check2T = check2;
tmpSeg._check3T = check3;
tmpSeg._aux0T = aux0;
tmpSeg._aux1T = aux1;
tmpSeg._stepT = step;
tmpSeg._callT = call;
tmpSeg._dataT = data;
tmpSeg._dataLenT = _dataLen;
if (_t && &tmpSeg != &(_t->_segT)) {
// swap SEGENV with transitional data
options = _t->_segT._optionsT;
for (size_t i=0; i<NUM_COLORS; i++) colors[i] = _t->_segT._colorT[i];
speed = _t->_segT._speedT;
intensity = _t->_segT._intensityT;
custom1 = _t->_segT._custom1T;
custom2 = _t->_segT._custom2T;
custom3 = _t->_segT._custom3T;
check1 = _t->_segT._check1T;
check2 = _t->_segT._check2T;
check3 = _t->_segT._check3T;
aux0 = _t->_segT._aux0T;
aux1 = _t->_segT._aux1T;
step = _t->_segT._stepT;
call = _t->_segT._callT;
data = _t->_segT._dataT;
_dataLen = _t->_segT._dataLenT;
}
//DEBUG_PRINTF("-- temp seg data: %p (%d,%p)\n", this, _dataLen, data);
}
void Segment::restoreSegenv(tmpsegd_t &tmpSeg) {
//DEBUG_PRINTF("-- Restoring temp seg: %p (%p)\n", this, tmpSeg);
if (_t && &(_t->_segT) != &tmpSeg) {
// update possibly changed variables to keep old effect running correctly
_t->_segT._aux0T = aux0;
_t->_segT._aux1T = aux1;
_t->_segT._stepT = step;
_t->_segT._callT = call;
//if (_t->_segT._dataT != data) DEBUG_PRINTF("--- data re-allocated: (%p) %p -> %p\n", this, _t->_segT._dataT, data);
_t->_segT._dataT = data; // sometimes memory gets re-allocated (!! INVESTIGATE WHY !!)
_t->_segT._dataLenT = _dataLen; // sometimes memory gets re-allocated (!! INVESTIGATE WHY !!)
}
options = tmpSeg._optionsT;
for (size_t i=0; i<NUM_COLORS; i++) colors[i] = tmpSeg._colorT[i];
speed = tmpSeg._speedT;
intensity = tmpSeg._intensityT;
custom1 = tmpSeg._custom1T;
custom2 = tmpSeg._custom2T;
custom3 = tmpSeg._custom3T;
check1 = tmpSeg._check1T;
check2 = tmpSeg._check2T;
check3 = tmpSeg._check3T;
aux0 = tmpSeg._aux0T;
aux1 = tmpSeg._aux1T;
step = tmpSeg._stepT;
call = tmpSeg._callT;
data = tmpSeg._dataT;
_dataLen = tmpSeg._dataLenT;
//DEBUG_PRINTF("-- temp seg data: %p (%d,%p)\n", this, _dataLen, data);
}
#endif
uint8_t Segment::currentBri(uint8_t briNew, bool useCct) { uint8_t Segment::currentBri(uint8_t briNew, bool useCct) {
uint32_t prog = progress(); uint32_t prog = progress();
if (transitional && _t && prog < 0xFFFFU) { if (prog < 0xFFFFU) {
if (useCct) return ((briNew * prog) + _t->_cctT * (0xFFFFU - prog)) >> 16; if (useCct) return ((briNew * prog) + _t->_cctT * (0xFFFFU - prog)) >> 16;
else return ((briNew * prog) + _t->_briT * (0xFFFFU - prog)) >> 16; else return ((briNew * prog) + _t->_briT * (0xFFFFU - prog)) >> 16;
} else {
return briNew;
} }
return briNew;
} }
uint8_t Segment::currentMode(uint8_t newMode) { uint8_t Segment::currentMode(uint8_t newMode) {
return (progress()>32767U) ? newMode : _t->_modeP; // change effect in the middle of transition #ifndef WLED_DISABLE_MODE_BLEND
uint16_t prog = progress(); // implicit check for transitional & _t in progress()
if (prog < 0xFFFFU) return _t->_modeT;
#endif
return newMode;
} }
uint32_t Segment::currentColor(uint8_t slot, uint32_t colorNew) { uint32_t Segment::currentColor(uint8_t slot, uint32_t colorNew) {
#ifndef WLED_DISABLE_MODE_BLEND
return transitional && _t ? color_blend(_t->_segT._colorT[slot], colorNew, progress(), true) : colorNew;
#else
return transitional && _t ? color_blend(_t->_colorT[slot], colorNew, progress(), true) : colorNew; return transitional && _t ? color_blend(_t->_colorT[slot], colorNew, progress(), true) : colorNew;
#endif
} }
CRGBPalette16 &Segment::currentPalette(CRGBPalette16 &targetPalette, uint8_t pal) { CRGBPalette16 &Segment::currentPalette(CRGBPalette16 &targetPalette, uint8_t pal) {
loadPalette(targetPalette, pal); loadPalette(targetPalette, pal);
if (transitional && _t && progress() < 0xFFFFU) { if (progress() < 0xFFFFU) {
// blend palettes // blend palettes
// there are about 255 blend passes of 48 "blends" to completely blend two palettes (in _dur time) // there are about 255 blend passes of 48 "blends" to completely blend two palettes (in _dur time)
// minimum blend time is 100ms maximum is 65535ms // minimum blend time is 100ms maximum is 65535ms
@ -332,18 +482,6 @@ CRGBPalette16 &Segment::currentPalette(CRGBPalette16 &targetPalette, uint8_t pal
return targetPalette; return targetPalette;
} }
void Segment::handleTransition() {
if (!transitional) return;
uint16_t _progress = progress();
if (_progress == 0xFFFFU) transitional = false; // finish transitioning segment
if (_t) { // thanks to @nXm AKA https://github.com/NMeirer
if (_progress == 0xFFFFU) {
delete _t;
_t = nullptr;
}
}
}
// relies on WS2812FX::service() to call it max every 8ms or more (MIN_SHOW_DELAY) // relies on WS2812FX::service() to call it max every 8ms or more (MIN_SHOW_DELAY)
void Segment::handleRandomPalette() { void Segment::handleRandomPalette() {
// just do a blend; if the palettes are identical it will just compare 48 bytes (same as _randomPalette == _newRandomPalette) // just do a blend; if the palettes are identical it will just compare 48 bytes (same as _randomPalette == _newRandomPalette)
@ -426,6 +564,7 @@ void Segment::setCCT(uint16_t k) {
void Segment::setOpacity(uint8_t o) { void Segment::setOpacity(uint8_t o) {
if (opacity == o) return; if (opacity == o) return;
if (fadeTransition) startTransition(strip.getTransition()); // start transition prior to change if (fadeTransition) startTransition(strip.getTransition()); // start transition prior to change
DEBUG_PRINT(F("-- Setting opacity: ")); DEBUG_PRINTLN(o);
opacity = o; opacity = o;
stateChanged = true; // send UDP/WS broadcast stateChanged = true; // send UDP/WS broadcast
} }
@ -444,7 +583,6 @@ void Segment::setMode(uint8_t fx, bool loadDefaults) {
if (fx != mode) { if (fx != mode) {
if (fadeTransition) startTransition(strip.getTransition()); // set effect transitions if (fadeTransition) startTransition(strip.getTransition()); // set effect transitions
mode = fx; mode = fx;
// load default values from effect string // load default values from effect string
if (loadDefaults) { if (loadDefaults) {
int16_t sOpt; int16_t sOpt;
@ -625,6 +763,7 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col)
} }
i += start; // starting pixel in a group i += start; // starting pixel in a group
uint32_t tmpCol = col;
// set all the pixels in the group // set all the pixels in the group
for (int j = 0; j < grouping; j++) { for (int j = 0; j < grouping; j++) {
uint16_t indexSet = i + ((reverse) ? -j : j); uint16_t indexSet = i + ((reverse) ? -j : j);
@ -633,11 +772,17 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col)
uint16_t indexMir = stop - indexSet + start - 1; uint16_t indexMir = stop - indexSet + start - 1;
indexMir += offset; // offset/phase indexMir += offset; // offset/phase
if (indexMir >= stop) indexMir -= len; // wrap if (indexMir >= stop) indexMir -= len; // wrap
strip.setPixelColor(indexMir, col); #ifndef WLED_DISABLE_MODE_BLEND
if (_modeBlend) tmpCol = color_blend(strip.getPixelColor(indexMir), col, 0xFFFFU - progress(), true);
#endif
strip.setPixelColor(indexMir, tmpCol);
} }
indexSet += offset; // offset/phase indexSet += offset; // offset/phase
if (indexSet >= stop) indexSet -= len; // wrap if (indexSet >= stop) indexSet -= len; // wrap
strip.setPixelColor(indexSet, col); #ifndef WLED_DISABLE_MODE_BLEND
if (_modeBlend) tmpCol = color_blend(strip.getPixelColor(indexSet), col, 0xFFFFU - progress(), true);
#endif
strip.setPixelColor(indexSet, tmpCol);
} }
} }
} }
@ -843,7 +988,7 @@ void Segment::fade_out(uint8_t rate) {
const uint16_t rows = virtualHeight(); // will be 1 for 1D const uint16_t rows = virtualHeight(); // will be 1 for 1D
rate = (255-rate) >> 1; rate = (255-rate) >> 1;
float mappedRate = float(rate) +1.1; float mappedRate = float(rate) +1.1f;
uint32_t color = colors[1]; // SEGCOLOR(1); // target color uint32_t color = colors[1]; // SEGCOLOR(1); // target color
int w2 = W(color); int w2 = W(color);
@ -1079,8 +1224,10 @@ void WS2812FX::service() {
// reset the segment runtime data if needed // reset the segment runtime data if needed
seg.resetIfRequired(); seg.resetIfRequired();
if (!seg.isActive()) continue;
// last condition ensures all solid segments are updated at the same time // last condition ensures all solid segments are updated at the same time
if (seg.isActive() && (nowUp > seg.next_time || _triggered || (doShow && seg.mode == FX_MODE_STATIC))) if (nowUp > seg.next_time || _triggered || (doShow && seg.mode == FX_MODE_STATIC))
{ {
doShow = true; doShow = true;
uint16_t delay = FRAMETIME; uint16_t delay = FRAMETIME;
@ -1095,10 +1242,25 @@ void WS2812FX::service() {
if (!cctFromRgb || correctWB) busses.setSegmentCCT(seg.currentBri(seg.cct, true), correctWB); if (!cctFromRgb || correctWB) busses.setSegmentCCT(seg.currentBri(seg.cct, true), correctWB);
for (uint8_t c = 0; c < NUM_COLORS; c++) _colors_t[c] = gamma32(_colors_t[c]); for (uint8_t c = 0; c < NUM_COLORS; c++) _colors_t[c] = gamma32(_colors_t[c]);
// effect blending (execute previous effect) // Effect blending
// actual code may be a bit more involved as effects have runtime data including allocated memory // When two effects are being blended, each may have different segment data, this
//if (seg.transitional && seg._modeP) (*_mode[seg._modeP])(progress()); // data needs to be saved first and then restored before running previous/transitional mode.
delay = (*_mode[seg.currentMode(seg.mode)])(); // The blending will largely depend on the effect behaviour since actual output (LEDs) may be
// 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(seg.mode); // this will return old mode while in transition
delay = (*_mode[seg.mode])(); // run new/current mode
#ifndef WLED_DISABLE_MODE_BLEND
if (seg.mode != tmpMode) {
Segment::tmpsegd_t _tmpSegData;
Segment::modeBlend(true); // set semaphore
seg.swapSegenv(_tmpSegData); // temporarily store new mode state (and swap it with transitional state)
uint16_t d2 = (*_mode[tmpMode])(); // run old mode
seg.restoreSegenv(_tmpSegData); // restore mode state (will also update transitional state)
delay = MIN(delay,d2); // use shortest delay
Segment::modeBlend(false); // unset semaphore
}
#endif
if (seg.mode != FX_MODE_HALLOWEEN_EYES) seg.call++; if (seg.mode != FX_MODE_HALLOWEEN_EYES) seg.call++;
if (seg.transitional && delay > FRAMETIME) delay = FRAMETIME; // force faster updates during transition if (seg.transitional && delay > FRAMETIME) delay = FRAMETIME; // force faster updates during transition
} }
@ -1273,9 +1435,7 @@ void WS2812FX::setMode(uint8_t segid, uint8_t m) {
if (m >= getModeCount()) m = getModeCount() - 1; if (m >= getModeCount()) m = getModeCount() - 1;
if (_segments[segid].mode != m) { if (_segments[segid].mode != m) {
_segments[segid].startTransition(_transitionDur); // set effect transitions _segments[segid].setMode(m); // do not load defaults
_segments[segid].markForReset();
_segments[segid].mode = m;
} }
} }
@ -1413,7 +1573,7 @@ void WS2812FX::purgeSegments(bool force) {
} }
if (deleted) { if (deleted) {
_segments.shrink_to_fit(); _segments.shrink_to_fit();
if (_mainSegment >= _segments.size()) setMainSegmentId(0); /*if (_mainSegment >= _segments.size())*/ setMainSegmentId(0);
} }
} }

View File

@ -144,10 +144,14 @@ void BusDigital::show() {
c = RGBW32(_data[offset],_data[offset+1],_data[offset+2],(Bus::hasWhite(_type)?_data[offset+3]:0)); c = RGBW32(_data[offset],_data[offset+1],_data[offset+2],(Bus::hasWhite(_type)?_data[offset+3]:0));
} }
uint16_t pix = i; uint16_t pix = i;
if (_reversed) pix = _len - pix -1; if (_reversed) pix = _len - pix -1;
else pix += _skip; pix += _skip;
PolyBus::setPixelColor(_busPtr, _iType, pix, c, co); PolyBus::setPixelColor(_busPtr, _iType, pix, c, co);
} }
#if !defined(STATUSLED) || STATUSLED>=0
if (_skip) PolyBus::setPixelColor(_busPtr, _iType, 0, 0, _colorOrderMap.getPixelColorOrder(_start, _colorOrder)); // paint skipped pixels black
#endif
for (int i=1; i<_skip; i++) PolyBus::setPixelColor(_busPtr, _iType, i, 0, _colorOrderMap.getPixelColorOrder(_start, _colorOrder)); // paint skipped pixels black
} }
PolyBus::show(_busPtr, _iType, !_buffering); // faster if buffer consistency is not important PolyBus::show(_busPtr, _iType, !_buffering); // faster if buffer consistency is not important
} }
@ -206,8 +210,8 @@ void IRAM_ATTR BusDigital::setPixelColor(uint16_t pix, uint32_t c) {
} }
if (Bus::hasWhite(_type)) _data[offset] = W(c); if (Bus::hasWhite(_type)) _data[offset] = W(c);
} else { } else {
if (_reversed) pix = _len - pix -1; if (_reversed) pix = _len - pix -1;
else pix += _skip; pix += _skip;
uint8_t co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder); uint8_t co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder);
if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs
uint16_t pOld = pix; uint16_t pOld = pix;
@ -237,8 +241,8 @@ uint32_t BusDigital::getPixelColor(uint16_t pix) {
} }
return c; return c;
} else { } else {
if (_reversed) pix = _len - pix -1; if (_reversed) pix = _len - pix -1;
else pix += _skip; pix += _skip;
uint8_t co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder); uint8_t co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder);
uint32_t c = restoreColorLossy(PolyBus::getPixelColor(_busPtr, _iType, (_type==TYPE_WS2812_1CH_X3) ? IC_INDEX_WS2812_1CH_3X(pix) : pix, co),_bri); uint32_t c = restoreColorLossy(PolyBus::getPixelColor(_busPtr, _iType, (_type==TYPE_WS2812_1CH_X3) ? IC_INDEX_WS2812_1CH_3X(pix) : pix, co),_bri);
if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs

View File

@ -21,6 +21,7 @@ void shortPressAction(uint8_t b)
case 1: ++effectCurrent %= strip.getModeCount(); stateChanged = true; colorUpdated(CALL_MODE_BUTTON); break; case 1: ++effectCurrent %= strip.getModeCount(); stateChanged = true; colorUpdated(CALL_MODE_BUTTON); break;
} }
} else { } else {
unloadPlaylist(); // applying a preset unloads the playlist
applyPreset(macroButton[b], CALL_MODE_BUTTON_PRESET); applyPreset(macroButton[b], CALL_MODE_BUTTON_PRESET);
} }
@ -42,6 +43,7 @@ void longPressAction(uint8_t b)
case 1: bri += 8; stateUpdated(CALL_MODE_BUTTON); buttonPressedTime[b] = millis(); break; // repeatable action case 1: bri += 8; stateUpdated(CALL_MODE_BUTTON); buttonPressedTime[b] = millis(); break; // repeatable action
} }
} else { } else {
unloadPlaylist(); // applying a preset unloads the playlist
applyPreset(macroLongPress[b], CALL_MODE_BUTTON_PRESET); applyPreset(macroLongPress[b], CALL_MODE_BUTTON_PRESET);
} }
@ -63,6 +65,7 @@ void doublePressAction(uint8_t b)
case 1: ++effectPalette %= strip.getPaletteCount(); colorUpdated(CALL_MODE_BUTTON); break; case 1: ++effectPalette %= strip.getPaletteCount(); colorUpdated(CALL_MODE_BUTTON); break;
} }
} else { } else {
unloadPlaylist(); // applying a preset unloads the playlist
applyPreset(macroDoublePress[b], CALL_MODE_BUTTON_PRESET); applyPreset(macroDoublePress[b], CALL_MODE_BUTTON_PRESET);
} }
@ -153,6 +156,7 @@ void handleAnalog(uint8_t b)
#ifdef ESP8266 #ifdef ESP8266
rawReading = analogRead(A0) << 2; // convert 10bit read to 12bit rawReading = analogRead(A0) << 2; // convert 10bit read to 12bit
#else #else
if ((btnPin[b] < 0) || (digitalPinToAnalogChannel(btnPin[b]) < 0)) return; // pin must support analog ADC - newer esp32 frameworks throw lots of warnings otherwise
rawReading = analogRead(btnPin[b]); // collect at full 12bit resolution rawReading = analogRead(btnPin[b]); // collect at full 12bit resolution
#endif #endif
yield(); // keep WiFi task running - analog read may take several millis on ESP8266 yield(); // keep WiFi task running - analog read may take several millis on ESP8266
@ -185,7 +189,7 @@ void handleAnalog(uint8_t b)
if (aRead == 0) { if (aRead == 0) {
briLast = bri; briLast = bri;
bri = 0; bri = 0;
} else{ } else {
bri = aRead; bri = aRead;
} }
} else if (macroDoublePress[b] == 249) { } else if (macroDoublePress[b] == 249) {
@ -262,7 +266,7 @@ void handleButton()
shortPressAction(b); shortPressAction(b);
buttonPressedBefore[b] = true; buttonPressedBefore[b] = true;
buttonPressedTime[b] = now; // continually update (for debouncing to work in release handler) buttonPressedTime[b] = now; // continually update (for debouncing to work in release handler)
return; continue;
} }
if (!buttonPressedBefore[b]) buttonPressedTime[b] = now; if (!buttonPressedBefore[b]) buttonPressedTime[b] = now;
@ -283,7 +287,7 @@ void handleButton()
// released after rising-edge short press action // released after rising-edge short press action
if (macroButton[b] && macroButton[b] == macroLongPress[b] && macroButton[b] == macroDoublePress[b]) { if (macroButton[b] && macroButton[b] == macroLongPress[b] && macroButton[b] == macroDoublePress[b]) {
if (dur > WLED_DEBOUNCE_THRESHOLD) buttonPressedBefore[b] = false; // debounce, blocks button for 50 ms once it has been released if (dur > WLED_DEBOUNCE_THRESHOLD) buttonPressedBefore[b] = false; // debounce, blocks button for 50 ms once it has been released
return; continue;
} }
if (dur < WLED_DEBOUNCE_THRESHOLD) {buttonPressedBefore[b] = false; continue;} // too short "press", debounce if (dur < WLED_DEBOUNCE_THRESHOLD) {buttonPressedBefore[b] = false; continue;} // too short "press", debounce

View File

@ -442,14 +442,14 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
#ifdef WLED_ENABLE_MQTT #ifdef WLED_ENABLE_MQTT
JsonObject if_mqtt = interfaces["mqtt"]; JsonObject if_mqtt = interfaces["mqtt"];
CJSON(mqttEnabled, if_mqtt["en"]); CJSON(mqttEnabled, if_mqtt["en"]);
getStringFromJson(mqttServer, if_mqtt[F("broker")], 33); getStringFromJson(mqttServer, if_mqtt[F("broker")], MQTT_MAX_SERVER_LEN+1);
CJSON(mqttPort, if_mqtt["port"]); // 1883 CJSON(mqttPort, if_mqtt["port"]); // 1883
getStringFromJson(mqttUser, if_mqtt[F("user")], 41); getStringFromJson(mqttUser, if_mqtt[F("user")], 41);
getStringFromJson(mqttPass, if_mqtt["psk"], 65); //normally not present due to security getStringFromJson(mqttPass, if_mqtt["psk"], 65); //normally not present due to security
getStringFromJson(mqttClientID, if_mqtt[F("cid")], 41); getStringFromJson(mqttClientID, if_mqtt[F("cid")], 41);
getStringFromJson(mqttDeviceTopic, if_mqtt[F("topics")][F("device")], 33); // "wled/test" getStringFromJson(mqttDeviceTopic, if_mqtt[F("topics")][F("device")], MQTT_MAX_TOPIC_LEN+1); // "wled/test"
getStringFromJson(mqttGroupTopic, if_mqtt[F("topics")][F("group")], 33); // "" getStringFromJson(mqttGroupTopic, if_mqtt[F("topics")][F("group")], MQTT_MAX_TOPIC_LEN+1); // ""
CJSON(retainMqttMsg, if_mqtt[F("rtn")]); CJSON(retainMqttMsg, if_mqtt[F("rtn")]);
#endif #endif
@ -481,7 +481,6 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
JsonObject if_ntp = interfaces[F("ntp")]; JsonObject if_ntp = interfaces[F("ntp")];
CJSON(ntpEnabled, if_ntp["en"]); CJSON(ntpEnabled, if_ntp["en"]);
getStringFromJson(ntpServerName, if_ntp[F("host")], 33); // "1.wled.pool.ntp.org" getStringFromJson(ntpServerName, if_ntp[F("host")], 33); // "1.wled.pool.ntp.org"
CJSON(ntpSyncInterval, if_ntp[F("int")]);
CJSON(currentTimezone, if_ntp[F("tz")]); CJSON(currentTimezone, if_ntp[F("tz")]);
CJSON(utcOffsetSecs, if_ntp[F("offset")]); CJSON(utcOffsetSecs, if_ntp[F("offset")]);
CJSON(useAMPM, if_ntp[F("ampm")]); CJSON(useAMPM, if_ntp[F("ampm")]);
@ -940,7 +939,6 @@ void serializeConfig() {
JsonObject if_ntp = interfaces.createNestedObject("ntp"); JsonObject if_ntp = interfaces.createNestedObject("ntp");
if_ntp["en"] = ntpEnabled; if_ntp["en"] = ntpEnabled;
if_ntp[F("host")] = ntpServerName; if_ntp[F("host")] = ntpServerName;
if_ntp[F("int")] = ntpSyncInterval;
if_ntp[F("tz")] = currentTimezone; if_ntp[F("tz")] = currentTimezone;
if_ntp[F("offset")] = utcOffsetSecs; if_ntp[F("offset")] = utcOffsetSecs;
if_ntp[F("ampm")] = useAMPM; if_ntp[F("ampm")] = useAMPM;

View File

@ -147,8 +147,9 @@
#define USERMOD_ID_SD_CARD 37 //Usermod "usermod_sd_card.h" #define USERMOD_ID_SD_CARD 37 //Usermod "usermod_sd_card.h"
#define USERMOD_ID_PWM_OUTPUTS 38 //Usermod "usermod_pwm_outputs.h #define USERMOD_ID_PWM_OUTPUTS 38 //Usermod "usermod_pwm_outputs.h
#define USERMOD_ID_SHT 39 //Usermod "usermod_sht.h #define USERMOD_ID_SHT 39 //Usermod "usermod_sht.h
#define USERMOD_ID_KLIPPER 40 // Usermod Klipper percentage #define USERMOD_ID_KLIPPER 40 //Usermod Klipper percentage
#define USERMOD_ID_WIREGUARD 41 //Usermod "wireguard.h" #define USERMOD_ID_WIREGUARD 41 //Usermod "wireguard.h"
#define USERMOD_ID_INTERNAL_TEMPERATURE 42 //Usermod "usermod_internal_temperature.h"
//Access point behavior //Access point behavior
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot #define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot

View File

@ -1034,6 +1034,7 @@ textarea {
/*padding: 1px 0 1px 20px;*/ /*padding: 1px 0 1px 20px;*/
display: var(--sgp); display: var(--sgp);
width: 100%; width: 100%;
position: relative;
} }
.pname { .pname {

View File

@ -683,6 +683,7 @@ ${i.opt&0x100?inforow("Debug","<button class=\"btn btn-xs\" onclick=\"requestJso
${inforow("Build",i.vid)} ${inforow("Build",i.vid)}
${inforow("Signal strength",i.wifi.signal +"% ("+ i.wifi.rssi, " dBm)")} ${inforow("Signal strength",i.wifi.signal +"% ("+ i.wifi.rssi, " dBm)")}
${inforow("Uptime",getRuntimeStr(i.uptime))} ${inforow("Uptime",getRuntimeStr(i.uptime))}
${inforow("Time",i.time)}
${inforow("Free heap",heap," kB")} ${inforow("Free heap",heap," kB")}
${i.psram?inforow("Free PSRAM",(i.psram/1024).toFixed(1)," kB"):""} ${i.psram?inforow("Free PSRAM",(i.psram/1024).toFixed(1)," kB"):""}
${inforow("Estimated current",pwru)} ${inforow("Estimated current",pwru)}
@ -834,7 +835,7 @@ function populateSegments(s)
} }
if (segCount < 2) { if (segCount < 2) {
gId(`segd${lSeg}`).classList.add("hide"); gId(`segd${lSeg}`).classList.add("hide");
gId(`segp0`).classList.add("hide"); if (parseInt(gId("seg0bri").value)==255) gId(`segp0`).classList.add("hide");
} }
if (!isM && !noNewSegs && (cfg.comp.seglen?parseInt(gId(`seg${lSeg}s`).value):0)+parseInt(gId(`seg${lSeg}e`).value)<ledCount) gId(`segr${lSeg}`).classList.remove("hide"); if (!isM && !noNewSegs && (cfg.comp.seglen?parseInt(gId(`seg${lSeg}s`).value):0)+parseInt(gId(`seg${lSeg}e`).value)<ledCount) gId(`segr${lSeg}`).classList.remove("hide");
gId('segutil2').style.display = (segCount > 1) ? "block":"none"; // rsbtn parent gId('segutil2').style.display = (segCount > 1) ? "block":"none"; // rsbtn parent
@ -1247,7 +1248,7 @@ function updateSelectedPalette(s)
if (s > 1 && s < 6) { if (s > 1 && s < 6) {
cd[0].classList.remove('hide'); // * Color 1 cd[0].classList.remove('hide'); // * Color 1
if (s > 2) cd[1].classList.remove('hide'); // * Color 1 & 2 if (s > 2) cd[1].classList.remove('hide'); // * Color 1 & 2
if (s == 5) cd[2].classList.remove('hide'); // all colors if (s > 3) cd[2].classList.remove('hide'); // all colors
} else { } else {
for (let i of cd) if (i.dataset.hide == '1') i.classList.add('hide'); for (let i of cd) if (i.dataset.hide == '1') i.classList.add('hide');
} }

View File

@ -2,7 +2,7 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/> <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport">
<title>WLED Settings</title> <title>WLED Settings</title>
<script> <script>
var d=document; var d=document;

View File

@ -2,8 +2,7 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=500"> <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport">
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
<title>2D Set-up</title> <title>2D Set-up</title>
<script> <script>
var d=document; var d=document;

View File

@ -1,8 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta name="viewport" content="width=500"> <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport">
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
<meta charset="utf-8"> <meta charset="utf-8">
<title>DMX Settings</title> <title>DMX Settings</title>
<script> <script>

View File

@ -2,8 +2,7 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=500"> <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport">
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
<title>LED Settings</title> <title>LED Settings</title>
<script> <script>
var d=document,laprev=55,maxB=1,maxV=0,maxM=4000,maxPB=4096,maxL=1333,maxLbquot=0; //maximum bytes for LED allocation: 4kB for 8266, 32kB for 32 var d=document,laprev=55,maxB=1,maxV=0,maxM=4000,maxPB=4096,maxL=1333,maxLbquot=0; //maximum bytes for LED allocation: 4kB for 8266, 32kB for 32

View File

@ -1,8 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta name="viewport" content="width=500"> <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport">
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
<meta charset="utf-8"> <meta charset="utf-8">
<title>PIN required</title> <title>PIN required</title>
<script> <script>

View File

@ -1,8 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta name="viewport" content="width=500"> <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport">
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Misc Settings</title> <title>Misc Settings</title>
<script> <script>

View File

@ -1,8 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta name="viewport" content="width=500"> <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport">
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Sync Settings</title> <title>Sync Settings</title>
<script>var d=document; <script>var d=document;

View File

@ -1,8 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta name="viewport" content="width=500"> <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport">
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Time Settings</title> <title>Time Settings</title>
<script> <script>
@ -171,13 +170,6 @@
Get time from NTP server: <input type="checkbox" name="NT"><br> Get time from NTP server: <input type="checkbox" name="NT"><br>
<input type="text" name="NS" maxlength="32"><br> <input type="text" name="NS" maxlength="32"><br>
Use 24h format: <input type="checkbox" name="CF"><br> Use 24h format: <input type="checkbox" name="CF"><br>
NTP refresh: <select name="NP">
<option value="86400">once</option>
<option value="43200" selected>twice</option>
<option value="21600">4 times</option>
<option value="14400">6 times</option>
<option value="10800">8 times</option>
</select> per day<br>
Time zone: Time zone:
<select name="TZ"> <select name="TZ">
<option value="0" selected>GMT(UTC)</option> <option value="0" selected>GMT(UTC)</option>

View File

@ -1,9 +1,8 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang="en">
<head lang="en"> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=500"> <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport">
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
<title>UI Settings</title> <title>UI Settings</title>
<script> <script>
var d = document; var d = document;

View File

@ -1,9 +1,8 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang="en">
<head lang="en"> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=500"> <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport">
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
<title>Usermod Settings</title> <title>Usermod Settings</title>
<script> <script>
var d = document; var d = document;

View File

@ -2,8 +2,7 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=500"> <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport">
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
<title>WiFi Settings</title> <title>WiFi Settings</title>
<script> <script>
var d = document; var d = document;

View File

@ -523,6 +523,7 @@ ${urows}
${inforow("Build",i.vid)} ${inforow("Build",i.vid)}
${inforow("Signal strength",i.wifi.signal +"% ("+ i.wifi.rssi, " dBm)")} ${inforow("Signal strength",i.wifi.signal +"% ("+ i.wifi.rssi, " dBm)")}
${inforow("Uptime",getRuntimeStr(i.uptime))} ${inforow("Uptime",getRuntimeStr(i.uptime))}
${inforow("Time",i.time)}
${inforow("Free heap",heap," kB")} ${inforow("Free heap",heap," kB")}
${i.psram?inforow("Free PSRAM",(i.psram/1024).toFixed(1)," kB"):""} ${i.psram?inforow("Free PSRAM",(i.psram/1024).toFixed(1)," kB"):""}
${inforow("Estimated current",pwru)} ${inforow("Estimated current",pwru)}

View File

@ -9,7 +9,7 @@
// Autogenerated from wled00/data/cpal/cpal.htm, do not edit!! // Autogenerated from wled00/data/cpal/cpal.htm, do not edit!!
const uint16_t PAGE_cpal_L = 4721; const uint16_t PAGE_cpal_L = 4721;
const uint8_t PAGE_cpal[] PROGMEM = { const uint8_t PAGE_cpal[] PROGMEM = {
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x13, 0xbd, 0x3b, 0x7f, 0x73, 0xdb, 0xb6, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0a, 0xbd, 0x3b, 0x7f, 0x73, 0xdb, 0xb6,
0x92, 0xff, 0xe7, 0x53, 0x20, 0x4c, 0x5f, 0x42, 0xd6, 0x14, 0x45, 0xd2, 0xb6, 0x64, 0x4b, 0xa2, 0x92, 0xff, 0xe7, 0x53, 0x20, 0x4c, 0x5f, 0x42, 0xd6, 0x14, 0x45, 0xd2, 0xb6, 0x64, 0x4b, 0xa2,
0x3b, 0xa9, 0x93, 0x77, 0xce, 0x8d, 0xdd, 0x64, 0x5e, 0x7c, 0x6e, 0x7b, 0x3e, 0xbf, 0x31, 0x4d, 0x3b, 0xa9, 0x93, 0x77, 0xce, 0x8d, 0xdd, 0x64, 0x5e, 0x7c, 0x6e, 0x7b, 0x3e, 0xbf, 0x31, 0x4d,
0x42, 0x12, 0x1b, 0x8a, 0xe0, 0x03, 0x21, 0xd9, 0xae, 0xac, 0xef, 0x7e, 0xbb, 0x00, 0x48, 0x91, 0x42, 0x12, 0x1b, 0x8a, 0xe0, 0x03, 0x21, 0xd9, 0xae, 0xac, 0xef, 0x7e, 0xbb, 0x00, 0x48, 0x91,

View File

@ -41,47 +41,47 @@ const char PAGE_dmxmap[] PROGMEM = R"=====()=====";
#endif #endif
// Autogenerated from wled00/data/update.htm, do not edit!! // Autogenerated from wled00/data/update.htm, do not edit!!
const uint16_t PAGE_update_length = 616; const uint16_t PAGE_update_length = 613;
const uint8_t PAGE_update[] PROGMEM = { const uint8_t PAGE_update[] PROGMEM = {
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0a, 0x75, 0x53, 0x4d, 0x6f, 0xd4, 0x30, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0a, 0x75, 0x53, 0x5d, 0x6f, 0xd4, 0x30,
0x10, 0xbd, 0xe7, 0x57, 0x18, 0x9f, 0x76, 0x25, 0xd6, 0x2e, 0x1f, 0x17, 0x4a, 0x92, 0x42, 0x69, 0x10, 0x7c, 0xcf, 0xaf, 0x70, 0xfd, 0x74, 0x27, 0x51, 0xbb, 0x20, 0x5e, 0x28, 0x49, 0x0a, 0x47,
0x85, 0x2a, 0x21, 0xb5, 0x52, 0x5b, 0x10, 0x27, 0xe4, 0xd8, 0x93, 0x8d, 0x59, 0xc7, 0x4e, 0xed, 0x2b, 0x54, 0x09, 0xa9, 0x95, 0xda, 0x82, 0x78, 0x42, 0x8e, 0xbd, 0xb9, 0x98, 0x73, 0xec, 0xd4,
0xc9, 0xae, 0x56, 0xa8, 0xff, 0x9d, 0x89, 0xb3, 0x5b, 0x10, 0x1f, 0x97, 0x28, 0xce, 0xbc, 0x79, 0xde, 0xdc, 0xe9, 0x84, 0xfa, 0xdf, 0xd9, 0x38, 0x77, 0x05, 0xf1, 0xf1, 0x12, 0xc5, 0xd9, 0xd9,
0x9e, 0x79, 0xef, 0xa5, 0x7c, 0x76, 0x71, 0xfd, 0xe1, 0xee, 0xeb, 0xcd, 0x25, 0xeb, 0xb0, 0x77, 0xf1, 0xee, 0xcc, 0xa4, 0x3c, 0xb9, 0xbc, 0xf9, 0x70, 0xff, 0xf5, 0xf6, 0x8a, 0x75, 0xd8, 0xbb,
0x75, 0x79, 0x78, 0x82, 0x32, 0x75, 0xd9, 0x03, 0x2a, 0xa6, 0x83, 0x47, 0xf0, 0x58, 0xf1, 0x9d, 0xba, 0x3c, 0x3c, 0x41, 0x99, 0xba, 0xec, 0x01, 0x15, 0xd3, 0xc1, 0x23, 0x78, 0xac, 0xf8, 0xce,
0x35, 0xd8, 0x55, 0x06, 0xb6, 0x56, 0xc3, 0x2a, 0x1f, 0x38, 0xf3, 0xaa, 0x87, 0x8a, 0x6f, 0x2d, 0x1a, 0xec, 0x2a, 0x03, 0x5b, 0xab, 0xe1, 0x34, 0x1f, 0x38, 0xf3, 0xaa, 0x87, 0x8a, 0x6f, 0x2d,
0xec, 0x86, 0x10, 0x91, 0xd7, 0x45, 0x89, 0x16, 0x1d, 0xd4, 0x5f, 0x3e, 0x5d, 0x5e, 0xb0, 0xfb, 0xec, 0x86, 0x10, 0x91, 0xd7, 0x45, 0x89, 0x16, 0x1d, 0xd4, 0x5f, 0x3e, 0x5d, 0x5d, 0xb2, 0x87,
0xc1, 0x28, 0x84, 0x52, 0xce, 0x9f, 0xca, 0xa4, 0xa3, 0x1d, 0xb0, 0x2e, 0xda, 0xd1, 0x6b, 0xb4, 0xc1, 0x28, 0x84, 0x52, 0xce, 0x9f, 0xca, 0xa4, 0xa3, 0x1d, 0xb0, 0x2e, 0xda, 0xd1, 0x6b, 0xb4,
0xc1, 0xb3, 0xf3, 0xc5, 0xf2, 0xc7, 0xce, 0x7a, 0x13, 0x76, 0xa2, 0xb3, 0x09, 0x43, 0xdc, 0x8b, 0xc1, 0xb3, 0xd5, 0x62, 0xf9, 0x63, 0x67, 0xbd, 0x09, 0x3b, 0xd1, 0xd9, 0x84, 0x21, 0xee, 0x45,
0x46, 0xe9, 0xcd, 0x62, 0xf9, 0xf8, 0x04, 0xb9, 0x27, 0x88, 0x09, 0x7a, 0xec, 0x69, 0x02, 0xb1, 0xa3, 0xf4, 0x66, 0xb1, 0x7c, 0x7a, 0x86, 0x3c, 0x10, 0xc4, 0x04, 0x3d, 0xf6, 0x34, 0x81, 0x58,
0x06, 0xbc, 0x74, 0x30, 0xbd, 0x9e, 0xef, 0xaf, 0xcc, 0x82, 0x8f, 0x2d, 0x5f, 0x8a, 0x84, 0x7b, 0x03, 0x5e, 0x39, 0x98, 0x5e, 0x57, 0xfb, 0x6b, 0xb3, 0xe0, 0x63, 0xcb, 0x97, 0x22, 0xe1, 0xde,
0x07, 0xc2, 0xd8, 0x34, 0x38, 0xb5, 0xaf, 0xb8, 0x0f, 0x1e, 0xf8, 0xf3, 0xff, 0xb6, 0xf4, 0x69, 0x81, 0x30, 0x36, 0x0d, 0x4e, 0xed, 0x2b, 0xee, 0x83, 0x07, 0xfe, 0xe2, 0xbf, 0x2d, 0x7d, 0x5a,
0xfd, 0x77, 0x4f, 0xe3, 0x82, 0xde, 0xf0, 0xc7, 0xa2, 0x94, 0x87, 0x11, 0x0f, 0xa3, 0xb2, 0x14, 0xff, 0xdd, 0xd3, 0xb8, 0xa0, 0x37, 0xfc, 0xa9, 0x28, 0xe5, 0x61, 0xc4, 0xc3, 0xa8, 0x2c, 0x45,
0x75, 0xc5, 0x65, 0x02, 0x44, 0xeb, 0xd7, 0x49, 0x26, 0xf1, 0x3d, 0x9d, 0x0d, 0xd5, 0x1b, 0x5e, 0x5d, 0x71, 0x99, 0x00, 0xd1, 0xfa, 0x75, 0x92, 0x49, 0x7c, 0x4f, 0x17, 0x43, 0xf5, 0x86, 0xd7,
0xff, 0x86, 0x9c, 0xa8, 0xea, 0xe2, 0x9d, 0xed, 0x27, 0x01, 0xd8, 0x18, 0xdd, 0x82, 0xcf, 0xf4, 0xbf, 0x21, 0x27, 0xaa, 0xba, 0x78, 0x67, 0xfb, 0x49, 0x00, 0x36, 0x46, 0xb7, 0xe0, 0x33, 0xbd,
0x3a, 0x25, 0xbe, 0x7c, 0x4b, 0xc8, 0x8c, 0x28, 0xe5, 0x2c, 0x69, 0x13, 0xcc, 0x9e, 0x05, 0xef, 0x4e, 0x89, 0x2f, 0xdf, 0x12, 0x32, 0x23, 0x4a, 0x39, 0x4b, 0xda, 0x04, 0xb3, 0x67, 0xc1, 0xbb,
0x82, 0x32, 0x15, 0xff, 0x08, 0xf8, 0x79, 0xb1, 0x24, 0xba, 0xee, 0x65, 0x5d, 0x64, 0xc9, 0x6e, 0xa0, 0x4c, 0xc5, 0x3f, 0x02, 0x7e, 0x5e, 0x2c, 0x89, 0xae, 0x7b, 0x55, 0x17, 0x59, 0xb2, 0xbb,
0x43, 0x8b, 0x3b, 0x15, 0xe1, 0x49, 0x3b, 0xaa, 0x94, 0x6d, 0x88, 0x3d, 0x23, 0x2f, 0xba, 0x40, 0xd0, 0xe2, 0x4e, 0x45, 0x78, 0xd6, 0x8e, 0x2a, 0x65, 0x1b, 0x62, 0xcf, 0xc8, 0x8b, 0x2e, 0x50,
0x3d, 0x37, 0xd7, 0xb7, 0x77, 0x9c, 0xa9, 0x2c, 0x4f, 0xc5, 0x85, 0x1c, 0x33, 0x90, 0x33, 0x4b, 0xcf, 0xed, 0xcd, 0xdd, 0x3d, 0x67, 0x2a, 0xcb, 0x53, 0x71, 0x21, 0xc7, 0x0c, 0xe4, 0xcc, 0x52,
0x35, 0x12, 0x84, 0x15, 0x40, 0xd2, 0xed, 0x07, 0x72, 0xa5, 0x1f, 0x1d, 0xda, 0x41, 0x45, 0x94, 0x8d, 0x04, 0x61, 0x05, 0x90, 0x74, 0xfb, 0x81, 0x5c, 0xe9, 0x47, 0x87, 0x76, 0x50, 0x11, 0xe5,
0x13, 0xc1, 0x8a, 0x60, 0x8a, 0xd3, 0xd5, 0x69, 0x6c, 0x7a, 0x4b, 0x76, 0xde, 0x4f, 0x37, 0x5f, 0x44, 0x70, 0x4a, 0x30, 0xc5, 0xe9, 0xea, 0x34, 0x36, 0xbd, 0x25, 0x3b, 0x1f, 0xa6, 0x9b, 0xaf,
0xf9, 0x84, 0xca, 0x39, 0x30, 0x6c, 0x0b, 0x31, 0x11, 0xe5, 0x29, 0x2b, 0xd3, 0xa0, 0x3c, 0x2b, 0x7d, 0x42, 0xe5, 0x1c, 0x18, 0xb6, 0x85, 0x98, 0x88, 0xf2, 0x9c, 0x95, 0x69, 0x50, 0x9e, 0x15,
0xb4, 0x53, 0x29, 0x55, 0x3c, 0xd9, 0x81, 0xd7, 0x27, 0xe2, 0xc5, 0x6b, 0x71, 0xb2, 0x6a, 0x5e, 0xda, 0xa9, 0x94, 0x2a, 0x9e, 0xec, 0xc0, 0xeb, 0x33, 0xf1, 0xf2, 0xb5, 0x38, 0xa3, 0x55, 0xa8,
0xd1, 0x36, 0x54, 0xa4, 0x2d, 0x62, 0x7d, 0x11, 0x76, 0x79, 0x0b, 0x86, 0x1d, 0x30, 0x47, 0x23, 0x42, 0x2b, 0xc4, 0xfa, 0x32, 0xec, 0xf2, 0x0a, 0x0c, 0x3b, 0x60, 0x8e, 0xee, 0x4f, 0xc8, 0x1a,
0x24, 0x64, 0x8d, 0xf5, 0x2a, 0xee, 0x89, 0x42, 0xb1, 0xa2, 0x8b, 0xd0, 0x56, 0xbc, 0x43, 0x1c, 0xeb, 0x55, 0xdc, 0x53, 0xbf, 0x62, 0x45, 0x17, 0xa1, 0xad, 0x78, 0x87, 0x38, 0xa4, 0x73, 0x29,
0xd2, 0xa9, 0x94, 0x6b, 0x8b, 0xdd, 0xd8, 0x08, 0x1d, 0x7a, 0xf9, 0xde, 0x46, 0x1d, 0x42, 0xd8, 0xd7, 0x16, 0xbb, 0xb1, 0x11, 0x3a, 0xf4, 0xf2, 0xbd, 0x8d, 0x3a, 0x84, 0xb0, 0xb1, 0x20, 0xa7,
0x58, 0x90, 0xd3, 0xca, 0x32, 0x82, 0x03, 0x95, 0x20, 0x71, 0x86, 0x2a, 0x92, 0x5f, 0x15, 0xff, 0x7d, 0x65, 0x04, 0x07, 0x2a, 0x41, 0xe2, 0x0c, 0x55, 0x24, 0xb3, 0x2a, 0xfe, 0xad, 0x71, 0xca,
0xd6, 0x38, 0xe5, 0x37, 0x24, 0x8b, 0xed, 0xd7, 0xac, 0xc8, 0x26, 0x1c, 0x79, 0xe8, 0x8b, 0x48, 0x6f, 0x48, 0x13, 0xdb, 0xaf, 0x59, 0x91, 0x1d, 0x38, 0xf2, 0xd0, 0x17, 0x91, 0x3a, 0x0b, 0xce,
0x9d, 0x05, 0x67, 0x92, 0xb0, 0xe1, 0x40, 0x7b, 0xa4, 0xf8, 0x93, 0x5a, 0xa4, 0xed, 0xfa, 0x2c, 0x24, 0x61, 0xc3, 0x81, 0xf6, 0x48, 0xf1, 0x27, 0xb5, 0x48, 0xdb, 0xf5, 0x45, 0xd6, 0xbe, 0x6a,
0xcb, 0x5f, 0xb5, 0x34, 0xe1, 0x2a, 0x3d, 0x8c, 0x24, 0xed, 0x14, 0x52, 0xa9, 0xf2, 0x0e, 0xa5, 0x69, 0xc2, 0xd3, 0xf4, 0x38, 0x92, 0xae, 0x53, 0x42, 0xa5, 0xca, 0x3b, 0x94, 0xd6, 0x0f, 0x23,
0xf5, 0xc3, 0x88, 0x6c, 0x96, 0xab, 0xb5, 0x0e, 0x8e, 0x81, 0x3e, 0x8a, 0x1a, 0xe1, 0x61, 0xb4, 0xb2, 0x59, 0xab, 0xd6, 0x3a, 0x38, 0xa6, 0xf9, 0xa8, 0x68, 0x84, 0xc7, 0xd1, 0x46, 0x30, 0x33,
0x11, 0xcc, 0x8c, 0x6e, 0x46, 0x44, 0xca, 0xe4, 0x0c, 0x9f, 0x65, 0x24, 0xb2, 0xd9, 0xa9, 0x67, 0xba, 0x19, 0x11, 0x29, 0x90, 0x33, 0x7c, 0xd6, 0x90, 0xc8, 0x66, 0x9b, 0x4e, 0x4a, 0x39, 0x97,
0xa5, 0x9c, 0xcb, 0xff, 0x80, 0xce, 0x87, 0x49, 0x7b, 0xed, 0xac, 0xde, 0x54, 0xfc, 0x7c, 0x92, 0xff, 0x01, 0x9d, 0x0f, 0x93, 0xf0, 0xda, 0x59, 0xbd, 0xa9, 0xf8, 0x6a, 0xd2, 0x7d, 0x45, 0x39,
0xfe, 0x9c, 0xa2, 0xfe, 0xab, 0x29, 0x7b, 0x54, 0x97, 0xc6, 0x6e, 0x8b, 0x6c, 0xe5, 0x14, 0x54, 0xff, 0xd5, 0x94, 0x0d, 0xaa, 0x4b, 0x63, 0xb7, 0x45, 0xf6, 0x71, 0x4a, 0x29, 0xd1, 0xd4, 0x99,
0xa2, 0xa9, 0x33, 0x3b, 0xa5, 0x4f, 0x08, 0x41, 0xe0, 0x4c, 0x7e, 0x93, 0x97, 0x65, 0x26, 0x30, 0x9d, 0xa2, 0x27, 0x84, 0x20, 0x70, 0x26, 0xbf, 0xcd, 0xcb, 0x32, 0x13, 0x98, 0x0f, 0xc8, 0xb4,
0x1f, 0x90, 0x69, 0x17, 0xe8, 0x10, 0x22, 0xcd, 0xda, 0x46, 0x48, 0x5d, 0xf6, 0x63, 0x50, 0x6b, 0x0b, 0x74, 0x08, 0x91, 0x66, 0x6d, 0x23, 0xa4, 0x2e, 0xfb, 0x31, 0xa8, 0x35, 0xb0, 0xf3, 0x65,
0x60, 0xa7, 0xcb, 0x52, 0x12, 0xdf, 0xb4, 0xee, 0x94, 0xba, 0x29, 0x82, 0xd3, 0xbf, 0xfd, 0x13, 0x29, 0x89, 0x6f, 0x5a, 0x77, 0x8a, 0xdc, 0x94, 0xbf, 0xe9, 0xc7, 0xfe, 0x09, 0x45, 0xc9, 0x0d,
0x46, 0x22, 0xf9, 0xe1, 0xf1, 0x03, 0x00, 0x00 0xd4, 0xee, 0x03, 0x00, 0x00
}; };

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -210,7 +210,7 @@ void sendImprovInfoResponse() {
//Use serverDescription if it has been changed from the default "WLED", else mDNS name //Use serverDescription if it has been changed from the default "WLED", else mDNS name
bool useMdnsName = (strcmp(serverDescription, "WLED") == 0 && strlen(cmDNS) > 0); bool useMdnsName = (strcmp(serverDescription, "WLED") == 0 && strlen(cmDNS) > 0);
char vString[20]; char vString[20];
sprintf_P(vString, PSTR("0.14.0-b4/%i"), VERSION); sprintf_P(vString, PSTR("0.14.0/%i"), VERSION);
const char *str[4] = {"WLED", vString, bString, useMdnsName ? cmDNS : serverDescription}; const char *str[4] = {"WLED", vString, bString, useMdnsName ? cmDNS : serverDescription};
sendImprovRPCResult(ImprovRPCType::Request_Info, 4, str); sendImprovRPCResult(ImprovRPCType::Request_Info, 4, str);

View File

@ -20,6 +20,7 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
byte id = elem["id"] | it; byte id = elem["id"] | it;
if (id >= strip.getMaxSegments()) return false; if (id >= strip.getMaxSegments()) return false;
bool newSeg = false;
int stop = elem["stop"] | -1; int stop = elem["stop"] | -1;
// append segment // append segment
@ -27,10 +28,14 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
if (stop <= 0) return false; // ignore empty/inactive segments if (stop <= 0) return false; // ignore empty/inactive segments
strip.appendSegment(Segment(0, strip.getLengthTotal())); strip.appendSegment(Segment(0, strip.getLengthTotal()));
id = strip.getSegmentsNum()-1; // segments are added at the end of list id = strip.getSegmentsNum()-1; // segments are added at the end of list
newSeg = true;
} }
//DEBUG_PRINTLN("-- JSON deserialize segment.");
Segment& seg = strip.getSegment(id); Segment& seg = strip.getSegment(id);
//DEBUG_PRINTF("-- Original segment: %p\n", &seg);
Segment prev = seg; //make a backup so we can tell if something changed Segment prev = seg; //make a backup so we can tell if something changed
//DEBUG_PRINTF("-- Duplicate segment: %p\n", &prev);
uint16_t start = elem["start"] | seg.start; uint16_t start = elem["start"] | seg.start;
if (stop < 0) { if (stop < 0) {
@ -115,8 +120,12 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
// do not call seg.setUp() here, as it may cause a crash due to concurrent access if the segment is currently drawing effects // do not call seg.setUp() here, as it may cause a crash due to concurrent access if the segment is currently drawing effects
// WS2812FX handles queueing of the change // WS2812FX handles queueing of the change
strip.setSegment(id, start, stop, grp, spc, of, startY, stopY); strip.setSegment(id, start, stop, grp, spc, of, startY, stopY);
if (newSeg) seg.refreshLightCapabilities(); // fix for #3403
if (seg.reset && seg.stop == 0) return true; // segment was deleted & is marked for reset, no need to change anything else if (seg.reset && seg.stop == 0) {
if (id == strip.getMainSegmentId()) strip.setMainSegmentId(0); // fix for #3403
return true; // segment was deleted & is marked for reset, no need to change anything else
}
byte segbri = seg.opacity; byte segbri = seg.opacity;
if (getVal(elem["bri"], &segbri)) { if (getVal(elem["bri"], &segbri)) {
@ -739,6 +748,10 @@ void serializeInfo(JsonObject root)
#endif #endif
root[F("uptime")] = millis()/1000 + rolloverMillis*4294967; root[F("uptime")] = millis()/1000 + rolloverMillis*4294967;
char time[32];
getTimeString(time);
root[F("time")] = time;
usermods.addToJsonInfo(root); usermods.addToJsonInfo(root);
uint16_t os = 0; uint16_t os = 0;
@ -975,9 +988,10 @@ void serializeNodes(JsonObject root)
// deserializes mode data string into JsonArray // deserializes mode data string into JsonArray
void serializeModeData(JsonArray fxdata) void serializeModeData(JsonArray fxdata)
{ {
char lineBuffer[128]; char lineBuffer[256];
for (size_t i = 0; i < strip.getModeCount(); i++) { for (size_t i = 0; i < strip.getModeCount(); i++) {
strncpy_P(lineBuffer, strip.getModeData(i), 127); strncpy_P(lineBuffer, strip.getModeData(i), sizeof(lineBuffer)/sizeof(char)-1);
lineBuffer[sizeof(lineBuffer)/sizeof(char)-1] = '\0'; // terminate string
if (lineBuffer[0] != 0) { if (lineBuffer[0] != 0) {
char* dataPtr = strchr(lineBuffer,'@'); char* dataPtr = strchr(lineBuffer,'@');
if (dataPtr) fxdata.add(dataPtr+1); if (dataPtr) fxdata.add(dataPtr+1);
@ -988,10 +1002,12 @@ void serializeModeData(JsonArray fxdata)
// deserializes mode names string into JsonArray // deserializes mode names string into JsonArray
// also removes effect data extensions (@...) from deserialised names // also removes effect data extensions (@...) from deserialised names
void serializeModeNames(JsonArray arr) { void serializeModeNames(JsonArray arr)
char lineBuffer[128]; {
char lineBuffer[256];
for (size_t i = 0; i < strip.getModeCount(); i++) { for (size_t i = 0; i < strip.getModeCount(); i++) {
strncpy_P(lineBuffer, strip.getModeData(i), 127); strncpy_P(lineBuffer, strip.getModeData(i), sizeof(lineBuffer)/sizeof(char)-1);
lineBuffer[sizeof(lineBuffer)/sizeof(char)-1] = '\0'; // terminate string
if (lineBuffer[0] != 0) { if (lineBuffer[0] != 0) {
char* dataPtr = strchr(lineBuffer,'@'); char* dataPtr = strchr(lineBuffer,'@');
if (dataPtr) *dataPtr = 0; // terminate mode data after name if (dataPtr) *dataPtr = 0; // terminate mode data after name

View File

@ -37,12 +37,12 @@ void applyValuesToSelectedSegs()
if (effectSpeed != selsegPrev.speed) {seg.speed = effectSpeed; stateChanged = true;} if (effectSpeed != selsegPrev.speed) {seg.speed = effectSpeed; stateChanged = true;}
if (effectIntensity != selsegPrev.intensity) {seg.intensity = effectIntensity; stateChanged = true;} if (effectIntensity != selsegPrev.intensity) {seg.intensity = effectIntensity; stateChanged = true;}
if (effectPalette != selsegPrev.palette) {seg.setPalette(effectPalette); stateChanged = true;} if (effectPalette != selsegPrev.palette) {seg.setPalette(effectPalette);}
if (effectCurrent != selsegPrev.mode) {seg.setMode(effectCurrent); stateChanged = true;} if (effectCurrent != selsegPrev.mode) {seg.setMode(effectCurrent);}
uint32_t col0 = RGBW32( col[0], col[1], col[2], col[3]); uint32_t col0 = RGBW32( col[0], col[1], col[2], col[3]);
uint32_t col1 = RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]); uint32_t col1 = RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]);
if (col0 != selsegPrev.colors[0]) {seg.setColor(0, col0); stateChanged = true;} if (col0 != selsegPrev.colors[0]) {seg.setColor(0, col0);}
if (col1 != selsegPrev.colors[1]) {seg.setColor(1, col1); stateChanged = true;} if (col1 != selsegPrev.colors[1]) {seg.setColor(1, col1);}
} }
} }
@ -161,6 +161,8 @@ void stateUpdated(byte callMode) {
void updateInterfaces(uint8_t callMode) void updateInterfaces(uint8_t callMode)
{ {
if (!interfaceUpdateCallMode || millis() - lastInterfaceUpdate < INTERFACE_UPDATE_COOLDOWN) return;
sendDataWs(); sendDataWs();
lastInterfaceUpdate = millis(); lastInterfaceUpdate = millis();
if (callMode == CALL_MODE_WS_SEND) return; if (callMode == CALL_MODE_WS_SEND) return;
@ -179,7 +181,7 @@ void updateInterfaces(uint8_t callMode)
void handleTransitions() void handleTransitions()
{ {
//handle still pending interface update //handle still pending interface update
if (interfaceUpdateCallMode && millis() - lastInterfaceUpdate > INTERFACE_UPDATE_COOLDOWN) updateInterfaces(interfaceUpdateCallMode); updateInterfaces(interfaceUpdateCallMode);
#ifndef WLED_DISABLE_MQTT #ifndef WLED_DISABLE_MQTT
if (doPublishMqtt) publishMqtt(); if (doPublishMqtt) publishMqtt();
#endif #endif
@ -187,7 +189,7 @@ void handleTransitions()
if (transitionActive && transitionDelayTemp > 0) if (transitionActive && transitionDelayTemp > 0)
{ {
float tper = (millis() - transitionStartTime)/(float)transitionDelayTemp; float tper = (millis() - transitionStartTime)/(float)transitionDelayTemp;
if (tper >= 1.0) if (tper >= 1.0f)
{ {
strip.setTransitionMode(false); strip.setTransitionMode(false);
transitionActive = false; transitionActive = false;

View File

@ -25,7 +25,7 @@ bool parseLx(int lxValue, byte* rgbw)
float tmpBri = floor((lxValue - 200000000) / 10000); ; float tmpBri = floor((lxValue - 200000000) / 10000); ;
uint16_t ct = (lxValue - 200000000) - (((uint8_t)tmpBri) * 10000); uint16_t ct = (lxValue - 200000000) - (((uint8_t)tmpBri) * 10000);
tmpBri *= 2.55; tmpBri *= 2.55f;
tmpBri = constrain(tmpBri, 0, 255); tmpBri = constrain(tmpBri, 0, 255);
colorKtoRGB(ct, rgbw); colorKtoRGB(ct, rgbw);

View File

@ -2,10 +2,26 @@
#include "wled.h" #include "wled.h"
#include "fcn_declare.h" #include "fcn_declare.h"
// on esp8266, building with `-D WLED_USE_UNREAL_MATH` saves around 7Kb flash and 1KB RAM
// warning: causes errors in sunset calculations, see #3400
#if defined(WLED_USE_UNREAL_MATH)
#define sinf sin_t
#define asinf asin_t
#define cosf cos_t
#define acosf acos_t
#define tanf tan_t
#define atanf atan_t
#define fmodf fmod_t
#define floorf floor_t
#else
#include <math.h>
#endif
/* /*
* Acquires time from NTP server * Acquires time from NTP server
*/ */
//#define WLED_DEBUG_NTP //#define WLED_DEBUG_NTP
#define NTP_SYNC_INTERVAL 42000UL //Get fresh NTP time about twice per day
Timezone* tz; Timezone* tz;
@ -179,7 +195,7 @@ void handleTime() {
void handleNetworkTime() void handleNetworkTime()
{ {
if (ntpEnabled && ntpConnected && millis() - ntpLastSyncTime > (1000UL*ntpSyncInterval) && WLED_CONNECTED) if (ntpEnabled && ntpConnected && millis() - ntpLastSyncTime > (1000*NTP_SYNC_INTERVAL) && WLED_CONNECTED)
{ {
if (millis() - ntpPacketSentTime > 10000) if (millis() - ntpPacketSentTime > 10000)
{ {
@ -411,8 +427,8 @@ int getSunriseUTC(int year, int month, int day, float lat, float lon, bool sunse
//1. first calculate the day of the year //1. first calculate the day of the year
float N1 = 275 * month / 9; float N1 = 275 * month / 9;
float N2 = (month + 9) / 12; float N2 = (month + 9) / 12;
float N3 = (1 + floor_t((year - 4 * floor_t(year / 4) + 2) / 3)); float N3 = (1.0f + floorf((year - 4 * floorf(year / 4) + 2.0f) / 3.0f));
float N = N1 - (N2 * N3) + day - 30; float N = N1 - (N2 * N3) + day - 30.0f;
//2. convert the longitude to hour value and calculate an approximate time //2. convert the longitude to hour value and calculate an approximate time
float lngHour = lon / 15.0f; float lngHour = lon / 15.0f;
@ -422,37 +438,37 @@ int getSunriseUTC(int year, int month, int day, float lat, float lon, bool sunse
float M = (0.9856f * t) - 3.289f; float M = (0.9856f * t) - 3.289f;
//4. calculate the Sun's true longitude //4. calculate the Sun's true longitude
float L = fmod_t(M + (1.916f * sin_t(DEG_TO_RAD*M)) + (0.02f * sin_t(2*DEG_TO_RAD*M)) + 282.634f, 360.0f); float L = fmodf(M + (1.916f * sinf(DEG_TO_RAD*M)) + (0.02f * sinf(2*DEG_TO_RAD*M)) + 282.634f, 360.0f);
//5a. calculate the Sun's right ascension //5a. calculate the Sun's right ascension
float RA = fmod_t(RAD_TO_DEG*atan_t(0.91764f * tan_t(DEG_TO_RAD*L)), 360.0f); float RA = fmodf(RAD_TO_DEG*atanf(0.91764f * tanf(DEG_TO_RAD*L)), 360.0f);
//5b. right ascension value needs to be in the same quadrant as L //5b. right ascension value needs to be in the same quadrant as L
float Lquadrant = floor_t( L/90) * 90; float Lquadrant = floorf( L/90) * 90;
float RAquadrant = floor_t(RA/90) * 90; float RAquadrant = floorf(RA/90) * 90;
RA = RA + (Lquadrant - RAquadrant); RA = RA + (Lquadrant - RAquadrant);
//5c. right ascension value needs to be converted into hours //5c. right ascension value needs to be converted into hours
RA /= 15.0f; RA /= 15.0f;
//6. calculate the Sun's declination //6. calculate the Sun's declination
float sinDec = 0.39782f * sin_t(DEG_TO_RAD*L); float sinDec = 0.39782f * sinf(DEG_TO_RAD*L);
float cosDec = cos_t(asin_t(sinDec)); float cosDec = cosf(asinf(sinDec));
//7a. calculate the Sun's local hour angle //7a. calculate the Sun's local hour angle
float cosH = (sin_t(DEG_TO_RAD*ZENITH) - (sinDec * sin_t(DEG_TO_RAD*lat))) / (cosDec * cos_t(DEG_TO_RAD*lat)); float cosH = (sinf(DEG_TO_RAD*ZENITH) - (sinDec * sinf(DEG_TO_RAD*lat))) / (cosDec * cosf(DEG_TO_RAD*lat));
if (cosH > 1 && !sunset) return 0; // the sun never rises on this location (on the specified date) if ((cosH > 1.0f) && !sunset) return 0; // the sun never rises on this location (on the specified date)
if (cosH < -1 && sunset) return 0; // the sun never sets on this location (on the specified date) if ((cosH < -1.0f) && sunset) return 0; // the sun never sets on this location (on the specified date)
//7b. finish calculating H and convert into hours //7b. finish calculating H and convert into hours
float H = sunset ? RAD_TO_DEG*acos_t(cosH) : 360 - RAD_TO_DEG*acos_t(cosH); float H = sunset ? RAD_TO_DEG*acosf(cosH) : 360 - RAD_TO_DEG*acosf(cosH);
H /= 15.0f; H /= 15.0f;
//8. calculate local mean time of rising/setting //8. calculate local mean time of rising/setting
float T = H + RA - (0.06571f * t) - 6.622f; float T = H + RA - (0.06571f * t) - 6.622f;
//9. adjust back to UTC //9. adjust back to UTC
float UT = fmod_t(T - lngHour, 24.0f); float UT = fmodf(T - lngHour, 24.0f);
// return in minutes from midnight // return in minutes from midnight
return UT*60; return UT*60;

View File

@ -112,7 +112,7 @@ int16_t loadPlaylist(JsonObject playlistObj, byte presetId) {
if (playlistEndPreset == 255 && currentPreset > 0) playlistEndPreset = currentPreset; if (playlistEndPreset == 255 && currentPreset > 0) playlistEndPreset = currentPreset;
if (playlistEndPreset > 250) playlistEndPreset = 0; if (playlistEndPreset > 250) playlistEndPreset = 0;
shuffle = shuffle || playlistObj["r"]; shuffle = shuffle || playlistObj["r"];
if (shuffle) playlistOptions += PL_OPTION_SHUFFLE; if (shuffle) playlistOptions |= PL_OPTION_SHUFFLE;
currentPlaylist = presetId; currentPlaylist = presetId;
DEBUG_PRINTLN(F("Playlist loaded.")); DEBUG_PRINTLN(F("Playlist loaded."));
@ -156,7 +156,7 @@ void serializePlaylist(JsonObject sObj) {
JsonArray ps = playlist.createNestedArray("ps"); JsonArray ps = playlist.createNestedArray("ps");
JsonArray dur = playlist.createNestedArray("dur"); JsonArray dur = playlist.createNestedArray("dur");
JsonArray transition = playlist.createNestedArray(F("transition")); JsonArray transition = playlist.createNestedArray(F("transition"));
playlist[F("repeat")] = (playlistIndex < 0) ? playlistRepeat - 1 : playlistRepeat; // remove added repetition count (if not yet running) playlist[F("repeat")] = (playlistIndex < 0 && playlistRepeat > 0) ? playlistRepeat - 1 : playlistRepeat; // remove added repetition count (if not yet running)
playlist["end"] = playlistEndPreset; playlist["end"] = playlistEndPreset;
playlist["r"] = playlistOptions & PL_OPTION_SHUFFLE; playlist["r"] = playlistOptions & PL_OPTION_SHUFFLE;
for (int i=0; i<playlistLen; i++) { for (int i=0; i<playlistLen; i++) {

View File

@ -347,14 +347,14 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
#ifdef WLED_ENABLE_MQTT #ifdef WLED_ENABLE_MQTT
mqttEnabled = request->hasArg(F("MQ")); mqttEnabled = request->hasArg(F("MQ"));
strlcpy(mqttServer, request->arg(F("MS")).c_str(), 33); strlcpy(mqttServer, request->arg(F("MS")).c_str(), MQTT_MAX_SERVER_LEN+1);
t = request->arg(F("MQPORT")).toInt(); t = request->arg(F("MQPORT")).toInt();
if (t > 0) mqttPort = t; if (t > 0) mqttPort = t;
strlcpy(mqttUser, request->arg(F("MQUSER")).c_str(), 41); strlcpy(mqttUser, request->arg(F("MQUSER")).c_str(), 41);
if (!isAsterisksOnly(request->arg(F("MQPASS")).c_str(), 41)) strlcpy(mqttPass, request->arg(F("MQPASS")).c_str(), 65); if (!isAsterisksOnly(request->arg(F("MQPASS")).c_str(), 41)) strlcpy(mqttPass, request->arg(F("MQPASS")).c_str(), 65);
strlcpy(mqttClientID, request->arg(F("MQCID")).c_str(), 41); strlcpy(mqttClientID, request->arg(F("MQCID")).c_str(), 41);
strlcpy(mqttDeviceTopic, request->arg(F("MD")).c_str(), 33); strlcpy(mqttDeviceTopic, request->arg(F("MD")).c_str(), MQTT_MAX_TOPIC_LEN+1);
strlcpy(mqttGroupTopic, request->arg(F("MG")).c_str(), 33); strlcpy(mqttGroupTopic, request->arg(F("MG")).c_str(), MQTT_MAX_TOPIC_LEN+1);
buttonPublishMqtt = request->hasArg(F("BM")); buttonPublishMqtt = request->hasArg(F("BM"));
retainMqttMsg = request->hasArg(F("RT")); retainMqttMsg = request->hasArg(F("RT"));
#endif #endif
@ -390,7 +390,6 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
ntpEnabled = request->hasArg(F("NT")); ntpEnabled = request->hasArg(F("NT"));
strlcpy(ntpServerName, request->arg(F("NS")).c_str(), 33); strlcpy(ntpServerName, request->arg(F("NS")).c_str(), 33);
useAMPM = !request->hasArg(F("CF")); useAMPM = !request->hasArg(F("CF"));
ntpSyncInterval = min(86400U, max(10800U, (unsigned int)request->arg(F("NP")).toInt()));
currentTimezone = request->arg(F("TZ")).toInt(); currentTimezone = request->arg(F("TZ")).toInt();
utcOffsetSecs = request->arg(F("UO")).toInt(); utcOffsetSecs = request->arg(F("UO")).toInt();

View File

@ -177,6 +177,10 @@
#include "../usermods/boblight/boblight.h" #include "../usermods/boblight/boblight.h"
#endif #endif
#ifdef USERMOD_INTERNAL_TEMPERATURE
#include "../usermods/Internal_Temperature_v2/usermod_internal_temperature.h"
#endif
#if defined(WLED_USE_SD_MMC) || defined(WLED_USE_SD_SPI) #if defined(WLED_USE_SD_MMC) || defined(WLED_USE_SD_SPI)
// This include of SD.h and SD_MMC.h must happen here, else they won't be // This include of SD.h and SD_MMC.h must happen here, else they won't be
// resolved correctly (when included in mod's header only) // resolved correctly (when included in mod's header only)
@ -365,4 +369,8 @@ void registerUsermods()
#ifdef USERMOD_SHT #ifdef USERMOD_SHT
usermods.add(new ShtUsermod()); usermods.add(new ShtUsermod());
#endif #endif
#ifdef USERMOD_INTERNAL_TEMPERATURE
usermods.add(new InternalTemperatureUsermod());
#endif
} }

View File

@ -148,8 +148,14 @@ bool oappendi(int i)
bool oappend(const char* txt) bool oappend(const char* txt)
{ {
uint16_t len = strlen(txt); uint16_t len = strlen(txt);
if (olen + len >= SETTINGS_STACK_BUF_SIZE) if (olen + len >= SETTINGS_STACK_BUF_SIZE) {
#ifdef WLED_DEBUG
DEBUG_PRINT(F("oappend() buffer overflow. Cannnot append "));
DEBUG_PRINT(len); DEBUG_PRINT(F(" bytes \t\""));
DEBUG_PRINT(txt); DEBUG_PRINTLN(F("\""));
#endif
return false; // buffer full return false; // buffer full
}
strcpy(obuf + olen, txt); strcpy(obuf + olen, txt);
olen += len; olen += len;
return true; return true;
@ -233,7 +239,8 @@ uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLe
if (mode < strip.getModeCount()) { if (mode < strip.getModeCount()) {
char lineBuffer[256]; char lineBuffer[256];
//strcpy_P(lineBuffer, (const char*)pgm_read_dword(&(WS2812FX::_modeData[mode]))); //strcpy_P(lineBuffer, (const char*)pgm_read_dword(&(WS2812FX::_modeData[mode])));
strcpy_P(lineBuffer, strip.getModeData(mode)); strncpy_P(lineBuffer, strip.getModeData(mode), sizeof(lineBuffer)/sizeof(char)-1);
lineBuffer[sizeof(lineBuffer)/sizeof(char)-1] = '\0'; // terminate string
size_t len = strlen(lineBuffer); size_t len = strlen(lineBuffer);
size_t j = 0; size_t j = 0;
for (; j < maxLen && j < len; j++) { for (; j < maxLen && j < len; j++) {
@ -245,6 +252,12 @@ uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLe
} else return 0; } else return 0;
} }
if (src == JSON_palette_names && mode > GRADIENT_PALETTE_COUNT) {
snprintf_P(dest, maxLen, PSTR("~ Custom %d~"), 255-mode);
dest[maxLen-1] = '\0';
return strlen(dest);
}
uint8_t qComma = 0; uint8_t qComma = 0;
bool insideQuotes = false; bool insideQuotes = false;
uint8_t printedChars = 0; uint8_t printedChars = 0;
@ -355,9 +368,9 @@ uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxL
int16_t extractModeDefaults(uint8_t mode, const char *segVar) int16_t extractModeDefaults(uint8_t mode, const char *segVar)
{ {
if (mode < strip.getModeCount()) { if (mode < strip.getModeCount()) {
char lineBuffer[128] = ""; char lineBuffer[256];
strncpy_P(lineBuffer, strip.getModeData(mode), 127); strncpy_P(lineBuffer, strip.getModeData(mode), sizeof(lineBuffer)/sizeof(char)-1);
lineBuffer[127] = '\0'; // terminate string lineBuffer[sizeof(lineBuffer)/sizeof(char)-1] = '\0'; // terminate string
if (lineBuffer[0] != 0) { if (lineBuffer[0] != 0) {
char* startPtr = strrchr(lineBuffer, ';'); // last ";" in FX data char* startPtr = strrchr(lineBuffer, ';'); // last ";" in FX data
if (!startPtr) return -1; if (!startPtr) return -1;
@ -507,7 +520,7 @@ um_data_t* simulateSound(uint8_t simulationId)
maxVol = 31; // this gets feedback fro UI maxVol = 31; // this gets feedback fro UI
binNum = 8; // this gets feedback fro UI binNum = 8; // this gets feedback fro UI
volumeRaw = volumeSmth; volumeRaw = volumeSmth;
my_magnitude = 10000.0 / 8.0f; //no idea if 10000 is a good value for FFT_Magnitude ??? my_magnitude = 10000.0f / 8.0f; //no idea if 10000 is a good value for FFT_Magnitude ???
if (volumeSmth < 1 ) my_magnitude = 0.001f; // noise gate closed - mute if (volumeSmth < 1 ) my_magnitude = 0.001f; // noise gate closed - mute
return um_data; return um_data;
@ -559,4 +572,4 @@ void enumerateLedmaps() {
} }
} }
} }

View File

@ -195,12 +195,15 @@ void WLED::loop()
#if WLED_WATCHDOG_TIMEOUT > 0 #if WLED_WATCHDOG_TIMEOUT > 0
// we finished our mainloop, reset the watchdog timer // we finished our mainloop, reset the watchdog timer
if (!strip.isUpdating()) static unsigned long lastWDTFeed = 0;
if (!strip.isUpdating() || millis() - lastWDTFeed > (WLED_WATCHDOG_TIMEOUT*500)) {
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
esp_task_wdt_reset(); esp_task_wdt_reset();
#else #else
ESP.wdtFeed(); ESP.wdtFeed();
#endif #endif
lastWDTFeed = millis();
}
#endif #endif
if (doReboot && (!doInitBusses || !doSerializeConfig)) // if busses have to be inited & saved, wait until next iteration if (doReboot && (!doInitBusses || !doSerializeConfig)) // if busses have to be inited & saved, wait until next iteration

View File

@ -8,7 +8,7 @@
*/ */
// version code in format yymmddb (b = daily build) // version code in format yymmddb (b = daily build)
#define VERSION 2308110 #define VERSION 2310130
//uncomment this if you have a "my_config.h" file you'd like to use //uncomment this if you have a "my_config.h" file you'd like to use
//#define WLED_USE_MY_CONFIG //#define WLED_USE_MY_CONFIG
@ -429,12 +429,18 @@ WLED_GLOBAL uint16_t pollReplyCount _INIT(0); // count numbe
// mqtt // mqtt
WLED_GLOBAL unsigned long lastMqttReconnectAttempt _INIT(0); // used for other periodic tasks too WLED_GLOBAL unsigned long lastMqttReconnectAttempt _INIT(0); // used for other periodic tasks too
#ifndef WLED_DISABLE_MQTT #ifndef WLED_DISABLE_MQTT
#ifndef MQTT_MAX_TOPIC_LEN
#define MQTT_MAX_TOPIC_LEN 32
#endif
#ifndef MQTT_MAX_SERVER_LEN
#define MQTT_MAX_SERVER_LEN 32
#endif
WLED_GLOBAL AsyncMqttClient *mqtt _INIT(NULL); WLED_GLOBAL AsyncMqttClient *mqtt _INIT(NULL);
WLED_GLOBAL bool mqttEnabled _INIT(false); WLED_GLOBAL bool mqttEnabled _INIT(false);
WLED_GLOBAL char mqttStatusTopic[40] _INIT(""); // this must be global because of async handlers WLED_GLOBAL char mqttStatusTopic[40] _INIT(""); // this must be global because of async handlers
WLED_GLOBAL char mqttDeviceTopic[33] _INIT(""); // main MQTT topic (individual per device, default is wled/mac) WLED_GLOBAL char mqttDeviceTopic[MQTT_MAX_TOPIC_LEN+1] _INIT(""); // main MQTT topic (individual per device, default is wled/mac)
WLED_GLOBAL char mqttGroupTopic[33] _INIT("wled/all"); // second MQTT topic (for example to group devices) WLED_GLOBAL char mqttGroupTopic[MQTT_MAX_TOPIC_LEN+1] _INIT("wled/all"); // second MQTT topic (for example to group devices)
WLED_GLOBAL char mqttServer[33] _INIT(""); // both domains and IPs should work (no SSL) WLED_GLOBAL char mqttServer[MQTT_MAX_SERVER_LEN+1] _INIT(""); // both domains and IPs should work (no SSL)
WLED_GLOBAL char mqttUser[41] _INIT(""); // optional: username for MQTT auth WLED_GLOBAL char mqttUser[41] _INIT(""); // optional: username for MQTT auth
WLED_GLOBAL char mqttPass[65] _INIT(""); // optional: password for MQTT auth WLED_GLOBAL char mqttPass[65] _INIT(""); // optional: password for MQTT auth
WLED_GLOBAL char mqttClientID[41] _INIT(""); // override the client ID WLED_GLOBAL char mqttClientID[41] _INIT(""); // override the client ID
@ -639,14 +645,13 @@ WLED_GLOBAL DNSServer dnsServer;
// network time // network time
WLED_GLOBAL bool ntpConnected _INIT(false); WLED_GLOBAL bool ntpConnected _INIT(false);
WLED_GLOBAL time_t localTime _INIT(0); WLED_GLOBAL time_t localTime _INIT(0);
WLED_GLOBAL uint32_t ntpSyncInterval _INIT(43200U);
WLED_GLOBAL unsigned long ntpLastSyncTime _INIT(999000000L); WLED_GLOBAL unsigned long ntpLastSyncTime _INIT(999000000L);
WLED_GLOBAL unsigned long ntpPacketSentTime _INIT(999000000L); WLED_GLOBAL unsigned long ntpPacketSentTime _INIT(999000000L);
WLED_GLOBAL IPAddress ntpServerIP; WLED_GLOBAL IPAddress ntpServerIP;
WLED_GLOBAL uint16_t ntpLocalPort _INIT(2390); WLED_GLOBAL uint16_t ntpLocalPort _INIT(2390);
WLED_GLOBAL uint16_t rolloverMillis _INIT(0); WLED_GLOBAL uint16_t rolloverMillis _INIT(0);
WLED_GLOBAL float longitude _INIT(0.0f); WLED_GLOBAL float longitude _INIT(0.0);
WLED_GLOBAL float latitude _INIT(0.0f); WLED_GLOBAL float latitude _INIT(0.0);
WLED_GLOBAL time_t sunrise _INIT(0); WLED_GLOBAL time_t sunrise _INIT(0);
WLED_GLOBAL time_t sunset _INIT(0); WLED_GLOBAL time_t sunset _INIT(0);
WLED_GLOBAL Toki toki _INIT(Toki()); WLED_GLOBAL Toki toki _INIT(Toki());

View File

@ -41,7 +41,7 @@ float sin_t(float x) {
float tan_t(float x) { float tan_t(float x) {
float c = cos_t(x); float c = cos_t(x);
if (c==0.0) return 0; if (c==0.0f) return 0;
float res = sin_t(x) / c; float res = sin_t(x) / c;
#ifdef WLED_DEBUG_MATH #ifdef WLED_DEBUG_MATH
Serial.printf("tan: %f,%f,%f,(%f)\n",x,res,tan(x),res-tan(x)); Serial.printf("tan: %f,%f,%f,(%f)\n",x,res,tan(x),res-tan(x));
@ -54,14 +54,14 @@ float tan_t(float x) {
float acos_t(float x) { float acos_t(float x) {
float negate = float(x < 0); float negate = float(x < 0);
float xabs = std::abs(x); float xabs = std::abs(x);
float ret = -0.0187293; float ret = -0.0187293f;
ret = ret * xabs; ret = ret * xabs;
ret = ret + 0.0742610; ret = ret + 0.0742610f;
ret = ret * xabs; ret = ret * xabs;
ret = ret - 0.2121144; ret = ret - 0.2121144f;
ret = ret * xabs; ret = ret * xabs;
ret = ret + HALF_PI; ret = ret + HALF_PI;
ret = ret * sqrt(1.0-xabs); ret = ret * sqrt(1.0f-xabs);
ret = ret - 2 * negate * ret; ret = ret - 2 * negate * ret;
float res = negate * PI + ret; float res = negate * PI + ret;
#ifdef WLED_DEBUG_MATH #ifdef WLED_DEBUG_MATH

View File

@ -478,6 +478,7 @@ void getSettingsJS(byte subPage, char* dest)
if (subPage == SUBPAGE_SYNC) if (subPage == SUBPAGE_SYNC)
{ {
char nS[32];
sappend('v',SET_F("UP"),udpPort); sappend('v',SET_F("UP"),udpPort);
sappend('v',SET_F("U2"),udpPort2); sappend('v',SET_F("U2"),udpPort2);
sappend('v',SET_F("GS"),syncGroups); sappend('v',SET_F("GS"),syncGroups);
@ -534,6 +535,9 @@ void getSettingsJS(byte subPage, char* dest)
sappends('s',SET_F("MG"),mqttGroupTopic); sappends('s',SET_F("MG"),mqttGroupTopic);
sappend('c',SET_F("BM"),buttonPublishMqtt); sappend('c',SET_F("BM"),buttonPublishMqtt);
sappend('c',SET_F("RT"),retainMqttMsg); sappend('c',SET_F("RT"),retainMqttMsg);
oappend(SET_F("d.Sf.MD.maxlength=")); oappend(itoa(MQTT_MAX_TOPIC_LEN,nS,10)); oappend(SET_F(";"));
oappend(SET_F("d.Sf.MG.maxlength=")); oappend(itoa(MQTT_MAX_TOPIC_LEN,nS,10)); oappend(SET_F(";"));
oappend(SET_F("d.Sf.MS.maxlength=")); oappend(itoa(MQTT_MAX_SERVER_LEN,nS,10)); oappend(SET_F(";"));
#else #else
oappend(SET_F("toggle('MQTT');")); // hide MQTT settings oappend(SET_F("toggle('MQTT');")); // hide MQTT settings
#endif #endif
@ -574,15 +578,6 @@ void getSettingsJS(byte subPage, char* dest)
sappend('c',SET_F("NT"),ntpEnabled); sappend('c',SET_F("NT"),ntpEnabled);
sappends('s',SET_F("NS"),ntpServerName); sappends('s',SET_F("NS"),ntpServerName);
sappend('c',SET_F("CF"),!useAMPM); sappend('c',SET_F("CF"),!useAMPM);
int syncIntervalIndex;
switch (ntpSyncInterval) {
case 86400: syncIntervalIndex = 0; break;
case 21600: syncIntervalIndex = 2; break;
case 14400: syncIntervalIndex = 3; break;
case 10800: syncIntervalIndex = 4; break;
default : syncIntervalIndex = 1; break;
}
sappend('i',SET_F("NP"),syncIntervalIndex);
sappend('i',SET_F("TZ"),currentTimezone); sappend('i',SET_F("TZ"),currentTimezone);
sappend('v',SET_F("UO"),utcOffsetSecs); sappend('v',SET_F("UO"),utcOffsetSecs);
char tm[32]; char tm[32];
@ -592,7 +587,7 @@ void getSettingsJS(byte subPage, char* dest)
sappends('s',SET_F("LT"),tm); sappends('s',SET_F("LT"),tm);
getTimeString(tm); getTimeString(tm);
sappends('m',SET_F("(\"times\")[0]"),tm); sappends('m',SET_F("(\"times\")[0]"),tm);
if ((int)(longitude*10.) || (int)(latitude*10.)) { if ((int)(longitude*10.0f) || (int)(latitude*10.0f)) {
sprintf_P(tm, PSTR("Sunrise: %02d:%02d Sunset: %02d:%02d"), hour(sunrise), minute(sunrise), hour(sunset), minute(sunset)); sprintf_P(tm, PSTR("Sunrise: %02d:%02d Sunset: %02d:%02d"), hour(sunrise), minute(sunrise), hour(sunset), minute(sunset));
sappends('m',SET_F("(\"times\")[1]"),tm); sappends('m',SET_F("(\"times\")[1]"),tm);
} }