diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml index 83854bd6..3771d9d5 100644 --- a/.github/ISSUE_TEMPLATE/bug.yml +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -48,7 +48,7 @@ body: attributes: label: What version/release of MM WLED? description: You can find this in by going to Config -> Security & Updates -> Scroll to Bottom. Copy and paste the entire line after "Server message" - placeholder: "e.g. build 2308250, WLEDMM_0.14.0-b27.31_esp32_4MB_M.bin" + placeholder: "e.g. build 2401030, WLEDMM_0.14.0-b29.35_esp32_4MB_M.bin" validations: required: true - type: dropdown diff --git a/.github/workflows/wled-ci.yml b/.github/workflows/wled-ci.yml index 59661ff8..d9933bd3 100644 --- a/.github/workflows/wled-ci.yml +++ b/.github/workflows/wled-ci.yml @@ -30,7 +30,7 @@ jobs: build: - name: Build Environments + name: Builds runs-on: ubuntu-latest needs: get_default_envs strategy: @@ -50,7 +50,7 @@ jobs: uses: actions/cache@v3 with: path: ~/.platformio - key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} + key: ${{ runner.os }}-${{ matrix.environment}}-${{ hashFiles('platformio.ini') }} - name: Set up Python uses: actions/setup-python@v4 with: diff --git a/.gitignore b/.gitignore index 789de0a9..c85fae0c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,21 +1,24 @@ -.pio .cache +.clang-format +.direnv +.DS_Store +.gitignore +.idea +.pio .pioenvs .piolibdeps .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 -/wled00/LittleFS +platformio_override.ini 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 diff --git a/CHANGELOG.md b/CHANGELOG.md index 594fa97e..11799d26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,15 +1,82 @@ -## WLED changelog +## [WLED upstream](https://github.com/Aircoookie/WLED/tree/0_14_1) changelog + +#### Build 2312290 +- Fix for #3622 +- NB: fix for #3613 #3609 are not needed in MoonModules fork +- Various tweaks and fixes + +#### Build 2312230 +- Fix for #2922 (option to force WiFi PHY mode to G on ESP8266) +- Fix for #3601, #3400 (incorrect sunrise/sunset, #3612 by @softhack007) + +#### Build 2312180 +- Bugfixes (#3593, #3490, #3573, #3517, #3561, #3555, #3541, #3536, #3522, #3533, #3508) + +#### Build 2311160 +- Bugfixes (#3496, #3487) +- New usermod: LDR sensor (#3490 by @JeffWDH) +- Effect: Twinklefox & Tinklecat metadata fix +- Effect: separate #HH and #MM for Scrolling Text (#3480) + +#### Build 2310010, build 2310130 +- Bugfixes for #3400, #3403, #3405 +- minor HTML optimizations +- audioreactive: bugfix for UDP sound sync (partly initialized packets) + +#### Build 2309240 +- Effect bugfixes and improvements (Meteor, Meteor Smooth, Scrolling Text) +- audioreactive: bugfixes for ES8388 and ES7243 init; minor improvements for analog inputs + +#### Build 2309050 +- Added receive and send sync groups to JSON API (#3317) (you can change sync groups using preset) +- Internal temperature usermod (#3246) +- New effect: Rolling Balls (a.k.a. linear bounce) (#1039) +- Various bug fixes and enhancements. + +#### Build 2308030 +- Fix ESP-NOW crash with AP mode Always + +#### Build 2307180 +- various fixes and improvements (ESP variants platform 5.3.0, effect optimizations, /json/cfg pin allocation) + +#### Build 2307130 +- larger `oappend()` stack buffer (3.5k) for ESP32 +- Preset cycle bugfix (#3262) +- effect updates (2D Plasmaball), `blur()` speedup +- 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) + +#### Build 2306270 +- ESP-NOW remote support (#3237) +- Pixel Magic tool (display pixel art) (#3249) +- Add WiFi network scan RPC command to Improv Serial (#3271) +- various fixes and improvements + +#### Build 2306210 +- 0.14.0-b3 release +- Multi relay usermod compile-time enabled option (-D MULTI_RELAY_ENABLED=true|false) + +#### Build 2306180 +- Added client-side option for applying effect defaults from metadata +- Improved ESP8266 stability by reducing WebSocket response resends +- Updated ESP8266 core to 3.1.2 + +#### Build 2306141 +- Lissajous improvements +- Scrolling Text improvements (leading 0) + +#### Build 2306140 +- Add settings PIN (un)locking to JSON post API #### Build 2306020 - 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) - Changes for allowing Alexa to change light color to White when auto-calculating from RGB (PR #3211) #### Build 2305280 - DDP protocol update (#3193) -- added PCF8574 I2C port expander support for Multi relay usermod - MQTT multipacket (fragmented) message fix - added option to retain MQTT brightness and color messages - new ethernet board: @srg74 Ethernet Shield @@ -340,7 +407,7 @@ - Added application level pong websockets reply (#2139) - Use AsyncTCP 1.0.3 as it mitigates the flickering issue from 0.13.0-b2 -- Fixed transition manually updated in preset overriden by field value +- Fixed transition manually updated in preset overridden by field value #### Build 2108050 @@ -684,7 +751,7 @@ #### Build 2101040 - Replaced Red & Blue effect with Aurora effect (PR #1589) -- Fixed HTTP changing segments uncommanded (#1618) +- Fixed HTTP changing segments un-commanded (#1618) - Updated copyright year and contributor page link #### Build 2012311 @@ -869,7 +936,7 @@ #### Build 2011040 -- Inversed Rain direction (fixes #1147) +- Inverted Rain direction (fixes #1147) #### Build 2011010 @@ -1080,7 +1147,7 @@ - Added module info page to web UI - Added realtime override functionality to web UI -- Added individial segment power and brightness to web UI +- Added individual segment power and brightness to web UI - Added feature to one-click select single segment only by tapping segment name - Removed palette jumping to default if color is changed diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b4fbef51..fdf1388c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,7 +14,7 @@ You are all set if you have enabled `Editor: Detect Indentation` in VS Code. #### Blocks -Whether the opening bracket of e.g. an `if` block is in the same line as the condition or in a separate line is up to your discretion. If there is only one statement, leaving out block braches is acceptable. +Whether the opening bracket of e.g. an `if` block is in the same line as the condition or in a separate line is up to your discretion. If there is only one statement, leaving out block braces is acceptable. Good: ```cpp diff --git a/package-lock.json b/package-lock.json index f02ad7c5..d22f144c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "wled", - "version": "0.14.0-b27.31", + "version": "0.14.0-b29.35", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "wled", - "version": "0.14.0-b27.31", + "version": "0.14.0-b29.35", "license": "GPL-3.0-or-later", "dependencies": { "clean-css": "^4.2.3", diff --git a/package.json b/package.json index db669843..47ea507d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wled", - "version": "0.14.0-b27.31", + "version": "0.14.0-b29.35", "description": "Tools for WLED project", "main": "tools/cdata.js", "directories": { diff --git a/platformio.ini b/platformio.ini index f1c121f6..a092c3c6 100644 --- a/platformio.ini +++ b/platformio.ini @@ -11,7 +11,7 @@ # 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, lolin_s2_mini, esp32c3dev, esp32s3dev_8MB +; 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 ; default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_8MB @@ -34,6 +34,7 @@ ; default_envs = esp8285_4CH_MagicHome ; default_envs = esp8285_H801 ; default_envs = d1_mini_5CH_Shojo_PCB +; default_envs = wemos_shield_esp32 ; default_envs = m5atom ; default_envs = esp32_eth ; default_envs = esp32dev_qio80 @@ -41,6 +42,7 @@ ; default_envs = esp32s2_saola ; default_envs = esp32c3dev ; default_envs = lolin_s2_mini +; default_envs = esp32s3dev_16MB_PSRAM_opi ; MoonModules entries ; =================== @@ -76,6 +78,7 @@ default_envs = ;; esp32s2_tinyUF2_PSRAM_S ;; experimental - only for adafruit -S2 boards with tinyUF2 bootloader !!! esp32s2_PSRAM_M ;; experimental esp32c3dev_4MB_M ;; experimental + esp32c3mini_dio_4MB_M ;; for boards that need "dio" flash mode (instead of qio) seeed_esp32c3_4MB_S ;; experimental esp32_4MB_V4_S ;; experimental esp32_16MB_V4_S ;; experimental, optimized for speed @@ -92,7 +95,7 @@ default_envs = src_dir = ./wled00 data_dir = ./wled00/data -build_cache_dir = ~/.buildcache +build_cache_dir = ~/.platformio/buildcache extra_configs = platformio_override.ini @@ -109,13 +112,14 @@ arduino_core_2_7_4 = espressif8266@2.6.2 arduino_core_3_0_0 = espressif8266@3.0.0 arduino_core_3_2_0 = espressif8266@3.2.0 arduino_core_4_1_0 = espressif8266@4.1.0 +arduino_core_3_1_2 = espressif8266@4.2.0 # Development platforms arduino_core_develop = https://github.com/platformio/platform-espressif8266#develop arduino_core_git = https://github.com/platformio/platform-espressif8266#feature/stage # Platform to use for ESP8266 -platform_wled_default = ${common.arduino_core_4_1_0} +platform_wled_default = ${common.arduino_core_3_1_2} # We use 2.7.4.7 for all, includes PWM flicker fix and Wstring optimization #platform_packages = tasmota/framework-arduinoespressif8266 @ 3.20704.7 platform_packages = platformio/framework-arduinoespressif8266 @@ -138,7 +142,7 @@ platform_packages = platformio/framework-arduinoespressif8266 # ------------------------------------------------------------------------------ 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 ;; for esp8266 - -DARDUINOJSON_DEBUG=1 ;; enables some debug asserts in arduinoJSON + -DARDUINOJSON_DEBUG=1 ;; WLEDMM: this enables some debug asserts in arduinoJSON # 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 @@ -230,8 +234,7 @@ upload_speed = 115200 # ------------------------------------------------------------------------------ lib_compat_mode = strict lib_deps = - fastled/FastLED @ 3.6.0 ;; 3.6.0 was release recently - ;https://github.com/FastLED/FastLED.git#master @3.6.0+sha.23c67b7 ;; up to 50% faster - using a "known good" hash, so we get predictable builds + fastled/FastLED @ 3.6.0 IRremoteESP8266 @ 2.8.2 ;;makuna/NeoPixelBus @ 2.7.5 ;; WLEDMM will be added in board specific sections ;;https://github.com/Aircoookie/ESPAsyncWebServer.git @ ~2.0.7 @@ -258,7 +261,7 @@ build_flags = -DESP8266 -DFP_IN_IROM ;-Wno-deprecated-declarations - ;; -Wno-register ;; leaves some warnings when compiling C files: command-line option '-Wno-register' is valid for C++/ObjC++ but not for C + ;-Wno-register ;; leaves some warnings when compiling C files: command-line option '-Wno-register' is valid for C++/ObjC++ but not for C ;-Dregister= # remove warnings in C++17 due to use of deprecated register keyword by the FastLED library ;; warning: this can be dangerous -Wno-misleading-indentation ; NONOSDK22x_190703 = 2.2.2-dev(38a443e) @@ -294,12 +297,13 @@ build_flags = -g -DARDUINO_ARCH_ESP32 #-DCONFIG_LITTLEFS_FOR_IDF_3_2 -D CONFIG_ASYNC_TCP_USE_WDT=0 + -D CONFIG_ASYNC_TCP_TASK_STACK_SIZE=9472 ;; WLEDMM increase stack by 1.25Kb, as audioreactive needs bigger SETTINGS_STACK_BUF_SIZE #use LITTLEFS library by lorol in ESP32 core 1.x.x instead of built-in in 2.x.x -D LOROL_LITTLEFS ; -DARDUINO_USB_CDC_ON_BOOT=0 ;; this flag is mandatory for "classic ESP32" when building with arduino-esp32 >=2.0.3 default_partitions = tools/WLED_ESP32_4MB_1MB_FS.csv ;; WLED standard for 4MB flash: 1.4MB firmware, 1MB filesystem -;default_partitions = tools/WLED_ESP32_4MB_256KB_FS.csv ;; Alternative for 4MB flash: 1.8MB firmware, 256KB filesystem (esptool erase_flash needed before changing) +;default_partitions = tools/WLED_ESP32_4MB_256KB_FS.csv ;; WLEDMM alternative for 4MB flash: 1.8MB firmware, 256KB filesystem (esptool erase_flash needed before changing) lib_deps = https://github.com/pbolduc/AsyncTCP.git @ 1.2.0 ;; WLEDMM this must be first in the list, otherwise Aircoookie/ESPAsyncWebServer pulls in an older version of AsyncTCP !! @@ -313,28 +317,24 @@ lib_deps = ;; ** For compiling with latest Frameworks (IDF4.4.x and arduino-esp32 v2.0.x) ** ;;; previous standard V4 platform -platformV4_pre = espressif32@ ~5.1.1 -platformV4_packages_pre = - platformio/framework-arduinoespressif32@ ~3.20004.0 +platformV4_pre = espressif32@5.2.0 +platformV4_packages_pre = toolchain-riscv32-esp @ 8.4.0+2021r2-patch5 ; required for platform version < 5.3.0, remove this line when upgrading to platform >=5.3.0 ;;; standard V4 platform -platformV4 = espressif32@5.2.0 +platformV4 = espressif32@5.3.0 platformV4_packages = - toolchain-riscv32-esp @ 8.4.0+2021r2-patch5 ; required for platform version < 5.3.0, remove this line when upgrading to platform >=5.3.0 - -;;; updated V4 platform (5.3.0) - experimental -;;platformV4_up = espressif32@ ~5.3.0 -;;platformV4_packages_up = ;;; experimental: latest V4 platform with latest arduino-esp32 2.0.9 + ESP-IDF 4.4.4 (may or may not work) -platformV4_xp = espressif32@ ~6.3.0 +platformV4_xp = espressif32@ ~6.4.0 platformV4_packages_xp = platformio/framework-arduinoespressif32 @ ~3.20009.0 ;; arduino-esp32 v2.0.9+ +;; platformV4_packages_xp = platformio/framework-arduinoespressif32 @ ~3.20011.0 ;; arduino-esp32 v2.0.11 (latest one supported in platformio) build_flagsV4 = -g -DARDUINO_ARCH_ESP32 -DESP32 -DCONFIG_LITTLEFS_FOR_IDF_3_2 -DLFS_THREADSAFE -D CONFIG_ASYNC_TCP_USE_WDT=0 - ; -DARDUINO_USB_CDC_ON_BOOT=0 ;; mandatory for "classic ESP32" when builing with arduino-esp32 >=2.0.3 + -D CONFIG_ASYNC_TCP_TASK_STACK_SIZE=9472 ;; WLEDMM increase stack by 1.25Kb, as audioreactive needs bigger SETTINGS_STACK_BUF_SIZE + ; -DARDUINO_USB_CDC_ON_BOOT=0 ;; mandatory for "classic ESP32" when building with arduino-esp32 >=2.0.3 ;;; V4.4.x libraries (without LOROL_LITTLEFS; with newer NeoPixelBus) lib_depsV4 = https://github.com/pbolduc/AsyncTCP.git @ 1.2.0 ;; WLEDMM this must be first in the list, otherwise Aircoookie/ESPAsyncWebServer pulls in an older version of AsyncTCP !! @@ -349,14 +349,14 @@ lib_depsV4 = ;; ;; please note that you can NOT update existing ESP32 installs with a "V4" build. Also updating by OTA will not work properly. ;; You need to completely erase your device (esptool erase_flash) first, then install the "V4" build from VSCode+platformio. -platform = espressif32@5.2.0 +platform = espressif32@5.3.0 platform_packages = - toolchain-riscv32-esp @ 8.4.0+2021r2-patch5 ; required for platform version < 5.3.0, remove this line when upgrading to platform >=5.3.0 build_flags = -g -Wshadow=compatible-local ;; emit warning in case a local variable "shadows" another local one -DARDUINO_ARCH_ESP32 -DESP32 #-DCONFIG_LITTLEFS_FOR_IDF_3_2 -D CONFIG_ASYNC_TCP_USE_WDT=0 + -D CONFIG_ASYNC_TCP_TASK_STACK_SIZE=9472 ;; WLEDMM increase stack by 1.25Kb, as audioreactive needs bigger SETTINGS_STACK_BUF_SIZE -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 lib_deps = @@ -368,13 +368,15 @@ lib_deps = ;; generic definitions for all ESP32-S2 boards platform = espressif32@5.2.0 platform_packages = - toolchain-riscv32-esp @ 8.4.0+2021r2-patch5 ; required for platform version < 5.3.0, remove this line when upgrading to platform >=5.3.0 + toolchain-riscv32-esp @ 8.4.0+2021r2-patch5 + toolchain-xtensa-esp32s2 @ 8.4.0+2021r2-patch5 build_flags = -g -DARDUINO_ARCH_ESP32 -DESP32 ;; WLEDMM -DARDUINO_ARCH_ESP32S2 -DCONFIG_IDF_TARGET_ESP32S2=1 -DCONFIG_LITTLEFS_FOR_IDF_3_2 -DLFS_THREADSAFE ;; WLEDMM -D CONFIG_ASYNC_TCP_USE_WDT=0 + -D CONFIG_ASYNC_TCP_TASK_STACK_SIZE=8614 ;; WLEDMM increase stack by 1Kb, as audioreactive needs bigger SETTINGS_STACK_BUF_SIZE -DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_USB_DFU_ON_BOOT=0 -DCO -DARDUINO_USB_MODE=0 ;; this flag is mandatory for ESP32-S2 ! @@ -388,15 +390,15 @@ lib_deps = [esp32c3] ;; generic definitions for all ESP32-C3 boards -platform = espressif32@5.2.0 +platform = espressif32@5.3.0 platform_packages = - toolchain-riscv32-esp @ 8.4.0+2021r2-patch5 ; required for platform version < 5.3.0, remove this line when upgrading to platform >=5.3.0 build_flags = -g -DARDUINO_ARCH_ESP32 -DESP32 ;; WLEDMM -DARDUINO_ARCH_ESP32C3 -DCONFIG_IDF_TARGET_ESP32C3=1 -DCONFIG_LITTLEFS_FOR_IDF_3_2 -DLFS_THREADSAFE ;; WLEDMM -D CONFIG_ASYNC_TCP_USE_WDT=0 + -D CONFIG_ASYNC_TCP_TASK_STACK_SIZE=9472 ;; WLEDMM increase stack by 1.25Kb, as audioreactive needs bigger SETTINGS_STACK_BUF_SIZE -DCO -DARDUINO_USB_MODE=1 ;; this flag is mandatory for ESP32-C3 ;; please make sure that the following flags are properly set (to 0 or 1) by your board.json, or included in your custom platformio_override.ini entry: @@ -409,9 +411,8 @@ lib_deps = [esp32s3] ;; generic definitions for all ESP32-S3 boards -platform = espressif32@5.2.0 +platform = espressif32@5.3.0 platform_packages = - toolchain-riscv32-esp @ 8.4.0+2021r2-patch5 ; required for platform version < 5.3.0, remove this line when upgrading to platform >=5.3.0 build_flags = -g -DESP32 -DARDUINO_ARCH_ESP32 @@ -419,6 +420,7 @@ build_flags = -g -DCONFIG_IDF_TARGET_ESP32S3=1 -DCONFIG_LITTLEFS_FOR_IDF_3_2 -DLFS_THREADSAFE ;; WLEDMM -D CONFIG_ASYNC_TCP_USE_WDT=0 + -D CONFIG_ASYNC_TCP_TASK_STACK_SIZE=9472 ;; WLEDMM increase stack by 1.25Kb, as audioreactive needs bigger SETTINGS_STACK_BUF_SIZE -DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_DFU_ON_BOOT=0 -DCO ;; please make sure that the following flags are properly set (to 0 or 1) by your board.json, or included in your custom platformio_override.ini entry: @@ -461,6 +463,7 @@ lib_deps = ${esp8266.lib_deps} ; board_build.ldscript = ${common.ldscript_1m128k} ; build_unflags = ${common.build_unflags} ; 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} [env:esp07] @@ -511,6 +514,21 @@ lib_deps = ${esp32.lib_deps} monitor_filters = esp32_exception_decoder board_build.partitions = ${esp32.default_partitions} +;WLEDMM: use WLEDMM build environments +; [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] board = esp32dev platform = ${esp32.platform} @@ -544,7 +562,8 @@ platform = ${esp32.platform} platform_packages = ${esp32.platform_packages} upload_speed = 921600 build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32_Ethernet -D RLYPIN=-1 -D WLED_USE_ETHERNET -D BTNPIN=-1 -D WLED_DISABLE_ESPNOW +build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32_Ethernet -D RLYPIN=-1 -D WLED_USE_ETHERNET -D BTNPIN=-1 + -D WLED_DISABLE_ESPNOW ;; ESP-NOW requires wifi, may crash with ethernet only lib_deps = ${esp32.lib_deps} board_build.partitions = ${esp32.default_partitions} @@ -558,6 +577,7 @@ board_build.flash_mode = qio upload_speed = 460800 build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32s2.build_flags} #-D WLED_RELEASE_NAME=S2_saola + ;-DLOLIN_WIFI_FIX ;; try this in case Wifi does not work -DARDUINO_USB_CDC_ON_BOOT=1 lib_deps = ${esp32s2.lib_deps} @@ -568,8 +588,9 @@ platform_packages = ${esp32c3.platform_packages} framework = arduino board = esp32-c3-devkitm-1 board_build.partitions = tools/WLED_ESP32_4MB_1MB_FS.csv -build_flags = ${common.build_flags} ${esp32c3.build_flags} #-D WLED_RELEASE_NAME=ESP32-C3 +build_flags = ${common.build_flags} ${esp32c3.build_flags} -D WLED_RELEASE_NAME=ESP32-C3 -D WLED_WATCHDOG_TIMEOUT=0 + -DLOLIN_WIFI_FIX ; seems to work much better with this -DARDUINO_USB_CDC_ON_BOOT=1 ;; for virtual CDC USB ;-DARDUINO_USB_CDC_ON_BOOT=0 ;; for serial-to-USB chip upload_speed = 460800 @@ -583,10 +604,10 @@ platform = ${esp32s3.platform} platform_packages = ${esp32s3.platform_packages} upload_speed = 921600 ; or 460800 build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} ${esp32s3.build_flags} +build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=ESP32-S3_8MB -D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0 -D ARDUINO_USB_CDC_ON_BOOT=0 ;; -D ARDUINO_USB_MODE=1 ;; for boards with serial-to-USB chip - ;-D ARDUINO_USB_CDC_ON_BOOT=1 ;; -D ARDUINO_USB_MODE=0 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB") + ;-D ARDUINO_USB_CDC_ON_BOOT=1 ;; -D ARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB") ;-D WLED_DEBUG lib_deps = ${esp32s3.lib_deps} board_build.partitions = tools/WLED_ESP32_8MB.csv @@ -595,11 +616,10 @@ board_build.flash_mode = qio ; board_build.flash_mode = dio ;; try this if you have problems at startup monitor_filters = esp32_exception_decoder -[env:esp32s3dev_8MB_PSRAM] -;; ESP32-TinyS3 development board, with 8MB FLASH and 8MB PSRAM (memory_type: qio_opi, qio_qspi, or opi_opi) -;board = um_tinys3 ; -> needs workaround from https://github.com/Aircoookie/WLED/pull/2905#issuecomment-1328049860 -;board = esp32s3box ; -> error: 'esp32_adc2gpio' was not declared in this scope -board = esp32-s3-devkitc-1 ; -> compiles, but does not support PSRAM +[env:esp32s3dev_8MB_PSRAM_opi] +;; ESP32-S3 development board, with 8MB FLASH and >= 8MB PSRAM (memory_type: qio_opi) +board = esp32-s3-devkitc-1 ;; generic dev board; the next line adds PSRAM support +board_build.arduino.memory_type = qio_opi ;; use with PSRAM: 8MB or 16MB platform = ${esp32s3.platform} platform_packages = ${esp32s3.platform_packages} upload_speed = 921600 @@ -607,7 +627,7 @@ build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32s3.build_flags} -D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0 ;-D ARDUINO_USB_CDC_ON_BOOT=0 ;; -D ARDUINO_USB_MODE=1 ;; for boards with serial-to-USB chip - -D ARDUINO_USB_CDC_ON_BOOT=1 ;; -D ARDUINO_USB_MODE=0 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB") + -D ARDUINO_USB_CDC_ON_BOOT=1 -D ARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB") ; -D WLED_RELEASE_NAME=ESP32-S3_PSRAM -D WLED_USE_PSRAM -DBOARD_HAS_PSRAM ; tells WLED that PSRAM shall be used lib_deps = ${esp32s3.lib_deps} @@ -616,6 +636,18 @@ board_build.f_flash = 80000000L board_build.flash_mode = qio monitor_filters = esp32_exception_decoder +[env:esp32s3dev_16MB_PSRAM_opi] +extends = env:esp32s3dev_8MB_PSRAM_opi +board_build.partitions = tools/WLED_ESP32_16MB.csv +board_upload.flash_size = 16MB + +[env:esp32s3dev_8MB_PSRAM_qspi] +;; ESP32-TinyS3 development board, with 8MB FLASH and PSRAM (memory_type: qio_qspi) +extends = env:esp32s3dev_8MB_PSRAM_opi +;board = um_tinys3 ; -> needs workaround from https://github.com/Aircoookie/WLED/pull/2905#issuecomment-1328049860 +board = esp32-s3-devkitc-1 ;; generic dev board; the next line adds PSRAM support +board_build.arduino.memory_type = qio_qspi ;; use with PSRAM: 2MB or 4MB + [env:esp8285_4CH_MagicHome] board = esp8285 platform = ${common.platform_wled_default} @@ -684,13 +716,14 @@ platform_packages = ${esp32s2.platform_packages} board = lolin_s2_mini board_build.partitions = tools/WLED_ESP32_4MB_1MB_FS.csv build_unflags = ${common.build_unflags} #-DARDUINO_USB_CDC_ON_BOOT=1 -build_flags = ${common.build_flags} ${esp32s2.build_flags} #-D WLED_RELEASE_NAME=LolinS2 +build_flags = ${common.build_flags} ${esp32s2.build_flags} -D WLED_RELEASE_NAME=ESP32-S2 -DBOARD_HAS_PSRAM -DARDUINO_USB_CDC_ON_BOOT=1 # try disabling and enabling unflag above in case of board-specific issues, will disable Serial -DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_USB_DFU_ON_BOOT=0 -DLOLIN_WIFI_FIX ; seems to work much better with this -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 CONFIG_ASYNC_TCP_USE_WDT=0 -D LEDPIN=16 @@ -726,6 +759,8 @@ upload_speed = 115200 lib_deps = ${esp32c3.lib_deps} board_build.partitions = tools/WLED_ESP32_2MB_noOTA.csv board_build.flash_mode = dio +board_upload.flash_size = 2MB +board_upload.maximum_size = 2097152 ;WLEDMM: see below ; [env:wemos_shield_esp32] @@ -739,7 +774,7 @@ board_build.flash_mode = dio ; -D RLYPIN=19 ; -D BTNPIN=17 ; -D IRPIN=18 -; -D UWLED_USE_MY_CONFIG +; -U WLED_USE_MY_CONFIG ; -D USERMOD_DALLASTEMPERATURE ; -D USERMOD_FOUR_LINE_DISPLAY ; -D TEMPERATURE_PIN=23 @@ -904,6 +939,16 @@ board_build.partitions = ${esp32.default_partitions} ; shared build flags and lib deps for minimum and maximum environment [common_mm] + +build_disable_sync_interfaces = + -D WLED_DISABLE_LOXONE + -D WLED_DISABLE_ALEXA + -D WLED_DISABLE_HUESYNC + -D WLED_DISABLE_MQTT + -D WLED_DISABLE_INFRARED + -D WLED_DISABLE_ADALIGHT ;; WLEDMM this board does not have a serial-to-USB chip. Better to disable serial protocols, to avoid crashes (see upstream #3128) + -D WLED_DISABLE_ESPNOW ;; ESP-NOW requires wifi, may crash with ethernet only + build_flags_S = -Wall -Wformat -Woverflow -Wuninitialized -Winit-self -Warray-bounds ; enables more warnings -Wno-attributes -Wno-unused-variable -Wno-unused-function -Wno-deprecated-declarations ;disables some stupid warnings @@ -914,20 +959,17 @@ build_flags_S = -D USERMOD_AUDIOREACTIVE -D UM_AUDIOREACTIVE_USE_NEW_FFT ; use latest (upstream) FFTLib, instead of older library modified by blazoncek. Slightly faster, more accurate, needs 2KB RAM extra ; -D USERMOD_ARTIFX ;; WLEDMM usermod - temporarily moved into "_M", due to problems in "_S" when compiling with -O2 - ; -D WLEDMM_FASTPATH ;; WLEDMM experimental option. Reduces audio lag (latency), and allows for faster LED framerates. May break compatibility with previous versions. + -D WLEDMM_FASTPATH ;; WLEDMM experimental option. Reduces audio lag (latency), and allows for faster LED framerates. May break compatibility with previous versions. ; -D WLED_DEBUG_HEAP ;; WLEDMM enable heap debugging - ; -D WLED_DISABLE_LOXONE - ; -D WLED_DISABLE_ALEXA - ; -D WLED_DISABLE_HUESYNC - ; -D WLED_DISABLE_MQTT - ; -D WLED_DISABLE_INFRARED - ; -D WLED_ENABLE_DMX + ${common_mm.build_disable_sync_interfaces} lib_deps_S = - https://github.com/kosme/arduinoFFT#develop @ 1.9.2+sha.419d7b0 ;; used for USERMOD_AUDIOREACTIVE - using "known working" hash + ;; https://github.com/kosme/arduinoFFT#develop @ 1.9.2+sha.419d7b0 ;; used for USERMOD_AUDIOREACTIVE - using "known working" hash + https://github.com/softhack007/arduinoFFT.git#develop @ 1.9.2 ;; used for USERMOD_AUDIOREACTIVE - optimized version, 10% faster on -S2/-C3 + animartrix_build_flags = -D USERMOD_ANIMARTRIX ;; WLEDMM usermod: CC BY-NC 3.0 licensed effects by Stefan Petrick -animartrix_lib_deps = https://github.com/netmindz/animartrix.git#f070fefc42febe2de3a2ab5d6d39e78bbc539702 +animartrix_lib_deps = https://github.com/netmindz/animartrix.git#18bf17389e57c69f11bc8d04ebe1d215422c7fb7 build_flags_M = -D USERMOD_ARTIFX ; WLEDMM usermod - temporarily moved into "_M", due to problems in "_S" when compiling with -O2 @@ -953,7 +995,7 @@ lib_deps_M = lib_deps_V4_M = ;https://github.com/blazoncek/OneWire.git ; includes bugfixes for inconsistent readings paulstoffregen/OneWire@ ^2.3.7 ; used for USERMOD_DALLASTEMPERATURE -> need newer release with bugfixes for -S3; still requires TEMPERATURE_PIN < 46 - olikraus/U8g2@ ^2.34.5 ; used for USERMOD_FOUR_LINE_DISPLAY -> need newer version with bugfixes for arduino-esp32 v2.0.4 (Wire inititialization) + olikraus/U8g2@ ^2.34.5 ; used for USERMOD_FOUR_LINE_DISPLAY -> need newer version with bugfixes for arduino-esp32 v2.0.4 (Wire initialization) ${common_mm.animartrix_lib_deps} build_flags_XL = @@ -961,7 +1003,7 @@ build_flags_XL = -D USERMOD_MPU6050_IMU ; gyro/accelero for USERMOD_GAMES (ONLY WORKS IF USERMOD_FOUR_LINE_DISPLAY NOT INCLUDED - I2C SHARING BUG) -D USERMOD_GAMES ; WLEDMM usermod -D USERMOD_BATTERY ;; enable Battery usermod - -D USERMOD_BATTERY_USE_LIPO ;; use new "decharging curve" for LiPo cells + -D USERMOD_BATTERY_USE_LIPO ;; use new "discharging curve" for LiPo cells -D USERMOD_BH1750 -D USERMOD_ANIMATED_STAIRCASE -D USERMOD_RTC ;; experimental @@ -970,8 +1012,8 @@ build_flags_XL = -D USERMOD_MULTI_RELAY -D USERMOD_PIRSWITCH -D USERMOD_PWM_FAN - ; -D USERMOD_PING_PONG_CLOCK //Removed as dots is confusing - -D USERMOD_BUZZER + ; -D USERMOD_PING_PONG_CLOCK ;; Removed as dots is confusing + ; -D USERMOD_BUZZER ;; Removed as it grabs gpio32 (pin needed by audioreactive) -D USERMOD_SN_PHOTORESISTOR -D USERMOD_BME280 -D USERMOD_DHT @@ -1013,32 +1055,34 @@ monitor_filters = esp32_exception_decoder [esp32_4MB_M_base] extends = esp32_4MB_S_base build_flags = ${esp32_4MB_S_base.build_flags} ${common_mm.build_flags_M} +build_unflags = ${esp32_4MB_S_base.build_unflags} ${common_mm.build_disable_sync_interfaces} lib_deps = ${esp32_4MB_S_base.lib_deps} ${common_mm.lib_deps_M} ; board_build.partitions = tools/WLED_ESP32-wrover_4MB.csv [esp32_4MB_XL_base] extends = esp32_4MB_M_base build_flags = ${esp32_4MB_M_base.build_flags} ${common_mm.build_flags_XL} +build_unflags = ${esp32_4MB_M_base.build_unflags} ${common_mm.build_disable_sync_interfaces} lib_deps = ${esp32_4MB_M_base.lib_deps} ${common_mm.lib_deps_XL} ; board_build.partitions = tools/WLED_ESP32-wrover_4MB.csv -;common default for all V4 min environments +;common default for all V4 min environments, including -S3, -S2, -C3 [esp32_4MB_V4_S_base] board = esp32dev upload_speed = 460800 ; or 921600 platform = ${esp32.platformV4} -platform_packages = - ${esp32.platformV4_packages} - toolchain-xtensa-esp32 @ 8.4.0+2021r2-patch5 ; align main tools with riscV tools +platform_packages = ${esp32.platformV4_packages} build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} ${esp32.build_flagsV4} ${common_mm.build_flags_S} +build_flags = ${common.build_flags} ${common_mm.build_flags_S} ;; do not include ${esp32.build_flagsV4} here !!!! -Wno-misleading-indentation -Wno-format-truncation -Wshadow=compatible-local ;; emit warning in case a local variable "shadows" another local one ;-Wstack-usage=2732 ;; warn if a function needs more that 30% of availeable stack ("stack usage might be unbounded", "stack usage is 2824 bytes") ;-Wsuggest-attribute=const -Wsuggest-attribute=pure ;; ask compiler for hints on attributes -D WLED_ENABLE_DMX_INPUT -lib_deps = ${esp32.lib_depsV4} ${common_mm.lib_deps_S} +lib_deps = ${common_mm.lib_deps_S} ;; do not include ${esp32.lib_depsV4} here !!!! https://github.com/someweisguy/esp_dmx.git#ff0ab49 ;; for DMX_INPUT +esp32_build_flags = ${esp32.build_flagsV4} ${esp32_4MB_V4_S_base.build_flags} ;; this is for esp32 only, including specific "V4" flags +esp32_lib_deps = ${esp32.lib_depsV4} ${esp32_4MB_V4_S_base.lib_deps} ;; this is for esp32 only, including specific "V4" flags board_build.partitions = ${esp32.default_partitions} board_build.f_flash = 80000000L ; use full 80MHz speed for flash (default = 40Mhz) board_build.flash_mode = dio ; (dio = dual i/o; more compatible than qio = quad i/o) @@ -1047,8 +1091,10 @@ board_build.flash_mode = dio ; (dio = dual i/o; more compatible than qio = quad [esp32_4MB_V4_M_base] extends = esp32_4MB_V4_S_base -build_flags = ${esp32_4MB_V4_S_base.build_flags} ${common_mm.build_flags_M} +build_flags = ${esp32_4MB_V4_S_base.build_flags} ${common_mm.build_flags_M} ;; generic, for all variants lib_deps = ${esp32_4MB_V4_S_base.lib_deps} ${common_mm.lib_deps_V4_M} +esp32_build_flags = ${esp32_4MB_V4_S_base.esp32_build_flags} ${common_mm.build_flags_M} ;; for esp32 only, including specific "V4" flags +esp32_lib_deps = ${esp32_4MB_V4_S_base.esp32_lib_deps} ${common_mm.lib_deps_V4_M} board_build.partitions = ${esp32_4MB_V4_S_base.board_build.partitions} ;board_build.flash_mode = qio ; (dio = dual i/o; more compatible than qio = quad i/o) @@ -1091,7 +1137,7 @@ build_flags = [Speed_Flags] build_flags = -O2 ;; optimize for performance instead of size - ;-ffast-math ;; gives a few (2-5) percent sppedup on ESP32-S3, but causes slight slowdown on classic ESP32 + ;-ffast-math ;; gives a few (2-5) percent speedup on ESP32-S3, but causes slight slowdown on classic ESP32 -mtarget-align -free -fipa-pta ;; these are very useful, too -fno-jump-tables -fno-tree-switch-conversion ;; needed -freorder-blocks -Wwrite-strings -fstrict-volatile-bitfields ;; needed @@ -1147,13 +1193,22 @@ build_flags = ${esp32_4MB_M_base.build_flags} extends = esp32_4MB_XL_base build_flags = ${esp32_4MB_XL_base.build_flags} -D WLED_RELEASE_NAME=esp32_4MB_XL -build_unflags = - -D USERMOD_ANIMARTRIX ;; Tips our memory usage over the limit + ;-D WLED_DISABLE_ALEXA + ;-D WLED_DISABLE_HUESYNC ;; Over the limits ? + -D WLED_DISABLE_LOXONE ;; Over the limits + ;-D WLED_DISABLE_MQTT + ;-D WLED_DISABLE_INFRARED + -D WLEDMM_SAVE_FLASH ;; a humble attempt to save a few extra bytes +build_unflags = ${esp32_4MB_XL_base.build_unflags} + -D USERMOD_ANIMARTRIX ;; Tips our memory usage over the limit + -D USERMOD_BUZZER ;; Over the limits, and steals GPIO 32 + -D USERMOD_SN_PHOTORESISTOR ;; Over the limits + -D WLEDMM_FASTPATH ;; Over the limits ; RAM: [== ] 24.4% (used 80060 bytes from 327680 bytes) ; Flash: [==========] 95.3% (used 1499037 bytes from 1572864 bytes) -; HELP !!!!! : -; RAM: [== ] 24.5% (used 80356 bytes from 327680 bytes) -; Flash: [==========] 99.9% (used 1571053 bytes from 1572864 bytes) +; !!! HELP !!!!! : +; RAM: [=== ] 26.2% (used 85756 bytes from 327680 bytes) +; Flash: [==========] 100.0% (used 1572553 bytes from 1572864 bytes) ;; standard framework build for 16MB flash, optimized for speed [env:esp32_16MB_S] @@ -1308,7 +1363,7 @@ build_flags = ${common.build_flags_esp8266} -D USERMOD_GAMES ; WLEDMM usermod ; -D USERMOD_ARTIFX ; this is compiling but not working due to low memory on 8266 -D USERMOD_BATTERY ;; enable Battery usermod - -D USERMOD_BATTERY_USE_LIPO ;; use new "decharging curve" for LiPo cells + -D USERMOD_BATTERY_USE_LIPO ;; use new "discharging curve" for LiPo cells -D WLED_DEBUG_HOST='"192.168.x.x"' ;; to send debug messages over network to host 192.168.x.y - FQDN is also possible -D WLED_DEBUG_PORT=1768 ;; port for network debugging. default = 7868 ; -D WLED_DEBUG @@ -1441,7 +1496,7 @@ lib_deps = ${esp8266.lib_deps} ; compiled with ESP-IDF 4.4.1 [env:esp32_4MB_V4_S] extends = esp32_4MB_V4_S_base -build_flags = ${esp32_4MB_V4_S_base.build_flags} +build_flags = ${esp32_4MB_V4_S_base.esp32_build_flags} -D WLED_RELEASE_NAME=esp32_4MB_V4_S -D WLED_WATCHDOG_TIMEOUT=0 #-D WLED_DISABLE_BROWNOUT_DET -D ARDUINO_USB_CDC_ON_BOOT=0 ; needed for arduino-esp32 >=2.0.4; avoids errors on startup @@ -1454,6 +1509,7 @@ build_flags = ${esp32_4MB_V4_S_base.build_flags} ; -D WLED_DEBUG ; -D SR_DEBUG ; -D MIC_LOGGER +lib_deps = ${esp32_4MB_V4_S_base.esp32_lib_deps} lib_ignore = IRremoteESP8266 ; use with WLED_DISABLE_INFRARED for faster compilation ; RAM: [=== ] 25.1% (used 82176 bytes from 327680 bytes) ; Flash: [========= ] 93.8% (used 1474893 bytes from 1572864 bytes) @@ -1461,7 +1517,7 @@ lib_ignore = IRremoteESP8266 ; use with WLED_DISABLE_INFRARED for faster compila ; compiled with ESP-IDF 4.4.1 [env:esp32_4MB_V4_M] extends = esp32_4MB_V4_M_base -build_flags = ${esp32_4MB_V4_M_base.build_flags} +build_flags = ${esp32_4MB_V4_M_base.esp32_build_flags} -D WLED_RELEASE_NAME=esp32_4MB_V4_M -D WLED_WATCHDOG_TIMEOUT=0 #-D WLED_DISABLE_BROWNOUT_DET -D ARDUINO_USB_CDC_ON_BOOT=0 ; needed for arduino-esp32 >=2.0.4; avoids errors on startup @@ -1470,6 +1526,7 @@ build_flags = ${esp32_4MB_V4_M_base.build_flags} -D WLED_DISABLE_HUESYNC ;RAM 122 bytes; FLASH 6308 bytes ;-D WLED_DISABLE_MQTT ; RAM 216 bytes; FLASH 16496 bytes -D WLED_DISABLE_INFRARED ;RAM 136 bytes; FLASH 24492 bytes ;; softhack007 disabled to stay below 100% flash size +lib_deps = ${esp32_4MB_V4_M_base.esp32_lib_deps} lib_ignore = IRremoteESP8266 ; use with WLED_DISABLE_INFRARED for faster compilation build_unflags = ${esp32_4MB_V4_M_base.build_unflags} -D USERMOD_ANIMARTRIX ;; Tips our memory usage over the limit @@ -1482,14 +1539,14 @@ build_unflags = ${esp32_4MB_V4_M_base.build_unflags} extends = esp32_4MB_V4_S_base build_unflags = ${esp32_4MB_V4_S_base.build_unflags} ${Speed_Flags.build_unflags} ;; to override -Os -build_flags = ${esp32_4MB_V4_S_base.build_flags} +build_flags = ${esp32_4MB_V4_S_base.esp32_build_flags} ${Speed_Flags.build_flags} ;; optimize for speed instead of size -D WLED_RELEASE_NAME=esp32_16MB_V4_S -D WLED_WATCHDOG_TIMEOUT=0 #-D WLED_DISABLE_BROWNOUT_DET -D ARDUINO_USB_CDC_ON_BOOT=0 ; needed for arduino-esp32 >=2.0.4; avoids errors on startup -D WLEDMM_FASTPATH ; WLEDMM experimental option. Reduces audio lag (latency), and allows for faster LED framerates. May break compatibility with previous versions. ;; ${common_mm.animartrix_build_flags} ;; breaks the build - Internal Compiler Error -lib_deps = ${esp32_4MB_V4_S_base.lib_deps} +lib_deps = ${esp32_4MB_V4_S_base.esp32_lib_deps} ;; ${common_mm.animartrix_lib_deps} board = esp32_16MB board_build.partitions = tools/WLED_ESP32_16MB.csv ;; WLED standard for 16MB flash: 2MB firmware, 12 MB filesystem @@ -1504,10 +1561,18 @@ board_build.partitions = tools/WLED_ESP32_16MB.csv ;; WLED standard for ; compiled with ESP-IDF 4.4.1 [env:esp32_16MB_V4_M] extends = esp32_4MB_V4_M_base -build_flags = ${esp32_4MB_V4_M_base.build_flags} +build_flags = ${esp32_4MB_V4_M_base.esp32_build_flags} -D WLED_RELEASE_NAME=esp32_16MB_V4_M -D WLED_WATCHDOG_TIMEOUT=0 #-D WLED_DISABLE_BROWNOUT_DET -D ARDUINO_USB_CDC_ON_BOOT=0 ; needed for arduino-esp32 >=2.0.4; avoids errors on startup + ;; -D WLED_ENABLE_DMX ;; disabled because it does not work with ESP-IDF 4.4.x (buggy driver in SparkFunDMX) + -D WLED_ENABLE_DMX_INPUT ;; needs more testing + -D LEDPIN=16 -D RLYPIN=19 + -D AUDIOPIN=-1 -D TEMPERATURE_PIN=23 -D PIR_SENSOR_PIN=-1 -D PWM_PIN=-1 + -D ENCODER_DT_PIN=35 -D ENCODER_CLK_PIN=39 -D ENCODER_SW_PIN=5 ; WLEDMM spec by @SERG74: use 35 and 39 instead of 18 and 19 (conflicts) + -D FLD_PIN_SCL=-1 -D FLD_PIN_SDA=-1 ; use global! + -D HW_PIN_SCL=22 -D HW_PIN_SDA=21 +lib_deps = ${esp32_4MB_V4_M_base.esp32_lib_deps} board = esp32_16MB board_build.partitions = tools/WLED_ESP32_16MB.csv ;; WLED standard for 16MB flash: 2MB firmware, 12 MB filesystem ;board_build.partitions = tools/WLED_ESP32_16MB_9MB_FS.csv ;; WLED extended for 16MB flash: 3.2MB firmware, 9 MB filesystem @@ -1518,14 +1583,15 @@ board_build.partitions = tools/WLED_ESP32_16MB.csv ;; WLED standard for extends = esp32_4MB_V4_M_base build_unflags = ${common.build_unflags} -D CORE_DEBUG_LEVEL=0 -build_flags = ${esp32_4MB_V4_M_base.build_flags} +build_flags = ${esp32_4MB_V4_M_base.esp32_build_flags} ${Debug_Flags.build_flags} -D CORE_DEBUG_LEVEL=4 ;; 0=none, 1=error, 2=warning, 3=info, 4=debug, 5=verbose -D WLED_DEBUG_HEAP ;; WLEDMM enable heap debugging -D WLED_RELEASE_NAME=esp32_16MB_V4_M_debug -D WLED_WATCHDOG_TIMEOUT=0 #-D WLED_DISABLE_BROWNOUT_DET -D ARDUINO_USB_CDC_ON_BOOT=0 ; needed for arduino-esp32 >=2.0.4; avoids errors on startup -board = esp32_16MB +lib_deps = ${esp32_4MB_V4_M_base.esp32_lib_deps} +board = esp32_16MB board_build.partitions = tools/WLED_ESP32_16MB.csv ;; WLED standard for 16MB flash: 2MB firmware, 12 MB filesystem ;board_build.partitions = tools/WLED_ESP32_16MB_9MB_FS.csv ;; WLED extended for 16MB flash: 3.2MB firmware, 9 MB filesystem monitor_filters = esp32_exception_decoder @@ -1537,12 +1603,13 @@ monitor_filters = esp32_exception_decoder extends = esp32_4MB_V4_S_base board = lolin_d32_pro ;board = esp32cam -build_flags = ${esp32_4MB_V4_S_base.build_flags} +build_flags = ${esp32_4MB_V4_S_base.esp32_build_flags} -D WLED_RELEASE_NAME=esp32_4MB_PSRAM_S -D WLED_WATCHDOG_TIMEOUT=0 #-D WLED_DISABLE_BROWNOUT_DET -D ARDUINO_USB_CDC_ON_BOOT=0 ; needed for arduino-esp32 >=2.0.4; avoids errors on startup -D WLEDMM_FASTPATH ; WLEDMM experimental option. Reduces audio lag (latency), and allows for faster LED framerates. May break compatibility with previous versions. -DBOARD_HAS_PSRAM -D WLED_USE_PSRAM_JSON ;; -D WLED_USE_PSRAM ;; WLED_USE_PSRAM causes major slow-down (slow LEDs) on some ESP32 boards + ;; -DALL_JSON_TO_PSRAM ;; WLEDMM experimental --> try to force all JSON stuff into PSRAM; gives more free heap. -D WLED_DISABLE_LOXONE ; FLASH 1272 bytes -D WLED_DISABLE_HUESYNC ; RAM 122 bytes; FLASH 6308 bytes -D WLED_DISABLE_ALEXA ; RAM 116 bytes; FLASH 13524 bytes @@ -1552,6 +1619,7 @@ build_flags = ${esp32_4MB_V4_S_base.build_flags} ; -D WLED_DEBUG ; -D SR_DEBUG ; -D MIC_LOGGER +lib_deps = ${esp32_4MB_V4_S_base.esp32_lib_deps} lib_ignore = IRremoteESP8266 ; use with WLED_DISABLE_INFRARED for faster compilation ;; RAM: [== ] 24.3% (used 79524 bytes from 327680 bytes) ;; Flash: [========= ] 93.2% (used 1466389 bytes from 1572864 bytes) @@ -1569,13 +1637,14 @@ build_unflags = ${esp32_4MB_V4_S_base.build_unflags} -mfix-esp32-psram-cache-issue ;; this fix is not needed any more for revision 3 -mfix-esp32-psram-cache-strategy=memw ;; same as above -build_flags = ${esp32_4MB_V4_S_base.build_flags} +build_flags = ${esp32_4MB_V4_S_base.esp32_build_flags} -DARDUINO_EVENT_RUNNING_CORE=0 ;; assign Wifi to core0, to have more CPU on core#1 (arduino loop) -DARDUINO_RUNNING_CORE=1 ;; should be default, but does not hurt -DCONFIG_MBEDTLS_DYNAMIC_BUFFER=1 ;; optional - seems to move more buffers into PSRAM ;;${Speed_Flags.build_flags} ;; optimize for speed instead of size --> over 100% flash, but works with 256KB filesystem (alternative partitions file) -D WLEDMM_FASTPATH ; WLEDMM experimental option. Reduces audio lag (latency), and allows for faster LED framerates. May break compatibility with previous versions. -DBOARD_HAS_PSRAM -D WLED_USE_PSRAM_JSON ;; -D WLED_USE_PSRAM ;; WLED_USE_PSRAM causes major slow-down (slow LEDs) on some ESP32 boards + ;; -DALL_JSON_TO_PSRAM ;; WLEDMM experimental --> try to force all JSON stuff into PSRAM; gives more free heap. ;;-D CONFIG_ESP32_REV_MIN=3 ;; disables PSRAM bug workarounds in the core, reducing the code size and improving overall performance. -D WLED_RELEASE_NAME=esp32_4MB_PSRAM_REV3_S -D WLED_WATCHDOG_TIMEOUT=0 #-D WLED_DISABLE_BROWNOUT_DET @@ -1590,6 +1659,7 @@ build_flags = ${esp32_4MB_V4_S_base.build_flags} ; -D WLED_DEBUG ; -D SR_DEBUG ; -D MIC_LOGGER +lib_deps = ${esp32_4MB_V4_S_base.esp32_lib_deps} lib_ignore = IRremoteESP8266 ; use with WLED_DISABLE_INFRARED for faster compilation ;; RAM: [==== ] 35.9% (used 117688 bytes from 327680 bytes) ;; Flash: [========= ] 94.5% (used 1487097 bytes from 1572864 bytes) @@ -1600,7 +1670,7 @@ extends = esp32_4MB_V4_M_base board = lolin_d32_pro ;board = esp32cam board_build.partitions = tools/WLED_ESP32_4MB_256KB_FS.csv ;; 1.8MB firmware, 256KB filesystem (esptool erase_flash needed when changing from "standard WLED" partitions) -build_flags = ${esp32_4MB_V4_M_base.build_flags} +build_flags = ${esp32_4MB_V4_M_base.esp32_build_flags} -D WLED_RELEASE_NAME=esp32_4MB_PSRAM_M -D WLED_WATCHDOG_TIMEOUT=0 #-D WLED_DISABLE_BROWNOUT_DET -D ARDUINO_USB_CDC_ON_BOOT=0 ; needed for arduino-esp32 >=2.0.4; avoids errors on startup @@ -1614,6 +1684,7 @@ build_flags = ${esp32_4MB_V4_M_base.build_flags} ; -D WLED_DEBUG ; -D SR_DEBUG ; -D MIC_LOGGER +lib_deps = ${esp32_4MB_V4_M_base.esp32_lib_deps} ;lib_ignore = IRremoteESP8266 ; use with WLED_DISABLE_INFRARED for faster compilation ;; RAM: [== ] 24.9% (used 81484 bytes from 327680 bytes) ;; Flash: [======== ] 84.6% (used 1607857 bytes from 1900544 bytes) @@ -1756,8 +1827,8 @@ board_build.partitions = tools/WLED_ESP32_8MB.csv ;; to ewowi - i'll optimize this entry later, as a few things can be inherited for sure. To softhack: sure ;-) [env:esp32s2_tinyUF2_PSRAM_S] extends = esp32_4MB_V4_S_base -platform = ${esp32.platformV4} -platform_packages = ${esp32.platformV4_packages} +platform = ${esp32s2.platform} ;; using 5.2.0, due to massive connectivity problems on -S2 with 5.3.0 +platform_packages = ${esp32s2.platform_packages} board = adafruit_qtpy_esp32s2 board_build.partitions = tools/partitions-4MB_spiffs-tinyuf2.csv ;; this is needed for tinyUF2 bootloader! Filename has to end in "tinyuf2.csv" @@ -1768,18 +1839,21 @@ build_unflags = ${common.build_unflags} -D USERMOD_DALLASTEMPERATURE ;; disabled because it hangs during usermod setup on -S3 (autodetect broken?) -D WLED_ENABLE_DMX ;; disabled because it does not work with ESP-IDF 4.4.x (buggy driver in SparkFunDMX) -D WLED_ENABLE_DMX_INPUT ;; needs more testing + -DWLEDMM_FASTPATH ;; needs more testing on -S2 build_flags = ${common.build_flags} ${esp32s2.build_flags} ; ${Debug_Flags.build_flags} ;ewowi: enabling debug causes Error: The program size (1463330 bytes) is greater than maximum allowed (1441792 bytes) -D WLED_WATCHDOG_TIMEOUT=0 -D CONFIG_ASYNC_TCP_USE_WDT=0 ${common_mm.build_flags_S} -Wno-misleading-indentation -Wno-format-truncation + -DCONFIG_MBEDTLS_DYNAMIC_BUFFER=1 ;; optional - allows some buffers to use PSRAM -D WLED_RELEASE_NAME=esp32S2_4MB_UF2_S -DARDUINO_USB_CDC_ON_BOOT=1 ;; mandatory, otherwise USB does not work!! -D WLED_DISABLE_ADALIGHT ;; disables serial protocols when using CDC USB (Serial RX will receive junk commands, unless its pulled down by resistor) -DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_USB_DFU_ON_BOOT=0 -D SERVERNAME='"WLED-S2"' -DBOARD_HAS_PSRAM -D WLED_USE_PSRAM_JSON ;; -D WLED_USE_PSRAM + -DALL_JSON_TO_PSRAM ;; WLEDMM experimental --> try to force all JSON stuff into PSRAM; gives more free heap. -D WLED_DISABLE_LOXONE ;; FLASH 1272 bytes -D WLED_DISABLE_HUESYNC ;; RAM 122 bytes; FLASH 6308 bytes -D WLED_DISABLE_ALEXA ;; RAM 116 bytes; FLASH 13524 bytes @@ -1809,8 +1883,8 @@ monitor_filters = esp32_exception_decoder ;; PINs assignments optimized for use with serg74 "mini shield" [env:esp32s2_PSRAM_M] extends = esp32_4MB_V4_M_base -platform = ${esp32.platformV4} ;; more stable on -S2 than 5.1.1 -platform_packages = ${esp32.platformV4_packages} +platform = ${esp32s2.platform} ;; using 5.2.0, due to massive connectivity problems on -S2 with 5.3.0 +platform_packages = ${esp32s2.platform_packages} board = lolin_s2_mini board_build.partitions = tools/WLED_ESP32_4MB_256KB_FS.csv ;; 1.8MB firmware, 256KB filesystem (esptool erase_flash needed when changing from "standard WLED" partitions) @@ -1822,6 +1896,7 @@ build_unflags = ${common.build_unflags} -D USERMOD_DALLASTEMPERATURE ;; disabled because it hangs during usermod setup on -S3 (autodetect broken?) -D WLED_ENABLE_DMX ;; disabled because it does not work with ESP-IDF 4.4.x (buggy driver in SparkFunDMX) -D WLED_ENABLE_DMX_INPUT ;; needs more testing + -DWLEDMM_FASTPATH ;; needs more testing on -S2 build_flags = ${common.build_flags} ${esp32s2.build_flags} ;; ${Debug_Flags.build_flags} -D WLED_WATCHDOG_TIMEOUT=0 -D CONFIG_ASYNC_TCP_USE_WDT=0 @@ -1829,6 +1904,7 @@ build_flags = ${common.build_flags} ${esp32s2.build_flags} -Wno-misleading-indentation -Wno-format-truncation -D WLED_RELEASE_NAME=esp32s2_4MB_M -DBOARD_HAS_PSRAM -D WLED_USE_PSRAM_JSON ;; -D WLED_USE_PSRAM + ;; -DALL_JSON_TO_PSRAM ;; WLEDMM experimental --> try to force all JSON stuff into PSRAM; gives more free heap. -DLOLIN_WIFI_FIX -DWLEDMM_WIFI_POWERON_HACK ;; seems to work much better with this -DARDUINO_USB_CDC_ON_BOOT=0 -DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_USB_DFU_ON_BOOT=1 -D WLED_DISABLE_ADALIGHT ;; disables serial protocols, as the board only has CDC USB @@ -1842,7 +1918,7 @@ build_flags = ${common.build_flags} ${esp32s2.build_flags} -D HW_PIN_SCL=35 -D HW_PIN_SDA=33 -D RLYPIN=9 ;; -D HW_PIN_MOSISPI=11 -D HW_PIN_CLOCKSPI=7 -D HW_PIN_MISOSPI=9 ;; 9 already in use for RELAY, 7 for IR - -D SR_DMTYPE=1 -D I2S_SDPIN=34 -D I2S_CKPIN=14 -D I2S_WSPIN=17 -D MCLK_PIN=-1 ;; reommended for mini shield + -D SR_DMTYPE=1 -D I2S_SDPIN=34 -D I2S_CKPIN=14 -D I2S_WSPIN=17 -D MCLK_PIN=-1 ;; recommended for mini shield ;; -D FFTTASK_PRIORITY=2 ;; useful for testing FFT timing. reduces audio latency, but makes effects slower. ;; -D STATUSLED=15 -D WLED_USE_MY_CONFIG @@ -1876,6 +1952,7 @@ build_unflags = ${common.build_unflags} -D WLED_ENABLE_DMX_INPUT ;; needs more testing ;-D WLED_DEBUG_HOST='"192.168.x.x"' ;; to disable net print -D USERMOD_ANIMARTRIX ;; Tips our memory usage over the limit + -DWLEDMM_FASTPATH ;; needs more testing on -C3 build_flags = ${common.build_flags} ${esp32c3.build_flags} ; -D WLED_DISABLE_OTA ;; OTA is not possible for boards with 2MB flash only (like some Ai-Thinker ESP32-C3-12F models) @@ -1907,6 +1984,23 @@ lib_ignore = ; RAM: [== ] 23.7% (used 77780 bytes from 327680 bytes) ; Flash: [========= ] 93.9% (used 1477456 bytes from 1572864 bytes) +;; MM environment for ESP32-C3 "mini" and "super mini" -> flash mode "dio" instead of "qio" (see #101) +[env:esp32c3mini_dio_4MB_M] +extends = env:esp32c3dev_4MB_M +board = lolin_c3_mini +board_build.flash_mode = dio ;; some super-mini boards are unstable with "qio" mode +;; board_build.partitions = tools/WLED_ESP32_4MB_256KB_FS.csv ;; optional: 1.8MB firmware, 256KB filesystem (esptool erase_flash needed when changing from "standard WLED" partitions) +;;; replace WLED_RELEASE_NAME, disable CDC_ON_BOOT +build_unflags = ${env:esp32c3dev_4MB_M.build_unflags} + -DARDUINO_USB_CDC_ON_BOOT=1 + -D WLED_RELEASE_NAME=esp32c3dev_4MB_M +build_flags = ${env:esp32c3dev_4MB_M.build_flags} + -DARDUINO_USB_CDC_ON_BOOT=0 + -D WLED_RELEASE_NAME=esp32c3mini_dio_4MB_M + -D WLED_DISABLE_BROWNOUT_DET ;; the board only has a 500mA LDO, better to disable brownout detection + -D WLED_DISABLE_ADALIGHT ;; to disable serial protocols for boards with CDC USB (Serial RX will receive junk commands, unless its pulled down by resistor) + -D HW_PIN_SDA=0 -D HW_PIN_SCL=1 ;; avoid pin conflicts + ;; MM environment for "seeed xiao -C3" boards [env:seeed_esp32c3_4MB_S] extends = env:esp32c3dev_4MB_M @@ -1916,6 +2010,7 @@ platform_packages = ${esp32.platformV4_packages_pre} board_build.flash_mode = qio upload_speed = 460800 build_unflags = ${env:esp32c3dev_4MB_M.build_unflags} + -DWLEDMM_FASTPATH ;; needs more testing on -C3 build_flags = ${common.build_flags} ${esp32c3.build_flags} -D WLED_WATCHDOG_TIMEOUT=0 -D CONFIG_ASYNC_TCP_USE_WDT=0 ${common_mm.build_flags_S} -Wno-misleading-indentation -Wno-format-truncation @@ -1945,9 +2040,11 @@ monitor_filters = esp32_exception_decoder # custom board environments # ------------------------------------------------------------------------------ -[wemos_shield_esp32_4MB_M_base] -extends = esp32_4MB_M_base -build_flags = ${esp32_4MB_M_base.build_flags} +;https://www.tindie.com/products/serg74/wled-shield-board-for-addressable-leds/ +;https://www.tindie.com/products/moonmodules/shield-board-for-esp32-for-wled-addressable-leds/ +[wemos_shield_esp32_4MB_S_base] +extends = esp32_4MB_S_base +build_flags = ${esp32_4MB_S_base.build_flags} -D ABL_MILLIAMPS_DEFAULT=9500 ; Wemos max 10A -D LEDPIN=16 -D RLYPIN=19 @@ -1963,11 +2060,21 @@ build_flags = ${esp32_4MB_M_base.build_flags} -D PWM_PIN=-1 ; -D WLED_USE_MY_CONFIG +[wemos_shield_esp32_4MB_M_base] +extends = wemos_shield_esp32_4MB_S_base +build_flags = ${wemos_shield_esp32_4MB_S_base.build_flags} ${common_mm.build_flags_M} +lib_deps = ${wemos_shield_esp32_4MB_S_base.lib_deps} ${common_mm.lib_deps_M} + [wemos_shield_esp32_4MB_XL_base] extends = wemos_shield_esp32_4MB_M_base build_flags = ${wemos_shield_esp32_4MB_M_base.build_flags} ${common_mm.build_flags_XL} lib_deps = ${wemos_shield_esp32_4MB_M_base.lib_deps} ${common_mm.lib_deps_XL} +[env:wemos_shield_esp32_4MB_S] +extends = wemos_shield_esp32_4MB_S_base +build_flags = ${wemos_shield_esp32_4MB_S_base.build_flags} + -D WLED_RELEASE_NAME=wemos_shield_esp32_4MB_S + [env:wemos_shield_esp32_4MB_M] extends = wemos_shield_esp32_4MB_M_base build_flags = ${wemos_shield_esp32_4MB_M_base.build_flags} @@ -1995,6 +2102,13 @@ build_unflags = ${common.build_unflags} ${Shield_LineIn.build_unflags} build_flags = ${wemos_shield_esp32_4MB_M_base.build_flags} ${Shield_LineIn.build_flags} -D WLED_RELEASE_NAME=wemos_shield_esp32_4MB_LineIn_M +[env:wemos_shield_esp32_16MB_S] +extends = wemos_shield_esp32_4MB_S_base +build_flags = ${wemos_shield_esp32_4MB_S_base.build_flags} + -D WLED_RELEASE_NAME=wemos_shield_esp32_16MB_S +board = esp32_16MB +board_build.partitions = tools/WLED_ESP32_16MB.csv ;; WLED standard for 16MB flash: 2MB firmware, 12 MB filesystem + [env:wemos_shield_esp32_16MB_M] extends = wemos_shield_esp32_4MB_M_base build_flags = ${wemos_shield_esp32_4MB_M_base.build_flags} @@ -2054,6 +2168,7 @@ board = esp32_16MB board_build.partitions = tools/WLED_ESP32_16MB.csv ;; WLED standard for 16MB flash: 2MB firmware, 12 MB filesystem ;board_build.partitions = tools/WLED_ESP32_16MB_9MB_FS.csv ;; WLED extended for 16MB flash: 3.2MB firmware, 9 MB filesystem +;https://www.athom.tech/blank-1/wled-esp32-music-addressable-led-strip-controller [env:athom_music_esp32_4MB_M] extends = esp32_4MB_M_base build_flags = ${esp32_4MB_M_base.build_flags} ${Athom_PDMmic.build_flags} @@ -2073,6 +2188,25 @@ build_flags = ${esp32_4MB_M_base.build_flags} ${Athom_PDMmic.build_flags} ; -D PWM_PIN=-1 ; -D WLED_USE_MY_CONFIG +;https://shop.myhome-control.de/Elektronik/ +[env:abc_wled_controller_v43_S] +extends = esp32_4MB_S_base +build_unflags = ${esp32_4MB_S_base.build_unflags} ${common_mm.build_disable_sync_interfaces} +build_flags = ${esp32_4MB_S_base.build_flags} + -D WLED_RELEASE_NAME=abc_wled_controller_v43_M + -D LEDPIN=16 + -D ABL_MILLIAMPS_DEFAULT=5000 ; 5A default. Max 13A depending on the wires connected + -D WLED_USE_ETHERNET + -D WLED_ETH_DEFAULT=9 ; ABC! WLED V43 & compatible + -D RLYPIN=-1 -D BTNPIN=-1 ;; Prevent clash + -D WLED_DISABLE_ESPNOW ;; ESP-NOW requires wifi, may crash with ethernet only + -D AUDIOPIN=-1 + -D FLD_PIN_SCL=-1 -D FLD_PIN_SDA=-1 ; use global! + ; -D WLED_USE_MY_CONFIG + -D SR_DMTYPE=4 -D I2S_SDPIN=32 -D I2S_WSPIN=15 -D I2S_CKPIN=14 -D MCLK_PIN=0 ; generic i2s with mclk 0 + -D SR_SQUELCH=1 -D SR_GAIN=60 ; increrase squelch if noise, in test 0 is okay, but only slightly + -D SR_FREQ_PROF=1 ; Generic line in + ; ESP32 WLED pico board with builtin ICS-43432 microphpone [env:esp32_pico_4MB_M] extends = esp32_4MB_M_base @@ -2118,7 +2252,7 @@ board = pico32 ;platform_packages = upload_speed = 256000 ;; or 115200 ;; or 460800 ; or 921600 (slower speeds are better when flashing without a soldered connection) -build_flags = ${esp32_4MB_V4_S_base.build_flags} +build_flags = ${esp32_4MB_V4_S_base.esp32_build_flags} -D ARDUINO_USB_CDC_ON_BOOT=0 ; needed for arduino-esp32 >=2.0.4; avoids errors on startup -D WLED_RELEASE_NAME=esp32_pico_4MB_V4_S -D WLED_DISABLE_BROWNOUT_DET @@ -2142,6 +2276,8 @@ build_flags = ${esp32_4MB_V4_S_base.build_flags} ; -D MCLK_PIN=0 -D SR_ENABLE_DEFAULT ;; enable audioreactive at first start - no need to manually set "enable", then reboot ; -D WLED_USE_MY_CONFIG +lib_deps = ${esp32_4MB_V4_S_base.esp32_lib_deps} ;lib_ignore = IRremoteESP8266 ; use with WLED_DISABLE_INFRARED for faster compilation ; RAM: [=== ] 25.4% (used 83144 bytes from 327680 bytes) ; Flash: [==========] 96.4% (used 1516029 bytes from 1572864 bytes) +; diff --git a/tools/ESP32-Chip_info.hpp b/tools/ESP32-Chip_info.hpp index 1e6fad8f..e8897242 100644 --- a/tools/ESP32-Chip_info.hpp +++ b/tools/ESP32-Chip_info.hpp @@ -82,7 +82,7 @@ return F("DOUT"); } -//******** Flash Chip Speed is NOT correctl !!!! ***** +//******** Flash Chip Speed is NOT correct !!!! ***** uint32_t my_ESP_getFlashChipSpeed(void) { const uint32_t spi_clock = REG_READ(SPI_CLOCK_REG(0)); @@ -413,7 +413,7 @@ void my_print_reset_reason(int reason) case 11 : Serial.print(" TGWDT_CPU_RESET");break; /**<11, Time Group reset CPU*/ case 12 : Serial.print(" SW_CPU_RESET");break; /**<12, Software reset CPU*/ case 13 : Serial.print(" RTCWDT_CPU_RESET");break; /**<13, RTC Watch dog Reset CPU*/ - case 14 : Serial.print(" EXT_CPU_RESET");break; /**<14, for APP CPU, reseted by PRO CPU*/ + case 14 : Serial.print(" EXT_CPU_RESET");break; /**<14, for APP CPU, reset by PRO CPU*/ case 15 : Serial.print(" RTCWDT_BROWN_OUT_RESET");break; /**<15, Reset when the vdd voltage is not stable*/ case 16 : Serial.print(" RTCWDT_RTC_RESET");break; /**<16, RTC Watch dog reset digital core and rtc module*/ case 17 : Serial.print(" TG1WDT_CPU_RESET");break; /**<17, Time Group1 reset CPU*/ @@ -452,7 +452,7 @@ void my_verbose_print_reset_reason(int reason) /* - * parts below were created by softhack007, licended under GPL v3.0 + * parts below were created by softhack007, licenced under GPL v3.0 */ void show_psram_info_part1(void) diff --git a/tools/cdata.js b/tools/cdata.js index 8959a588..561d390e 100644 --- a/tools/cdata.js +++ b/tools/cdata.js @@ -223,6 +223,7 @@ writeHtmlGzipped("wled00/data/index.htm", "wled00/html_ui.h", 'index'); writeHtmlGzipped("wled00/data/simple.htm", "wled00/html_simple.h", 'simple'); writeHtmlGzipped("wled00/data/pixart/pixart.htm", "wled00/html_pixart.h", 'pixart'); writeHtmlGzipped("wled00/data/cpal/cpal.htm", "wled00/html_cpal.h", 'cpal'); +writeHtmlGzipped("wled00/data/pxmagic/pxmagic.htm", "wled00/html_pxmagic.h", 'pxmagic'); /* writeChunks( "wled00/data", diff --git a/usermods/Animated_Staircase/Animated_Staircase.h b/usermods/Animated_Staircase/Animated_Staircase.h index 20c240c7..9365a17e 100644 --- a/usermods/Animated_Staircase/Animated_Staircase.h +++ b/usermods/Animated_Staircase/Animated_Staircase.h @@ -16,7 +16,7 @@ class Animated_Staircase : public Usermod { /* configuration (available in API and stored in flash) */ bool enabled = false; // Enable this usermod unsigned long segment_delay_ms = 150; // Time between switching each segment - unsigned long on_time_ms = 30000; // The time for the light to stay on + unsigned long on_time_ms = 5000; // The time for the light to stay on - TroyHacks: 5s for testing int8_t topPIRorTriggerPin = -1; // disabled int8_t bottomPIRorTriggerPin = -1; // disabled int8_t topEchoPin = -1; // disabled @@ -131,7 +131,7 @@ class Animated_Staircase : public Usermod { * received within this time, an object is detected * and the function will return true. * - * The speed of sound is 343 meters per second at 20 degress Celcius. + * The speed of sound is 343 meters per second at 20 degrees Celsius. * Since the sound has to travel back and forth, the detection * distance for the sensor in cm is (0.0343 * maxTimeUs) / 2. * @@ -161,28 +161,37 @@ class Animated_Staircase : public Usermod { if ((millis() - lastScanTime) > scanDelay) { lastScanTime = millis(); - bottomSensorRead = bottomSensorWrite || - (!useUSSensorBottom ? - (bottomPIRorTriggerPin<0 ? false : digitalRead(bottomPIRorTriggerPin)) : - ultrasoundRead(bottomPIRorTriggerPin, bottomEchoPin, bottomMaxDist*59) // cm to us - ); - topSensorRead = topSensorWrite || - (!useUSSensorTop ? - (topPIRorTriggerPin<0 ? false : digitalRead(topPIRorTriggerPin)) : - ultrasoundRead(topPIRorTriggerPin, topEchoPin, topMaxDist*59) // cm to us - ); + if (useUSSensorBottom) { + bottomSensorRead = ultrasoundRead(bottomPIRorTriggerPin, bottomEchoPin, bottomMaxDist*59); // US + } else if (bottomPIRorTriggerPin > 0) { + bottomSensorRead = digitalRead(bottomPIRorTriggerPin); // PIR + } else { + bottomSensorRead = false; // DUNNO + } + + if (useUSSensorTop) { + topSensorRead = ultrasoundRead(topPIRorTriggerPin, topEchoPin, topMaxDist*59); // US + } else if (topPIRorTriggerPin > 0) { + topSensorRead = digitalRead(topPIRorTriggerPin); // PIR + } else { + topSensorRead = false; // DUNNO + } if (bottomSensorRead != bottomSensorState) { bottomSensorState = bottomSensorRead; // change previous state sensorChanged = true; - publishMqtt(true, bottomSensorState ? "on" : "off"); + #ifndef WLED_DISABLE_MQTT + publishMqtt(true, bottomSensorState ? "on" : "off"); + #endif DEBUG_PRINTLN(F("Bottom sensor changed.")); } if (topSensorRead != topSensorState) { topSensorState = topSensorRead; // change previous state sensorChanged = true; - publishMqtt(false, topSensorState ? "on" : "off"); + #ifndef WLED_DISABLE_MQTT + publishMqtt(false, topSensorState ? "on" : "off"); + #endif DEBUG_PRINTLN(F("Top sensor changed.")); } @@ -224,7 +233,13 @@ class Animated_Staircase : public Usermod { if (bottomSensorState || topSensorState) return; // Swipe OFF in the direction of the last sensor detection - swipe = lastSensor; + // WLED-MM/TroyHacks: This should follow you up/down the stairs. + if (lastSensor == SWIPE_UP) { + swipe = SWIPE_DOWN; + } else { + swipe = SWIPE_UP; + } + on = false; DEBUG_PRINT(F("OFF -> Swipe ")); @@ -253,7 +268,7 @@ class Animated_Staircase : public Usermod { } } - // send sesnor values to JSON API + // send sensor values to JSON API void writeSensorsToJson(JsonObject& staircase) { staircase[F("top-sensor")] = topSensorRead; staircase[F("bottom-sensor")] = bottomSensorRead; @@ -302,7 +317,7 @@ class Animated_Staircase : public Usermod { seg.setOption(SEG_OPTION_ON, true); } strip.trigger(); // force strip update - stateChanged = true; // inform external dvices/UI of change + stateChanged = true; // inform external devices/UI of change colorUpdated(CALL_MODE_DIRECT_CHANGE); DEBUG_PRINTLN(F("Animated Staircase disabled.")); } @@ -486,7 +501,7 @@ class Animated_Staircase : public Usermod { bottomEchoPin = top[FPSTR(_bottomEcho_pin)] | bottomEchoPin; topMaxDist = top[FPSTR(_topEchoCm)] | topMaxDist; - topMaxDist = min(150,max(30,(int)topMaxDist)); // max distnace ~1.5m (a lag of 9ms may be expected) + topMaxDist = min(150,max(30,(int)topMaxDist)); // max distance ~1.5m (a lag of 9ms may be expected) bottomMaxDist = top[FPSTR(_bottomEchoCm)] | bottomMaxDist; bottomMaxDist = min(150,max(30,(int)bottomMaxDist)); // max distance ~1.5m (a lag of 9ms may be expected) diff --git a/usermods/Animated_Staircase/README.md b/usermods/Animated_Staircase/README.md index 61c1cb2d..320b744a 100644 --- a/usermods/Animated_Staircase/README.md +++ b/usermods/Animated_Staircase/README.md @@ -11,7 +11,7 @@ The Animated Staircase can be controlled by the WLED API. Change settings such a speed, on/off time and distance by sending an HTTP request, see below. ## WLED integration -To include this usermod in your WLED setup, you have to be able to [compile WLED from source](https://github.com/Aircoookie/WLED/wiki/Compiling-WLED). +To include this usermod in your WLED setup, you have to be able to [compile WLED from source](https://kno.wled.ge/advanced/compiling-wled/). Before compiling, you have to make the following modifications: @@ -38,7 +38,7 @@ Maximum distance for ultrasonic sensor can be configured as the time needed for You _may_ need to use 10k pull-down resistors on the selected PIR pins, depending on the sensor. ## WLED configuration -1. In the WLED UI, confgure a segment for each step. The lowest step of the stairs is the +1. In the WLED UI, configure a segment for each step. The lowest step of the stairs is the lowest segment id. 2. Save your segments into a preset. 3. Ideally, add the preset in the config > LED setup menu to the "apply @@ -91,7 +91,7 @@ To enable the usermod again, use `"enabled":true`. Alternatively you can use _Usermod_ Settings page where you can change other parameters as well. ### Changing animation parameters and detection range of the ultrasonic HC-SR04 sensor -Using _Usermod_ Settings page you can define different usermod parameters, includng sensor pins, delay between segment activation etc. +Using _Usermod_ Settings page you can define different usermod parameters, including sensor pins, delay between segment activation etc. When an ultrasonic sensor is enabled you can enter maximum detection distance in centimeters separately for top and bottom sensors. diff --git a/usermods/BH1750_v2/readme.md b/usermods/BH1750_v2/readme.md index 05a033cf..6e6c693d 100644 --- a/usermods/BH1750_v2/readme.md +++ b/usermods/BH1750_v2/readme.md @@ -9,7 +9,7 @@ The luminance is displayed in both the Info section of the web UI, as well as pu - This must be added under `lib_deps` in your `platformio.ini` (or `platformio_override.ini`). - Data is published over MQTT - make sure you've enabled the MQTT sync interface. -## Compiliation +## Compilation To enable, compile with `USERMOD_BH1750` defined (e.g. in `platformio_override.ini`) ```ini diff --git a/usermods/BH1750_v2/usermod_bh1750.h b/usermods/BH1750_v2/usermod_bh1750.h index 0cb4bf18..5b5fa25f 100644 --- a/usermods/BH1750_v2/usermod_bh1750.h +++ b/usermods/BH1750_v2/usermod_bh1750.h @@ -28,7 +28,7 @@ #define USERMOD_BH1750_FIRST_MEASUREMENT_AT 10000 #endif -// only report if differance grater than offset value +// only report if difference grater than offset value #ifndef USERMOD_BH1750_OFFSET_VALUE #define USERMOD_BH1750_OFFSET_VALUE 2 // WLEDMM this makes more sense #endif @@ -118,8 +118,8 @@ private: JsonObject device = doc.createNestedObject(F("device")); // attach the sensor to the same device device[F("name")] = serverDescription; device[F("identifiers")] = "wled-sensor-" + String(mqttClientID); - device[F("manufacturer")] = F("WLED"); - device[F("model")] = F("FOSS"); + device[F("manufacturer")] = F(WLED_BRAND); //WLEDMM + Moustachauve/Wled-Native + device[F("model")] = F(WLED_PRODUCT_NAME); //WLEDMM + Moustachauve/Wled-Native device[F("sw_version")] = versionString; String temp; diff --git a/usermods/BME280_v2/usermod_bme280.h b/usermods/BME280_v2/usermod_bme280.h index 3b9c80ec..d9351ffa 100644 --- a/usermods/BME280_v2/usermod_bme280.h +++ b/usermods/BME280_v2/usermod_bme280.h @@ -32,7 +32,7 @@ private: // set the default pins based on the architecture, these get overridden by Usermod menu settings #ifdef ESP8266 - //uint8_t RST_PIN = 16; // Uncoment for Heltec WiFi-Kit-8 + //uint8_t RST_PIN = 16; // Un-comment for Heltec WiFi-Kit-8 #endif int8_t ioPin[2] = {i2c_scl, i2c_sda}; // I2C pins: SCL, SDA...defaults to Arch hardware pins but overridden at setup() bool initDone = false; @@ -80,7 +80,7 @@ private: static const char _name[]; static const char _enabled[]; - // Read the BME280/BMP280 Sensor (which one runs depends on whether Celsius or Farenheit being set in Usermod Menu) + // Read the BME280/BMP280 Sensor (which one runs depends on whether Celsius or Fahrenheit being set in Usermod Menu) void UpdateBME280Data(int SensorType) { float _temperature, _humidity, _pressure; @@ -163,8 +163,8 @@ private: JsonObject device = doc.createNestedObject(F("device")); // attach the sensor to the same device device[F("name")] = serverDescription; device[F("identifiers")] = "wled-sensor-" + String(mqttClientID); - device[F("manufacturer")] = F("WLED"); - device[F("model")] = F("FOSS"); + device[F("manufacturer")] = F(WLED_BRAND); //WLEDMM + Moustachauve/Wled-Native + device[F("model")] = F(WLED_PRODUCT_NAME); //WLEDMM + Moustachauve/Wled-Native device[F("sw_version")] = versionString; String temp; diff --git a/usermods/Battery/battery_defaults.h b/usermods/Battery/battery_defaults.h index c1e3c6bb..60dd4c4b 100644 --- a/usermods/Battery/battery_defaults.h +++ b/usermods/Battery/battery_defaults.h @@ -56,7 +56,7 @@ // auto-off feature #ifndef USERMOD_BATTERY_AUTO_OFF_ENABLED - #define USERMOD_BATTERY_AUTO_OFF_ENABLED true + #define USERMOD_BATTERY_AUTO_OFF_ENABLED false #endif #ifndef USERMOD_BATTERY_AUTO_OFF_THRESHOLD @@ -78,4 +78,4 @@ #ifndef USERMOD_BATTERY_LOW_POWER_INDICATOR_DURATION #define USERMOD_BATTERY_LOW_POWER_INDICATOR_DURATION 5 -#endif \ No newline at end of file +#endif diff --git a/usermods/Battery/readme.md b/usermods/Battery/readme.md index d55573ab..999c0a54 100644 --- a/usermods/Battery/readme.md +++ b/usermods/Battery/readme.md @@ -19,7 +19,7 @@ If you have an ESP32 board, connect the positive side of the battery to ADC1 (GP - 💯 Displays current battery voltage - 🚥 Displays battery level - 🚫 Auto-off with configurable Threshold -- 🚨 Low power indicator with many configuration posibilities +- 🚨 Low power indicator with many configuration possibilities ## 🎈 Installation @@ -41,7 +41,7 @@ define `USERMOD_BATTERY` in `wled00/my_config.h` | `USERMOD_BATTERY_MEASUREMENT_INTERVAL` | ms | battery check interval. defaults to 30 seconds | | `USERMOD_BATTERY_MIN_VOLTAGE` | v | minimum battery voltage. default is 2.6 (18650 battery standard) | | `USERMOD_BATTERY_MAX_VOLTAGE` | v | maximum battery voltage. default is 4.2 (18650 battery standard) | -| `USERMOD_BATTERY_TOTAL_CAPACITY` | mAh | the capacity of all cells in parralel sumed up | +| `USERMOD_BATTERY_TOTAL_CAPACITY` | mAh | the capacity of all cells in parallel summed up | | `USERMOD_BATTERY_CALIBRATION` | | offset / calibration number, fine tune the measured voltage by the microcontroller | | Auto-Off | --- | --- | | `USERMOD_BATTERY_AUTO_OFF_ENABLED` | true/false | enables auto-off | diff --git a/usermods/Battery/usermod_v2_Battery.h b/usermods/Battery/usermod_v2_Battery.h index cd518b9a..bd3bf62c 100644 --- a/usermods/Battery/usermod_v2_Battery.h +++ b/usermods/Battery/usermod_v2_Battery.h @@ -118,7 +118,7 @@ class UsermodBattery : public Usermod { #ifdef ARDUINO_ARCH_ESP32 if ((batteryPin <0) || !pinManager.isPinAnalog(batteryPin)) return(-1.0f); // WLEDMM avoid reading from invalid pin - // use calibrated millivolts analogread on esp32 (150 mV ~ 2450 mV default attentuation) and divide by 1000 to get from milivolts to volts and multiply by voltage multiplier and apply calibration value + // use calibrated millivolts analogread on esp32 (150 mV ~ 2450 mV default attenuation) and divide by 1000 to get from milliVolts to volts and multiply by voltage multiplier and apply calibration value return (analogReadMilliVolts(batteryPin) / 1000.0f) * voltageMultiplier + calibration; #else // use analog read on esp8266 ( 0V ~ 1V no attenuation options) and divide by ADC precision 1023 and multiply by voltage multiplier and apply calibration value @@ -216,7 +216,7 @@ class UsermodBattery : public Usermod */ #ifdef USERMOD_BATTERY_USE_LIPO batteryLevel = mapf(voltage, minBatteryVoltage, maxBatteryVoltage, 0, 100); // basic mapping - // LiPo batteries have a differnt dischargin curve, see + // LiPo batteries have a different dischargin curve, see // https://blog.ampow.com/lipo-voltage-chart/ if (batteryLevel < 40.0f) batteryLevel = mapf(batteryLevel, 0, 40, 0, 12); // last 45% -> drops very quickly @@ -413,7 +413,7 @@ class UsermodBattery : public Usermod oappend(SET_F("addInfo('Battery:indicator:threshold', 1, '%');")); oappend(SET_F("addInfo('Battery:indicator:duration', 1, 's');")); - // cannot quite get this mf to work. its exeeding some buffer limit i think + // cannot quite get this mf to work. its exceeding some buffer limit i think // what i wanted is a list of all presets to select one from // oappend(SET_F("bd=addDropdown('Battery:low-power-indicator', 'preset');")); // the loop generates: oappend(SET_F("addOption(bd, 'preset name', preset id);")); @@ -612,7 +612,7 @@ class UsermodBattery : public Usermod /* - * Get the capacity of all cells in parralel sumed up + * Get the capacity of all cells in parallel summed up * unit: mAh */ unsigned int getTotalBatteryCapacity() @@ -788,7 +788,7 @@ class UsermodBattery : public Usermod /* - * Get low-power-indicator status when the indication is done thsi returns true + * Get low-power-indicator status when the indication is done this returns true */ bool getLowPowerIndicatorDone() { diff --git a/usermods/DHT/usermod_dht.h b/usermods/DHT/usermod_dht.h index b6142f43..05a7267b 100644 --- a/usermods/DHT/usermod_dht.h +++ b/usermods/DHT/usermod_dht.h @@ -49,7 +49,7 @@ #endif // how many seconds after boot to take first measurement, 90 seconds -// 90 gives enough time to OTA update firmware if this crashses +// 90 gives enough time to OTA update firmware if this crashes #ifndef USERMOD_DHT_FIRST_MEASUREMENT_AT #define USERMOD_DHT_FIRST_MEASUREMENT_AT 90000 #endif diff --git a/usermods/EXAMPLE_v2/usermod_v2_example.h b/usermods/EXAMPLE_v2/usermod_v2_example.h index ba2ffc4e..b2a257f0 100644 --- a/usermods/EXAMPLE_v2/usermod_v2_example.h +++ b/usermods/EXAMPLE_v2/usermod_v2_example.h @@ -58,7 +58,7 @@ class MyExampleUsermod : public Usermod { long testLong; int8_t testPins[2]; - // any private methods should go here (non-inline methosd should be defined out of class) + // any private methods should go here (non-inline method should be defined out of class) void publishMqtt(const char* state, bool retain = false); // example for publishing MQTT message diff --git a/usermods/Enclosure_with_OLED_temp_ESP07/usermod.cpp b/usermods/Enclosure_with_OLED_temp_ESP07/usermod.cpp index 1ca16050..823ad747 100644 --- a/usermods/Enclosure_with_OLED_temp_ESP07/usermod.cpp +++ b/usermods/Enclosure_with_OLED_temp_ESP07/usermod.cpp @@ -15,23 +15,23 @@ OneWire oneWire(13); DallasTemperature sensor(&oneWire); long temptimer = millis(); long lastMeasure = 0; -#define Celsius // Show temperature mesaurement in Celcius otherwise is in Fahrenheit +#define Celsius // Show temperature measurement in Celsius otherwise is in Fahrenheit // If display does not work or looks corrupted check the // constructor reference: // https://github.com/olikraus/u8g2/wiki/u8x8setupcpp // or check the gallery: // https://github.com/olikraus/u8g2/wiki/gallery -// --> First choise of cheap I2C OLED 128X32 0.91" +// --> First choice of cheap I2C OLED 128X32 0.91" U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(U8X8_PIN_NONE, U8X8_PIN_SCL, U8X8_PIN_SDA); // Pins are Reset, SCL, SDA -// --> Second choise of cheap I2C OLED 128X64 0.96" or 1.3" +// --> Second choice of cheap I2C OLED 128X64 0.96" or 1.3" //U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(U8X8_PIN_NONE, U8X8_PIN_SCL, U8X8_PIN_SDA); // Pins are Reset, SCL, SDA // gets called once at boot. Do all initialization that doesn't depend on // network here void userSetup() { sensor.begin(); //Start Dallas temperature sensor u8x8.begin(); - //u8x8.setFlipMode(1); //Uncoment if using WLED Wemos shield + //u8x8.setFlipMode(1); //Un-comment if using WLED Wemos shield u8x8.setPowerSave(0); u8x8.setContrast(10); //Contrast setup will help to preserve OLED lifetime. In case OLED need to be brighter increase number up to 255 u8x8.setFont(u8x8_font_chroma48medium8_r); @@ -71,7 +71,7 @@ void userLoop() { if (mqtt != nullptr) { sensor.requestTemperatures(); -//Gets prefered temperature scale based on selection in definitions section +//Gets preferred temperature scale based on selection in definitions section #ifdef Celsius float board_temperature = sensor.getTempCByIndex(0); #else @@ -138,11 +138,11 @@ void userLoop() { // First row with Wifi name u8x8.setCursor(1, 0); u8x8.print(knownSsid.substring(0, u8x8.getCols() > 1 ? u8x8.getCols() - 2 : 0)); - // Print `~` char to indicate that SSID is longer, than owr dicplay + // Print `~` char to indicate that SSID is longer than our display if (knownSsid.length() > u8x8.getCols()) u8x8.print("~"); - // Second row with IP or Psssword + // Second row with IP or Password u8x8.setCursor(1, 1); // Print password in AP mode and if led is OFF. if (apActive && bri == 0) diff --git a/usermods/Enclosure_with_OLED_temp_ESP07/usermod_bme280.cpp b/usermods/Enclosure_with_OLED_temp_ESP07/usermod_bme280.cpp index d5fd4a0c..29a4332d 100644 --- a/usermods/Enclosure_with_OLED_temp_ESP07/usermod_bme280.cpp +++ b/usermods/Enclosure_with_OLED_temp_ESP07/usermod_bme280.cpp @@ -10,7 +10,7 @@ void UpdateBME280Data(); -#define Celsius // Show temperature mesaurement in Celcius otherwise is in Fahrenheit +#define Celsius // Show temperature measurement in Celsius otherwise is in Fahrenheit BME280I2C bme; // Default : forced mode, standby time = 1000 ms // Oversampling = pressure ×1, temperature ×1, humidity ×1, filter off, @@ -20,14 +20,14 @@ uint8_t SDA_PIN = 21; #else //ESP8266 boards uint8_t SCL_PIN = 5; uint8_t SDA_PIN = 4; -// uint8_t RST_PIN = 16; // Uncoment for Heltec WiFi-Kit-8 +// uint8_t RST_PIN = 16; // Un-comment for Heltec WiFi-Kit-8 #endif //The SCL and SDA pins are defined here. //ESP8266 Wemos D1 mini board use SCL=5 SDA=4 while ESP32 Wemos32 mini board use SCL=22 SDA=21 #define U8X8_PIN_SCL SCL_PIN #define U8X8_PIN_SDA SDA_PIN -//#define U8X8_PIN_RESET RST_PIN // Uncoment for Heltec WiFi-Kit-8 +//#define U8X8_PIN_RESET RST_PIN // Un-comment for Heltec WiFi-Kit-8 // If display does not work or looks corrupted check the // constructor reference: @@ -36,9 +36,9 @@ uint8_t SDA_PIN = 4; // https://github.com/olikraus/u8g2/wiki/gallery // --> First choise of cheap I2C OLED 128X32 0.91" U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(U8X8_PIN_NONE, U8X8_PIN_SCL, U8X8_PIN_SDA); // Pins are Reset, SCL, SDA -// --> Second choise of cheap I2C OLED 128X64 0.96" or 1.3" +// --> Second choice of cheap I2C OLED 128X64 0.96" or 1.3" //U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(U8X8_PIN_NONE, U8X8_PIN_SCL, U8X8_PIN_SDA); // Pins are Reset, SCL, SDA -// --> Third choise of Heltec WiFi-Kit-8 OLED 128X32 0.91" +// --> Third choice of Heltec WiFi-Kit-8 OLED 128X32 0.91" //U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(U8X8_PIN_RESET, U8X8_PIN_SCL, U8X8_PIN_SDA); // Constructor for Heltec WiFi-Kit-8 // gets called once at boot. Do all initialization that doesn't depend on network here @@ -181,11 +181,11 @@ void userLoop() { // First row with Wifi name u8x8.setCursor(1, 0); u8x8.print(knownSsid.substring(0, u8x8.getCols() > 1 ? u8x8.getCols() - 2 : 0)); - // Print `~` char to indicate that SSID is longer, than owr dicplay + // Print `~` char to indicate that SSID is longer than our display if (knownSsid.length() > u8x8.getCols()) u8x8.print("~"); - // Second row with IP or Psssword + // Second row with IP or Password u8x8.setCursor(1, 1); // Print password in AP mode and if led is OFF. if (apActive && bri == 0) diff --git a/usermods/Fix_unreachable_netservices_v2/readme.md b/usermods/Fix_unreachable_netservices_v2/readme.md index 24d5ff5a..006eaf9f 100644 --- a/usermods/Fix_unreachable_netservices_v2/readme.md +++ b/usermods/Fix_unreachable_netservices_v2/readme.md @@ -2,7 +2,7 @@ **Attention: This usermod compiles only for ESP8266** -This usermod-v2 modification performs a ping request to a local IP address every 60 seconds. This ensures WLED net services remain accessible in some problematic WLAN environments. +This usermod-v2 modification performs a ping request to a local IP address every 60 seconds. This ensures WLED net services remain accessible in some problematic WiFi environments. The modification works with static or DHCP IP address configuration. @@ -24,7 +24,7 @@ The usermod supports the following state changes: | JSON key | Value range | Description | |-------------|------------------|---------------------------------| -| PingDelayMs | 5000 to 18000000 | Deactivdate/activate the sensor | +| PingDelayMs | 5000 to 18000000 | Deactivate/activate the sensor | Changes also persist after a reboot. diff --git a/usermods/LDR_Dusk_Dawn_v2/README.md b/usermods/LDR_Dusk_Dawn_v2/README.md new file mode 100644 index 00000000..5e33518a --- /dev/null +++ b/usermods/LDR_Dusk_Dawn_v2/README.md @@ -0,0 +1,26 @@ +# LDR_Dusk_Dawn_v2 +This usermod will obtain readings from a Light Dependent Resistor (LDR) and will turn on/off specific presets based on those readings. This is useful for exterior lighting situations where you want the lights to only be on when it is dark out. + +# Installation +Add "-D USERMOD_LDR_DUSK_DAWN" to your platformio.ini [common] build_flags and build. + +Example: +``` +[common] +build_flags = + -D USERMOD_LDR_DUSK_DAWN # Enable LDR Dusk Dawn Usermod +``` + +# Usermod Settings +Setting | Description | Default +--- | --- | --- +Enabled | Enable/Disable the LDR functionality. | Disabled +LDR Pin | The analog capable pin your LDR is connected to. | 34 +Threshold Minutes | The number of minutes of consistent readings above/below the on/off threshold before the LED state will change. | 5 +Threshold | The analog read value threshold from the LDR. Readings lower than this number will count towards changing the LED state to off. You can see the current LDR reading by going into the info section when LDR functionality is enabled. | 1000 +On Preset | The WLED preset to be used for the LED on state. | 1 +Off Preset | The WLED preset to be used for the LED off state. | 2 + +## Author +[@jeffwdh](https://github.com/jeffwdh) +jeffwdh@tarball.ca diff --git a/usermods/LDR_Dusk_Dawn_v2/usermod_LDR_Dusk_Dawn_v2.h b/usermods/LDR_Dusk_Dawn_v2/usermod_LDR_Dusk_Dawn_v2.h new file mode 100644 index 00000000..393fc223 --- /dev/null +++ b/usermods/LDR_Dusk_Dawn_v2/usermod_LDR_Dusk_Dawn_v2.h @@ -0,0 +1,153 @@ +#pragma once +#include "wled.h" + +#ifndef ARDUINO_ARCH_ESP32 + // 8266 does not support analogRead on user selectable pins + #error only ESP32 is supported by usermod LDR_DUSK_DAWN +#endif + +class LDR_Dusk_Dawn_v2 : public Usermod { + private: + // Defaults + bool ldrEnabled = false; + int ldrPin = 34; //A2 on Adafruit Huzzah32 + int ldrThresholdMinutes = 5; // How many minutes of readings above/below threshold until it switches LED state + int ldrThreshold = 1000; // Readings higher than this number will turn off LED. + int ldrOnPreset = 1; // Default "On" Preset + int ldrOffPreset = 2; // Default "Off" Preset + + // Variables + bool initDone = false; + bool ldrEnabledPreviously = false; // Was LDR enabled for the previous check? First check is always no. + int ldrOffCount; // Number of readings above the threshold + int ldrOnCount; // Number of readings below the threshold + int ldrReading = 0; // Last LDR reading + int ldrLEDState; // Current LED on/off state + unsigned long lastMillis = 0; + static const char _name[]; + + public: + void setup() { + // register ldrPin + if ((ldrPin >= 0) && (digitalPinToAnalogChannel(ldrPin) >= 0)) { + if(!pinManager.allocatePin(ldrPin, false, PinOwner::UM_LDR_DUSK_DAWN)) ldrEnabled = false; // pin already in use -> disable usermod + else pinMode(ldrPin, INPUT); // alloc success -> configure pin for input + } else ldrEnabled = false; // invalid pin -> disable usermod + initDone = true; + } + + void loop() { + // Only update every 10 seconds + if (millis() - lastMillis > 10000) { + if ( (ldrEnabled == true) + && (ldrPin >= 0) && (digitalPinToAnalogChannel(ldrPin) >= 0) ) { // make sure that pin is valid for analogread() + // Default state is off + if (ldrEnabledPreviously == false) { + applyPreset(ldrOffPreset); + ldrEnabledPreviously = true; + ldrLEDState = 0; + } + + // Get LDR reading and increment counter by number of seconds since last read + ldrReading = analogRead(ldrPin); + if (ldrReading <= ldrThreshold) { + ldrOnCount = ldrOnCount + 10; + ldrOffCount = 0; + } else { + ldrOffCount = ldrOffCount + 10; + ldrOnCount = 0; + } + + if (ldrOnCount >= (ldrThresholdMinutes * 60)) { + ldrOnCount = 0; + // If LEDs were previously off, turn on + if (ldrLEDState == 0) { + applyPreset(ldrOnPreset); + ldrLEDState = 1; + } + } + + if (ldrOffCount >= (ldrThresholdMinutes * 60)) { + ldrOffCount = 0; + // If LEDs were previously on, turn off + if (ldrLEDState == 1) { + applyPreset(ldrOffPreset); + ldrLEDState = 0; + } + } + } else { + // LDR is disabled, reset variables to default + ldrReading = 0; + ldrOnCount = 0; + ldrOffCount = 0; + ldrLEDState = 0; + ldrEnabledPreviously = false; + } + lastMillis = millis(); + } + } + + void addToConfig(JsonObject& root) { + JsonObject top = root.createNestedObject(FPSTR(_name)); + top["Enabled"] = ldrEnabled; + top["LDR Pin"] = ldrPin; + top["Threshold Minutes"] = ldrThresholdMinutes; + top["Threshold"] = ldrThreshold; + top["On Preset"] = ldrOnPreset; + top["Off Preset"] = ldrOffPreset; + } + + bool readFromConfig(JsonObject& root) { + int8_t oldLdrPin = ldrPin; + JsonObject top = root[FPSTR(_name)]; + bool configComplete = !top.isNull(); + configComplete &= getJsonValue(top["Enabled"], ldrEnabled); + configComplete &= getJsonValue(top["LDR Pin"], ldrPin); + configComplete &= getJsonValue(top["Threshold Minutes"], ldrThresholdMinutes); + configComplete &= getJsonValue(top["Threshold"], ldrThreshold); + configComplete &= getJsonValue(top["On Preset"], ldrOnPreset); + configComplete &= getJsonValue(top["Off Preset"], ldrOffPreset); + + if (initDone && (ldrPin != oldLdrPin)) { + // pin changed - un-register previous pin, register new pin + if (oldLdrPin >= 0) pinManager.deallocatePin(oldLdrPin, PinOwner::UM_LDR_DUSK_DAWN); + setup(); // setup new pin + } + return configComplete; + } + + void addToJsonInfo(JsonObject& root) { + // If "u" object does not exist yet we need to create it + JsonObject user = root["u"]; + if (user.isNull()) user = root.createNestedObject("u"); + + JsonArray LDR_Enabled = user.createNestedArray("LDR dusk/dawn enabled"); + LDR_Enabled.add(ldrEnabled); + if (!ldrEnabled) return; // do not add more if usermod is disabled + + JsonArray LDR_Reading = user.createNestedArray("LDR reading"); + LDR_Reading.add(ldrReading); + + JsonArray LDR_State = user.createNestedArray("LDR turned LEDs on"); + LDR_State.add(bool(ldrLEDState)); + + // Optional debug information: + //JsonArray LDR_On_Count = user.createNestedArray("LDR on count"); + //LDR_On_Count.add(ldrOnCount); + + //JsonArray LDR_Off_Count = user.createNestedArray("LDR off count"); + //LDR_Off_Count.add(ldrOffCount); + + //bool pinValid = ((ldrPin >= 0) && (digitalPinToAnalogChannel(ldrPin) >= 0)); + //if (pinManager.getPinOwner(ldrPin) != PinOwner::UM_LDR_DUSK_DAWN) pinValid = false; + //JsonArray LDR_valid = user.createNestedArray(F("LDR pin")); + //LDR_valid.add(ldrPin); + //LDR_valid.add(pinValid ? F(" OK"): F(" invalid")); + } + + uint16_t getId() { + return USERMOD_ID_LDR_DUSK_DAWN; + } +}; + +const char LDR_Dusk_Dawn_v2::_name[] PROGMEM = "LDR_Dusk_Dawn_v2"; diff --git a/usermods/PIR_sensor_switch/readme.md b/usermods/PIR_sensor_switch/readme.md index 574bd06d..85a5a74c 100644 --- a/usermods/PIR_sensor_switch/readme.md +++ b/usermods/PIR_sensor_switch/readme.md @@ -23,7 +23,7 @@ You can also use usermod's off timer instead of sensor's. In such case rotate th ## Usermod installation -**NOTE:** Usermod has been included in master branch of WLED so it can be compiled in directly just by defining `-D USERMOD_PIRSWITCH` and optionaly `-D PIR_SENSOR_PIN=16` to override default pin. You can also change the default off time by adding `-D PIR_SENSOR_OFF_SEC=30`. +**NOTE:** Usermod has been included in master branch of WLED so it can be compiled in directly just by defining `-D USERMOD_PIRSWITCH` and optionally `-D PIR_SENSOR_PIN=16` to override default pin. You can also change the default off time by adding `-D PIR_SENSOR_OFF_SEC=30`. ## API to enable/disable the PIR sensor from outside. For example from another usermod: @@ -31,7 +31,7 @@ To query or change the PIR sensor state the methods `bool PIRsensorEnabled()` an When the PIR sensor state changes an MQTT message is broadcasted with topic `wled/deviceMAC/motion` and message `on` or `off`. Usermod can also be configured to send just the MQTT message but not change WLED state using settings page as well as responding to motion only at night -(assuming NTP and lattitude/longitude are set to determine sunrise/sunset times). +(assuming NTP and latitude/longitude are set to determine sunrise/sunset times). ### There are two options to get access to the usermod instance: @@ -85,7 +85,7 @@ Have fun - @gegu & @blazoncek 2021-11 * Added information about dynamic configuration options -* Added option to temporary enable/disble usermod from WLED UI (Info dialog) +* Added option to temporary enable/disable usermod from WLED UI (Info dialog) 2022-11 * Added compile time option for off timer. diff --git a/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h b/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h index 288edb32..1bf7b0d1 100644 --- a/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h +++ b/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h @@ -189,8 +189,8 @@ private: JsonObject device = doc.createNestedObject(F("device")); // attach the sensor to the same device device[F("name")] = serverDescription; device[F("ids")] = String(F("wled-sensor-")) + mqttClientID; - device[F("mf")] = "WLED"; - device[F("mdl")] = F("FOSS"); + device[F("mf")] = F(WLED_BRAND); //WLEDMM + Moustachauve/Wled-Native + device[F("mdl")] = F(WLED_PRODUCT_NAME); //WLEDMM + Moustachauve/Wled-Native device[F("sw")] = versionString; sprintf_P(buf, PSTR("homeassistant/binary_sensor/%s/config"), uid); @@ -205,7 +205,7 @@ private: /** * Read and update PIR sensor state. - * Initilize/reset switch off timer + * Initialize/reset switch off timer */ bool updatePIRsensorState() { diff --git a/usermods/PWM_fan/readme.md b/usermods/PWM_fan/readme.md index 1fbfe0e6..6a44acf3 100644 --- a/usermods/PWM_fan/readme.md +++ b/usermods/PWM_fan/readme.md @@ -5,7 +5,7 @@ v2 Usermod to to control PWM fan with RPM feedback and temperature control This usermod requires the Dallas Temperature usermod to obtain temperature information. If it's not available, the fan will run at 100% speed. If the fan does not have _tachometer_ (RPM) output you can set the _tachometer-pin_ to -1 to disable that feature. -You can also set the thershold temperature at which fan runs at lowest speed. If the measured temperature is 3°C greater than the threshold temperature, the fan will run at 100%. +You can also set the threshold temperature at which fan runs at lowest speed. If the measured temperature is 3°C greater than the threshold temperature, the fan will run at 100%. If the _tachometer_ is supported, the current speed (in RPM) will be displayed on the WLED Info page. @@ -22,7 +22,7 @@ This includes: * PWM output pin (can be configured at compile time `-D PWM_PIN=xx`) * tachometer input pin (can be configured at compile time `-D TACHO_PIN=xx`) * sampling frequency in seconds -* threshold temperature in degees C +* threshold temperature in degrees Celsius _NOTE:_ You may also need to tweak Dallas Temperature usermod sampling frequency to match PWM fan sampling frequency. diff --git a/usermods/PWM_fan/usermod_PWM_fan.h b/usermods/PWM_fan/usermod_PWM_fan.h index d8aa7a1a..c9ccf14d 100644 --- a/usermods/PWM_fan/usermod_PWM_fan.h +++ b/usermods/PWM_fan/usermod_PWM_fan.h @@ -75,7 +75,7 @@ class PWMFanUsermod : public Usermod { pinMode(tachoPin, INPUT); digitalWrite(tachoPin, HIGH); attachInterrupt(digitalPinToInterrupt(tachoPin), rpm_fan, FALLING); - DEBUG_PRINTLN(F("Tacho sucessfully initialized.")); + DEBUG_PRINTLN(F("Tacho successfully initialized.")); } void deinitTacho(void) { @@ -118,12 +118,12 @@ class PWMFanUsermod : public Usermod { if (pwmChannel == 255) { //no more free LEDC channels deinitPWMfan(); return; } - // configure LED PWM functionalitites + // configure LED PWM functionalities ledcSetup(pwmChannel, 25000, 8); // attach the channel to the GPIO to be controlled ledcAttachPin(pwmPin, pwmChannel); #endif - DEBUG_PRINTLN(F("Fan PWM sucessfully initialized.")); + DEBUG_PRINTLN(F("Fan PWM successfully initialized.")); } void deinitPWMfan(void) { diff --git a/usermods/SN_Photoresistor/usermod_sn_photoresistor.h b/usermods/SN_Photoresistor/usermod_sn_photoresistor.h index 60861e4c..1e92d7d7 100644 --- a/usermods/SN_Photoresistor/usermod_sn_photoresistor.h +++ b/usermods/SN_Photoresistor/usermod_sn_photoresistor.h @@ -30,7 +30,7 @@ #define USERMOD_SN_PHOTORESISTOR_RESISTOR_VALUE 10000.0f #endif -// only report if differance grater than offset value +// only report if difference grater than offset value #ifndef USERMOD_SN_PHOTORESISTOR_OFFSET_VALUE #define USERMOD_SN_PHOTORESISTOR_OFFSET_VALUE 5 #endif diff --git a/usermods/TTGO-T-Display/usermod.cpp b/usermods/TTGO-T-Display/usermod.cpp index b126d40a..cbba0777 100644 --- a/usermods/TTGO-T-Display/usermod.cpp +++ b/usermods/TTGO-T-Display/usermod.cpp @@ -3,7 +3,7 @@ * This file allows you to add own functionality to WLED more easily * See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality * EEPROM bytes 2750+ are reserved for your custom use case. (if you extend #define EEPSIZE in const.h) - * bytes 2400+ are currently ununsed, but might be used for future wled features + * bytes 2400+ are currently unused, but might be used for future wled features */ /* @@ -144,7 +144,7 @@ void userLoop() { // First row with Wifi name tft.setCursor(1, 1); tft.print(knownSsid.substring(0, tftcharwidth > 1 ? tftcharwidth - 1 : 0)); - // Print `~` char to indicate that SSID is longer, than our dicplay + // Print `~` char to indicate that SSID is longer than our display if (knownSsid.length() > tftcharwidth) tft.print("~"); diff --git a/usermods/Temperature/readme.md b/usermods/Temperature/readme.md index 2657c6c8..b41e3e11 100644 --- a/usermods/Temperature/readme.md +++ b/usermods/Temperature/readme.md @@ -18,7 +18,7 @@ Copy the example `platformio_override.ini` to the root directory. This file sho * `USERMOD_DALLASTEMPERATURE` - enables this user mod wled00/usermods_list.cpp * `USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL` - number of milliseconds between measurements, defaults to 60000 ms (60s) -All parameters can be configured at runtime via the Usermods settings page, including pin, temperature in degrees Celsius or Farenheit and measurement interval. +All parameters can be configured at runtime via the Usermods settings page, including pin, temperature in degrees Celsius or Fahrenheit and measurement interval. ## Project link diff --git a/usermods/Wemos_D1_mini+Wemos32_mini_shield/usermod.cpp b/usermods/Wemos_D1_mini+Wemos32_mini_shield/usermod.cpp index 78cc32a8..e7d1212a 100644 --- a/usermods/Wemos_D1_mini+Wemos32_mini_shield/usermod.cpp +++ b/usermods/Wemos_D1_mini+Wemos32_mini_shield/usermod.cpp @@ -34,30 +34,30 @@ uint8_t DALLAS_PIN =23; uint8_t SCL_PIN = 5; uint8_t SDA_PIN = 4; uint8_t DALLAS_PIN =13; -// uint8_t RST_PIN = 16; // Uncoment for Heltec WiFi-Kit-8 +// uint8_t RST_PIN = 16; // Un-comment for Heltec WiFi-Kit-8 #endif //The SCL and SDA pins are defined here. //ESP8266 Wemos D1 mini board use SCL=5 SDA=4 while ESP32 Wemos32 mini board use SCL=22 SDA=21 #define U8X8_PIN_SCL SCL_PIN #define U8X8_PIN_SDA SDA_PIN -//#define U8X8_PIN_RESET RST_PIN // Uncoment for Heltec WiFi-Kit-8 +//#define U8X8_PIN_RESET RST_PIN // Un-comment for Heltec WiFi-Kit-8 // Dallas sensor reading timer long temptimer = millis(); long lastMeasure = 0; -#define Celsius // Show temperature mesaurement in Celcius otherwise is in Fahrenheit +#define Celsius // Show temperature measurement in Celsius otherwise is in Fahrenheit // If display does not work or looks corrupted check the // constructor reference: // https://github.com/olikraus/u8g2/wiki/u8x8setupcpp // or check the gallery: // https://github.com/olikraus/u8g2/wiki/gallery -// --> First choise of cheap I2C OLED 128X32 0.91" +// --> First choice of cheap I2C OLED 128X32 0.91" U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(U8X8_PIN_NONE, U8X8_PIN_SCL, U8X8_PIN_SDA); // Pins are Reset, SCL, SDA -// --> Second choise of cheap I2C OLED 128X64 0.96" or 1.3" +// --> Second choice of cheap I2C OLED 128X64 0.96" or 1.3" //U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(U8X8_PIN_NONE, U8X8_PIN_SCL, U8X8_PIN_SDA); // Pins are Reset, SCL, SDA -// --> Third choise of Heltec WiFi-Kit-8 OLED 128X32 0.91" +// --> Third choice of Heltec WiFi-Kit-8 OLED 128X32 0.91" //U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(U8X8_PIN_RESET, U8X8_PIN_SCL, U8X8_PIN_SDA); // Constructor for Heltec WiFi-Kit-8 // gets called once at boot. Do all initialization that doesn't depend on network here void userSetup() { @@ -97,7 +97,7 @@ void userLoop() { //----> Dallas temperature sensor MQTT publishing temptimer = millis(); -// Timer to publishe new temperature every 60 seconds +// Timer to publish new temperature every 60 seconds if (temptimer - lastMeasure > 60000) { lastMeasure = temptimer; @@ -106,7 +106,7 @@ void userLoop() { if (mqtt != nullptr) { // Serial.println(Dallas(DALLAS_PIN,0)); -//Gets prefered temperature scale based on selection in definitions section +//Gets preferred temperature scale based on selection in definitions section #ifdef Celsius int16_t board_temperature = Dallas(DALLAS_PIN,0); #else @@ -173,11 +173,11 @@ void userLoop() { // First row with Wifi name u8x8.setCursor(1, 0); u8x8.print(knownSsid.substring(0, u8x8.getCols() > 1 ? u8x8.getCols() - 2 : 0)); - // Print `~` char to indicate that SSID is longer, than owr dicplay + // Print `~` char to indicate that SSID is longer than our display if (knownSsid.length() > u8x8.getCols()) u8x8.print("~"); - // Second row with IP or Psssword + // Second row with IP or Password u8x8.setCursor(1, 1); // Print password in AP mode and if led is OFF. if (apActive && bri == 0) diff --git a/usermods/Wemos_D1_mini+Wemos32_mini_shield/usermod_bme280.cpp b/usermods/Wemos_D1_mini+Wemos32_mini_shield/usermod_bme280.cpp index c9d9a527..ff1cf7e5 100644 --- a/usermods/Wemos_D1_mini+Wemos32_mini_shield/usermod_bme280.cpp +++ b/usermods/Wemos_D1_mini+Wemos32_mini_shield/usermod_bme280.cpp @@ -6,7 +6,7 @@ void UpdateBME280Data(); -#define Celsius // Show temperature mesaurement in Celcius otherwise is in Fahrenheit +#define Celsius // Show temperature measurement in Celsius otherwise is in Fahrenheit BME280I2C bme; // Default : forced mode, standby time = 1000 ms // Oversampling = pressure ×1, temperature ×1, humidity ×1, filter off, @@ -16,25 +16,25 @@ uint8_t SDA_PIN = 21; #else //ESP8266 boards uint8_t SCL_PIN = 5; uint8_t SDA_PIN = 4; -// uint8_t RST_PIN = 16; // Uncoment for Heltec WiFi-Kit-8 +// uint8_t RST_PIN = 16; // Un-comment for Heltec WiFi-Kit-8 #endif //The SCL and SDA pins are defined here. //ESP8266 Wemos D1 mini board use SCL=5 SDA=4 while ESP32 Wemos32 mini board use SCL=22 SDA=21 #define U8X8_PIN_SCL SCL_PIN #define U8X8_PIN_SDA SDA_PIN -//#define U8X8_PIN_RESET RST_PIN // Uncoment for Heltec WiFi-Kit-8 +//#define U8X8_PIN_RESET RST_PIN // Un-comment for Heltec WiFi-Kit-8 // If display does not work or looks corrupted check the // constructor reference: // https://github.com/olikraus/u8g2/wiki/u8x8setupcpp // or check the gallery: // https://github.com/olikraus/u8g2/wiki/gallery -// --> First choise of cheap I2C OLED 128X32 0.91" +// --> First choice of cheap I2C OLED 128X32 0.91" U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(U8X8_PIN_NONE, U8X8_PIN_SCL, U8X8_PIN_SDA); // Pins are Reset, SCL, SDA -// --> Second choise of cheap I2C OLED 128X64 0.96" or 1.3" +// --> Second choice of cheap I2C OLED 128X64 0.96" or 1.3" //U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(U8X8_PIN_NONE, U8X8_PIN_SCL, U8X8_PIN_SDA); // Pins are Reset, SCL, SDA -// --> Third choise of Heltec WiFi-Kit-8 OLED 128X32 0.91" +// --> Third choice of Heltec WiFi-Kit-8 OLED 128X32 0.91" //U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(U8X8_PIN_RESET, U8X8_PIN_SCL, U8X8_PIN_SDA); // Constructor for Heltec WiFi-Kit-8 // gets called once at boot. Do all initialization that doesn't depend on network here @@ -179,11 +179,11 @@ void userLoop() { // First row with Wifi name u8x8.setCursor(1, 0); u8x8.print(knownSsid.substring(0, u8x8.getCols() > 1 ? u8x8.getCols() - 2 : 0)); - // Print `~` char to indicate that SSID is longer, than owr dicplay + // Print `~` char to indicate that SSID is longer, than our display if (knownSsid.length() > u8x8.getCols()) u8x8.print("~"); - // Second row with IP or Psssword + // Second row with IP or Password u8x8.setCursor(1, 1); // Print password in AP mode and if led is OFF. if (apActive && bri == 0) diff --git a/usermods/artifx/arti.h b/usermods/artifx/arti.h index 19d6b493..2e5fda45 100644 --- a/usermods/artifx/arti.h +++ b/usermods/artifx/arti.h @@ -9,7 +9,7 @@ - #define ARDUINOJSON_DEFAULT_NESTING_LIMIT 100 //set this in ArduinoJson!!!, currently not necessary... - IF UPDATING THIS FILE IN THE WLED REPO, SEND A PULL REQUEST TO https://github.com/ewoudwijma/ARTI AS WELL!!! @later - - Code improvememt + - Code improvement - See 'for some weird reason this causes a crash on esp32' - check why column/lineno not correct - Definition improvements @@ -2181,7 +2181,7 @@ public: ERROR_ARTI("%s %s %s unknown\n", spaces+50-depth, key, variable_name); valueStack->push(floatNull); } - } // ! founnd + } // ! fouund visitedAlready = true; break; } diff --git a/usermods/artifx/arti_wled.h b/usermods/artifx/arti_wled.h index 8796e1c1..78627a25 100644 --- a/usermods/artifx/arti_wled.h +++ b/usermods/artifx/arti_wled.h @@ -9,7 +9,7 @@ #pragma once -// For testing porposes, definitions should not only run on Arduino but also on Windows etc. +// For testing purposes, definitions should not only run on Arduino but also on Windows etc. // Because compiling on arduino takes seriously more time than on Windows. // The plugin.h files replace native arduino calls by windows simulated calls (e.g. setPixelColor will become printf) @@ -185,7 +185,7 @@ float ARTI::arti_external_function(uint8_t function, float par1, float par2, flo float halfLength = (circleLength-1)/2.0; - //calculate circle positions, round to 5 digits and then round again to cater for radians inprecision (e.g. 3.49->3.5->4) + //calculate circle positions, round to 5 digits and then round again to cater for radians imprecision (e.g. 3.49->3.5->4) int x = round(round((sin(radians(par1)) * halfLength + halfLength) * 10)/10) + deltaWidth; int y = round(round((halfLength - cos(radians(par1)) * halfLength) * 10)/10) + deltaHeight; return SEGMENT.XY(x,y); diff --git a/usermods/artifx/artifx.js b/usermods/artifx/artifx.js index d1658077..f2386448 100644 --- a/usermods/artifx/artifx.js +++ b/usermods/artifx/artifx.js @@ -82,7 +82,7 @@ function populateCEEditor(name, segID)

Compile and Run Log

- Run log > 3 seconds is send to Serial Ouput.
+ Run log > 3 seconds is send to Serial Output.
🥚 🥚 🥚`; diff --git a/usermods/artifx/usermod_v2_artifx.h b/usermods/artifx/usermod_v2_artifx.h index 1962ed24..ee0899d8 100644 --- a/usermods/artifx/usermod_v2_artifx.h +++ b/usermods/artifx/usermod_v2_artifx.h @@ -19,7 +19,7 @@ ARTI * arti; //effect function uint16_t mode_ARTIFX(void) { //tbd: move statics to SEGMENT.data - static bool succesful; + static bool successful; static bool notEnoughHeap; static char previousEffect[charLength]; @@ -46,20 +46,20 @@ uint16_t mode_ARTIFX(void) { // artiWrapper = reinterpret_cast(SEGENV.data); arti = new ARTI(); - succesful = arti->setup("/wledv033.json", currentEffect); + successful = arti->setup("/wledv033.json", currentEffect); - if (!succesful) - ERROR_ARTI("Setup not succesful\n"); + if (!successful) + ERROR_ARTI("Setup not successful\n"); } else { - if (succesful) // && SEGENV.call < 250 for each frame + if (successful) // && SEGENV.call < 250 for each frame { if (FREE_SIZE <= 20000) { ERROR_ARTI("Not enough free heap (%u <= 30000)\n", FREE_SIZE); notEnoughHeap = true; - succesful = false; + successful = false; } else { @@ -71,7 +71,7 @@ uint16_t mode_ARTIFX(void) { // previousCall = SEGENV.call; // } - succesful = arti->loop(); + successful = arti->loop(); } } else @@ -79,7 +79,7 @@ uint16_t mode_ARTIFX(void) { arti->closeLog(); if (notEnoughHeap && FREE_SIZE > 20000) { ERROR_ARTI("Again enough free heap, restart effect (%u > 30000)\n", FREE_SIZE); - succesful = true; + successful = true; notEnoughHeap = false; strcpy(previousEffect, ""); // force new create } diff --git a/usermods/audioreactive/audio_reactive.h b/usermods/audioreactive/audio_reactive.h index c4669869..05576890 100644 --- a/usermods/audioreactive/audio_reactive.h +++ b/usermods/audioreactive/audio_reactive.h @@ -21,13 +21,18 @@ * .... */ -#define FFT_PREFER_EXACT_PEAKS // use different FFT wndowing -> results in "sharper" peaks and less "leaking" into other frequencies +#define FFT_PREFER_EXACT_PEAKS // use different FFT windowing -> results in "sharper" peaks and less "leaking" into other frequencies //#define SR_STATS #if !defined(FFTTASK_PRIORITY) +#if defined(WLEDMM_FASTPATH) && !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && defined(ARDUINO_ARCH_ESP32) +// FASTPATH: use higher priority, to avoid that webserver (ws, json, etc) delays sample processing +//#define FFTTASK_PRIORITY 3 // competing with async_tcp +#define FFTTASK_PRIORITY 4 // above async_tcp +#else #define FFTTASK_PRIORITY 1 // standard: looptask prio -//#define FFTTASK_PRIORITY 2 // above looptask, below asyc_tcp -//#define FFTTASK_PRIORITY 4 // above asyc_tcp +//#define FFTTASK_PRIORITY 2 // above looptask, below async_tcp +#endif #endif #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) @@ -86,8 +91,27 @@ #define PLOT_FLUSH() #endif +// sanity checks +#ifdef ARDUINO_ARCH_ESP32 + // we need more space in for oappend() stack buffer -> SETTINGS_STACK_BUF_SIZE and CONFIG_ASYNC_TCP_TASK_STACK_SIZE + #if SETTINGS_STACK_BUF_SIZE < 3904 // 3904 is required for WLEDMM-0.14.0-b28 + #warning please increase SETTINGS_STACK_BUF_SIZE >= 3904 + #endif + #if (CONFIG_ASYNC_TCP_TASK_STACK_SIZE - SETTINGS_STACK_BUF_SIZE) < 4352 // at least 4096+256 words of free task stack is needed by async_tcp alone + #error remaining async_tcp stack will be too low - please increase CONFIG_ASYNC_TCP_TASK_STACK_SIZE + #endif +#endif + +// audiosync constants +#define AUDIOSYNC_NONE 0x00 // UDP sound sync off +#define AUDIOSYNC_SEND 0x01 // UDP sound sync - send mode +#define AUDIOSYNC_REC 0x02 // UDP sound sync - receiver mode +#define AUDIOSYNC_REC_PLUS 0x06 // UDP sound sync - receiver + local mode (uses local input if no receiving udp sound) +#define AUDIOSYNC_IDLE_MS 2500 // timeout for "receiver idle" (milliseconds) + static volatile bool disableSoundProcessing = false; // if true, sound processing (FFT, filters, AGC) will be suspended. "volatile" as its shared between tasks. -static uint8_t audioSyncEnabled = 0; // bit field: bit 0 - send, bit 1 - receive (config value) +static uint8_t audioSyncEnabled = AUDIOSYNC_NONE; // bit field: bit 0 - send, bit 1 - receive, bit 2 - use local if not receiving +static bool audioSyncSequence = true; // if true, the receiver will drop out-of-sequence packets static bool udpSyncConnected = false; // UDP connection status -> true if connected to multicast group #define NUM_GEQ_CHANNELS 16 // number of frequency channels. Don't change !! @@ -109,9 +133,13 @@ static float volumeSmth = 0.0f; // either sampleAvg or sampleAgc static float FFT_MajorPeak = 1.0f; // FFT: strongest (peak) frequency static float FFT_Magnitude = 0.0f; // FFT: volume (magnitude) of peak frequency static bool samplePeak = false; // Boolean flag for peak - used in effects. Responding routine may reset this flag. Auto-reset after strip.getMinShowDelay() -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 time as samplePeak, but reset by transmitAudioData static unsigned long timeOfPeak = 0; // time of last sample peak detection. -static uint8_t fftResult[NUM_GEQ_CHANNELS]= {0};// Our calculated freq. channel result table to be used by effects +volatile bool haveNewFFTResult = false; // flag to directly inform UDP sound sender when new FFT results are available (to reduce latency). Flag is reset at next UDP send + +static uint8_t fftResult[NUM_GEQ_CHANNELS]= {0}; // Our calculated freq. channel result table to be used by effects +static float fftCalc[NUM_GEQ_CHANNELS] = {0.0f}; // Try and normalize fftBin values to a max of 4096, so that 4096/16 = 256. (also used by dynamics limiter) +static float fftAvg[NUM_GEQ_CHANNELS] = {0.0f}; // Calculated frequency channel results, with smoothing (used if dynamics limiter is ON) // TODO: probably best not used by receive nodes static float agcSensitivity = 128; // AGC sensitivity estimation, based on agc gain (multAgc). calculated by getSensitivity(). range 0..255 @@ -123,7 +151,7 @@ static uint16_t decayTime = 300; // int: decay time in milliseconds // peak detection #ifdef ARDUINO_ARCH_ESP32 -static void detectSamplePeak(void); // peak detection function (needs scaled FFT reasults in vReal[]) - no used for 8266 receive-only mode +static void detectSamplePeak(void); // peak detection function (needs scaled FFT results in vReal[]) - no used for 8266 receive-only mode #endif static void autoResetPeak(void); // peak auto-reset function static uint8_t maxVol = 31; // (was 10) Reasonable value for constant volume for 'peak detector', as it won't always trigger (deprecated) @@ -150,7 +178,7 @@ static uint8_t inputLevel = 128; // UI slider value #endif // user settable options for FFTResult scaling -static uint8_t FFTScalingMode = 3; // 0 none; 1 optimized logarithmic; 2 optimized linear; 3 optimized sqare root +static uint8_t FFTScalingMode = 3; // 0 none; 1 optimized logarithmic; 2 optimized linear; 3 optimized square root #ifndef SR_FREQ_PROF static uint8_t pinkIndex = 0; // 0: default; 1: line-in; 2: IMNP441 #else @@ -220,7 +248,7 @@ static void postProcessFFTResults(bool noiseGateOpen, int numberOfChannels); // static TaskHandle_t FFT_Task = nullptr; // Table of multiplication factors so that we can even out the frequency response. -#define MAX_PINK 10 // 0 = standard, 1= line-in (pink moise only), 2..4 = IMNP441, 5..6 = ICS-43434, ,7=SPM1423, 8..9 = userdef, 10= flat (no pink noise adjustment) +#define MAX_PINK 10 // 0 = standard, 1= line-in (pink noise only), 2..4 = IMNP441, 5..6 = ICS-43434, ,7=SPM1423, 8..9 = userdef, 10= flat (no pink noise adjustment) static const float fftResultPink[MAX_PINK+1][NUM_GEQ_CHANNELS] = { { 1.70f, 1.71f, 1.73f, 1.78f, 1.68f, 1.56f, 1.55f, 1.63f, 1.79f, 1.62f, 1.80f, 2.06f, 2.47f, 3.35f, 6.83f, 9.55f }, // 0 default from SR WLED // { 1.30f, 1.32f, 1.40f, 1.46f, 1.52f, 1.57f, 1.68f, 1.80f, 1.89f, 2.00f, 2.11f, 2.21f, 2.30f, 2.39f, 3.09f, 4.34f }, // - Line-In Generic -> pink noise adjustment only @@ -244,7 +272,7 @@ static const float fftResultPink[MAX_PINK+1][NUM_GEQ_CHANNELS] = { /* how to make your own profile: * =============================== * preparation: make sure your microphone has direct line-of-sigh with the speaker, 1-2meter distance is best - * Prepare your HiFi equipment: disable all "Sound enhancements" - like Loudness, Equalizer, Bass Boost. Bass/Trebble controls set to middle. + * Prepare your HiFi equipment: disable all "Sound enhancements" - like Loudness, Equalizer, Bass Boost. Bass/Treble controls set to middle. * Your HiFi equipment should receive its audio input from Line-In, SPDIF, HDMI, or another "undistorted" connection (like CDROM). * Try not to use Bluetooth or MP3 when playing the "pink noise" audio. BT-audio and MP3 both perform "acoustic adjustments" that we don't want now. @@ -258,7 +286,7 @@ static const float fftResultPink[MAX_PINK+1][NUM_GEQ_CHANNELS] = { * Your own profile: * - Target for each LED bar is 50% to 75% of the max height --> 8(high) x 16(wide) panel means target = 5. 32 x 16 means target = 22. - * - From left to right - count the LEDs in each of the 16 frequency colums (that's why you need the photo). This is the barheight for each channel. + * - From left to right - count the LEDs in each of the 16 frequency columns (that's why you need the photo). This is the barheight for each channel. * - math time! Find the multiplier that will bring each bar to to target. * * in case of square root scale: multiplier = (target * target) / (barheight * barheight) * * in case of linear scale: multiplier = target / barheight @@ -280,8 +308,6 @@ static float sampleTime = 0; // avg (blocked) time for reading I2S sample // FFT Task variables (filtering and post-processing) static float lastFftCalc[NUM_GEQ_CHANNELS] = {0.0f}; // backup of last FFT channels (before postprocessing) -static float fftCalc[NUM_GEQ_CHANNELS] = {0.0f}; // Try and normalize fftBin values to a max of 4096, so that 4096/16 = 256. -static float fftAvg[NUM_GEQ_CHANNELS] = {0.0f}; // Calculated frequency channel results, with smoothing (used if dynamics limiter is ON) #if !defined(CONFIG_IDF_TARGET_ESP32C3) // audio source parameters and constant @@ -360,7 +386,7 @@ static float mapf(float x, float in_min, float in_max, float out_min, float out_ return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } -// compute average of several FFT resut bins +// compute average of several FFT result bins // linear average static float fftAddAvgLin(int from, int to) { float result = 0.0f; @@ -430,7 +456,7 @@ void FFTcode(void * parameter) for(uint_fast16_t binInd = 0; binInd < samplesFFT; binInd++) { float binFreq = binInd * binWidth + binWidth/2.0f; if (binFreq > (SAMPLE_RATE * 0.42f)) - binFreq = (SAMPLE_RATE * 0.42f) - 0.25 * (binFreq - (SAMPLE_RATE * 0.42f)); // supress noise and aliasing + binFreq = (SAMPLE_RATE * 0.42f) - 0.25 * (binFreq - (SAMPLE_RATE * 0.42f)); // suppress noise and aliasing pinkFactors[binInd] = sqrtf(binFreq) / pinkcenter; } pinkFactors[0] *= 0.5; // suppress 0-42hz bin @@ -442,7 +468,7 @@ void FFTcode(void * parameter) // taskYIELD(), yield(), vTaskDelay() and esp_task_wdt_feed() didn't seem to work. // Don't run FFT computing code if we're in Receive mode or in realtime mode - if (disableSoundProcessing || (audioSyncEnabled & 0x02)) { + if (disableSoundProcessing || (audioSyncEnabled == AUDIOSYNC_REC)) { isFirstRun = false; vTaskDelayUntil( &xLastWakeTime, xFrequency); // release CPU, and let I2S fill its buffers continue; @@ -482,7 +508,7 @@ void FFTcode(void * parameter) #endif xLastWakeTime = xTaskGetTickCount(); // update "last unblocked time" for vTaskDelay - isFirstRun = !isFirstRun; // toggle throtte + isFirstRun = !isFirstRun; // toggle throttle #ifdef MIC_LOGGER float datMin = 0.0f; @@ -499,6 +525,11 @@ void FFTcode(void * parameter) } #endif +#if defined(WLEDMM_FASTPATH) && !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && defined(ARDUINO_ARCH_ESP32) + // experimental - be nice to LED update task (trying to avoid flickering) - dual core only + if (strip.isServicing()) delay(2); +#endif + // band pass filter - can reduce noise floor by a factor of 50 // downside: frequencies below 100Hz will be ignored if ((useInputFilter > 0) && (useInputFilter < 99)) { @@ -619,7 +650,7 @@ void FFTcode(void * parameter) * * Andrew's updated mapping of 256 bins down to the 16 result bins with Sample Freq = 10240, samplesFFT = 512 and some overlap. * Based on testing, the lowest/Start frequency is 60 Hz (with bin 3) and a highest/End frequency of 5120 Hz in bin 255. - * Now, Take the 60Hz and multiply by 1.320367784 to get the next frequency and so on until the end. Then detetermine the bins. + * Now, Take the 60Hz and multiply by 1.320367784 to get the next frequency and so on until the end. Then determine the bins. * End frequency = Start frequency * multiplier ^ 16 * Multiplier = (End frequency/ Start frequency) ^ 1/16 * Multiplier = 1.320367784 @@ -673,7 +704,7 @@ void FFTcode(void * parameter) fftCalc[13] = fftAddAvg(86,103); // 18 3704 - 4479 high mid fftCalc[14] = fftAddAvg(104,164) * 0.88f; // 61 4479 - 7106 high mid + high -- with slight damping } - else if (freqDist == 1) { //WLEDMM: Rightshft: note ewowi: frequencies in comments are not correct + else if (freqDist == 1) { //WLEDMM: Rightshift: note ewowi: frequencies in comments are not correct if (useInputFilter==1) { // skip frequencies below 100hz fftCalc[ 0] = 0.8f * fftAddAvg(1,1); @@ -717,7 +748,7 @@ void FFTcode(void * parameter) memcpy(fftCalc, lastFftCalc, sizeof(fftCalc)); // restore last "good" channels } - // post-processing of frequency channels (pink noise adjustment, AGC, smooting, scaling) + // post-processing of frequency channels (pink noise adjustment, AGC, smoothing, scaling) if (pinkIndex > MAX_PINK) pinkIndex = MAX_PINK; //postProcessFFTResults((fabsf(sampleAvg) > 0.25f)? true : false , NUM_GEQ_CHANNELS); postProcessFFTResults((fabsf(volumeSmth)>0.25f)? true : false , NUM_GEQ_CHANNELS); // this function modifies fftCalc, fftAvg and fftResult @@ -736,6 +767,9 @@ void FFTcode(void * parameter) autoResetPeak(); detectSamplePeak(); + // we have new results - notify UDP sound send + haveNewFFTResult = true; + #if !defined(I2S_GRAB_ADC1_COMPLETELY) if ((audioSource == nullptr) || (audioSource->getType() != AudioSource::Type_I2SAdc)) // the "delay trick" does not help for analog ADC #endif @@ -775,7 +809,7 @@ static void runMicFilter(uint16_t numSamples, float *sampleBuffer) // p // FIR lowpass, to remove high frequency noise float highFilteredSample; if (i < (numSamples-1)) highFilteredSample = beta1*sampleBuffer[i] + beta2*last_vals[0] + beta2*sampleBuffer[i+1]; // smooth out spikes - else highFilteredSample = beta1*sampleBuffer[i] + beta2*last_vals[0] + beta2*last_vals[1]; // spcial handling for last sample in array + else highFilteredSample = beta1*sampleBuffer[i] + beta2*last_vals[0] + beta2*last_vals[1]; // special handling for last sample in array last_vals[1] = last_vals[0]; last_vals[0] = sampleBuffer[i]; sampleBuffer[i] = highFilteredSample; @@ -904,7 +938,7 @@ static void autoResetPeak(void) { uint16_t MinShowDelay = MAX(50, strip.getMinShowDelay()); // Fixes private class variable compiler error. Unsure if this is the correct way of fixing the root problem. -THATDONFC if (millis() - timeOfPeak > MinShowDelay) { // Auto-reset of samplePeak after a complete frame has passed. samplePeak = false; - if (audioSyncEnabled == 0) udpSamplePeak = false; // this is normally reset by transmitAudioData + if (audioSyncEnabled == AUDIOSYNC_NONE) udpSamplePeak = false; // this is normally reset by transmitAudioData } } @@ -966,7 +1000,7 @@ class AudioReactive : public Usermod { float sampleRaw; // 04 Bytes - either "sampleRaw" or "rawSampleAgc" depending on soundAgc setting float sampleSmth; // 04 Bytes - either "sampleAvg" or "sampleAgc" depending on soundAgc setting uint8_t samplePeak; // 01 Bytes - 0 no peak; >=1 peak detected. In future, this will also provide peak Magnitude - uint8_t reserved1; // 01 Bytes - for future extensions - not used yet + uint8_t frameCounter; // 01 Bytes - track duplicate/out of order packets uint8_t fftResult[16]; // 16 Bytes float FFT_Magnitude; // 04 Bytes float FFT_MajorPeak; // 04 Bytes @@ -998,7 +1032,11 @@ class AudioReactive : public Usermod { // variables for UDP sound sync WiFiUDP fftUdp; // UDP object for sound sync (from WiFi UDP, not Async UDP!) unsigned long lastTime = 0; // last time of running UDP Microphone Sync +#if defined(WLEDMM_FASTPATH) + const uint16_t delayMs = 5; // I don't want to sample too often and overload WLED +#else const uint16_t delayMs = 10; // I don't want to sample too often and overload WLED +#endif uint16_t audioSyncPort= 11988;// default port for UDP sound sync bool updateIsRunning = false; // true during OTA. @@ -1010,7 +1048,7 @@ class AudioReactive : public Usermod { // variables used by getSample() and agcAvg() int16_t micIn = 0; // Current sample starts with negative values and large values, which is why it's 16 bit signed - double sampleMax = 0.0; // Max sample over a few seconds. Needed for AGC controler. + double sampleMax = 0.0; // Max sample over a few seconds. Needed for AGC controller. double micLev = 0.0; // Used to convert returned value to have '0' as minimum. A leveller float expAdjF = 0.0f; // Used for exponential filter. float sampleReal = 0.0f; // "sampleRaw" as float, to provide bits that are lost otherwise (before amplification by sampleGain or inputLevel). Needed for AGC. @@ -1048,7 +1086,7 @@ class AudioReactive : public Usermod { //////////////////// void logAudio() { - if (disableSoundProcessing && (!udpSyncConnected || ((audioSyncEnabled & 0x02) == 0))) return; // no audio availeable + if (disableSoundProcessing && (!udpSyncConnected || ((audioSyncEnabled & AUDIOSYNC_REC) == 0))) return; // no audio available #ifdef MIC_LOGGER // Debugging functions for audio input and sound processing. Comment out the values you want to see PLOT_PRINT("volumeSmth:"); PLOT_PRINT(volumeSmth + 256.0f); PLOT_PRINT("\t"); // +256 to move above other lines @@ -1141,13 +1179,13 @@ class AudioReactive : public Usermod { * 2. we use two setpoints, one at ~60%, and one at ~80% of the maximum signal * 3. the amplification depends on signal level: * a) normal zone - very slow adjustment - * b) emergency zome (<10% or >90%) - very fast adjustment + * b) emergency zone (<10% or >90%) - very fast adjustment */ void agcAvg(unsigned long the_time) { const int AGC_preset = (soundAgc > 0)? (soundAgc-1): 0; // make sure the _compiler_ knows this value will not change while we are inside the function - float lastMultAgc = multAgc; // last muliplier used + float lastMultAgc = multAgc; // last multiplier used float multAgcTemp = multAgc; // new multiplier float tmpAgc = sampleReal * multAgc; // what-if amplified signal @@ -1187,13 +1225,13 @@ class AudioReactive : public Usermod { if (((multAgcTemp > 0.085f) && (multAgcTemp < 6.5f)) //integrator anti-windup by clamping && (multAgc*sampleMax < agcZoneStop[AGC_preset])) //integrator ceiling (>140% of max) - control_integrated += control_error * 0.002 * 0.25; // 2ms = intgration time; 0.25 for damping + control_integrated += control_error * 0.002 * 0.25; // 2ms = integration time; 0.25 for damping else - control_integrated *= 0.9; // spin down that beasty integrator + control_integrated *= 0.9; // spin down that integrator beast // apply PI Control tmpAgc = sampleReal * lastMultAgc; // check "zone" of the signal using previous gain - if ((tmpAgc > agcZoneHigh[AGC_preset]) || (tmpAgc < soundSquelch + agcZoneLow[AGC_preset])) { // upper/lower emergy zone + if ((tmpAgc > agcZoneHigh[AGC_preset]) || (tmpAgc < soundSquelch + agcZoneLow[AGC_preset])) { // upper/lower emergency zone multAgcTemp = lastMultAgc + agcFollowFast[AGC_preset] * agcControlKp[AGC_preset] * control_error; multAgcTemp += agcFollowFast[AGC_preset] * agcControlKi[AGC_preset] * control_integrated; } else { // "normal zone" @@ -1201,7 +1239,7 @@ class AudioReactive : public Usermod { multAgcTemp += agcFollowSlow[AGC_preset] * agcControlKi[AGC_preset] * control_integrated; } - // limit amplification again - PI controler sometimes "overshoots" + // limit amplification again - PI controller sometimes "overshoots" //multAgcTemp = constrain(multAgcTemp, 0.015625f, 32.0f); // 1/64 < multAgcTemp < 32 if (multAgcTemp > 32.0f) multAgcTemp = 32.0f; if (multAgcTemp < 1.0f/64.0f) multAgcTemp = 1.0f/64.0f; @@ -1231,7 +1269,7 @@ class AudioReactive : public Usermod { void getSample() { float sampleAdj; // Gain adjusted sample value - float tmpSample; // An interim sample variable used for calculatioins. + float tmpSample; // An interim sample variable used for calculations. #ifdef WLEDMM_FASTPATH constexpr float weighting = 0.35f; // slightly reduced filter strength, to reduce audio latency constexpr float weighting2 = 0.25f; @@ -1407,7 +1445,7 @@ class AudioReactive : public Usermod { if (limiterOn == false) return; long delta_time = millis() - last_time; - delta_time = constrain(delta_time , 1, 1000); // below 1ms -> 1ms; above 1sec -> sily lil hick-up + delta_time = constrain(delta_time , 1, 1000); // below 1ms -> 1ms; above 1sec -> silly lil hick-up float deltaSample = volumeSmth - last_volumeSmth; if (attackTime > 0) { // user has defined attack time > 0 @@ -1425,6 +1463,39 @@ class AudioReactive : public Usermod { last_time = millis(); } + // MM experimental: limiter to smooth GEQ samples (only for UDP sound receiver mode) + // target value (if gotNewSample) : fftCalc + // last filtered value: fftAvg + void limitGEQDynamics(bool gotNewSample) { + constexpr float bigChange = 202; // just a representative number - a large, expected sample value + constexpr float smooth = 0.8f; // a bit of filtering + static unsigned long last_time = 0; + + if (limiterOn == false) return; + + if (gotNewSample) { // take new FFT samples as target values + for(unsigned i=0; i < NUM_GEQ_CHANNELS; i++) { + fftCalc[i] = fftResult[i]; + fftResult[i] = fftAvg[i]; + } + } + + long delta_time = millis() - last_time; + delta_time = constrain(delta_time , 1, 1000); // below 1ms -> 1ms; above 1sec -> silly lil hick-up + float maxAttack = (attackTime <= 0) ? 255.0f : (bigChange * float(delta_time) / float(attackTime)); + float maxDecay = (decayTime <= 0) ? -255.0f : (-bigChange * float(delta_time) / float(decayTime)); + + for(unsigned i=0; i < NUM_GEQ_CHANNELS; i++) { + float deltaSample = fftCalc[i] - fftAvg[i]; + if (deltaSample > maxAttack) deltaSample = maxAttack; + if (deltaSample < maxDecay) deltaSample = maxDecay; + deltaSample = deltaSample * smooth; + fftAvg[i] = fmaxf(0.0f, fminf(255.0f, fftAvg[i] + deltaSample)); + fftResult[i] = fftAvg[i]; + } + last_time = millis(); + } + ////////////////////// // UDP Sound Sync // ////////////////////// @@ -1435,7 +1506,7 @@ class AudioReactive : public Usermod { // necessary as we also want to transmit in "AP Mode", but the standard "connected()" callback only reacts on STA connection static unsigned long last_connection_attempt = 0; - if ((audioSyncPort <= 0) || ((audioSyncEnabled & 0x03) == 0)) return; // Sound Sync not enabled + if ((audioSyncPort <= 0) || (audioSyncEnabled == AUDIOSYNC_NONE)) return; // Sound Sync not enabled if (!(apActive || WLED_CONNECTED || interfacesInited)) { if (udpSyncConnected) { udpSyncConnected = false; @@ -1443,11 +1514,11 @@ class AudioReactive : public Usermod { receivedFormat = 0; DEBUGSR_PRINTLN(F("AR connectUDPSoundSync(): connection lost, UDP closed.")); } - return; // neither AP nor other connections availeable + return; // neither AP nor other connections available } if (udpSyncConnected) return; // already connected if (millis() - last_connection_attempt < 15000) return; // only try once in 15 seconds - if (updateIsRunning) return; // don't reconect during OTA + if (updateIsRunning) return; // don't reconnect during OTA // if we arrive here, we need a UDP connection but don't have one last_connection_attempt = millis(); @@ -1457,16 +1528,19 @@ class AudioReactive : public Usermod { void transmitAudioData() { if (!udpSyncConnected) return; + static uint8_t frameCounter = 0; //DEBUGSR_PRINTLN("Transmitting UDP Mic Packet"); audioSyncPacket transmitData; + memset(reinterpret_cast(&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); // transmit samples that were not modified by limitSampleDynamics() transmitData.sampleRaw = (soundAgc) ? rawSampleAgc: sampleRaw; transmitData.sampleSmth = (soundAgc) ? sampleAgc : sampleAvg; transmitData.samplePeak = udpSamplePeak ? 1:0; udpSamplePeak = false; // Reset udpSamplePeak after we've transmitted it - transmitData.reserved1 = 0; + transmitData.frameCounter = frameCounter; for (int i = 0; i < NUM_GEQ_CHANNELS; i++) { transmitData.fftResult[i] = (uint8_t)constrain(fftResult[i], 0, 254); @@ -1479,7 +1553,8 @@ class AudioReactive : public Usermod { fftUdp.write(reinterpret_cast(&transmitData), sizeof(transmitData)); fftUdp.endPacket(); } - return; + + frameCounter++; } // transmitAudioData() #endif static bool isValidUdpSyncVersion(const char *header) { @@ -1489,8 +1564,29 @@ class AudioReactive : public Usermod { return strncmp_P(header, UDP_SYNC_HEADER_v1, 6) == 0; } - void decodeAudioData(int packetSize, uint8_t *fftBuff) { + bool decodeAudioData(int packetSize, uint8_t *fftBuff) { + if((0 == packetSize) || (nullptr == fftBuff)) return false; // sanity check audioSyncPacket *receivedPacket = reinterpret_cast(fftBuff); + + // validate sequence, discard out-of-sequence packets + static uint8_t lastFrameCounter = 0; + // add info for UI + if ((receivedPacket->frameCounter > 0) && (lastFrameCounter > 0)) receivedFormat = 3; // v2+ + else receivedFormat = 2; // v2 + // check sequence + bool sequenceOK = false; + if(receivedPacket->frameCounter > lastFrameCounter) sequenceOK = true; // sequence OK + if((lastFrameCounter < 12) && (receivedPacket->frameCounter > 248)) sequenceOK = false; // prevent sequence "roll-back" due to late packets (1->254) + if((lastFrameCounter > 248) && (receivedPacket->frameCounter < 12)) sequenceOK = true; // handle roll-over (255 -> 0) + if(audioSyncSequence == false) sequenceOK = true; // sequence checking disabled by user + if((sequenceOK == false) && (receivedPacket->frameCounter != 0)) { // always accept "0" - its the legacy value + DEBUGSR_PRINTF("Skipping audio frame out of order or duplicated - %u vs %u\n", lastFrameCounter, receivedPacket->frameCounter); + return false; // reject out-of sequence frame + } + else { + lastFrameCounter = receivedPacket->frameCounter; + } + // update samples for effects volumeSmth = fmaxf(receivedPacket->sampleSmth, 0.0f); volumeRaw = fmaxf(receivedPacket->sampleRaw, 0.0f); @@ -1515,6 +1611,7 @@ class AudioReactive : public Usermod { my_magnitude = fmaxf(receivedPacket->FFT_Magnitude, 0.0f); FFT_Magnitude = my_magnitude; FFT_MajorPeak = constrain(receivedPacket->FFT_MajorPeak, 1.0f, 11025.0f); // restrict value to range expected by effects + return true; } void decodeAudioData_v1(int packetSize, uint8_t *fftBuff) { @@ -1577,16 +1674,15 @@ class AudioReactive : public Usermod { // VERIFY THAT THIS IS A COMPATIBLE PACKET if (packetSize == sizeof(audioSyncPacket) && (isValidUdpSyncVersion((const char *)fftUdpBuffer))) { - decodeAudioData(packetSize, fftUdpBuffer); - //DEBUGSR_PRINTLN("Finished parsing UDP Sync Packet v2"); - haveFreshData = true; receivedFormat = 2; + haveFreshData = decodeAudioData(packetSize, fftUdpBuffer); + //DEBUGSR_PRINTLN("Finished parsing UDP Sync Packet v2"); } else { if (packetSize == sizeof(audioSyncPacket_v1) && (isValidUdpSyncVersion_v1((const char *)fftUdpBuffer))) { decodeAudioData_v1(packetSize, fftUdpBuffer); + receivedFormat = 1; //DEBUGSR_PRINTLN("Finished parsing UDP Sync Packet v1"); haveFreshData = true; - receivedFormat = 1; } else receivedFormat = 0; // unknown format } } @@ -1641,7 +1737,7 @@ class AudioReactive : public Usermod { um_data->u_type[10] = UMT_FLOAT; #else // ESP8266 - // See https://github.com/MoonModules/WLED/pull/60#issuecomment-1666972133 for explaination of these alternative sources of data + // See https://github.com/MoonModules/WLED/pull/60#issuecomment-1666972133 for explanation of these alternative sources of data um_data->u_data[6] = &maxVol; // assigned in effect function from UI element!!! (Puddlepeak, Ripplepeak, Waterfall) um_data->u_type[6] = UMT_BYTE; @@ -1739,6 +1835,23 @@ class AudioReactive : public Usermod { if (i2c_sda >= 0) sdaPin = -1; // -1 = use global if (i2c_scl >= 0) sclPin = -1; + if (audioSource) audioSource->initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin); + break; + case 7: + #ifdef use_wm8978_mic + DEBUGSR_PRINTLN(F("AR: WM8978 Source (Mic)")); + #else + DEBUGSR_PRINTLN(F("AR: WM8978 Source (Line-In)")); + #endif + audioSource = new WM8978Source(SAMPLE_RATE, BLOCK_SIZE, 1.0f); + //useInputFilter = 0; // to disable low-cut software filtering and restore previous behaviour + delay(100); + // WLEDMM align global pins + if ((sdaPin >= 0) && (i2c_sda < 0)) i2c_sda = sdaPin; // copy usermod prefs into globals (if globals not defined) + if ((sclPin >= 0) && (i2c_scl < 0)) i2c_scl = sclPin; + if (i2c_sda >= 0) sdaPin = -1; // -1 = use global + if (i2c_scl >= 0) sclPin = -1; + if (audioSource) audioSource->initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin); break; @@ -1758,7 +1871,7 @@ class AudioReactive : public Usermod { if (!audioSource) enabled = false; // audio failed to initialise #endif - if (enabled) onUpdateBegin(false); // create FFT task, and initailize network + if (enabled) onUpdateBegin(false); // create FFT task, and initialize network #ifdef ARDUINO_ARCH_ESP32 if (FFT_Task == nullptr) enabled = false; // FFT task creation failed @@ -1803,7 +1916,7 @@ class AudioReactive : public Usermod { DEBUGSR_PRINTLN(F("AR connected(): old UDP connection closed.")); } - if (audioSyncPort > 0 && (audioSyncEnabled & 0x03)) { + if ((audioSyncPort > 0) && (audioSyncEnabled > AUDIOSYNC_NONE)) { #ifdef ARDUINO_ARCH_ESP32 udpSyncConnected = fftUdp.beginMulticast(IPAddress(239, 0, 0, 1), audioSyncPort); #else @@ -1844,7 +1957,18 @@ class AudioReactive : public Usermod { return; } // We cannot wait indefinitely before processing audio data - if (strip.isUpdating() && (millis() - lastUMRun < 2)) return; // be nice, but not too nice + if (strip.isServicing() && (millis() - lastUMRun < 2)) return; // WLEDMM isServicing() is the critical part (be nice, but not too nice) + + // sound sync "receive or local" + bool useNetworkAudio = false; + if (audioSyncEnabled > AUDIOSYNC_SEND) { // we are in "receive" or "receive+local" mode + if (udpSyncConnected && ((millis() - last_UDPTime) <= AUDIOSYNC_IDLE_MS)) + useNetworkAudio = true; + else + useNetworkAudio = false; + if (audioSyncEnabled == AUDIOSYNC_REC) + useNetworkAudio = true; // don't fall back to local audio in standard "receive mode" + } // suspend local sound processing when "real time mode" is active (E131, UDP, ADALIGHT, ARTNET) if ( (realtimeOverride == REALTIME_OVERRIDE_NONE) // please add other overrides here if needed @@ -1855,27 +1979,32 @@ class AudioReactive : public Usermod { ||(realtimeMode == REALTIME_MODE_ARTNET) ) ) // please add other modes here if needed { #ifdef WLED_DEBUG - if ((disableSoundProcessing == false) && (audioSyncEnabled == 0)) { // we just switched to "disabled" + if ((disableSoundProcessing == false) && (audioSyncEnabled < AUDIOSYNC_REC)) { // we just switched to "disabled" DEBUG_PRINTLN("[AR userLoop] realtime mode active - audio processing suspended."); DEBUG_PRINTF( " RealtimeMode = %d; RealtimeOverride = %d\n", int(realtimeMode), int(realtimeOverride)); } #endif disableSoundProcessing = true; + useNetworkAudio = false; } else { #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_DEBUG) - if ((disableSoundProcessing == true) && (audioSyncEnabled == 0) && audioSource->isInitialized()) { // we just switched to "enabled" + if ((disableSoundProcessing == true) && (audioSyncEnabled < AUDIOSYNC_REC) && audioSource->isInitialized()) { // we just switched to "enabled" DEBUG_PRINTLN("[AR userLoop] realtime mode ended - audio processing resumed."); DEBUG_PRINTF( " RealtimeMode = %d; RealtimeOverride = %d\n", int(realtimeMode), int(realtimeOverride)); } #endif - if ((disableSoundProcessing == true) && (audioSyncEnabled == 0)) lastUMRun = millis(); // just left "realtime mode" - update timekeeping + if ((disableSoundProcessing == true) && (audioSyncEnabled < AUDIOSYNC_REC)) lastUMRun = millis(); // just left "realtime mode" - update timekeeping disableSoundProcessing = false; } - if (audioSyncEnabled & 0x02) disableSoundProcessing = true; // make sure everything is disabled IF in audio Receive mode - if (audioSyncEnabled & 0x01) disableSoundProcessing = false; // keep running audio IF we're in audio Transmit mode + if (audioSyncEnabled == AUDIOSYNC_REC) disableSoundProcessing = true; // make sure everything is disabled IF in audio Receive mode + if (audioSyncEnabled & AUDIOSYNC_SEND) disableSoundProcessing = false; // keep running audio IF we're in audio Transmit mode #ifdef ARDUINO_ARCH_ESP32 - if (!audioSource->isInitialized()) disableSoundProcessing = true; // no audio source + if (!audioSource->isInitialized()) { // no audio source + disableSoundProcessing = true; + if (audioSyncEnabled > AUDIOSYNC_SEND) useNetworkAudio = true; + } + if ((audioSyncEnabled == AUDIOSYNC_REC_PLUS) && useNetworkAudio) disableSoundProcessing = true; // UDP sound receiving - disable local audio #ifdef SR_DEBUG // debug info in case that task stack usage changes @@ -1888,7 +2017,7 @@ class AudioReactive : public Usermod { #endif // Only run the sampling code IF we're not in Receive mode or realtime mode - if (!(audioSyncEnabled & 0x02) && !disableSoundProcessing) { + if ((audioSyncEnabled != AUDIOSYNC_REC) && !disableSoundProcessing && !useNetworkAudio) { if (soundAgc > AGC_NUM_PRESETS) soundAgc = 0; // make sure that AGC preset is valid (to avoid array bounds violation) unsigned long t_now = millis(); // remember current time @@ -1897,9 +2026,9 @@ class AudioReactive : public Usermod { #if defined(SR_DEBUG) // complain when audio userloop has been delayed for long time. Currently we need userloop running between 500 and 1500 times per second. - // softhack007 disabled temporarily - avoid serial console spam with MANY leds and low FPS - //if ((userloopDelay > /*23*/ 65) && !disableSoundProcessing && (audioSyncEnabled == 0)) { - //DEBUG_PRINTF("[AR userLoop] hickup detected -> was inactive for last %d millis!\n", userloopDelay); + // softhack007 disabled temporarily - avoid serial console spam with MANY LEDs and low FPS + //if ((userloopDelay > /*23*/ 65) && !disableSoundProcessing && (audioSyncEnabled == AUDIOSYNC_NONE)) { + //DEBUG_PRINTF("[AR userLoop] hiccup detected -> was inactive for last %d millis!\n", userloopDelay); //} #endif @@ -1945,27 +2074,33 @@ class AudioReactive : public Usermod { connectUDPSoundSync(); // ensure we have a connection - if needed // UDP Microphone Sync - receive mode - if ((audioSyncEnabled & 0x02) && udpSyncConnected) { + if ((audioSyncEnabled & AUDIOSYNC_REC) && udpSyncConnected) { // Only run the audio listener code if we're in Receive mode static float syncVolumeSmth = 0; bool have_new_sample = false; if (millis() - lastTime > delayMs) { have_new_sample = receiveAudioData(); - if (have_new_sample) last_UDPTime = millis(); + if (have_new_sample) { + last_UDPTime = millis(); + useNetworkAudio = true; // UDP input arrived - use it + } lastTime = millis(); } else { #ifdef ARDUINO_ARCH_ESP32 fftUdp.flush(); // WLEDMM: Flush this if we haven't read it. Does not work on 8266. #endif } - if (have_new_sample) syncVolumeSmth = volumeSmth; // remember received sample - else volumeSmth = syncVolumeSmth; // restore originally received sample for next run of dynamics limiter - limitSampleDynamics(); // run dynamics limiter on received volumeSmth, to hide jumps and hickups + if (useNetworkAudio) { + if (have_new_sample) syncVolumeSmth = volumeSmth; // remember received sample + else volumeSmth = syncVolumeSmth; // restore originally received sample for next run of dynamics limiter + limitSampleDynamics(); // run dynamics limiter on received volumeSmth, to hide jumps and hickups + limitGEQDynamics(have_new_sample); // WLEDMM experimental: smooth FFT (GEQ) samples + } } else { receivedFormat = 0; } - if ( (audioSyncEnabled & 0x02) // receive mode + if ( (audioSyncEnabled & AUDIOSYNC_REC) // receive mode && udpSyncConnected // connected && (receivedFormat > 0) // we actually received something in the past && ((millis() - last_UDPTime) > 25000)) { // close connection after 25sec idle @@ -2011,7 +2146,12 @@ class AudioReactive : public Usermod { #ifdef ARDUINO_ARCH_ESP32 //UDP Microphone Sync - transmit mode - if ((audioSyncEnabled & 0x01) && (millis() - lastTime > 20)) { + #if defined(WLEDMM_FASTPATH) + if ((audioSyncEnabled & AUDIOSYNC_SEND) && (haveNewFFTResult || (millis() - lastTime > 24))) { // fastpath: send data once results are ready, or each 25ms as fallback (max sampling time is 23ms) + #else + if ((audioSyncEnabled & AUDIOSYNC_SEND) && (millis() - lastTime > 20)) { // standard: send data each 20ms + #endif + haveNewFFTResult = false; // reset notification // Only run the transmit code IF we're in Transmit mode transmitAudioData(); lastTime = millis(); @@ -2161,7 +2301,15 @@ class AudioReactive : public Usermod { infoArr.add(uiDomString); if (enabled) { + bool audioSyncIDLE = false; // true if sound sync is not receiving + #ifdef ARDUINO_ARCH_ESP32 + // audio sync status + if ((audioSyncEnabled & AUDIOSYNC_REC) && (!udpSyncConnected || (millis() - last_UDPTime > AUDIOSYNC_IDLE_MS))) // connected and nothing received in 2.5sec + audioSyncIDLE = true; + if ((audioSource == nullptr) || (!audioSource->isInitialized())) // local audio not configured + audioSyncIDLE = false; + // Input Level Slider if (disableSoundProcessing == false) { // only show slider when audio processing is running if (soundAgc > 0) { @@ -2188,11 +2336,11 @@ class AudioReactive : public Usermod { // The following can be used for troubleshooting user errors and is so not enclosed in #ifdef WLED_DEBUG // current Audio input infoArr = user.createNestedArray(F("Audio Source")); - if (audioSyncEnabled & 0x02) { + if ((audioSyncEnabled == AUDIOSYNC_REC) || (!audioSyncIDLE && (audioSyncEnabled == AUDIOSYNC_REC_PLUS))){ // UDP sound sync - receive mode infoArr.add(F("UDP sound sync")); if (udpSyncConnected) { - if (millis() - last_UDPTime < 2500) + if (millis() - last_UDPTime < AUDIOSYNC_IDLE_MS) infoArr.add(F(" - receiving")); else infoArr.add(F(" - idle")); @@ -2207,7 +2355,7 @@ class AudioReactive : public Usermod { } else { // Analog or I2S digital input if (audioSource && (audioSource->isInitialized())) { - // audio source sucessfully configured + // audio source successfully configured if (audioSource->getType() == AudioSource::Type_I2SAdc) { infoArr.add(F("ADC analog")); } else { @@ -2240,13 +2388,13 @@ class AudioReactive : public Usermod { } // AGC or manual Gain - if ((soundAgc==0) && (disableSoundProcessing == false) && !(audioSyncEnabled & 0x02)) { + if ((soundAgc == 0) && (disableSoundProcessing == false) && !(audioSyncEnabled == AUDIOSYNC_REC)) { infoArr = user.createNestedArray(F("Manual Gain")); float myGain = ((float)sampleGain/40.0f * (float)inputLevel/128.0f) + 1.0f/16.0f; // non-AGC gain from presets infoArr.add(roundf(myGain*100.0f) / 100.0f); infoArr.add("x"); } - if (soundAgc && (disableSoundProcessing == false) && !(audioSyncEnabled & 0x02)) { + if ((soundAgc > 0) && (disableSoundProcessing == false) && !(audioSyncEnabled == AUDIOSYNC_REC)) { infoArr = user.createNestedArray(F("AGC Gain")); infoArr.add(roundf(multAgc*100.0f) / 100.0f); infoArr.add("x"); @@ -2255,18 +2403,24 @@ class AudioReactive : public Usermod { // UDP Sound Sync status infoArr = user.createNestedArray(F("UDP Sound Sync")); if (audioSyncEnabled) { - if (audioSyncEnabled & 0x01) { + if (audioSyncEnabled & AUDIOSYNC_SEND) { infoArr.add(F("send mode")); - if ((udpSyncConnected) && (millis() - lastTime < 2500)) infoArr.add(F(" v2")); - } else if (audioSyncEnabled & 0x02) { + if ((udpSyncConnected) && (millis() - lastTime < AUDIOSYNC_IDLE_MS)) infoArr.add(F(" v2+")); + } else if (audioSyncEnabled == AUDIOSYNC_REC) { infoArr.add(F("receive mode")); + } else if (audioSyncEnabled == AUDIOSYNC_REC_PLUS) { + infoArr.add(F("receive+local mode")); } } else infoArr.add("off"); if (audioSyncEnabled && !udpSyncConnected) infoArr.add(" (unconnected)"); - if (audioSyncEnabled && udpSyncConnected && (millis() - last_UDPTime < 2500)) { + if (audioSyncEnabled && udpSyncConnected && (millis() - last_UDPTime < AUDIOSYNC_IDLE_MS)) { if (receivedFormat == 1) infoArr.add(F(" v1")); if (receivedFormat == 2) infoArr.add(F(" v2")); + if (receivedFormat == 3) { + if (audioSyncSequence) infoArr.add(F(" v2+")); // Sequence checking enabled + else infoArr.add(F(" v2")); + } } #if defined(WLED_DEBUG) || defined(SR_DEBUG) || defined(SR_STATS) @@ -2418,6 +2572,7 @@ class AudioReactive : public Usermod { JsonObject sync = top.createNestedObject("sync"); sync[F("port")] = audioSyncPort; sync[F("mode")] = audioSyncEnabled; + sync[F("check_sequence")] = audioSyncSequence; } @@ -2486,6 +2641,7 @@ class AudioReactive : public Usermod { configComplete &= getJsonValue(top["sync"][F("port")], audioSyncPort); configComplete &= getJsonValue(top["sync"][F("mode")], audioSyncEnabled); + configComplete &= getJsonValue(top["sync"][F("check_sequence")], audioSyncSequence); return configComplete; } @@ -2548,7 +2704,11 @@ class AudioReactive : public Usermod { #else oappend(SET_F("addOption(dd,'ES8388 ☾',6);")); #endif - + #if SR_DMTYPE==7 + oappend(SET_F("addOption(dd,'WM8978 ☾ (⎌)',7);")); + #else + oappend(SET_F("addOption(dd,'WM8978 ☾',7);")); + #endif #ifdef SR_SQUELCH oappend(SET_F("addInfo('AudioReactive:config:squelch',1,'⎌ ")); oappendi(SR_SQUELCH); oappend("');"); // 0 is field type, 1 is actual field #endif @@ -2652,12 +2812,20 @@ class AudioReactive : public Usermod { oappend(SET_F("addInfo('AudioReactive:frequency:profile',1,'☾');")); #endif oappend(SET_F("dd=addDropdown('AudioReactive','sync:mode');")); - oappend(SET_F("addOption(dd,'Off',0);")); + oappend(SET_F("addOption(dd,'Off',0);")); // AUDIOSYNC_NONE #ifdef ARDUINO_ARCH_ESP32 - oappend(SET_F("addOption(dd,'Send',1);")); + oappend(SET_F("addOption(dd,'Send',1);")); // AUDIOSYNC_SEND #endif - oappend(SET_F("addOption(dd,'Receive',2);")); - oappend(SET_F("addInfo('AudioReactive:sync:mode',1,'
Sync audio data with other WLEDs');")); + oappend(SET_F("addOption(dd,'Receive',2);")); // AUDIOSYNC_REC +#ifdef ARDUINO_ARCH_ESP32 + oappend(SET_F("addOption(dd,'Receive or Local',6);")); // AUDIOSYNC_REC_PLUS +#endif + // check_sequence: Receiver skips out-of-sequence packets when enabled + oappend(SET_F("dd=addDropdown('AudioReactive','sync:check_sequence');")); + oappend(SET_F("addOption(dd,'Off',0);")); + oappend(SET_F("addOption(dd,'On',1);")); + + oappend(SET_F("addInfo('AudioReactive:sync:check_sequence',1,'when receiving
Sync audio data with other WLEDs');")); // must append this to the last field of 'sync' oappend(SET_F("addInfo('AudioReactive:digitalmic:type',1,'requires reboot!');")); // 0 is field type, 1 is actual field #ifdef ARDUINO_ARCH_ESP32 @@ -2700,7 +2868,7 @@ class AudioReactive : public Usermod { oappend(SET_F("xOpt('AudioReactive:digitalmic:pin[]',5,' ⎌',")); oappendi(ES7243_SCLPIN); oappend(");"); #endif oappend(SET_F("dRO('AudioReactive:digitalmic:pin[]',5);")); // disable read only pins -#endif +#endif } diff --git a/usermods/audioreactive/audio_source.h b/usermods/audioreactive/audio_source.h index 9ca3e0c2..2009efbb 100644 --- a/usermods/audioreactive/audio_source.h +++ b/usermods/audioreactive/audio_source.h @@ -45,7 +45,7 @@ // benefit: analog mic inputs will be sampled contiously -> better response times and less "glitches" // WARNING: this option WILL lock-up your device in case that any other analogRead() operation is performed; // for example if you want to read "analog buttons" -//#define I2S_GRAB_ADC1_COMPLETELY // (experimental) continously sample analog ADC microphone. WARNING will cause analogRead() lock-up +//#define I2S_GRAB_ADC1_COMPLETELY // (experimental) continuously sample analog ADC microphone. WARNING will cause analogRead() lock-up // data type requested from the I2S driver - currently we always use 32bit //#define I2S_USE_16BIT_SAMPLES // (experimental) define this to request 16bit - more efficient but possibly less compatible @@ -72,7 +72,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 (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0)) && (ESP_IDF_VERSION <= ESP_IDF_VERSION_VAL(4, 4, 4)) +#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0)) && (ESP_IDF_VERSION <= ESP_IDF_VERSION_VAL(4, 4, 6)) // fixed in IDF 4.4.5, however arduino-esp32 2.0.14 did an "I2S rollback" to 4.4.4 // 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/8538 I2S channel selection issue? (IDFGH-6918) @@ -163,7 +163,7 @@ class AudioSource { SRate_t _sampleRate; // Microphone sampling rate int _blockSize; // I2S block size bool _initialized; // Gets set to true if initialization is successful - bool _i2sMaster; // when false, ESP32 will be in I2S SLAVE mode (for devices that only operate in MASTER mode). Only workds in newer IDF >= 4.4.x + bool _i2sMaster; // when false, ESP32 will be in I2S SLAVE mode (for devices that only operate in MASTER mode). Only works in newer IDF >= 4.4.x float _sampleScale; // pre-scaling factor for I2S samples I2S_datatype newSampleBuffer[I2S_SAMPLES_MAX+4] = { 0 }; // global buffer for i2s_read }; @@ -418,7 +418,7 @@ class I2SSource : public AudioSource { }; /* ES7243 Microphone - This is an I2S microphone that requires ininitialization over + This is an I2S microphone that requires initialization over I2C before I2S data can be received */ class ES7243 : public I2SSource { @@ -483,8 +483,8 @@ public: } }; -/* ES8388 Sound Modude - This is an I2S sound processing unit that requires ininitialization over +/* ES8388 Sound Module + This is an I2S sound processing unit that requires initialization over I2C before I2S data can be received. */ class ES8388Source : public I2SSource { @@ -532,7 +532,7 @@ class ES8388Source : public I2SSource { // The mics *and* line-in are BOTH connected to LIN2/RIN2 on the AudioKit // so there's no way to completely eliminate the mics. It's also hella noisy. // Line-in works OK on the AudioKit, generally speaking, as the mics really need - // amplification to be noticable in a quiet room. If you're in a very loud room, + // amplification to be noticeable in a quiet room. If you're in a very loud room, // the mics on the AudioKit WILL pick up sound even in line-in mode. // TL;DR: Don't use the AudioKit for anything, use the LyraT. // @@ -615,6 +615,97 @@ class ES8388Source : public I2SSource { }; +class WM8978Source : public I2SSource { + private: + // I2C initialization functions for WM8978 + void _wm8978I2cBegin() { + Wire.setClock(400000); + } + + void _wm8978I2cWrite(uint8_t reg, uint16_t val) { + #ifndef WM8978_ADDR + #define WM8978_ADDR 0x1A + #endif + char buf[2]; + buf[0] = (reg << 1) | ((val >> 8) & 0X01); + buf[1] = val & 0XFF; + Wire.beginTransmission(WM8978_ADDR); + Wire.write((const uint8_t*)buf, 2); + uint8_t i2cErr = Wire.endTransmission(); // i2cErr == 0 means OK + if (i2cErr != 0) { + DEBUGSR_PRINTF("AR: WM8978 I2C write failed with error=%d (addr=0x%X, reg 0x%X, val 0x%X).\n", i2cErr, WM8978_ADDR, reg, val); + } + } + + void _wm8978InitAdc() { + // https://www.mouser.com/datasheet/2/76/WM8978_v4.5-1141768.pdf + // Sets ADC to around what AudioReactive expects, and loops line-in to line-out/headphone for monitoring. + // Registries are decimal, settings are 9-bit binary as that's how everything is listed in the docs + // ...which makes it easier to reference the docs. + // + _wm8978I2cBegin(); + + _wm8978I2cWrite( 0,0b000000000); // Reset all settings + _wm8978I2cWrite( 1,0b000001011); // Power Management 1 - power off most things + _wm8978I2cWrite( 2,0b110110011); // Power Management 2 - enable output and amp stages (amps may lift signal but it works better on the ADCs) + _wm8978I2cWrite( 3,0b000001100); // Power Management 3 - enable L&R output mixers + _wm8978I2cWrite( 4,0b001010000); // Audio Interface - standard I2S, 24-bit + _wm8978I2cWrite( 5,0b000000001); // Loopback Enable + _wm8978I2cWrite( 6,0b000000000); // Clock generation control - use external mclk + _wm8978I2cWrite( 7,0b000000100); // Sets sample rate to ~24kHz (only used for internal calculations, not I2S) + _wm8978I2cWrite(14,0b010001000); // 128x ADC oversampling - high pass filter disabled as it kills the bass response + _wm8978I2cWrite(43,0b000110000); // Mute signal paths we don't use + _wm8978I2cWrite(44,0b000000000); // Disconnect microphones + _wm8978I2cWrite(45,0b111000000); // Mute signal paths we don't use + _wm8978I2cWrite(46,0b111000000); // Mute signal paths we don't use + _wm8978I2cWrite(47,0b001000000); // 0dB gain on left line-in + _wm8978I2cWrite(48,0b001000000); // 0dB gain on right line-in + _wm8978I2cWrite(49,0b000000010); // Mixer thermal shutdown enable + _wm8978I2cWrite(50,0b000010110); // Output mixer enable only left bypass at 0dB gain + _wm8978I2cWrite(51,0b000010110); // Output mixer enable only right bypass at 0dB gain + _wm8978I2cWrite(52,0b110111001); // Left line-out enabled at 0dB gain + _wm8978I2cWrite(53,0b110111001); // Right line-out enabled at 0db gain + _wm8978I2cWrite(54,0b001000000); // Mute left speaker output + _wm8978I2cWrite(55,0b101000000); // Mute right speaker output + + } + + public: + WM8978Source(SRate_t sampleRate, int blockSize, float sampleScale = 1.0f, bool i2sMaster=true) : + I2SSource(sampleRate, blockSize, sampleScale, i2sMaster) { + _config.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT; + }; + + void initialize(int8_t i2swsPin, int8_t i2ssdPin, int8_t i2sckPin, int8_t mclkPin) { + DEBUGSR_PRINTLN("WM8978Source:: initialize();"); + + // if ((i2sckPin < 0) || (mclkPin < 0)) { // WLEDMM not sure if this check is needed here, too + // ERRORSR_PRINTF("\nAR: invalid I2S WM8978 pin: SCK=%d, MCLK=%d\n", i2sckPin, mclkPin); + // return; + // } + // BUG: "use global I2C pins" are valid as -1, and -1 is seen as invalid here. + // Workaround: Set I2C pins here, which will also set them globally. + // Bug also exists in ES7243. + if ((i2c_sda < 0) || (i2c_scl < 0)) { // check that global I2C pins are not "undefined" + ERRORSR_PRINTF("\nAR: invalid WM8978 global I2C pins: SDA=%d, SCL=%d\n", i2c_sda, i2c_scl); + return; + } + if (!pinManager.joinWire(i2c_sda, i2c_scl)) { // WLEDMM specific: start I2C with globally defined pins + ERRORSR_PRINTF("\nAR: failed to join I2C bus with SDA=%d, SCL=%d\n", i2c_sda, i2c_scl); + return; + } + + // First route mclk, then configure ADC over I2C, then configure I2S + _wm8978InitAdc(); + I2SSource::initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin); + } + + void deinitialize() { + I2SSource::deinitialize(); + } + +}; + #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0) #if !defined(SOC_I2S_SUPPORTS_ADC) && !defined(SOC_I2S_SUPPORTS_ADC_DAC) #warning this MCU does not support analog sound input @@ -622,7 +713,7 @@ class ES8388Source : public I2SSource { #endif #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) -// ADC over I2S is only availeable in "classic" ESP32 +// ADC over I2S is only available in "classic" ESP32 /* ADC over I2S Microphone This microphone is an ADC pin sampled via the I2S interval diff --git a/usermods/audioreactive/readme.md b/usermods/audioreactive/readme.md index d9f9ea78..1dd5f5d9 100644 --- a/usermods/audioreactive/readme.md +++ b/usermods/audioreactive/readme.md @@ -1,6 +1,6 @@ # Audioreactive usermod -Enabless controlling LEDs via audio input. Audio source can be a microphone or analog-in (AUX) using an appropriate adapter. +Enables controlling LEDs via audio input. Audio source can be a microphone or analog-in (AUX) using an appropriate adapter. Supported microphones range from analog (MAX4466, MAX9814, ...) to digital (INMP441, ICS-43434, ...). Does audio processing and provides data structure that specially written effects can use. @@ -19,7 +19,7 @@ This usermod is an evolution of [SR-WLED](https://github.com/atuline/WLED), and ## Supported MCUs This audioreactive usermod works best on "classic ESP32" (dual core), and on ESP32-S3 which also has dual core and hardware floating point support. -It will compile succesfully for ESP32-S2 and ESP32-C3, however might not work well, as other WLED functions will become slow. Audio processing requires a lot of computing power, which can be problematic on smaller MCUs like -S2 and -C3. +It will compile successfully for ESP32-S2 and ESP32-C3, however might not work well, as other WLED functions will become slow. Audio processing requires a lot of computing power, which can be problematic on smaller MCUs like -S2 and -C3. Analog audio is only possible on "classic" ESP32, but not on other MCUs like ESP32-S3. @@ -35,7 +35,7 @@ Customised _arduinoFFT_ library for use with this usermod can be found at https: ### using latest (develop) _arduinoFFT_ library Alternatively, you can use the latest arduinoFFT development version. -ArduinoFFT `develop` library is slightly more accurate, and slighly faster than our customised library, however also needs additional 2kB RAM. +ArduinoFFT `develop` library is slightly more accurate, and slightly faster than our customised library, however also needs additional 2kB RAM. * `build_flags` = `-D USERMOD_AUDIOREACTIVE` `-D UM_AUDIOREACTIVE_USE_NEW_FFT` * `lib_deps`= `https://github.com/kosme/arduinoFFT#develop @ 1.9.2` @@ -63,7 +63,7 @@ You can use the following additional flags in your `build_flags` * `-D SR_GAIN=x` : Default "gain" setting (60) * `-D I2S_USE_RIGHT_CHANNEL`: Use RIGHT instead of LEFT channel (not recommended unless you strictly need this). * `-D I2S_USE_16BIT_SAMPLES`: Use 16bit instead of 32bit for internal sample buffers. Reduces sampling quality, but frees some RAM ressources (not recommended unless you absolutely need this). -* `-D I2S_GRAB_ADC1_COMPLETELY`: Experimental: continously sample analog ADC microphone. Only effective on ESP32. WARNING this _will_ cause conflicts(lock-up) with any analogRead() call. +* `-D I2S_GRAB_ADC1_COMPLETELY`: Experimental: continuously sample analog ADC microphone. Only effective on ESP32. WARNING this _will_ cause conflicts(lock-up) with any analogRead() call. * `-D MIC_LOGGER` : (debugging) Logs samples from the microphone to serial USB. Use with serial plotter (Arduino IDE) * `-D SR_DEBUG` : (debugging) Additional error diagnostics and debug info on serial USB. diff --git a/usermods/mcu_temp/mcuTemp.h b/usermods/mcu_temp/mcuTemp.h index d38bac2b..73272cd1 100644 --- a/usermods/mcu_temp/mcuTemp.h +++ b/usermods/mcu_temp/mcuTemp.h @@ -2,6 +2,9 @@ #include "wled.h" +// constants +#define MCUT_READ_TIME_MS 7500 // read once in 7.5 seconds + // class name. Use something descriptive and leave the ": public Usermod" part :) class mcuTemp : public Usermod { @@ -9,7 +12,7 @@ class mcuTemp : public Usermod private: float mcutemp = 0; - // any private methods should go here (non-inline methosd should be defined out of class) + // any private methods should go here (non-inline method should be defined out of class) void publishMqtt(const char *state, bool retain = false); // example for publishing MQTT message public: @@ -25,27 +28,34 @@ public: void loop() { + static unsigned long lastMQQTTime = 0; // if usermod is disabled or called during strip updating just exit // NOTE: on very long strips strip.isUpdating() may always return true so update accordingly - if (!enabled || strip.isUpdating()) + if (!enabled || (strip.isUpdating() && (millis() - lastTime < MCUT_READ_TIME_MS))) return; + if (millis() - lastTime < MCUT_READ_TIME_MS) return; // reading each 8 seconds should be enough + #ifdef ESP8266 // ESP8266 // does not seem possible mcutemp = -1; #elif defined(CONFIG_IDF_TARGET_ESP32S2) // ESP32S2 mcutemp = -1; #else // ESP32 ESP32S3 and ESP32C3 - mcutemp = roundf(temperatureRead() * 100) / 100; + float newmcutemp = roundf(temperatureRead() * 10) / 10; + if (abs(newmcutemp - 53.3f) > 0.05f) mcutemp = (mcutemp + 2.0f * newmcutemp) / 3.0f; // skip error value (128 => 53.3deg), apply some filtering #endif - if (millis() - lastTime > 10000) +#ifndef WLED_DISABLE_MQTT + if (millis() - lastMQQTTime > 15000) { char array[10]; - snprintf(array, sizeof(array), "%f", mcutemp); + snprintf(array, sizeof(array), "%3.1f", mcutemp); publishMqtt(array); - lastTime = millis(); + lastMQQTTime = millis(); } +#endif + lastTime = millis(); } /* * addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API. @@ -61,8 +71,9 @@ public: // this code adds "u":{"ExampleUsermod":[20," lux"]} to the info object // int reading = 20; + if (!enabled) return; JsonArray lightArr = user.createNestedArray(FPSTR(_name)); // name - lightArr.add(mcutemp); // value + lightArr.add(roundf(10.0f * mcutemp)/10.0f); // value, rounded to 1 decimal lightArr.add(F(" °C")); // unit // if you are implementing a sensor usermod, you may publish sensor data @@ -72,7 +83,7 @@ public: // temp.add(reading); // temp.add(F("lux")); } - +/* void addToJsonState(JsonObject &root) { } @@ -96,7 +107,7 @@ public: void handleOverlayDraw() { } - +*/ /* * getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!). * This could be used in the future for the system to determine whether your usermod is installed. diff --git a/usermods/mpu6050_imu/usermod_mpu6050_imu.h b/usermods/mpu6050_imu/usermod_mpu6050_imu.h index e923e1f9..1e784d95 100644 --- a/usermods/mpu6050_imu/usermod_mpu6050_imu.h +++ b/usermods/mpu6050_imu/usermod_mpu6050_imu.h @@ -185,7 +185,7 @@ class MPU6050Driver : public Usermod { //INTERRUPT_PIN = -1; //return; } - if ((INTERRUPT_PIN >= 0) && (pinManager.getPinOwner(INTERRUPT_PIN) != PinOwner::UM_IMU) // only allocate pin if we don't ownn it already + if ((INTERRUPT_PIN >= 0) && (pinManager.getPinOwner(INTERRUPT_PIN) != PinOwner::UM_IMU) // only allocate pin if we don't own it already && !pinManager.allocatePin(INTERRUPT_PIN, false, PinOwner::UM_IMU)) { //enabled = false; diff --git a/usermods/mqtt_switch_v2/README.md b/usermods/mqtt_switch_v2/README.md index 148e4a56..744d7fe3 100644 --- a/usermods/mqtt_switch_v2/README.md +++ b/usermods/mqtt_switch_v2/README.md @@ -50,5 +50,5 @@ This usermod listens on `[mqttDeviceTopic]/switch/0/set` (where 0 is replaced wi Feedback about the current state is provided at `[mqttDeviceTopic]/switch/0/state`. ### Home Assistant auto-discovery -Auto-discovery information is automatically published and you shoudn't have to do anything to register the switches in Home Assistant. +Auto-discovery information is automatically published and you shouldn't have to do anything to register the switches in Home Assistant. diff --git a/usermods/multi_relay/readme.md b/usermods/multi_relay/readme.md index 71a54070..1f3bec7a 100644 --- a/usermods/multi_relay/readme.md +++ b/usermods/multi_relay/readme.md @@ -2,7 +2,7 @@ This usermod-v2 modification allows the connection of multiple relays, each with individual delay and on/off mode. Usermod supports PCF8574 I2C port expander to reduce GPIO use. -PCF8574 supports 8 outputs and each output corresponds to a relay in WLED (relay 0 = port 0, etc). I you are using more than 8 relays with multiple PCF8574 make sure their addresses are set conscutively (e.g. 0x20 and 0x21). You can set address of first expander in settings. +PCF8574 supports 8 outputs and each output corresponds to a relay in WLED (relay 0 = port 0, etc). I you are using more than 8 relays with multiple PCF8574 make sure their addresses are set in sequence (e.g. 0x20 and 0x21). You can set address of first expander in settings. (**NOTE:** Will require Wire library and global I2C pins defined.) ## HTTP API diff --git a/usermods/multi_relay/usermod_multi_relay.h b/usermods/multi_relay/usermod_multi_relay.h index b8cabebb..cf0aca22 100644 --- a/usermods/multi_relay/usermod_multi_relay.h +++ b/usermods/multi_relay/usermod_multi_relay.h @@ -196,7 +196,7 @@ class MultiRelay : public Usermod { }; -// class implementetion +// class implementation void MultiRelay::publishMqtt(int relay) { #ifndef WLED_DISABLE_MQTT @@ -496,10 +496,10 @@ void MultiRelay::setup() { * loop() is called continuously. Here you can check for events, read sensors, etc. */ void MultiRelay::loop() { - yield(); - if (!enabled || strip.isUpdating()) return; - static unsigned long lastUpdate = 0; + yield(); + if (!enabled || (strip.isUpdating() && millis() - lastUpdate < 100)) return; + if (millis() - lastUpdate < 100) return; // update only 10 times/s lastUpdate = millis(); diff --git a/usermods/quinled-an-penta/readme.md b/usermods/quinled-an-penta/readme.md index 2338747d..c1260d91 100644 --- a/usermods/quinled-an-penta/readme.md +++ b/usermods/quinled-an-penta/readme.md @@ -2,7 +2,7 @@ The (un)official usermod to get the best out of the QuinLED-An-Penta (https://quinled.info/quinled-an-penta/), e.g. using the OLED and the SHT30 temperature/humidity sensor. ## Requirements -* "u8gs" by olikraus, v2.28 or higher: https://github.com/olikraus/u8g2 +* "u8g2" by olikraus, v2.28 or higher: https://github.com/olikraus/u8g2 * "SHT85" by Rob Tillaart, v0.2 or higher: https://github.com/RobTillaart/SHT85 ## Usermod installation diff --git a/usermods/sd_card/readme.md b/usermods/sd_card/readme.md index 299b68eb..96390c05 100644 --- a/usermods/sd_card/readme.md +++ b/usermods/sd_card/readme.md @@ -20,7 +20,7 @@ | `pinSourceSelect` | GPIO that is connected to SD's `SS`(source select) / `CS`(chip select) | 16 | | `pinSourceClock` | GPIO that is connected to SD's `SCLK` (source clock) / `CLK`(clock) | 14 | | `pinPoci` | GPIO that is connected to SD's `POCI` (Peripheral-Out-Ctrl-In) / `MISO` (deprecated) | 36 | - | `pinPico` | GPIO that is connected to SD's `PICO` (Peripheral-In-Ctrl-Out) / `MOSI` (deprecated) | 14 | + | `pinPico` | GPIO that is connected to SD's `PICO` (Peripheral-In-Ctrl-Out) / `MOSI` (deprecated) | 15 | | `sdEnable` | Enable to read data from the SD-card | true | Following new naming convention of [OSHWA](https://www.oshwa.org/a-resolution-to-redefine-spi-signal-names/) @@ -31,4 +31,4 @@ - checks if the specified file is available on the SD card ```cpp bool file_onSD(const char *filepath) {...} - ``` \ No newline at end of file + ``` diff --git a/usermods/seven_segment_display/readme.md b/usermods/seven_segment_display/readme.md index a5294701..792393a8 100644 --- a/usermods/seven_segment_display/readme.md +++ b/usermods/seven_segment_display/readme.md @@ -17,7 +17,7 @@ The number of individual LEDs per segment. 7 segments per digit. #### perPeriod -- ssLEDPerPeriod The number of individual LEDs per period. A ':' (colon) has two periods. #### startIdx -- ssStartLED -Index of the LED the display starts at. Enabless a seven segment display to be in the middle of a string. +Index of the LED the display starts at. Enables a seven segment display to be in the middle of a string. #### timeEnable -- ssTimeEnabled When true, when displayMask is configured for a time output and no message is set, the time will be displayed. #### scrollSpd -- ssScrollSpeed diff --git a/usermods/seven_segment_display/usermod_v2_seven_segment_display.h b/usermods/seven_segment_display/usermod_v2_seven_segment_display.h index e5b726e5..20fef15d 100644 --- a/usermods/seven_segment_display/usermod_v2_seven_segment_display.h +++ b/usermods/seven_segment_display/usermod_v2_seven_segment_display.h @@ -409,7 +409,7 @@ public: if (mqttGroupTopic[0] != 0) { - //subcribe for sevenseg messages on the group topic + //subscribe for sevenseg messages on the group topic sprintf_P(subBuffer, PSTR("%s/%S/+/set"), mqttGroupTopic, _str_sevenSeg); mqtt->subscribe(subBuffer, 2); } @@ -417,7 +417,7 @@ public: bool onMqttMessage(char *topic, char *payload) { - //If topic beings iwth sevenSeg cut it off, otherwise not our message. + //If topic beings with sevenSeg cut it off, otherwise not our message. size_t topicPrefixLen = strlen_P(PSTR("/sevenSeg/")); if (strncmp_P(topic, PSTR("/sevenSeg/"), topicPrefixLen) == 0) topic += topicPrefixLen; diff --git a/usermods/seven_segment_display_reloaded/usermod_seven_segment_reloaded.h b/usermods/seven_segment_display_reloaded/usermod_seven_segment_reloaded.h index 27977405..3afe775f 100644 --- a/usermods/seven_segment_display_reloaded/usermod_seven_segment_reloaded.h +++ b/usermods/seven_segment_display_reloaded/usermod_seven_segment_reloaded.h @@ -470,14 +470,14 @@ public: if (mqttGroupTopic[0] != 0) { - //subcribe for sevenseg messages on the group topic + //subscribe for sevenseg messages on the group topic sprintf_P(subBuffer, PSTR("%s/%S/+/set"), mqttGroupTopic, _str_name); mqtt->subscribe(subBuffer, 2); } } bool onMqttMessage(char *topic, char *payload) { - //If topic beings iwth sevenSeg cut it off, otherwise not our message. + //If topic begins with sevenSeg cut it off, otherwise not our message. size_t topicPrefixLen = strlen_P(PSTR("/wledSS/")); if (strncmp_P(topic, PSTR("/wledSS/"), topicPrefixLen) == 0) { topic += topicPrefixLen; diff --git a/usermods/sht/usermod_sht.h b/usermods/sht/usermod_sht.h index bf99afd2..7583a823 100644 --- a/usermods/sht/usermod_sht.h +++ b/usermods/sht/usermod_sht.h @@ -331,7 +331,7 @@ void ShtUsermod::loop() /** * Whenever MQTT is connected, publish HA autodiscovery topics. * - * Is only donce once. + * Is only done once. * * @see Usermod::onMqttConnect() * @see UsermodManager::onMqttConnect() diff --git a/usermods/usermod_rotary_brightness_color/usermod_rotary_brightness_color.h b/usermods/usermod_rotary_brightness_color/usermod_rotary_brightness_color.h index 61b76ba1..85a9a160 100644 --- a/usermods/usermod_rotary_brightness_color/usermod_rotary_brightness_color.h +++ b/usermods/usermod_rotary_brightness_color/usermod_rotary_brightness_color.h @@ -23,7 +23,7 @@ private: unsigned char Enc_B; unsigned char Enc_A_prev = 0; - // private class memebers configurable by Usermod Settings (defaults set inside readFromConfig()) + // private class members configurable by Usermod Settings (defaults set inside readFromConfig()) int8_t pins[3]; // pins[0] = DT from encoder, pins[1] = CLK from encoder, pins[2] = CLK from encoder (optional) int fadeAmount; // how many points to fade the Neopixel with each step @@ -162,7 +162,7 @@ public: * - configComplete is used to return false if any value is missing, not just if the main object is missing * - The defaults are loaded every time readFromConfig() is run, not just once after boot * - * This ensures that missing values are added to the config, with their default values, in the rare but plauible cases of: + * This ensures that missing values are added to the config, with their default values, in the rare but plausible cases of: * - a single value being missing at boot, e.g. if the Usermod was upgraded and a new setting was added * - a single value being missing after boot (e.g. if the cfg.json was manually edited and a value was removed) * diff --git a/usermods/usermod_v2_auto_save/usermod_v2_auto_save.h b/usermods/usermod_v2_auto_save/usermod_v2_auto_save.h index 4acd6b15..1dd0a69a 100644 --- a/usermods/usermod_v2_auto_save/usermod_v2_auto_save.h +++ b/usermods/usermod_v2_auto_save/usermod_v2_auto_save.h @@ -109,7 +109,7 @@ class AutoSaveUsermod : public Usermod { // network here void setup() { #ifdef USERMOD_FOUR_LINE_DISPLAY - // This Usermod has enhanced funcionality if + // This Usermod has enhanced functionality if // FourLineDisplayUsermod is available. display = (FourLineDisplayUsermod*) usermods.lookup(USERMOD_ID_FOUR_LINE_DISP); #endif @@ -156,7 +156,7 @@ class AutoSaveUsermod : public Usermod { if (autoSaveAfter && now > autoSaveAfter) { autoSaveAfter = 0; - // Time to auto save. You may have some flickry? + // Time to auto save. You may have some flickery? saveSettings(); displayOverlay(); } diff --git a/usermods/usermod_v2_four_line_display/readme.md b/usermods/usermod_v2_four_line_display/readme.md index 26250cb5..a0ed44d7 100644 --- a/usermods/usermod_v2_four_line_display/readme.md +++ b/usermods/usermod_v2_four_line_display/readme.md @@ -23,7 +23,7 @@ This file should be placed in the same directory as `platformio.ini`. * `FLD_PIN_SCL` - The display SCL pin, defaults to 5 * `FLD_PIN_SDA` - The display SDA pin, defaults to 4 -All of the parameters can be configured via the Usermods settings page, inluding GPIO pins. +All of the parameters can be configured via the Usermods settings page, including GPIO pins. ### PlatformIO requirements diff --git a/usermods/usermod_v2_four_line_display/usermod_v2_four_line_display.h b/usermods/usermod_v2_four_line_display/usermod_v2_four_line_display.h index 7f052648..4f0c9c57 100644 --- a/usermods/usermod_v2_four_line_display/usermod_v2_four_line_display.h +++ b/usermods/usermod_v2_four_line_display/usermod_v2_four_line_display.h @@ -11,7 +11,7 @@ // for WLED. // // Dependencies -// * This usermod REQURES the ModeSortUsermod +// * This usermod REQUIRES the ModeSortUsermod // * This Usermod works best, by far, when coupled // with RotaryEncoderUIUsermod. // @@ -398,7 +398,7 @@ class FourLineDisplayUsermod : public Usermod { drawString(getCols() - 1, 0, "~"); } - // Second row with IP or Psssword + // Second row with IP or Password drawGlyph(0, lineHeight, 68, u8x8_font_open_iconic_embedded_1x1); // wifi icon // Print password in AP mode and if led is OFF. if (apActive && bri == 0) { diff --git a/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h b/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h index fc037a49..cc6d7b29 100644 --- a/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h +++ b/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h @@ -11,7 +11,7 @@ #include "4LD_wled_fonts.c" #ifndef FLD_ESP32_NO_THREADS -#define FLD_ESP32_USE_THREADS // comment out to use 0.13.x behaviour without parallel update task - slower, but more robust. May delay other tasks like LEDs or audioreactive!! + #define FLD_ESP32_USE_THREADS // comment out to use 0.13.x behaviour without parallel update task - slower, but more robust. May delay other tasks like LEDs or audioreactive!! #endif //#define OLD_4LD_FONTS // comment out if you prefer the "classic" look with blocky fonts (saves 1K flash) @@ -671,7 +671,7 @@ void FourLineDisplayUsermod::setup() { } // start SPI now! #ifdef ARDUINO_ARCH_ESP32 - if (isHW) SPI.begin(spi_sclk, spi_miso, spi_mosi); // ESP32 - will silently fail if SPI alread active. + if (isHW) SPI.begin(spi_sclk, spi_miso, spi_mosi); // ESP32 - will silently fail if SPI already active. #else if (isHW) SPI.begin(); // ESP8266 - SPI pins are fixed #endif @@ -1339,7 +1339,7 @@ void FourLineDisplayUsermod::sleepOrClock(bool sleepEnable) { bool FourLineDisplayUsermod::handleButton(uint8_t b) { yield(); if (!enabled - || b // butto 0 only + || b // button 0 only || buttonType[b] == BTN_TYPE_SWITCH || buttonType[b] == BTN_TYPE_NONE || buttonType[b] == BTN_TYPE_RESERVED diff --git a/usermods/usermod_v2_klipper_percentage/readme.md b/usermods/usermod_v2_klipper_percentage/readme.md index 0619bf85..e967d6b2 100644 --- a/usermods/usermod_v2_klipper_percentage/readme.md +++ b/usermods/usermod_v2_klipper_percentage/readme.md @@ -10,7 +10,7 @@ curl --location --request GET 'http://[]/printer/objects/query?virtual_sdcard=pr ## Usage Compile the source with the buildflag `-D USERMOD_KLIPPER_PERCENTAGE` added. -You can also use the WLBD bot in the Discord by simply extending an exsisting build enviroment: +You can also use the WLBD bot in the Discord by simply extending an existing build environment: ``` [env:esp32klipper] extends = env:esp32dev @@ -23,7 +23,7 @@ build_flags = ${common.build_flags_esp32} -D USERMOD_KLIPPER_PERCENTAGE Checkbox to enable or disable the overlay ### Klipper IP: -IP adress of your Klipper instance you want to poll. ESP has to be restarted after change +IP address of your Klipper instance you want to poll. ESP has to be restarted after change ### Direction : 0 = normal diff --git a/usermods/usermod_v2_klipper_percentage/usermod_v2_klipper_percentage.h b/usermods/usermod_v2_klipper_percentage/usermod_v2_klipper_percentage.h index 0e19cc80..2f591b15 100644 --- a/usermods/usermod_v2_klipper_percentage/usermod_v2_klipper_percentage.h +++ b/usermods/usermod_v2_klipper_percentage/usermod_v2_klipper_percentage.h @@ -79,7 +79,7 @@ public: httpGet(wifiClient, errorMessage); if (strcmp(errorMessage, "") == 0) { - PSRAMDynamicJsonDocument klipperDoc(4096); // in practive about 2673 + PSRAMDynamicJsonDocument klipperDoc(4096); // in practice about 2673 DeserializationError error = deserializeJson(klipperDoc, wifiClient); if (error) { diff --git a/usermods/usermod_v2_mode_sort/usermod_v2_mode_sort.h b/usermods/usermod_v2_mode_sort/usermod_v2_mode_sort.h index 092206bb..5ce044dd 100644 --- a/usermods/usermod_v2_mode_sort/usermod_v2_mode_sort.h +++ b/usermods/usermod_v2_mode_sort/usermod_v2_mode_sort.h @@ -59,7 +59,7 @@ int re_qstringCmp(const void *ap, const void *bp) { // Lowercase bVal -= 32; } - // Relly we shouldn't ever get to '\0' + // Really we shouldn't ever get to '\0' if (aVal == '"' || bVal == '"' || aVal == '\0' || bVal == '\0') { // We're done. one is a substring of the other // or something happenend and the quote didn't stop us. diff --git a/usermods/usermod_v2_ping_pong_clock/readme.md b/usermods/usermod_v2_ping_pong_clock/readme.md index 9f01b3eb..f8219489 100644 --- a/usermods/usermod_v2_ping_pong_clock/readme.md +++ b/usermods/usermod_v2_ping_pong_clock/readme.md @@ -7,4 +7,4 @@ Contains a modification to use WLED in combination with the Ping Pong Ball LED C To install this Usermod, you instruct PlatformIO to compile the Project with the USERMOD_PING_PONG_CLOCK flag. WLED then automatically provides you with various settings on the Usermod Page. -Note: Depending on the size of your clock, you may have to update the led indices for the indivdual numbers and the base indices. +Note: Depending on the size of your clock, you may have to update the led indices for the individual numbers and the base indices. diff --git a/usermods/usermod_v2_ping_pong_clock/usermod_v2_ping_pong_clock.h b/usermods/usermod_v2_ping_pong_clock/usermod_v2_ping_pong_clock.h index a690c1b1..40ff675c 100644 --- a/usermods/usermod_v2_ping_pong_clock/usermod_v2_ping_pong_clock.h +++ b/usermods/usermod_v2_ping_pong_clock/usermod_v2_ping_pong_clock.h @@ -18,15 +18,15 @@ private: // ---- Variables for correct LED numbering below, edit only if your clock is built different ---- - int baseH = 43; // Adress for the one place of the hours - int baseHH = 7; // Adress for the tens place of the hours - int baseM = 133; // Adress for the one place of the minutes - int baseMM = 97; // Adress for the tens place of the minutes - int colon1 = 79; // Adress for the first colon led - int colon2 = 80; // Adress for the second colon led + int baseH = 43; // Address for the one place of the hours + int baseHH = 7; // Address for the tens place of the hours + int baseM = 133; // Address for the one place of the minutes + int baseMM = 97; // Address for the tens place of the minutes + int colon1 = 79; // Address for the first colon led + int colon2 = 80; // Address for the second colon led // Matrix for the illumination of the numbers - // Note: These only define the increments of the base adress. e.g. to define the second Minute you have to add the baseMM to every led position + // Note: These only define the increments of the base address. e.g. to define the second Minute you have to add the baseMM to every led position const int numbers[10][10] = { { 0, 1, 4, 6, 13, 15, 18, 19, -1, -1 }, // 0: null diff --git a/usermods/usermod_v2_rotary_encoder_ui/usermod_v2_rotary_encoder_ui.h b/usermods/usermod_v2_rotary_encoder_ui/usermod_v2_rotary_encoder_ui.h index 1e85c518..f9f5700e 100644 --- a/usermods/usermod_v2_rotary_encoder_ui/usermod_v2_rotary_encoder_ui.h +++ b/usermods/usermod_v2_rotary_encoder_ui/usermod_v2_rotary_encoder_ui.h @@ -20,7 +20,7 @@ // Change between modes by pressing a button. // // Dependencies -// * This usermod REQURES the ModeSortUsermod +// * This usermod REQUIRES the ModeSortUsermod // * This Usermod works best coupled with // FourLineDisplayUsermod. // @@ -113,7 +113,7 @@ public: // tracking the owner tags.... pinA = pinB = pinC = -1; enabled = false; - DEBUG_PRINTLN(F("Failed to alocate GPIO pins for Usermod Rotary Encoder.")); //WLEDMM add debug info + DEBUG_PRINTLN(F("Failed to allocate GPIO pins for Usermod Rotary Encoder.")); //WLEDMM add debug info return; } diff --git a/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h b/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h index 17943bab..4b0e00a2 100644 --- a/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h +++ b/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h @@ -4,7 +4,7 @@ // // Inspired by the original v2 usermods -// * usermod_v2_rotaty_encoder_ui +// * usermod_v2_rotary_encoder_ui // // v2 usermod that provides a rotary encoder-based UI. // @@ -79,7 +79,7 @@ static int re_qstringCmp(const void *ap, const void *bp) { // Lowercase bVal -= 32; } - // Relly we shouldn't ever get to '\0' + // Really we shouldn't ever get to '\0' if (aVal == '"' || bVal == '"' || aVal == '\0' || bVal == '\0') { // We're done. one is a substring of the other // or something happenend and the quote didn't stop us. @@ -436,7 +436,7 @@ void RotaryEncoderUIUsermod::setup() // tracking the owner tags.... pinA = pinB = pinC = -1; enabled = false; - DEBUG_PRINTLN(F("Failed to alocate GPIO pins for Usermod Rotary Encoder (ALT).")); //WLEDMM add debug info + DEBUG_PRINTLN(F("Failed to allocate GPIO pins for Usermod Rotary Encoder (ALT).")); //WLEDMM add debug info return; } @@ -542,7 +542,7 @@ void RotaryEncoderUIUsermod::loop() bool changedState = false; char lineBuffer[64] = { '\0' }; do { - // finde new state + // find new state switch (newState) { case 0: strcpy_P(lineBuffer, PSTR("Brightness")); changedState = true; break; case 1: if (!extractModeSlider(effectCurrent, 0, lineBuffer, 63)) newState++; else changedState = true; break; // speed diff --git a/usermods/usermod_v2_weather/usermod_v2_weather.h b/usermods/usermod_v2_weather/usermod_v2_weather.h index 95e02379..10f7b03c 100644 --- a/usermods/usermod_v2_weather/usermod_v2_weather.h +++ b/usermods/usermod_v2_weather/usermod_v2_weather.h @@ -7,7 +7,7 @@ // #define WEATHER_DEBUG -//declare weathermod global variables (always precede with weather_ (psuedo class static variables) +//declare weathermod global variables (always precede with weather_ (pseudo class static variables) static uint32_t usermods_pushLoop = 0; //effect pushes loop to execute. might be interesting for audioreactive too static uint8_t weather_units = 1; //config var metric (celsius) is default. (Standard=Kelvin, Imperial is Fahrenheit) static float weather_minTemp = 0; //config var @@ -159,7 +159,7 @@ class WeatherUsermod : public Usermod { } void loop() { - // return if no location or no api key (reset lastTume to force loop) + // return if no location or no api key (reset lastTime to force loop) if (fabs(latitude) < 0.00001 && fabs(latitude) < 0.00001) {strcpy(errorMessage, PSTR("No location")); lastTime = 0; return;} if (strcmp(apiKey.c_str(), "") == 0) {strcpy(errorMessage, PSTR("No api key")); lastTime = 0; return;} @@ -181,12 +181,12 @@ class WeatherUsermod : public Usermod { if (strcmp(errorMessage, "") == 0) { // https://arduinojson.org/v6/how-to/deserialize-a-very-large-document/ - StaticJsonDocument<256> filter; //in practive about 128 + StaticJsonDocument<256> filter; //in practice about 128 filter["list"][0]["dt"] = true; filter["list"][0]["main"]["temp"] = true; filter["city"]["name"] = true; filter["city"]["country"] = true; - PSRAMDynamicJsonDocument weatherDoc(4096); //in practive about 2673 + PSRAMDynamicJsonDocument weatherDoc(4096); //in practice about 2673 // Parse JSON object DeserializationError error = deserializeJson(weatherDoc, client, DeserializationOption::Filter(filter)); @@ -206,7 +206,7 @@ class WeatherUsermod : public Usermod { JsonObject weatherDocObject = weatherDoc.as(); JsonArray list = weatherDocObject[F("list")]; JsonObject city = weatherDocObject["city"]; - strcat(errorMessage, city["name"]); //api succesfull + strcat(errorMessage, city["name"]); //api successful strcat(errorMessage, city["country"]); uint8_t i = 0; @@ -319,10 +319,10 @@ class WeatherUsermod : public Usermod { oappend(SET_F("dd=addDropdown('Weather','units');")); oappend(SET_F("addOption(dd,'Kelvin',0);")); - oappend(SET_F("addOption(dd,'Celcius',1);")); + oappend(SET_F("addOption(dd,'Celsius',1);")); oappend(SET_F("addOption(dd,'Fahrenheit',2);")); oappend(SET_F("addInfo('Weather:units',1,'Set time and location in time settings');")); - oappend(SET_F("addInfo('Weather:apiKey',1,'Create acount on openweathermap.org and copy the key');")); + oappend(SET_F("addInfo('Weather:apiKey',1,'Create account on openweathermap.org and copy the key');")); oappend(SET_F("addInfo('Weather:minTemp',1,'Changing values: Reboot to (re)load forecast');")); } diff --git a/usermods/usermod_v2_word_clock/readme.md b/usermods/usermod_v2_word_clock/readme.md index 1dde2223..c42ee0ee 100644 --- a/usermods/usermod_v2_word_clock/readme.md +++ b/usermods/usermod_v2_word_clock/readme.md @@ -8,7 +8,7 @@ active: enable/disable usermod diplayItIs: enable/disable display of "Es ist" on the clock ledOffset: number of LEDs before the wordclock LEDs -### Update for alternatative wiring pattern +### Update for alternative wiring pattern Based on this fantastic work I added an alternative wiring pattern. The original used a long wire to connect DO to DI, from one line to the next line. diff --git a/usermods/usermod_v2_word_clock/usermod_v2_word_clock.h b/usermods/usermod_v2_word_clock/usermod_v2_word_clock.h index 058b8318..b66be290 100644 --- a/usermods/usermod_v2_word_clock/usermod_v2_word_clock.h +++ b/usermods/usermod_v2_word_clock/usermod_v2_word_clock.h @@ -7,8 +7,8 @@ * See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality * * This usermod can be used to drive a wordclock with a 11x10 pixel matrix with WLED. There are also 4 additional dots for the minutes. - * The visualisation is desribed in 4 mask with LED numbers (single dots for minutes, minutes, hours and "clock/Uhr"). - * There are 2 parameters to chnage the behaviour: + * The visualisation is described in 4 mask with LED numbers (single dots for minutes, minutes, hours and "clock/Uhr"). + * There are 2 parameters to change the behaviour: * * active: enable/disable usermod * diplayItIs: enable/disable display of "Es ist" on the clock. diff --git a/usermods/wizlights/readme.md b/usermods/wizlights/readme.md index a0e0a8b8..9e633043 100644 --- a/usermods/wizlights/readme.md +++ b/usermods/wizlights/readme.md @@ -1,6 +1,6 @@ # Controlling Wiz lights -Enabless controlling [WiZ](https://www.wizconnected.com/en/consumer/) lights that are part of the same network as the WLED controller. +Enables controlling [WiZ](https://www.wizconnected.com/en/consumer/) lights that are part of the same network as the WLED controller. The mod takes the colors from the first few pixels and sends them to the lights. @@ -8,7 +8,7 @@ The mod takes the colors from the first few pixels and sends them to the lights. - Interval (ms) - How frequently to update the WiZ lights, in milliseconds. - - Setting it too low may causse the ESP to become unresponsive. + - Setting it too low may cause the ESP to become unresponsive. - Send Delay (ms) - An optional millisecond delay after updating each WiZ light. - Can help smooth out effects when using a large number of WiZ lights diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 74a705b4..af613916 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -48,10 +48,10 @@ static uint16_t triwave16(uint16_t in) { } /* - * Generates a tristate square wave w/ attac & decay + * Generates a tristate square wave w/ attack & decay * @param x input value 0-255 * @param pulsewidth 0-127 - * @param attdec attac & decay, max. pulsewidth / 2 + * @param attdec attack & decay, max. pulsewidth / 2 * @returns signed waveform value */ static int8_t tristate_square8(uint8_t x, uint8_t pulsewidth, uint8_t attdec) { @@ -73,6 +73,12 @@ static int8_t tristate_square8(uint8_t x, uint8_t pulsewidth, uint8_t attdec) { return 0; } +// float version of map() // WLEDMM moved here so its available for all effects +static float mapf(float x, float in_min, float in_max, float out_min, float out_max){ + if (in_max == in_min) return (out_min); // WLEDMM avoid div/0 + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; +} + // effect functions /* @@ -80,7 +86,7 @@ static int8_t tristate_square8(uint8_t x, uint8_t pulsewidth, uint8_t attdec) { */ uint16_t mode_static(void) { SEGMENT.fill(SEGCOLOR(0)); - return 350; + return strip.isOffRefreshRequired() ? FRAMETIME : FRAMETIME_FIXED_SLOW; // WLEDMM to ensure smooth color changes from DMX (PR #73) } static const char _data_FX_MODE_STATIC[] PROGMEM = "Solid"; @@ -1205,7 +1211,7 @@ static const char _data_FX_MODE_COMET[] PROGMEM = "Lighthouse@!,Fade rate;!,!;!" /* * Fireworks function. */ -uint16_t mode_fireworks() { +static uint16_t mode_fireworks_core(bool useaudio) { if (SEGLEN == 1) return mode_static(); const uint16_t width = SEGMENT.is2D() ? SEGMENT.virtualWidth() : SEGMENT.virtualLength(); const uint16_t height = SEGMENT.virtualHeight(); @@ -1221,27 +1227,60 @@ uint16_t mode_fireworks() { bool valid1 = (SEGENV.aux0 < width*height); bool valid2 = (SEGENV.aux1 < width*height); uint32_t sv1 = 0, sv2 = 0; + + // WLEDMM begin + um_data_t *um_data; + if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { + useaudio = false; // no audio - fallback to standard behaviour (don't use soundSim) + } + bool addPixels = true; // false -> inhibit new pixels in silence + unsigned myIntensity = 129 - (SEGMENT.intensity >> 1); // make parameter explicit, so we can work with it + int soundColor = -1; // -1 = random color; 0..255 = use as palette index + + if (useaudio) { + float volumeSmth = *(float*) um_data->u_data[0]; + float FFT_MajorPeak = *(float*) um_data->u_data[4]; + uint8_t samplePeak = *(uint8_t*)um_data->u_data[3]; + if ((volumeSmth > 1.0f) && (FFT_MajorPeak > 60.0f)) { // we have sound - select color based on major frequency + float musicIndex = logf(FFT_MajorPeak); // log scaling of peak freq + soundColor = mapf(musicIndex, 4.6f, 9.06f, 0, 255); // pick color from frequency (4.6 = ln(100), 9.06 = ln(8600)) + soundColor = constrain(soundColor, 0, 255); // remove over-shoot + if (samplePeak > 0) myIntensity -= myIntensity / 2; // increase effect intensity at peaks + else if (volumeSmth > 96.0f) myIntensity -= myIntensity / 4; // increase effect intensity slightly when music plays + myIntensity = constrain(myIntensity, 0, 129); + } else { // silence -> fade away + valid1 = valid2 = false; // do not copy last pixels + addPixels = false; // don't add new pixels + } + } + // WLEDMM end + if (valid1) sv1 = SEGMENT.is2D() ? SEGMENT.getPixelColorXY(SEGENV.aux0%width, SEGENV.aux0/width) : SEGMENT.getPixelColor(SEGENV.aux0); // get spark color if (valid2) sv2 = SEGMENT.is2D() ? SEGMENT.getPixelColorXY(SEGENV.aux1%width, SEGENV.aux1/width) : SEGMENT.getPixelColor(SEGENV.aux1); if (!SEGENV.step) SEGMENT.blur(16); if (valid1) { if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(SEGENV.aux0%width, SEGENV.aux0/width, sv1); else SEGMENT.setPixelColor(SEGENV.aux0, sv1); } // restore spark color after blur if (valid2) { if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(SEGENV.aux1%width, SEGENV.aux1/width, sv2); else SEGMENT.setPixelColor(SEGENV.aux1, sv2); } // restore old spark color after blur + if (addPixels) // WLEDMM for (int i=0; i> 1)) == 0) { + if (random8(myIntensity) == 0) { // WLEDMM uint16_t index = random16(width*height); uint16_t j = index % width, k = index / width; - uint32_t col = SEGMENT.color_from_palette(random8(), false, false, 0); + uint32_t col = SEGMENT.color_from_palette((soundColor > 0) ? soundColor + random8(24) : random8(), false, false, 0); // WLEDMM if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(j, k, col); else SEGMENT.setPixelColor(index, col); SEGENV.aux1 = SEGENV.aux0; // old spark - SEGENV.aux0 = index; // remember where spark occured + SEGENV.aux0 = index; // remember where spark occurred } } return FRAMETIME; } + +uint16_t mode_fireworks(void) { return mode_fireworks_core(false); } static const char _data_FX_MODE_FIREWORKS[] PROGMEM = "Fireworks@,Frequency;!,!;!;12;ix=192,pal=11"; +uint16_t mode_fireworks_audio(void) { return mode_fireworks_core(true); } +static const char _data_FX_MODE_FIREWORKS_AR[] PROGMEM = "Fireworks audio ☾@,Frequency;!,!;!;1v,12;ix=192,pal=11"; //Twinkling LEDs running. Inspired by https://github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/Rain.h uint16_t mode_rain() { @@ -1272,8 +1311,8 @@ uint16_t mode_rain() { SEGENV.aux0++; // increase spark index SEGENV.aux1++; } - if (SEGENV.aux0 == 0) SEGENV.aux0 = UINT16_MAX; // reset previous spark positiom - if (SEGENV.aux1 == 0) SEGENV.aux0 = UINT16_MAX; // reset previous spark positiom + if (SEGENV.aux0 == 0) SEGENV.aux0 = UINT16_MAX; // reset previous spark position + if (SEGENV.aux1 == 0) SEGENV.aux0 = UINT16_MAX; // reset previous spark position if (SEGENV.aux0 >= width*height) SEGENV.aux0 = 0; // ignore if (SEGENV.aux1 >= width*height) SEGENV.aux1 = 0; } @@ -1716,7 +1755,7 @@ uint16_t mode_multi_comet(void) { } comets[i]++; } else { - if(!random(SEGLEN)) { + if(!random16(SEGLEN)) { comets[i] = 0; } } @@ -1850,10 +1889,10 @@ uint16_t mode_lightning(void) { } SEGENV.aux1--; - SEGENV.step = millis(); + SEGENV.step = strip.now; //return random8(4, 10); // each flash only lasts one frame/every 24ms... originally 4-10 milliseconds } else { - if (millis() - SEGENV.step > SEGENV.aux0) { + if (strip.now - SEGENV.step > SEGENV.aux0) { SEGENV.aux1--; if (SEGENV.aux1 < 2) SEGENV.aux1 = 0; @@ -1861,7 +1900,7 @@ uint16_t mode_lightning(void) { if (SEGENV.aux1 == 2) { SEGENV.aux0 = (random8(255 - SEGMENT.speed) * 100); // delay between strikes } - SEGENV.step = millis(); + SEGENV.step = strip.now; } } return FRAMETIME; @@ -1916,6 +1955,71 @@ uint16_t mode_pride_2015(void) { static const char _data_FX_MODE_PRIDE_2015[] PROGMEM = "Pride 2015@!;;"; +////////////////////// +// PARTYJERK // +////////////////////// +// by @tonyxforce +// NB: This effects expects a palette that starts with black and then ramps up brightness. +// Currently works best with the "color gradient" and the "colors 1&2" palettes +uint16_t mode_partyjerk() { + if (SEGENV.call == 0) { + SEGMENT.fill(BLACK); // clear LEDs + SEGENV.aux0 = 0; + SEGENV.aux1 = 0; + SEGENV.step = 0; + } + /* + * use of persistent variables: + * aux0: hueDelay + * aux1: hue + * step: pos + */ + + um_data_t *um_data; + if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { + // add support for no audio + um_data = simulateSound(SEGMENT.soundSim); + } + float volumeSmth = *(float*) um_data->u_data[0]; + + SEGENV.aux0++; + if (SEGENV.aux1 > 254) { + SEGENV.aux1 = 0; + } + if (SEGENV.aux0 > map(SEGMENT.custom1, 0, 255, 0, 14)) { + SEGENV.aux0 = 0; + SEGENV.aux1++; + } + + uint_fast32_t speed = 0; + uint16_t counter = 0; + + if (volumeSmth * 2 > (255 - SEGMENT.intensity)) { + speed = SEGMENT.speed * map(SEGMENT.custom2, 0, 255, 0, 100); + } else { + speed = SEGMENT.speed; + }; + + SEGENV.step += speed; + counter = SEGENV.step >> 8; + + for (unsigned i = 0; i < SEGLEN; i++) { + uint8_t colorIndex = ((i * 255) / SEGLEN) - counter; + uint32_t paletteColor = SEGMENT.color_from_palette(colorIndex, false, PALETTE_MOVING_WRAP, 255); + uint8_t r = R(paletteColor); + uint8_t g = G(paletteColor); + uint8_t b = B(paletteColor); + uint8_t activeColor = max(r, max(g, b)); + + CRGB rgb(CHSV(SEGENV.aux1, 255, activeColor)); + SEGMENT.setPixelColor((uint16_t)i, rgb.r, rgb.g, rgb.b); + }; + + return FRAMETIME; +} // mode_partyjerk() +static const char _data_FX_MODE_PARTYJERK[] PROGMEM = "Party jerk@Effect speed,Sensitivity,Color change speed,Effect speed active multiplier;!,!;!;1v;c1=8,c2=48,m12=0,si=0"; + + //eight colored dots, weaving in and out of sync with each other uint16_t mode_juggle(void) { if (SEGLEN == 1) return mode_static(); @@ -2003,7 +2107,7 @@ uint16_t mode_fire_2012() { // Step 1. Cool down every cell a little for (int i = 0; i < SEGLEN; i++) { - uint8_t cool = (it != SEGENV.step) ? random8((((20 + SEGMENT.speed/3) * 16) / SEGLEN)+2) : random(4); + uint8_t cool = (it != SEGENV.step) ? random8((((20 + SEGMENT.speed/3) * 16) / SEGLEN)+2) : random8(4); uint8_t minTemp = (i> 2) +8); uint16_t in = counter * SEGLEN >> 16; + const int max = SEGMENT.palette==5 || !SEGMENT.check1 ? 240 : 255; // fade all leds to colors[1] in LEDs one step for (int i = 0; i < SEGLEN; i++) { - if (random8() <= 255 - SEGMENT.intensity) - { - byte meteorTrailDecay = 128 + random8(127); + if (random8() <= 255 - SEGMENT.intensity) { + byte meteorTrailDecay = 162 + random8(92); trail[i] = scale8(trail[i], meteorTrailDecay); - SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i, true, false, 0), trail[i])); + uint32_t col = SEGMENT.check1 ? SEGMENT.color_from_palette(i, true, false, 0, trail[i]) : SEGMENT.color_from_palette(trail[i], false, true, 255); + SEGMENT.setPixelColor(i, col); } } // draw meteor - for (int j = 0; j < meteorSize; j++) { + for (unsigned j = 0; j < meteorSize; j++) { uint16_t index = in + j; if (index >= SEGLEN) { index -= SEGLEN; } - trail[index] = 240; - SEGMENT.setPixelColor(index, SEGMENT.color_from_palette(index, true, false, 0)); + trail[index] = max; + uint32_t col = SEGMENT.check1 ? SEGMENT.color_from_palette(index, true, false, 0, trail[index]) : SEGMENT.color_from_palette(trail[index], false, true, 255); + SEGMENT.setPixelColor(index, col); } return FRAMETIME; } -static const char _data_FX_MODE_METEOR[] PROGMEM = "Meteor@!,Trail length;!,!;!;1"; +static const char _data_FX_MODE_METEOR[] PROGMEM = "Meteor@!,Trail,,,,Gradient;;!;1"; // smooth meteor effect @@ -2338,35 +2444,35 @@ uint16_t mode_meteor_smooth() { byte* trail = SEGENV.data; - byte meteorSize= 1+ SEGLEN / 10; + const unsigned meteorSize= 1+ SEGLEN / 20; // 5% uint16_t in = map((SEGENV.step >> 6 & 0xFF), 0, 255, 0, SEGLEN -1); + const int max = SEGMENT.palette==5 || !SEGMENT.check1 ? 240 : 255; // fade all leds to colors[1] in LEDs one step for (int i = 0; i < SEGLEN; i++) { - if (trail[i] != 0 && random8() <= 255 - SEGMENT.intensity) - { - int change = 3 - random8(12); //change each time between -8 and +3 - trail[i] += change; - if (trail[i] > 245) trail[i] = 0; - if (trail[i] > 240) trail[i] = 240; - SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i, true, false, 0), trail[i])); + if (/*trail[i] != 0 &&*/ random8() <= 255 - SEGMENT.intensity) { + int change = trail[i] + 4 - random8(24); //change each time between -20 and +4 + trail[i] = constrain(change, 0, max); + uint32_t col = SEGMENT.check1 ? SEGMENT.color_from_palette(i, true, false, 0, trail[i]) : SEGMENT.color_from_palette(trail[i], false, true, 255); + SEGMENT.setPixelColor(i, col); } } // draw meteor - for (int j = 0; j < meteorSize; j++) { + for (unsigned j = 0; j < meteorSize; j++) { uint16_t index = in + j; if (index >= SEGLEN) { index -= SEGLEN; } - trail[index] = 240; - SEGMENT.setPixelColor(index, SEGMENT.color_from_palette(index, true, false, 0)); + trail[index] = max; + uint32_t col = SEGMENT.check1 ? SEGMENT.color_from_palette(index, true, false, 0, trail[index]) : SEGMENT.color_from_palette(trail[index], false, true, 255); + SEGMENT.setPixelColor(index, col); } SEGENV.step += SEGMENT.speed +1; return FRAMETIME; } -static const char _data_FX_MODE_METEOR_SMOOTH[] PROGMEM = "Meteor Smooth@!,Trail length;!,!;!;1"; +static const char _data_FX_MODE_METEOR_SMOOTH[] PROGMEM = "Meteor Smooth@!,Trail,,,,Gradient;;!;1"; //Railway Crossing / Christmas Fairy lights @@ -2637,14 +2743,14 @@ uint16_t mode_twinklefox() { return twinklefox_base(false); } -static const char _data_FX_MODE_TWINKLEFOX[] PROGMEM = "Twinklefox@!,Twinkle rate;;!"; +static const char _data_FX_MODE_TWINKLEFOX[] PROGMEM = "Twinklefox@!,Twinkle rate;!,!;!"; uint16_t mode_twinklecat() { return twinklefox_base(true); } -static const char _data_FX_MODE_TWINKLECAT[] PROGMEM = "Twinklecat@!,Twinkle rate;;!"; +static const char _data_FX_MODE_TWINKLECAT[] PROGMEM = "Twinklecat@!,Twinkle rate;!,!;!"; //inspired by https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/#LEDStripEffectBlinkingHalloweenEyes @@ -2837,7 +2943,7 @@ uint16_t mode_bouncing_balls(void) { uint16_t numBalls = (SEGMENT.intensity * (maxNumBalls - 1)) / 255 + 1; // minimum 1 ball const float gravity = -9.81f; // standard value of gravity const bool hasCol2 = SEGCOLOR(2); - const unsigned long time = millis(); + const unsigned long time = strip.now; if (SEGENV.call == 0) { for (size_t i = 0; i < maxNumBalls; i++) balls[i].lastBounceTime = time; @@ -2943,7 +3049,7 @@ static uint16_t rolling_balls(void) { if (SEGMENT.check1) { for (int j = i+1; j < numBalls; j++) { if (balls[j].velocity != balls[i].velocity) { - // tcollided + balls[j].lastBounceUpdate is acutal time of collision (this keeps precision with long to float conversions) + // tcollided + balls[j].lastBounceUpdate is actual time of collision (this keeps precision with long to float conversions) float tcollided = (cfac*(balls[i].height - balls[j].height) + balls[i].velocity*float(balls[j].lastBounceUpdate - balls[i].lastBounceUpdate))/(balls[j].velocity - balls[i].velocity); @@ -3084,7 +3190,7 @@ typedef struct Spark { * POPCORN * modified from https://github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/Popcorn.h */ -uint16_t mode_popcorn(void) { +static uint16_t mode_popcorn_core(bool useaudio) { if (SEGLEN == 1) return mode_static(); //allocate segment data uint16_t strips = SEGMENT.nrOfVStrips(); @@ -3096,20 +3202,44 @@ uint16_t mode_popcorn(void) { bool hasCol2 = SEGCOLOR(2); if (!SEGMENT.check2) SEGMENT.fill(hasCol2 ? BLACK : SEGCOLOR(1)); + // WLEDMM init um_data + um_data_t *um_data; + if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { + // no audio - fallback to standard behaviour + useaudio = false; + um_data = simulateSound(SEGMENT.soundSim); // dummy + } + struct virtualStrip { - static void runStrip(uint16_t stripNr, Spark* popcorn) { + static void runStrip(uint16_t stripNr, Spark* popcorn, bool useaudio, um_data_t *um_data) { // WLEDMM added useaudio and um_data float gravity = -0.0001 - (SEGMENT.speed/200000.0); // m/s/s gravity *= SEGLEN; uint8_t numPopcorn = SEGMENT.intensity*maxNumPopcorn/255; if (numPopcorn == 0) numPopcorn = 1; + // WLEDMM audioreactive vars + float volumeSmth = *(float*) um_data->u_data[0]; + int16_t volumeRaw = *(int16_t*) um_data->u_data[1]; + uint8_t samplePeak = *(uint8_t*) um_data->u_data[3]; for(int i = 0; i < numPopcorn; i++) { if (popcorn[i].pos >= 0.0f) { // if kernel is active, update its position popcorn[i].pos += popcorn[i].vel; popcorn[i].vel += gravity; } else { // if kernel is inactive, randomly pop it - if (random8() < 2) { // POP!!! + bool doPopCorn = false; // WLEDMM allows to inhibit new pops + // WLEDMM begin + if (useaudio) { + if ( (volumeSmth > 1.0f) // no pops in silence + &&((samplePeak > 0) || (volumeRaw > 128)) // try to pop at onsets (our peek detector still sucks) + &&(random8() < 4) ) // stay somewhat random + doPopCorn = true; + } else { + if (random8() < 2) doPopCorn = true; // default POP!!! + } + // WLEDMM end + + if (doPopCorn) { // POP!!! popcorn[i].pos = 0.01f; uint16_t peakHeight = 128 + random8(128); //0-255 @@ -3137,12 +3267,16 @@ uint16_t mode_popcorn(void) { }; for (int stripNr=0; stripNr(SEGENV.data); @@ -3280,10 +3414,36 @@ uint16_t mode_starburst(void) { float particleIgnition = 250.0f; // How long to "flash" float particleFadeTime = 1500.0f; // Fade out time + // WLEDMM init um_data + um_data_t *um_data; + if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { + // no audio - fallback to standard behaviour + useaudio = false; + um_data = simulateSound(SEGMENT.soundSim); // dummy + } + float volumeSmth = *(float*) um_data->u_data[0]; + int16_t volumeRaw = *(int16_t*) um_data->u_data[1]; + uint8_t samplePeak = *(uint8_t*) um_data->u_data[3]; + for (int j = 0; j < numStars; j++) { // speed to adjust chance of a burst, max is nearly always. - if (random8((144-(SEGMENT.speed >> 1))) == 0 && stars[j].birth == 0) + bool doNewStar = random8((144-(SEGMENT.speed >> 1))) == 0; // WLEDMM original spawning trigger + // WLEDMM begin + if (useaudio) { + doNewStar = false; + int burstplus = (volumeSmth > 159)? 96:0; // high volume -> more stars + if (volumeRaw <= 56) burstplus = -64; // low volume -> fewer stars + int birthrate = (144-(SEGMENT.speed >> 1)) - burstplus; + birthrate = constrain(birthrate, 4, 144); + if ( (volumeSmth > 1.0f) // no bursts in silence + && ((samplePeak > 0) || (volumeRaw > 48)) // try to burst with sound + && (random8(birthrate) == 0) ) // original random rate + doNewStar = true; + } + // WLEDMM end + + if (doNewStar && stars[j].birth == 0) // WLEDMM { // Pick a random color and location. uint16_t startPos = (SEGLEN > 1) ? random16(SEGLEN-1) : 0; @@ -3291,7 +3451,7 @@ uint16_t mode_starburst(void) { stars[j].color = CRGB(SEGMENT.color_wheel(random8())); stars[j].pos = startPos; - stars[j].vel = maxSpeed * (float)(random8())/255.0 * multiplier; + stars[j].vel = maxSpeed * (float)(random8())/255.0f * multiplier; stars[j].birth = it; stars[j].last = it; // more fragments means larger burst effect @@ -3369,8 +3529,12 @@ uint16_t mode_starburst(void) { return FRAMETIME; } #undef STARBURST_MAX_FRAG + +uint16_t mode_starburst(void) { return mode_starburst_core(false); } static const char _data_FX_MODE_STARBURST[] PROGMEM = "Fireworks Starburst@Chance,Fragments,,,,,Overlay;,!;!;;pal=11,m12=0"; +uint16_t mode_starburst_audio(void) { return mode_starburst_core(true); } +static const char _data_FX_MODE_STARBURST_AR[] PROGMEM = "Fw Starburst audio ☾@Chance,Fragments,,,,,Overlay;,!;!;1v;pal=11,m12=0"; /* * Exploding fireworks effect @@ -3629,12 +3793,12 @@ uint16_t mode_tetrix(void) { // initialize dropping on first call or segment full if (SEGENV.call == 0) { drop->stack = 0; // reset brick stack size - drop->step = millis() + 2000; // start by fading out strip + drop->step = strip.now + 2000; // start by fading out strip if (SEGMENT.check1) drop->col = 0;// use only one color from palette } if (drop->step == 0) { // init brick - // speed calcualtion: a single brick should reach bottom of strip in X seconds + // speed calculation: a single brick should reach bottom of strip in X seconds // if the speed is set to 1 this should take 5s and at 255 it should take 0.25s // as this is dependant on SEGLEN it should be taken into account and the fact that effect runs every FRAMETIME s int speed = SEGMENT.speed ? SEGMENT.speed : random8(1,255); @@ -3663,13 +3827,13 @@ uint16_t mode_tetrix(void) { } else { // we hit bottom drop->step = 0; // proceed with next brick, go back to init drop->stack += drop->brick; // increase the stack size - if (drop->stack >= SEGLEN) drop->step = millis() + 2000; // fade out stack + if (drop->stack >= SEGLEN) drop->step = strip.now + 2000; // fade out stack } } if (drop->step > 2) { // fade strip drop->brick = 0; // reset brick size (no more growing) - if (drop->step > millis()) { + if (drop->step > strip.now) { // allow fading of virtual strip for (int i = 0; i < SEGLEN; i++) SEGMENT.blendPixelColor(indexToVStrip(i, stripNr), SEGCOLOR(1), 25); // 10% blend } else { @@ -3717,7 +3881,7 @@ static const char _data_FX_MODE_PLASMA[] PROGMEM = "Plasma@Phase,!;!;!"; /* * Percentage display - * Intesity values from 0-100 turn on the leds. + * Intensity values from 0-100 turn on the leds. */ uint16_t mode_percent(void) { @@ -3770,7 +3934,7 @@ static const char _data_FX_MODE_PERCENT[] PROGMEM = "Percent@,% of fill,,,,One c /* * Modulates the brightness similar to a heartbeat - * (unimplemented?) tries to draw an ECG aproximation on a 2D matrix + * (unimplemented?) tries to draw an ECG approximation on a 2D matrix */ uint16_t mode_heartbeat(void) { uint8_t bpm = 40 + (SEGMENT.speed >> 3); @@ -3928,14 +4092,14 @@ uint16_t mode_sunrise() { //speed 60 - 120 : sunset time in minutes - 60; //speed above: "breathing" rise and set if (SEGENV.call == 0 || SEGMENT.speed != SEGENV.aux0) { - SEGENV.step = millis(); //save starting time, millis() because now can change from sync + SEGENV.step = strip.now; //save starting time, strip.now because now can change from sync SEGENV.aux0 = SEGMENT.speed; } SEGMENT.fill(BLACK); uint16_t stage = 0xFFFF; - uint32_t s10SinceStart = (millis() - SEGENV.step) /100; //tenths of seconds + uint32_t s10SinceStart = (strip.now - SEGENV.step) /100; //tenths of seconds if (SEGMENT.speed > 120) { //quick sunrise and sunset uint16_t counter = (strip.now >> 1) * (((SEGMENT.speed -120) >> 1) +1); @@ -4014,6 +4178,7 @@ static const char _data_FX_MODE_PHASEDNOISE[] PROGMEM = "Phased Noise@!,!;!,!;!" uint16_t mode_twinkleup(void) { // A very short twinkle routine with fade-in and dual controls. By Andrew Tuline. + uint16_t prevSeed = random16_get_seed(); // save seed so we can restore it at the end of the function random16_set_seed(535); // The randomizer needs to be re-set each time through the loop in order for the same 'random' numbers to be the same each time through. for (int i = 0; i < SEGLEN; i++) { @@ -4023,6 +4188,7 @@ uint16_t mode_twinkleup(void) { // A very short twinkle routine SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(random8()+strip.now/100, false, PALETTE_SOLID_WRAP, 0), pixBri)); } + random16_set_seed(prevSeed); // restore original seed so other effects can use "random" PRNG return FRAMETIME; } static const char _data_FX_MODE_TWINKLEUP[] PROGMEM = "Twinkleup@!,Intensity;!,!;!;;m12=0"; @@ -4039,9 +4205,9 @@ uint16_t mode_noisepal(void) { // Slow noise CRGBPalette16* palettes = reinterpret_cast(SEGENV.data); uint16_t changePaletteMs = 4000 + SEGMENT.speed *10; //between 4 - 6.5sec - if (millis() - SEGENV.step > changePaletteMs) + if (strip.now - SEGENV.step > changePaletteMs) { - SEGENV.step = millis(); + SEGENV.step = strip.now; uint8_t baseI = random8(); palettes[1] = CRGBPalette16(CHSV(baseI+random8(64), 255, random8(128,255)), CHSV(baseI+128, 255, random8(128,255)), CHSV(baseI+random8(92), 192, random8(128,255)), CHSV(baseI+random8(92), 255, random8(128,255))); @@ -4198,7 +4364,7 @@ uint16_t mode_dancing_shadows(void) SEGMENT.fill(BLACK); - unsigned long time = millis(); + unsigned long time = strip.now; bool respawn = false; for (size_t i = 0; i < numSpotlights; i++) { @@ -4392,8 +4558,8 @@ uint16_t mode_tv_simulator(void) { } // create a new sceene - if (((millis() - tvSimulator->sceeneStart) >= tvSimulator->sceeneDuration) || SEGENV.aux1 == 0) { - tvSimulator->sceeneStart = millis(); // remember the start of the new sceene + if (((strip.now - tvSimulator->sceeneStart) >= tvSimulator->sceeneDuration) || SEGENV.aux1 == 0) { + tvSimulator->sceeneStart = strip.now; // remember the start of the new sceene tvSimulator->sceeneDuration = random16(60* 250* colorSpeed, 60* 750 * colorSpeed); // duration of a "movie sceene" which has similar colors (5 to 15 minutes with max speed slider) tvSimulator->sceeneColorHue = random16( 0, 768); // random start color-tone for the sceene tvSimulator->sceeneColorSat = random8 ( 100, 130 + colorIntensity); // random start color-saturation for the sceene @@ -4444,13 +4610,13 @@ uint16_t mode_tv_simulator(void) { tvSimulator->fadeTime = random16(0, tvSimulator->totalTime); // Pixel-to-pixel transition time if (random8(10) < 3) tvSimulator->fadeTime = 0; // Force scene cut 30% of time - tvSimulator->startTime = millis(); + tvSimulator->startTime = strip.now; } // end of initialization // how much time is elapsed ? - tvSimulator->elapsed = millis() - tvSimulator->startTime; + tvSimulator->elapsed = strip.now - tvSimulator->startTime; - // fade from prev volor to next color + // fade from prev color to next color if (tvSimulator->elapsed < tvSimulator->fadeTime) { r = map(tvSimulator->elapsed, 0, tvSimulator->fadeTime, tvSimulator->pr, nr); g = map(tvSimulator->elapsed, 0, tvSimulator->fadeTime, tvSimulator->pg, ng); @@ -4507,15 +4673,15 @@ class AuroraWave { public: void init(uint32_t segment_length, CRGB color) { - ttl = random(500, 1501); + ttl = random16(500, 1501); basecolor = color; - basealpha = random(60, 101) / (float)100; + basealpha = random8(60, 101) / (float)100; age = 0; - width = random(segment_length / 20, segment_length / W_WIDTH_FACTOR); //half of width to make math easier + width = random16(segment_length / 20, segment_length / W_WIDTH_FACTOR); //half of width to make math easier if (!width) width = 1; - center = random(101) / (float)100 * segment_length; - goingleft = random(0, 2) == 0; - speed_factor = (random(10, 31) / (float)100 * W_MAX_SPEED / 255); + center = random8(101) / (float)100 * segment_length; + goingleft = random8(0, 2) == 0; + speed_factor = (random8(10, 31) / (float)100 * W_MAX_SPEED / 255); alive = true; } @@ -4600,7 +4766,7 @@ uint16_t mode_aurora(void) { waves = reinterpret_cast(SEGENV.data); for (int i = 0; i < SEGENV.aux1; i++) { - waves[i].init(SEGLEN, CRGB(SEGMENT.color_from_palette(random8(), false, false, random(0, 3)))); + waves[i].init(SEGLEN, CRGB(SEGMENT.color_from_palette(random8(), false, false, random8(0, 3)))); } } else { waves = reinterpret_cast(SEGENV.data); @@ -4612,7 +4778,7 @@ uint16_t mode_aurora(void) { if(!(waves[i].stillAlive())) { //If a wave dies, reinitialize it starts over. - waves[i].init(SEGLEN, CRGB(SEGMENT.color_from_palette(random8(), false, false, random(0, 3)))); + waves[i].init(SEGLEN, CRGB(SEGMENT.color_from_palette(random8(), false, false, random8(0, 3)))); } } @@ -4653,7 +4819,7 @@ uint16_t mode_perlinmove(void) { if (SEGENV.call == 0) SEGENV.setUpLeds(); // WLEDMM use lossless getPixelColor() SEGMENT.fade_out(255-SEGMENT.custom1); for (int i = 0; i < SEGMENT.intensity/16 + 1; i++) { - uint16_t locn = inoise16(millis()*128/(260-SEGMENT.speed)+i*15000, millis()*128/(260-SEGMENT.speed)); // Get a new pixel location from moving noise. + uint16_t locn = inoise16(strip.now*128/(260-SEGMENT.speed)+i*15000, strip.now*128/(260-SEGMENT.speed)); // Get a new pixel location from moving noise. uint16_t pixloc = map(locn, 50*256, 192*256, 0, SEGLEN-1); // Map that to the length of the strand, and ensure we don't go over. SEGMENT.setPixelColor(pixloc, SEGMENT.color_from_palette(pixloc%255, false, PALETTE_SOLID_WRAP, 0)); } @@ -4670,7 +4836,7 @@ static const char _data_FX_MODE_PERLINMOVE[] PROGMEM = "Perlin Move@!,# of pixel uint16_t mode_wavesins(void) { for (int i = 0; i < SEGLEN; i++) { - uint8_t bri = sin8(millis()/4 + i * SEGMENT.intensity); + uint8_t bri = sin8(strip.now/4 + i * SEGMENT.intensity); uint8_t index = beatsin8(SEGMENT.speed, SEGMENT.custom1, SEGMENT.custom1+SEGMENT.custom2, 0, i * (SEGMENT.custom3<<3)); //SEGMENT.setPixelColor(i, ColorFromPalette(SEGPALETTE, index, bri, LINEARBLEND)); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0, bri)); @@ -4688,8 +4854,8 @@ static const char _data_FX_MODE_WAVESINS[] PROGMEM = "Wavesins@!,Brightness vari uint16_t mode_FlowStripe(void) { const uint16_t hl = SEGLEN * 10 / 13; - uint8_t hue = millis() / (SEGMENT.speed+1); - uint32_t t = millis() / (SEGMENT.intensity/8+1); + uint8_t hue = strip.now / (SEGMENT.speed+1); + uint32_t t = strip.now / (SEGMENT.intensity/8+1); for (int i = 0; i < SEGLEN; i++) { int c = (abs(i - hl) / hl) * 127; @@ -4725,7 +4891,7 @@ uint16_t mode_2DBlackHole(void) { // By: Stepko https://editor.soulma } SEGMENT.fadeToBlackBy(16 + (SEGMENT.speed>>3)); // create fading trails - unsigned long t = millis()/128; // timebase + unsigned long t = strip.now/128; // timebase // outer stars for (size_t i = 0; i < 8; i++) { x = beatsin8(SEGMENT.custom1>>3, 0, cols - 1, 0, ((i % 2) ? 128 : 0) + t * i); @@ -4819,8 +4985,8 @@ uint16_t mode_2Ddna(void) { // dna originally by by ldirko at https://pa SEGMENT.fadeToBlackBy(64); for (int i = 0; i < cols; i++) { - SEGMENT.setPixelColorXY(i, beatsin8(SEGMENT.speed/8, 0, rows-1, 0, i*4 ), ColorFromPalette(SEGPALETTE, i*5+millis()/17, beatsin8(5, 55, 255, 0, i*10), LINEARBLEND)); - SEGMENT.setPixelColorXY(i, beatsin8(SEGMENT.speed/8, 0, rows-1, 0, i*4+128), ColorFromPalette(SEGPALETTE, i*5+128+millis()/17, beatsin8(5, 55, 255, 0, i*10+128), LINEARBLEND)); + SEGMENT.setPixelColorXY(i, beatsin8(SEGMENT.speed/8, 0, rows-1, 0, i*4 ), ColorFromPalette(SEGPALETTE, i*5+strip.now/17, beatsin8(5, 55, 255, 0, i*10), LINEARBLEND)); + SEGMENT.setPixelColorXY(i, beatsin8(SEGMENT.speed/8, 0, rows-1, 0, i*4+128), ColorFromPalette(SEGPALETTE, i*5+128+strip.now/17, beatsin8(5, 55, 255, 0, i*10+128), LINEARBLEND)); } SEGMENT.blur(SEGMENT.intensity>>3); @@ -4846,7 +5012,7 @@ uint16_t mode_2DDNASpiral() { // By: ldirko https://editor.soulma uint8_t speeds = SEGMENT.speed/2 + 1; uint8_t freq = SEGMENT.intensity/8; - uint32_t ms = millis() / 20; + uint32_t ms = strip.now / 20; SEGMENT.fadeToBlackBy(135); for (int i = 0; i < rows; i++) { @@ -4892,7 +5058,7 @@ uint16_t mode_2DDrift() { // By: Stepko https://editor.soulmateli SEGMENT.fadeToBlackBy(128); const uint16_t maxDim = MAX(cols, rows)/2; - unsigned long t = millis() / (32 - (SEGMENT.speed>>3)); + unsigned long t = strip.now / (32 - (SEGMENT.speed>>3)); unsigned long t_20 = t/20; // softhack007: pre-calculating this gives about 10% speedup for (float i = 1; i < maxDim; i += 0.25) { float angle = radians(t * (maxDim - i)); @@ -4932,7 +5098,7 @@ uint16_t mode_2Dfirenoise(void) { // firenoise2d. By Andrew Tuline for (int j=0; j < cols; j++) { for (int i=0; i < rows; i++) { - indexx = inoise8(j*yscale*rows/255, i*xscale+millis()/4); // We're moving along our Perlin map. + indexx = inoise8(j*yscale*rows/255, i*xscale+strip.now/4); // We're moving along our Perlin map. SEGMENT.setPixelColorXY(j, i, ColorFromPalette(SEGPALETTE, min(i*(indexx)>>4, 255), i*255/cols, LINEARBLEND)); // With that value, look up the 8 bit colour palette value and assign it to the current LED. } // for i } // for j @@ -4996,7 +5162,7 @@ uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https: if (SEGENV.call == 0 || strip.now - SEGMENT.step > 3000) { SEGENV.step = strip.now; SEGENV.aux0 = 0; - random16_set_seed(millis()>>2); //seed the random generator + random16_set_seed(strip.now>>2); //seed the random generator //give the leds random state and colors (based on intensity, colors from palette or all posible colors are chosen) for (int x = 0; x < cols; x++) for (int y = 0; y < rows; y++) { @@ -5073,7 +5239,7 @@ uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https: bool repetition = false; for (int i=0; i softhack007: not exacly. Different CRC means diferent image; same CRC means nothing (could be same or slightly different). + // -> softhack007: not exacly. Different CRC means different image; same CRC means nothing (could be same or slightly different). if (!repetition) SEGENV.step = strip.now; //if no repetition avoid reset // remember CRCs across frames crcBuffer[SEGENV.aux0] = crc; @@ -5172,8 +5338,8 @@ uint16_t mode_2DJulia(void) { // An animated Julia set reAl = -0.94299f; // PixelBlaze example imAg = 0.3162f; - reAl += sin_t((float)millis()/305.f)/20.f; - imAg += sin_t((float)millis()/405.f)/20.f; + reAl += sin_t((float)strip.now/305.f)/20.f; + imAg += sin_t((float)strip.now/405.f)/20.f; dx = (xmax - xmin) / (cols); // Scale the delta x and y values to our matrix size. dy = (ymax - ymin) / (rows); @@ -5242,7 +5408,7 @@ uint16_t mode_2DLissajous(void) { // By: Andrew Tuline for (int i=0; i < maxLoops; i ++) { float xlocn = float(sin8(phase/2 + (i* SEGMENT.speed)/64)) / 255.0f; // WLEDMM align speed with original effect float ylocn = float(cos8(phase/2 + i*2)) / 255.0f; - //SEGMENT.setPixelColorXY(xlocn, ylocn, SEGMENT.color_from_palette(millis()/100+i, false, PALETTE_SOLID_WRAP, 0)); // draw pixel with anti-aliasing + //SEGMENT.setPixelColorXY(xlocn, ylocn, SEGMENT.color_from_palette(strip.now/100+i, false, PALETTE_SOLID_WRAP, 0)); // draw pixel with anti-aliasing unsigned palIndex = (256*ylocn) + phase/2 + (i* SEGMENT.speed)/64; SEGMENT.setPixelColorXY(xlocn, ylocn, SEGMENT.color_from_palette(palIndex, false, PALETTE_SOLID_WRAP, 0)); // draw pixel with anti-aliasing - color follows rotation } @@ -5253,12 +5419,12 @@ uint16_t mode_2DLissajous(void) { // By: Andrew Tuline uint_fast8_t ylocn = cos8(phase/2 + i*2); xlocn = (cols < 2) ? 1 : (map(2*xlocn, 0,511, 0,2*(cols-1)) +1) /2; // softhack007: "*2 +1" for proper rounding ylocn = (rows < 2) ? 1 : (map(2*ylocn, 0,511, 0,2*(rows-1)) +1) /2; // "rows > 2" is needed to avoid div/0 in map() - SEGMENT.setPixelColorXY((uint8_t)xlocn, (uint8_t)ylocn, SEGMENT.color_from_palette(millis()/100+i, false, PALETTE_SOLID_WRAP, 0)); + SEGMENT.setPixelColorXY((uint8_t)xlocn, (uint8_t)ylocn, SEGMENT.color_from_palette(strip.now/100+i, false, PALETTE_SOLID_WRAP, 0)); } return FRAMETIME; } // mode_2DLissajous() -static const char _data_FX_MODE_2DLISSAJOUS[] PROGMEM = "Lissajous ☾@X frequency,Fade rate,,,Speed,,,☾ Smooth Style;!;!;2;;sx=64,c3=15"; +static const char _data_FX_MODE_2DLISSAJOUS[] PROGMEM = "Lissajous ☾@X frequency,Fade rate,,,Speed,,,☾ Smooth Style;!;!;2;sx=64,c3=15"; /////////////////////// @@ -5409,7 +5575,7 @@ uint16_t mode_2Dnoise(void) { // By Andrew Tuline for (int y = 0; y < rows; y++) { for (int x = 0; x < cols; x++) { - uint8_t pixelHue8 = inoise8(x * scale, y * scale, millis() / (16 - SEGMENT.speed/16)); + uint8_t pixelHue8 = inoise8(x * scale, y * scale, strip.now / (16 - SEGMENT.speed/16)); SEGMENT.setPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, pixelHue8)); } } @@ -5435,7 +5601,7 @@ uint16_t mode_2DPlasmaball(void) { // By: Stepko https://edito SEGMENT.fadeToBlackBy(SEGMENT.custom1>>2); - uint_fast32_t t = (millis() * 8) / (256 - SEGMENT.speed); // optimized to avoid float + uint_fast32_t t = (strip.now * 8) / (256 - SEGMENT.speed); // optimized to avoid float for (int i = 0; i < cols; i++) { uint16_t thisVal = inoise8(i * 30, t, t); uint16_t thisMax = map(thisVal, 0, 255, 0, cols-1); @@ -5474,15 +5640,14 @@ uint16_t mode_2DPolarLights(void) { // By: Kostyantyn Matviyevskyy https const uint16_t cols = SEGMENT.virtualWidth(); const uint16_t rows = SEGMENT.virtualHeight(); - CRGBPalette16 auroraPalette = {0x000000, 0x003300, 0x006600, 0x009900, 0x00cc00, 0x00ff00, 0x33ff00, 0x66ff00, 0x99ff00, 0xccff00, 0xffff00, 0xffcc00, 0xff9900, 0xff6600, 0xff3300, 0xff0000}; + const CRGBPalette16 auroraPalette = {0x000000, 0x003300, 0x006600, 0x009900, 0x00cc00, 0x00ff00, 0x33ff00, 0x66ff00, 0x99ff00, 0xccff00, 0xffff00, 0xffcc00, 0xff9900, 0xff6600, 0xff3300, 0xff0000}; if (SEGENV.call == 0) { SEGMENT.setUpLeds(); SEGMENT.fill(BLACK); - SEGENV.step = 0; } - float adjustHeight = (float)map(rows, 8, 32, 28, 12); // maybe use mapf() ??? + float adjustHeight = mapf(rows, 8, 32, 28, 12); // maybe use mapf() ??? // WLEDMM yes! uint16_t adjScale = map(cols, 8, 64, 310, 63); /* if (SEGENV.aux1 != SEGMENT.custom1/12) { // Hacky palette rotation. We need that black. @@ -5502,19 +5667,36 @@ uint16_t mode_2DPolarLights(void) { // By: Kostyantyn Matviyevskyy https uint16_t _scale = map(SEGMENT.intensity, 0, 255, 30, adjScale); byte _speed = map(SEGMENT.speed, 0, 255, 128, 16); - for (int x = 0; x < cols; x++) { - for (int y = 0; y < rows; y++) { - SEGENV.step++; - SEGMENT.setPixelColorXY(x, y, ColorFromPalette(auroraPalette, - qsub8( - inoise8((SEGENV.step%2) + x * _scale, y * 16 + SEGENV.step % 16, SEGENV.step / _speed), - fabsf((float)rows / 2.0f - (float)y) * adjustHeight))); + //WLEDMM add SuperSync control + uint16_t xStart, xEnd, yStart, yEnd; + if (SEGMENT.check1) { //Master (sync on needs to show the whole effect, children only their first panel) + xStart = strip.panel[0].xOffset; + xEnd = strip.panel[0].xOffset + strip.panel[0].width; + yStart = strip.panel[0].yOffset; + yEnd = strip.panel[0].yOffset + strip.panel[0].height; + } + else { + xStart = 0; + xEnd = cols; + yStart = 0; + yEnd = rows; + } + + SEGENV.step = (strip.now * (cols * rows)) / 25; // baseline 40fps + const float rows_2 = (float)rows / 2.0f; // WLEDMM faster to pre-calculate this + for (int x = xStart; x < xEnd; x++) { + for (int y = yStart; y < yEnd; y++) { + SEGENV.step++; + SEGMENT.setPixelColorXY(x, y, ColorFromPalette(auroraPalette, + qsub8( + inoise8((SEGENV.step%2) + x * _scale, y * 16 + SEGENV.step % 16, SEGENV.step / _speed), + fabsf(rows_2 - (float)y) * adjustHeight))); // WLEDMM } } return FRAMETIME; } // mode_2DPolarLights() -static const char _data_FX_MODE_2DPOLARLIGHTS[] PROGMEM = "Polar Lights@!,Scale;;;2"; +static const char _data_FX_MODE_2DPOLARLIGHTS[] PROGMEM = "Polar Lights@!,Scale,,,,SuperSync;;;2"; ///////////////////////// @@ -5561,7 +5743,7 @@ uint16_t mode_2DSindots(void) { // By: ldirko http SEGMENT.fadeToBlackBy(SEGMENT.custom1>>3); - byte t1 = millis() / (257 - SEGMENT.speed); // 20; + byte t1 = strip.now / (257 - SEGMENT.speed); // 20; byte t2 = sin8(t1) / 4 * 2; for (int i = 0; i < 13; i++) { byte x = sin8(t1 + i * SEGMENT.intensity/8)*(cols-1)/255; // max index now 255x15/255=15! @@ -5606,7 +5788,7 @@ uint16_t mode_2Dsquaredswirl(void) { // By: Mark Kriegsman. https://g uint8_t n = beatsin8(15, kBorderWidth, rows-kBorderWidth); uint8_t p = beatsin8(20, kBorderWidth, rows-kBorderWidth); - uint16_t ms = millis(); + uint16_t ms = strip.now; SEGMENT.addPixelColorXY(i, m, ColorFromPalette(SEGPALETTE, ms/29, 255, LINEARBLEND)); SEGMENT.addPixelColorXY(j, n, ColorFromPalette(SEGPALETTE, ms/41, 255, LINEARBLEND)); @@ -5634,7 +5816,7 @@ uint16_t mode_2DSunradiation(void) { // By: ldirko https://edi SEGMENT.fill(BLACK); } - unsigned long t = millis() / 4; + unsigned long t = strip.now / 4; int index = 0; uint8_t someVal = SEGMENT.speed/4; // Was 25. for (int j = 0; j < (rows + 2); j++) { @@ -5771,7 +5953,8 @@ uint16_t mode_2Dcrazybees(void) { uint8_t posX, posY, aimX, aimY, hue; int8_t deltaX, deltaY, signX, signY, error; void aimed(uint16_t w, uint16_t h) { - random16_set_seed(millis()); + if (!true) //WLEDMM SuperSync + random16_set_seed(strip.now); aimX = random8(0, w); aimY = random8(0, h); hue = random8(); @@ -5787,6 +5970,8 @@ uint16_t mode_2Dcrazybees(void) { bee_t *bee = reinterpret_cast(SEGENV.data); if (SEGENV.call == 0) { + if (true) //WLEDMM SuperSync + random16_set_seed(strip.now); SEGMENT.setUpLeds(); SEGMENT.fill(BLACK); for (size_t i = 0; i < n; i++) { @@ -5796,8 +5981,8 @@ uint16_t mode_2Dcrazybees(void) { } } - if (millis() > SEGENV.step) { - SEGENV.step = millis() + (FRAMETIME * 8 / ((SEGMENT.speed>>5)+1)); + if (strip.now > SEGENV.step) { + SEGENV.step = strip.now + (FRAMETIME * 8 / ((SEGMENT.speed>>5)+1)); SEGMENT.fadeToBlackBy(32); @@ -5874,8 +6059,8 @@ uint16_t mode_2Dghostrider(void) { } } - if (millis() > SEGENV.step) { - SEGENV.step = millis() + 1024 / (cols+rows); + if (strip.now > SEGENV.step) { + SEGENV.step = strip.now + 1024 / (cols+rows); SEGMENT.fadeToBlackBy((SEGMENT.speed>>2)+64); @@ -5901,7 +6086,7 @@ uint16_t mode_2Dghostrider(void) { if (lighter->reg[i]) { lighter->lightersPosY[i] = lighter->gPosY; lighter->lightersPosX[i] = lighter->gPosX; - lighter->Angle[i] = lighter->gAngle + random(-10, 10); + lighter->Angle[i] = lighter->gAngle + ((int)random8(20) - 10); lighter->time[i] = 0; lighter->reg[i] = false; } else { @@ -5964,7 +6149,7 @@ uint16_t mode_2Dfloatingblobs(void) { // Bounce balls around for (size_t i = 0; i < Amount; i++) { - if (SEGENV.step < millis()) blob->color[i] = add8(blob->color[i], 4); // slowly change color + if (SEGENV.step < strip.now) blob->color[i] = add8(blob->color[i], 4); // slowly change color // change radius if needed if (blob->grow[i]) { // enlarge radius until it is >= 4 @@ -6011,7 +6196,7 @@ uint16_t mode_2Dfloatingblobs(void) { } SEGMENT.blur(SEGMENT.custom1>>2); - if (SEGENV.step < millis()) SEGENV.step = millis() + 2000; // change colors every 2 seconds + if (SEGENV.step < strip.now) SEGENV.step = strip.now + 2000; // change colors every 2 seconds return FRAMETIME; } @@ -6046,9 +6231,10 @@ uint16_t mode_2Dscrollingtext(void) { char text[33] = {'\0'}; unsigned maxLen = (SEGMENT.name) ? min(32, (int)strlen(SEGMENT.name)) : 0; // WLEDMM make it robust against too long segment names if (SEGMENT.name) for (size_t i=0,j=0; i31 && SEGMENT.name[i]<128) text[j++] = SEGMENT.name[i]; + const bool zero = strchr(text, '0') != nullptr; - if (!strlen(text) || !strncmp_P(text,PSTR("#F"),2) || !strncmp_P(text,PSTR("#P"),2) || !strncmp_P(text,PSTR("#DATE"),5) || !strncmp_P(text,PSTR("#DDMM"),5) || !strncmp_P(text,PSTR("#MMDD"),5) || !strncmp_P(text,PSTR("#TIME"),5) || !strncmp_P(text,PSTR("#HHMM"),5)) { // fallback if empty segment name: display date and time - char sec[5]; + if (!strlen(text) || !strncmp_P(text,PSTR("#F"),2) || !strncmp_P(text,PSTR("#P"),2) || !strncmp_P(text,PSTR("#DATE"),5) || !strncmp_P(text,PSTR("#DDMM"),5) || !strncmp_P(text,PSTR("#MMDD"),5) || !strncmp_P(text,PSTR("#TIME"),5) || !strncmp_P(text,PSTR("#HH"),3) || !strncmp_P(text,PSTR("#MM"),3)) { // fallback if empty segment name: display date and time + char sec[5]= {'\0'}; byte AmPmHour = hour(localTime); boolean isitAM = true; if (useAMPM) { @@ -6057,22 +6243,24 @@ uint16_t mode_2Dscrollingtext(void) { } if (useAMPM) sprintf_P(sec, PSTR(" %2s"), (isitAM ? "AM" : "PM")); else sprintf_P(sec, PSTR(":%02d"), second(localTime)); - if (!strncmp_P(text,PSTR("#DATE"),5)) sprintf_P(text, PSTR("%d.%d.%d"), day(localTime), month(localTime), year(localTime)); - else if (!strncmp_P(text,PSTR("#DDMM"),5)) sprintf_P(text, PSTR("%d.%d"), day(localTime), month(localTime)); - else if (!strncmp_P(text,PSTR("#MMDD"),5)) sprintf_P(text, PSTR("%d/%d"), month(localTime), day(localTime)); - else if (!strncmp_P(text,PSTR("#TIME"),5)) sprintf_P(text, PSTR("%2d:%02d%s"), AmPmHour, minute(localTime), sec); - else if (!strncmp_P(text,PSTR("#HHMM"),5)) sprintf_P(text, PSTR("%2d:%02d"), AmPmHour, minute(localTime)); + if (!strncmp_P(text,PSTR("#DATE"),5)) sprintf_P(text, zero?PSTR("%02d.%02d.%04d"):PSTR("%d.%d.%d"), day(localTime), month(localTime), year(localTime)); + else if (!strncmp_P(text,PSTR("#DDMM"),5)) sprintf_P(text, zero?PSTR("%02d.%02d") :PSTR("%d.%d"), day(localTime), month(localTime)); + else if (!strncmp_P(text,PSTR("#MMDD"),5)) sprintf_P(text, zero?PSTR("%02d/%02d") :PSTR("%d/%d"), month(localTime), day(localTime)); + else if (!strncmp_P(text,PSTR("#TIME"),5)) sprintf_P(text, zero?PSTR("%02d:%02d%s") :PSTR("%2d:%02d%s"), AmPmHour, minute(localTime), sec); + else if (!strncmp_P(text,PSTR("#HHMM"),5)) sprintf_P(text, zero?PSTR("%02d:%02d") :PSTR("%d:%02d"), AmPmHour, minute(localTime)); + else if (!strncmp_P(text,PSTR("#HH"),3)) sprintf_P(text, zero?PSTR("%02d") :PSTR("%d"), AmPmHour); + else if (!strncmp_P(text,PSTR("#MM"),3)) sprintf_P(text, zero?PSTR("%02d") :PSTR("%d"), minute(localTime)); else if (!strncmp_P(text,PSTR("#FPS"),4)) sprintf_P(text, PSTR("%2d"), (int) strip.getFps()); // WLEDMM else if (!strncmp_P(text,PSTR("#POW"),4)) sprintf_P(text, PSTR("%3.2fA"), float(strip.currentMilliamps)/1000.0f); // WLEDMM - else sprintf_P(text, PSTR("%s %d, %d %2d:%02d%s"), monthShortStr(month(localTime)), day(localTime), year(localTime), AmPmHour, minute(localTime), sec); + else sprintf_P(text, PSTR("%s %d, %d %d:%02d%s"), monthShortStr(month(localTime)), day(localTime), year(localTime), AmPmHour, minute(localTime), sec); } const int numberOfLetters = strlen(text); - if (SEGENV.step < millis()) { + if (SEGENV.step < strip.now) { if ((numberOfLetters * letterWidth) > cols) ++SEGENV.aux0 %= (numberOfLetters * letterWidth) + cols; // offset else SEGENV.aux0 = (cols + (numberOfLetters * letterWidth))/2; ++SEGENV.aux1 &= 0xFF; // color shift - SEGENV.step = millis() + map(SEGMENT.speed, 0, 255, 10*FRAMETIME_FIXED, 2*FRAMETIME_FIXED); + SEGENV.step = strip.now + map(SEGMENT.speed, 0, 255, 10*FRAMETIME_FIXED, 2*FRAMETIME_FIXED); if (!SEGMENT.check2) { for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++ ) SEGMENT.blendPixelColorXY(x, y, SEGCOLOR(1), 255 - (SEGMENT.custom1>>1)); @@ -6288,7 +6476,7 @@ uint16_t mode_2DSwirl(void) { uint8_t j = beatsin8( 41*SEGMENT.speed/255, borderWidth, rows - borderWidth); uint8_t ni = (cols - 1) - i; uint8_t nj = (cols - 1) - j; - uint16_t ms = millis(); + uint16_t ms = strip.now; um_data_t *um_data; if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { @@ -6341,7 +6529,7 @@ uint16_t mode_2DWaverly(void) { if ((SEGENV.check2) && (volumeSmth > 0.5f)) volumeSmth = soundPressure; // show sound pressure instead of volume if (SEGENV.check3) volumeSmth = 255.0 - agcSensitivity; // show AGC level instead of volume - long t = millis() / 2; + long t = strip.now / 2; for (int i = 0; i < cols; i++) { uint16_t thisVal = volumeSmth*SEGMENT.intensity/64 * inoise8(i * 45 , t , t)/64; // WLEDMM back to SR code uint16_t thisMax = map(thisVal, 0, 512, 0, rows); @@ -6360,11 +6548,6 @@ static const char _data_FX_MODE_2DWAVERLY[] PROGMEM = "Waverly ☾@Amplification #endif // WLED_DISABLE_2D -// float version of map() -static float mapf(float x, float in_min, float in_max, float out_min, float out_max){ - return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; -} - // Gravity struct requited for GRAV* effects typedef struct Gravity { int topLED; @@ -6395,14 +6578,14 @@ uint16_t mode_gravcenter(void) { // Gravcenter. By Andrew Tuline. SEGMENT.fade_out(251); // 30% float segmentSampleAvg = volumeSmth * (float)SEGMENT.intensity / 255.0f; - segmentSampleAvg *= 0.125; // divide by 8, to compensate for later "sensitivty" upscaling + segmentSampleAvg *= 0.125; // divide by 8, to compensate for later "sensitivity" upscaling float mySampleAvg = mapf(segmentSampleAvg*2.0, 0, 32, 0, (float)SEGLEN/2.0); // map to pixels available in current segment uint16_t tempsamp = constrain(mySampleAvg, 0, SEGLEN/2); // Keep the sample from overflowing. uint8_t gravity = 8 - SEGMENT.speed/32; for (int i=0; itopLED--; if (gravcen->topLED >= 0) { - SEGMENT.setPixelColor(gravcen->topLED+SEGLEN/2, SEGMENT.color_from_palette(millis(), false, PALETTE_SOLID_WRAP, 0)); - SEGMENT.setPixelColor(SEGLEN/2-1-gravcen->topLED, SEGMENT.color_from_palette(millis(), false, PALETTE_SOLID_WRAP, 0)); + SEGMENT.setPixelColor(gravcen->topLED+SEGLEN/2, SEGMENT.color_from_palette(strip.now, false, PALETTE_SOLID_WRAP, 0)); + SEGMENT.setPixelColor(SEGLEN/2-1-gravcen->topLED, SEGMENT.color_from_palette(strip.now, false, PALETTE_SOLID_WRAP, 0)); } gravcen->gravityCounter = (gravcen->gravityCounter + 1) % gravity; @@ -6450,14 +6633,14 @@ uint16_t mode_gravcentric(void) { // Gravcentric. By Andrew SEGMENT.fade_out(253); // 50% float segmentSampleAvg = volumeSmth * (float)SEGMENT.intensity / 255.0; - segmentSampleAvg *= 0.125f; // divide by 8, to compensate for later "sensitivty" upscaling + segmentSampleAvg *= 0.125f; // divide by 8, to compensate for later "sensitivity" upscaling float mySampleAvg = mapf(segmentSampleAvg*2.0, 0.0f, 32.0f, 0.0f, (float)SEGLEN/2.0); // map to pixels availeable in current segment int tempsamp = constrain(mySampleAvg, 0, SEGLEN/2); // Keep the sample from overflowing. uint8_t gravity = 8 - SEGMENT.speed/32; for (int i=0; i 1) && ((blendVal < 1) || (blendVal > 254))) blendVal = millis() % 192; // provides flickering when overtuned + //if ((realVolume > 1) && ((blendVal < 1) || (blendVal > 254))) blendVal = strip.now % 192; // provides flickering when overtuned //else blendVal = constrain(blendVal, 32, 255); // and saturation for all if (realVolume > 0.85) // hide main "bar" in silence for (int i=0; itopLED > 0) && (SEGMENT.speed < 255)){ // hide top pixel if speed = 255 if (SEGENV.check2 || SEGENV.check3) - SEGMENT.setPixelColor(gravcen->topLED, SEGMENT.color_from_palette(max(uint16_t(millis()/16),(uint16_t)2), false, PALETTE_SOLID_WRAP, 0)); // flicker a bit slower + SEGMENT.setPixelColor(gravcen->topLED, SEGMENT.color_from_palette(max(uint16_t(strip.now/16),(uint16_t)2), false, PALETTE_SOLID_WRAP, 0)); // flicker a bit slower else - SEGMENT.setPixelColor(gravcen->topLED, SEGMENT.color_from_palette(max(uint16_t(millis()/2),(uint16_t)2), false, PALETTE_SOLID_WRAP, 0)); // normal flickering + SEGMENT.setPixelColor(gravcen->topLED, SEGMENT.color_from_palette(max(uint16_t(strip.now/2),(uint16_t)2), false, PALETTE_SOLID_WRAP, 0)); // normal flickering } gravcen->gravityCounter = (gravcen->gravityCounter + 1) % gravity; @@ -6576,7 +6759,7 @@ uint16_t mode_juggles(void) { // Juggles. By Andrew Tuline. uint16_t my_sampleAgc = fmax(fmin(volumeSmth, 255.0), 0); for (size_t i=0; i 0.5f) ? 255 : 0; @@ -6661,7 +6844,7 @@ uint16_t mode_midnoise(void) { // Midnoise. By Andrew Tuline. //SEGMENT.fade_out(SEGMENT.speed); float tmpSound2 = volumeSmth * (float)SEGMENT.intensity / 256.0; // Too sensitive. - tmpSound2 *= (float)SEGMENT.intensity / 128.0; // Reduce sensitity/length. + tmpSound2 *= (float)SEGMENT.intensity / 128.0; // Reduce sensitivity/length. int maxLen = mapf(tmpSound2, 0, 127, 0, SEGLEN/2); if (maxLen >SEGLEN/2) maxLen = SEGLEN/2; @@ -6699,7 +6882,7 @@ uint16_t mode_noisefire(void) { // Noisefire. By Andrew Tuline. if (SEGENV.call == 0) SEGMENT.fill(BLACK); for (int i = 0; i < SEGLEN; i++) { - uint16_t index = inoise8(i*SEGMENT.speed/64,millis()*SEGMENT.speed/64*SEGLEN/255); // X location is constant, but we move along the Y at the rate of millis(). By Andrew Tuline. + uint16_t index = inoise8(i*SEGMENT.speed/64,strip.now*SEGMENT.speed/64*SEGLEN/255); // X location is constant, but we move along the Y at the rate of strip.now. By Andrew Tuline. index = (255 - i*256/SEGLEN) * index/(256-SEGMENT.intensity); // Now we need to scale index so that it gets blacker as we get close to one of the ends. // This is a simple y=mx+b equation that's been scaled. index/128 is another scaling. @@ -6774,7 +6957,7 @@ uint16_t mode_pixelwave(void) { // Pixelwave. By Andrew Tuline. rawPixel = rawPixel*rawPixel / 256.0f; // WLEDMM square scaling to emphasize peaks int pixBri = rawPixel * (SEGMENT.intensity+1) / 96; - SEGMENT.setPixelColor(SEGLEN/2, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(millis()/5, false, PALETTE_SOLID_WRAP, 0), pixBri)); + SEGMENT.setPixelColor(SEGLEN/2, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(strip.now/5, false, PALETTE_SOLID_WRAP, 0), pixBri)); for (int i = SEGLEN - 1; i > SEGLEN/2; i--) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i-1)); //move to the left for (int i = 0; i < SEGLEN/2; i++) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); // move to the right } @@ -6838,7 +7021,7 @@ uint16_t mode_puddlepeak(void) { // Puddlepeak. By Andrew Tuline. uint16_t size = 0; uint8_t fadeVal = map(SEGMENT.speed,0,255, 224, 254); - uint16_t pos = random(SEGLEN); // Set a random starting position. + uint16_t pos = random16(SEGLEN); // Set a random starting position. um_data_t *um_data; if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { @@ -6870,7 +7053,7 @@ uint16_t mode_puddlepeak(void) { // Puddlepeak. By Andrew Tuline. } for (int i=0; iu_data[0]; if (SEGENV.call == 0) SEGENV.setUpLeds(); // WLEDMM use lossless getPixelColor() - myVals[millis()%32] = volumeSmth; // filling values semi randomly + myVals[strip.now%32] = volumeSmth; // filling values semi randomly SEGMENT.fade_out(64+(SEGMENT.speed>>1)); @@ -7177,7 +7360,7 @@ uint16_t mode_freqmatrix(void) { // Freqmatrix. By Andreas Plesch if (FFT_MajorPeak > MAX_FREQUENCY) FFT_MajorPeak = 1; // MajorPeak holds the freq. value which is most abundant in the last sample. - // With our sampling rate of 10240Hz we have a usable freq range from roughtly 80Hz to 10240/2 Hz + // With our sampling rate of 10240Hz we have a usable freq range from roughly 80Hz to 10240/2 Hz // we will treat everything with less than 65Hz as 0 if ((FFT_MajorPeak > 80.0f) && (volumeSmth > 0.25f)) { // WLEDMM @@ -7198,7 +7381,7 @@ uint16_t mode_freqmatrix(void) { // Freqmatrix. By Andreas Plesch return FRAMETIME; } // mode_freqmatrix() -static const char _data_FX_MODE_FREQMATRIX[] PROGMEM = "Freqmatrix@Speed,Sound effect,Low bin,High bin,Sensivity;;;1f;c1=18,c2=48,c3=6,m12=3,si=0"; // Corner, Beatsin; notes range C3 to C7 +static const char _data_FX_MODE_FREQMATRIX[] PROGMEM = "Freqmatrix@Speed,Sound effect,Low bin,High bin,Sensitivity;;;1f;c1=18,c2=48,c3=6,m12=3,si=0"; // Corner, Beatsin; notes range C3 to C7 ////////////////////// @@ -7282,7 +7465,7 @@ uint16_t mode_freqwave(void) { // Freqwave. By Andreas Pleschun if (FFT_MajorPeak > MAX_FREQUENCY) FFT_MajorPeak = 1.0f; // MajorPeak holds the freq. value which is most abundant in the last sample. - // With our sampling rate of 10240Hz we have a usable freq range from roughtly 80Hz to 10240/2 Hz + // With our sampling rate of 10240Hz we have a usable freq range from roughly 80Hz to 10240/2 Hz // we will treat everything with less than 65Hz as 0 if ((FFT_MajorPeak < 80) || (volumeSmth < 1.0f) || (FFT_MajorPeak > 10800)) { // silence or out-of-range --> black @@ -7345,7 +7528,7 @@ uint16_t mode_gravfreq(void) { // Gravfreq. By Andrew Tuline. SEGMENT.fadeToBlackBy(96); float segmentSampleAvg = volumeSmth * (float)SEGMENT.intensity / 255.0f; - segmentSampleAvg *= 0.125; // divide by 8, to compensate for later "sensitivty" upscaling + segmentSampleAvg *= 0.125f; // divide by 8, to compensate for later "sensitivity" upscaling float mySampleAvg = mapf(segmentSampleAvg*2.0f, 0,32, 0, (float)SEGLEN/2.0); // map to pixels availeable in current segment int tempsamp = constrain(mySampleAvg,0,SEGLEN/2); // Keep the sample from overflowing. @@ -7374,7 +7557,7 @@ uint16_t mode_gravfreq(void) { // Gravfreq. By Andrew Tuline. SEGENV.aux0 = indexNew; return FRAMETIME; } // mode_gravfreq() -static const char _data_FX_MODE_GRAVFREQ[] PROGMEM = "Gravfreq ☾@Rate of fall,Sensivity;!,!;!;1f;ix=128,m12=0,si=0"; // Pixels, Beatsin +static const char _data_FX_MODE_GRAVFREQ[] PROGMEM = "Gravfreq ☾@Rate of fall,Sensitivity;!,!;!;1f;ix=128,m12=0,si=0"; // Pixels, Beatsin ////////////////////// @@ -7398,7 +7581,7 @@ uint16_t mode_noisemove(void) { // Noisemove. By: Andrew Tuli uint8_t numBins = map(SEGMENT.intensity,0,255,0,16); // Map slider to fftResult bins. for (int i=0; i= (256U - SEGMENT.intensity)) { - SEGENV.step = millis(); + if (strip.now - SEGENV.step >= (256U - SEGMENT.intensity)) { + SEGENV.step = strip.now; rippleTime = true; } @@ -7785,7 +7968,7 @@ uint16_t mode_2Ddistortionwaves() { uint8_t w = 2; - uint16_t a = millis()/32; + uint16_t a = strip.now/32; uint16_t a2 = a/2; uint16_t a3 = a/3; @@ -7849,21 +8032,38 @@ uint16_t mode_2Dsoap() { // init if (SEGENV.call == 0) { + if (true) {//WLEDMM SuperSync + random16_set_seed(535); + USER_PRINTF("SuperSync\n"); + } SEGMENT.setUpLeds(); *noise32_x = random16(); *noise32_y = random16(); *noise32_z = random16(); } else { - *noise32_x += mov; - *noise32_y += mov; - *noise32_z += mov; + if (!true) { //WLEDMM SuperSync + *noise32_x += mov; + *noise32_y += mov; + *noise32_z += mov; + } + } + + //WLEDMM: changing noise calculation for SuperSync to make it deterministic using strip.now + uint32_t noise32_x_MM = *noise32_x; + uint32_t noise32_y_MM = *noise32_y; + uint32_t noise32_z_MM = *noise32_z; + + if (true) { //WLEDMM SuperSync + noise32_x_MM = *noise32_x + mov * strip.now / 100; //10 fps (original 20-40 fps, depending on realized fps) + noise32_y_MM = *noise32_y + mov * strip.now / 100; + noise32_z_MM = *noise32_z + mov * strip.now / 100; } for (int i = 0; i < cols; i++) { int32_t ioffset = scale32_x * (i - cols / 2); for (int j = 0; j < rows; j++) { int32_t joffset = scale32_y * (j - rows / 2); - uint8_t data = inoise16(*noise32_x + ioffset, *noise32_y + joffset, *noise32_z) >> 8; + uint8_t data = inoise16(noise32_x_MM + ioffset, noise32_y_MM + joffset, noise32_z_MM) >> 8; //WLEDMM SuperSync noise3d[XY(i,j)] = scale8(noise3d[XY(i,j)], smoothness) + scale8(data, 255 - smoothness); } } @@ -7960,26 +8160,46 @@ uint16_t mode_2Doctopus() { uint8_t *offsX = reinterpret_cast(SEGENV.data + dataSize); uint8_t *offsY = reinterpret_cast(SEGENV.data + dataSize + 1); + //WLEDMM add SuperSync control + uint16_t xStart, xEnd, yStart, yEnd; + if (SEGMENT.check1) { //Master (sync on needs to show the whole effect, children only their first panel) + xStart = strip.panel[0].xOffset; + xEnd = strip.panel[0].xOffset + strip.panel[0].width; + yStart = strip.panel[0].yOffset; + yEnd = strip.panel[0].yOffset + strip.panel[0].height; + } + else { + xStart = 0; + xEnd = cols; + yStart = 0; + yEnd = rows; + } + // re-init if SEGMENT dimensions or offset changed if (SEGENV.call == 0 || SEGENV.aux0 != cols || SEGENV.aux1 != rows || SEGMENT.custom1 != *offsX || SEGMENT.custom2 != *offsY) { - SEGENV.step = 0; // t + if (!true) //WLEDMM SuperSync + SEGENV.step = 0; // t SEGENV.aux0 = cols; SEGENV.aux1 = rows; *offsX = SEGMENT.custom1; *offsY = SEGMENT.custom2; const uint8_t C_X = cols / 2 + (SEGMENT.custom1 - 128)*cols/255; const uint8_t C_Y = rows / 2 + (SEGMENT.custom2 - 128)*rows/255; - for (int x = 0; x < cols; x++) { - for (int y = 0; y < rows; y++) { + for (int x = xStart; x < xEnd; x++) { + for (int y = yStart; y < yEnd; y++) { rMap[XY(x, y)].angle = 40.7436f * atan2f(y - C_Y, x - C_X); // avoid 128*atan2()/PI rMap[XY(x, y)].radius = hypotf(x - C_X, y - C_Y) * mapp; //thanks Sutaburosu } } } - SEGENV.step += SEGMENT.speed / 32 + 1; // 1-4 range - for (int x = 0; x < cols; x++) { - for (int y = 0; y < rows; y++) { + if (true) // WLEDMM SuperSync + SEGENV.step = strip.now * (SEGMENT.speed / 32 + 1) / 25; // WLEDMM 40fps + else + SEGENV.step += SEGMENT.speed / 32 + 1; // 1-4 range + + for (int x = xStart; x < xEnd; x++) { + for (int y = yStart; y < yEnd; y++) { byte angle = rMap[XY(x,y)].angle; byte radius = rMap[XY(x,y)].radius; //CRGB c = CHSV(SEGENV.step / 2 - radius, 255, sin8(sin8((angle * 4 - radius) / 4 + SEGENV.step) + radius - SEGENV.step * 2 + angle * (SEGMENT.custom3/3+1))); @@ -7991,7 +8211,7 @@ uint16_t mode_2Doctopus() { } return FRAMETIME; } -static const char _data_FX_MODE_2DOCTOPUS[] PROGMEM = "Octopus@!,,Offset X,Offset Y,Legs;;!;2;"; +static const char _data_FX_MODE_2DOCTOPUS[] PROGMEM = "Octopus@!,,Offset X,Offset Y,Legs, SuperSync;;!;2;"; //Waving Cell @@ -8003,7 +8223,7 @@ uint16_t mode_2Dwavingcell() { const uint16_t cols = SEGMENT.virtualWidth(); const uint16_t rows = SEGMENT.virtualHeight(); - uint32_t t = millis()/(257-SEGMENT.speed); + uint32_t t = strip.now/(257-SEGMENT.speed); uint8_t aX = SEGMENT.custom1/16 + 9; uint8_t aY = SEGMENT.custom2/16 + 1; uint8_t aZ = SEGMENT.custom3 + 1; @@ -8023,7 +8243,7 @@ static const char _data_FX_MODE_2DWAVINGCELL[] PROGMEM = "Waving Cell@!,,Amplitu static const char _data_RESERVED[] PROGMEM = "RSVD"; // add (or replace reserved) effect mode and data into vector -// use id==255 to find unallocatd gaps (with "Reserved" data string) +// use id==255 to find unallocated gaps (with "Reserved" data string) // if vector size() is smaller than id (single) data is appended at the end (regardless of id) void WS2812FX::addEffect(uint8_t id, mode_ptr mode_fn, const char *mode_name) { if (id == 255) { // find empty slot @@ -8173,6 +8393,7 @@ void WS2812FX::setupEffectData() { // --- 1D audio effects --- addEffect(FX_MODE_PIXELS, &mode_pixels, _data_FX_MODE_PIXELS); addEffect(FX_MODE_PIXELWAVE, &mode_pixelwave, _data_FX_MODE_PIXELWAVE); + addEffect(FX_MODE_PARTYJERK, &mode_partyjerk, _data_FX_MODE_PARTYJERK); addEffect(FX_MODE_JUGGLES, &mode_juggles, _data_FX_MODE_JUGGLES); addEffect(FX_MODE_MATRIPIX, &mode_matripix, _data_FX_MODE_MATRIPIX); addEffect(FX_MODE_GRAVIMETER, &mode_gravimeter, _data_FX_MODE_GRAVIMETER); @@ -8206,6 +8427,11 @@ void WS2812FX::setupEffectData() { addEffect(FX_MODE_WAVESINS, &mode_wavesins, _data_FX_MODE_WAVESINS); addEffect(FX_MODE_ROCKTAVES, &mode_rocktaves, _data_FX_MODE_ROCKTAVES); + // --- WLEDSR experimental 1D audio enhanced + addEffect(FX_MODE_POPCORN_AR, &mode_popcorn_audio, _data_FX_MODE_POPCORN_AR); + addEffect(FX_MODE_STARBURST_AR, &mode_starburst_audio, _data_FX_MODE_STARBURST_AR); + addEffect(FX_MODE_FIREWORKS_AR, &mode_fireworks_audio, _data_FX_MODE_FIREWORKS_AR); + // --- 2D effects --- #ifndef WLED_DISABLE_2D addEffect(FX_MODE_2DSPACESHIPS, &mode_2Dspaceships, _data_FX_MODE_2DSPACESHIPS); diff --git a/wled00/FX.h b/wled00/FX.h index 93a4ae34..1cba9000 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -33,6 +33,7 @@ bool canUseSerial(void); // WLEDMM implemented in wled_serial.cpp void strip_wait_until_idle(String whoCalledMe); // WLEDMM implemented in FX_fcn.cpp +bool strip_uses_global_leds(void); // WLEDMM implemented in FX_fcn.cpp #define FASTLED_INTERNAL //remove annoying pragma messages #define USE_GET_MILLISECOND_TIMER @@ -334,8 +335,17 @@ void strip_wait_until_idle(String whoCalledMe); // WLEDMM implemented in FX_fcn. #define FX_MODE_ROCKTAVES 185 #define FX_MODE_2DAKEMI 186 #define FX_MODE_ARTIFX 187 //WLEDMM ARTIFX +#define FX_MODE_PARTYJERK 188 -#define MODE_COUNT 188 +// Experimental Audioresponsive modes from WLED-SR +// #define FX_MODE_3DSphereMove 189 // experimental WLED-SR "cube" mode +#define FX_MODE_POPCORN_AR 190 // WLED-SR audioreactive popcorn +// #define FX_MODE_MULTI_COMET_AR 191 // WLED-SR audioreactive multi-comet +#define FX_MODE_STARBURST_AR 192 // WLED-SR audioreactive fireworks starburst +// #define FX_MODE_PALETTE_AR 193 // WLED-SR audioreactive palette +#define FX_MODE_FIREWORKS_AR 194 // WLED-SR audioreactive fireworks + +#define MODE_COUNT 195 typedef enum mapping1D2D { M12_Pixels = 0, @@ -397,7 +407,7 @@ typedef struct Segment { uint16_t aux0; // custom var uint16_t aux1; // custom var byte* data = nullptr; // effect data pointer // WLEDMM initialize to nullptr - CRGB* ledsrgb = nullptr; // local leds[] array (may be a pointer to global) //WLEDMM rename to ledsrgb to search on them (temp?), and initialilize to nullptr + CRGB* ledsrgb = nullptr; // local leds[] array (may be a pointer to global) //WLEDMM rename to ledsrgb to search on them (temp?), and initialize to nullptr size_t ledsrgbSize; //WLEDMM static CRGB *_globalLeds; // global leds[] array static uint16_t maxWidth, maxHeight; // these define matrix width & height (max. segment dimensions) @@ -423,12 +433,12 @@ typedef struct Segment { uint8_t _briT; // temporary brightness uint8_t _cctT; // temporary CCT 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 blends possible) uint8_t _modeP; // previous mode/effect //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() + unsigned long _start; // must accommodate millis() uint16_t _dur; Transition(uint16_t dur=750) : _briT(255) @@ -507,7 +517,11 @@ typedef struct Segment { if (name) Serial.printf(" name=%s (%p)", name, name); if (data) Serial.printf(" dataLen=%d (%p)", (int)_dataLen, data); if (ledsrgb) Serial.printf(" [%sledsrgb %u bytes]", Segment::_globalLeds ? "global ":"",length()*sizeof(CRGB)); + if (strip_uses_global_leds() == true) Serial.println((Segment::_globalLeds != nullptr) ? F(" using global buffer.") : F(", using global buffer but Segment::_globalLeds is NULL!!")); Serial.println(); + #ifdef ARDUINO_ARCH_ESP32 + Serial.flush(); + #endif } #endif @@ -516,7 +530,7 @@ typedef struct Segment { strip_wait_until_idle("~Segment()"); #endif - if (!Segment::_globalLeds && (ledsrgb != nullptr)) {free(ledsrgb); ledsrgb = nullptr;} + if ((Segment::_globalLeds == nullptr) && !strip_uses_global_leds() && (ledsrgb != nullptr)) {free(ledsrgb); ledsrgb = nullptr;} // WLEDMM we need "!strip_uses_global_leds()" to avoid crashes (#104) if (name) { delete[] name; name = nullptr; } if (_t) { transitional = false; delete _t; _t = nullptr; } deallocateData(); diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 1452de7d..999684b1 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -51,8 +51,9 @@ void WS2812FX::setUpMatrix() { } } - // safety check - if (Segment::maxWidth * Segment::maxHeight > MAX_LEDS || Segment::maxWidth <= 1 || Segment::maxHeight <= 1) { + // safety check + // WLEDMM no check on Segment::maxWidth * Segment::maxHeight > MAX_LEDS || + if (Segment::maxWidth <= 1 || Segment::maxHeight <= 1) { DEBUG_PRINTF("2D Bounds error. %d x %d\n", Segment::maxWidth, Segment::maxHeight); isMatrix = false; Segment::maxWidth = _length; @@ -158,7 +159,7 @@ void WS2812FX::setUpMatrix() { } else { // memory allocation error customMappingTableSize = 0; USER_PRINTLN(F("Ledmap alloc error.")); - isMatrix = false; + isMatrix = false; //WLEDMM does not like this done in teh background while end users are confused whats happened... panels = 0; panel.clear(); Segment::maxWidth = _length; @@ -172,7 +173,7 @@ void WS2812FX::setUpMatrix() { } // absolute matrix version of setPixelColor() -void IRAM_ATTR_YN WS2812FX::setPixelColorXY(int x, int y, uint32_t col) //WLEDMM: IRAM_ATTR conditionaly +void IRAM_ATTR_YN WS2812FX::setPixelColorXY(int x, int y, uint32_t col) //WLEDMM: IRAM_ATTR conditionally { #ifndef WLED_DISABLE_2D if (!isMatrix) return; // not a matrix set-up @@ -206,7 +207,7 @@ uint32_t WS2812FX::getPixelColorXY(uint16_t x, uint16_t y) { // XY(x,y) - gets pixel index within current segment (often used to reference leds[] array element) // WLEDMM Segment::XY()is declared inline, see FX.h -void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) //WLEDMM: IRAM_ATTR conditionaly +void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) //WLEDMM: IRAM_ATTR conditionally { if (Segment::maxHeight==1) return; // not a matrix set-up if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 6b45977f..c62ae60d 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -82,7 +82,10 @@ void strip_wait_until_idle(String whoCalledMe) { } #endif } - +// WLEDMM another helper for segment class +bool strip_uses_global_leds(void) { + return strip.useLedsArray; +} /////////////////////////////////////////////////////////////////////////////// // Segment class implementation @@ -146,7 +149,7 @@ Segment::Segment(Segment &&orig) noexcept { orig.jMap = nullptr; //WLEDMM jMap } -// copy assignment --> overwrite segment withg orig - deletes old buffers in "this", but does not change orig! +// copy assignment --> overwrite segment with orig - deletes old buffers in "this", but does not change orig! Segment& Segment::operator= (const Segment &orig) { DEBUG_PRINTLN(F("-- Copy-assignment segment --")); if (this != &orig) { @@ -201,12 +204,14 @@ Segment& Segment::operator= (Segment &&orig) noexcept { } bool Segment::allocateData(size_t len) { - if (data && _dataLen >= len) { - if (call == 0) memset(data, 0, len); // WLEDMM: clear data when SEGENV.call==0 - return true; //already allocated + // WLEDMM + if (data && _dataLen >= len) { // already allocated enough (reduce fragmentation) + if ((call == 0) && (len > 0)) memset(data, 0, len); // erase buffer if called during effect initialisation + return true; } //DEBUG_PRINTF("allocateData(%u) start %d, stop %d, vlen %d\n", len, start, stop, virtualLength()); deallocateData(); + if (len == 0) return false; // nothing to do if (Segment::getUsedSegmentData() + len > MAX_SEGMENT_DATA) return false; //not enough memory // do not use SPI RAM on ESP32 since it is slow //#if defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM) && defined(WLED_USE_PSRAM) @@ -271,7 +276,7 @@ void Segment::setUpLeds() { } CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) { - static unsigned long _lastPaletteChange = 0; // perhaps it should be per segment + static unsigned long _lastPaletteChange = millis() - 990000; // perhaps it should be per segment //WLEDMM changed init value to avoid pure orange after startup static CRGBPalette16 randomPalette = CRGBPalette16(DEFAULT_COLOR); static CRGBPalette16 prevRandomPalette = CRGBPalette16(CRGB(BLACK)); byte tcp[76] = { 255 }; //WLEDMM: prevent out-of-range access in loadDynamicGradientPalette() @@ -294,7 +299,7 @@ CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) { switch (pal) { case 0: //default palette. Exceptions for specific effects above targetPalette = PartyColors_p; break; - case 1: {//periodically replace palette with a random one. Transition palette change in 500ms + case 1: {//Random smooth: periodically replace palette with a random one. Transition palette change in 500ms uint32_t timeSinceLastChange = millis() - _lastPaletteChange; if (timeSinceLastChange > randomPaletteChangeTime * 1000U) { prevRandomPalette = randomPalette; @@ -349,7 +354,7 @@ CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) { CRGB sec = gamma32(colors[1]); CRGB ter = gamma32(colors[2]); targetPalette = CRGBPalette16(ter,sec,prim); break;} - case 5: {//primary + secondary (+tert if not off), more distinct + case 5: {//primary + secondary (+tertiary if not off), more distinct CRGB prim = gamma32(colors[0]); CRGB sec = gamma32(colors[1]); if (colors[2]) { @@ -833,7 +838,7 @@ void xyFromBlock(uint16_t &x,uint16_t &y, uint16_t i, uint16_t vW, uint16_t vH, } -void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) //WLEDMM: IRAM_ATTR conditionaly +void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) //WLEDMM: IRAM_ATTR conditionally { if (!isActive()) return; // not active #ifndef WLED_DISABLE_2D @@ -942,7 +947,7 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) //WLEDMM: IRAM_ATT uint16_t len = length(); uint8_t _bri_t = currentBri(on ? opacity : 0); - if (!_bri_t && !transitional && fadeTransition) return; // if _bri_t == 0 && segment is not transitionig && transitions are enabled then save a few CPU cycles + if (!_bri_t && !transitional && fadeTransition) return; // if _bri_t == 0 && segment is not transitioning && transitions are enabled then save a few CPU cycles if (_bri_t < 255) { byte r = scale8(R(col), _bri_t); byte g = scale8(G(col), _bri_t); @@ -1223,7 +1228,7 @@ void Segment::fade_out(uint8_t rate) { int g1 = G(color); int b1 = B(color); - int wdelta = mappedRate_r * (w2 - w1); // WLEDMM use receprocal - its faster + int wdelta = mappedRate_r * (w2 - w1); // WLEDMM use reciprocal - its faster int rdelta = mappedRate_r * (r2 - r1); int gdelta = mappedRate_r * (g2 - g1); int bdelta = mappedRate_r * (b2 - b1); @@ -1502,7 +1507,7 @@ void WS2812FX::enumerateLedmaps() { void WS2812FX::finalizeInit(void) { //reset segment runtimes - suspendStripService = true; // WELDMM avoid running effects on an incomplete strip + suspendStripService = true; // WLEDMM avoid running effects on an incomplete strip for (segment &seg : _segments) { seg.markForReset(); seg.resetIfRequired(); @@ -1583,11 +1588,11 @@ void WS2812FX::finalizeInit(void) DEBUG_PRINTLN(F("Loading custom ledmaps")); deserializeMap(); // (re)load default ledmap _isServicing = false; // WLEDMM - suspendStripService = false; // WELDMM ready, run ! + suspendStripService = false; // WLEDMM ready, run ! } // WLEDMM wait until strip is idle (=not servicing). -// on 8266 this function does nothing, because we can only do "buisy waiting" on ESP32 +// on 8266 this function does nothing, because we can only do "busy waiting" on ESP32 #define MAX_IDLE_WAIT_MS 50 // seems to work in most cases void WS2812FX::waitUntilIdle(void) { #if defined(ARDUINO_ARCH_ESP32) && defined(WLEDMM_PROTECT_SERVICE) @@ -1755,7 +1760,7 @@ void WS2812FX::estimateCurrentAndLimitBri() { uint8_t scaleB = (scaleI > 255) ? 255 : scaleI; uint8_t newBri = scale8(_brightness, scaleB); // to keep brightness uniform, sets virtual busses too - softhack007: apply reductions immediately - if (scaleB < 255) busses.setBrightness(scaleB, true); // NPB-LG has already applied brightness, so its suffifient to post-apply scaling ==> use scaleB instead of newBri + if (scaleB < 255) busses.setBrightness(scaleB, true); // NPB-LG has already applied brightness, so its sufficient to post-apply scaling ==> use scaleB instead of newBri busses.setBrightness(newBri, false); // set new brightness for next frame //currentMilliamps = (powerSum0 * newBri) / puPerMilliamp; // for NPBrightnessBus currentMilliamps = (powerSum0 * scaleB) / puPerMilliamp; // for NPBus-LG @@ -1768,8 +1773,7 @@ void WS2812FX::estimateCurrentAndLimitBri() { } void WS2812FX::show(void) { - - // avoid race condition, caputre _callback value + // avoid race condition, capture _callback value show_callback callback = _callback; if (callback) callback(); @@ -1788,7 +1792,7 @@ void WS2812FX::show(void) { if (diff > 0) fpsCurr = 1000 / diff; _cumulativeFps = (3 * _cumulativeFps + fpsCurr +2) >> 2; // "+2" for proper rounding (2/4 = 0.5) #if defined(ARDUINO_ARCH_ESP32) && defined(WLEDMM_FASTPATH) - _lastShow = b4show; // WLEDMM this is more accurate, however it also icreases CPU load - strip.service will run more frequently + _lastShow = b4show; // WLEDMM this is more accurate, however it also increases CPU load - strip.service will run more frequently #else _lastShow = now; #endif @@ -1815,7 +1819,7 @@ bool WS2812FX::isUpdating() { /** * Returns the refresh rate of the LED strip. Useful for finding out whether a given setup is fast enough. - * Only updates on show() or is set to 0 fps if last show is more than 2 secs ago, so accurary varies + * Only updates on show() or is set to 0 fps if last show is more than 2 secs ago, so accuracy varies */ uint16_t WS2812FX::getFps() { if (millis() - _lastShow > 2000) return 0; @@ -1976,7 +1980,7 @@ void WS2812FX::purgeSegments(bool force) { } if (deleted) { _segments.shrink_to_fit(); - if (_mainSegment >= _segments.size()) setMainSegmentId(0); + /*if (_mainSegment >= _segments.size())*/ setMainSegmentId(0); } } @@ -2235,7 +2239,7 @@ bool WS2812FX::deserializeMap(uint8_t n) { if (n) sprintf(fileName +7, "%d", n); //WLEDMM: trick to not include 0 in ledmap.json strcat(fileName, ".json"); isFile = WLED_FS.exists(fileName); - } else { //WLEDM add segment name as ledmap.name + } else { //WLEDMM add segment name as ledmap.name uint8_t segment_index = 0; for (segment &seg : _segments) { if (n == 10 + segment_index && !isFile && seg.name != nullptr) { @@ -2249,7 +2253,7 @@ bool WS2812FX::deserializeMap(uint8_t n) { if (!isFile) { // erase custom mapping if selecting nonexistent ledmap.json (n==0) - //WLEDM: doubt this is necessary as return false causes setupMatrix to deal with this !!!! + //WLEDMM: doubt this is necessary as return false causes setupMatrix to deal with this !!!! if (!isMatrix && !n) { customMappingSize = 0; loadedLedmap = 0; //WLEDMM diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 2f330b75..14e0888a 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -70,7 +70,7 @@ void ColorOrderMap::add(uint16_t start, uint16_t len, uint8_t colorOrder) { uint8_t IRAM_ATTR ColorOrderMap::getPixelColorOrder(uint16_t pix, uint8_t defaultColorOrder) const { if (_count == 0) return defaultColorOrder; - // upper nibble containd W swap information + // upper nibble contains W swap information uint8_t swapW = defaultColorOrder >> 4; for (uint8_t i = 0; i < _count; i++) { if (pix >= _mappings[i].start && pix < (_mappings[i].start + _mappings[i].len)) { @@ -83,7 +83,7 @@ uint8_t IRAM_ATTR ColorOrderMap::getPixelColorOrder(uint16_t pix, uint8_t defaul uint32_t Bus::autoWhiteCalc(uint32_t c) { uint8_t aWM = _autoWhiteMode; - if (_gAWM < 255) aWM = _gAWM; + if (_gAWM != AW_GLOBAL_DISABLED) aWM = _gAWM; if (aWM == RGBW_MODE_MANUAL_ONLY) return c; uint8_t w = W(c); //ignore auto-white calculation if w>0 and mode DUAL (DUAL behaves as BRIGHTER if w==0) diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index 220fd930..2f860ae1 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -98,7 +98,7 @@ class Bus { { _type = type; _start = start; - _autoWhiteMode = Bus::hasWhite(_type) ? aw : RGBW_MODE_MANUAL_ONLY; + _autoWhiteMode = Bus::hasWhite(type) ? aw : RGBW_MODE_MANUAL_ONLY; }; virtual ~Bus() {} //throw the bus under the bus @@ -129,7 +129,7 @@ class Bus { } virtual bool hasWhite() { return Bus::hasWhite(_type); } static bool hasWhite(uint8_t type) { - if ((type >= TYPE_WS2812_1CH && type <= TYPE_WS2812_WWA) || type == TYPE_SK6812_RGBW || type == TYPE_TM1814) return true; // digital types with white channel + if ((type >= TYPE_WS2812_1CH && type <= TYPE_WS2812_WWA) || type == TYPE_SK6812_RGBW || type == TYPE_TM1814 || type == TYPE_UCS8904) return true; // digital types with white channel if (type > TYPE_ONOFF && type <= TYPE_ANALOG_5CH && type != TYPE_ANALOG_3CH) return true; // analog types with white channel if (type == TYPE_NET_DDP_RGBW) return true; // network types with white channel return false; diff --git a/wled00/bus_wrapper.h b/wled00/bus_wrapper.h index 8473938e..a5b9d7a7 100644 --- a/wled00/bus_wrapper.h +++ b/wled00/bus_wrapper.h @@ -69,17 +69,17 @@ #define I_32_RN_NEO_3 21 #define I_32_I0_NEO_3 22 #define I_32_I1_NEO_3 23 -#define I_32_BB_NEO_3 24 // bitbangging on ESP32 not recommended +#define I_32_BB_NEO_3 24 // bitbanging on ESP32 not recommended //RGBW #define I_32_RN_NEO_4 25 #define I_32_I0_NEO_4 26 #define I_32_I1_NEO_4 27 -#define I_32_BB_NEO_4 28 // bitbangging on ESP32 not recommended +#define I_32_BB_NEO_4 28 // bitbanging on ESP32 not recommended //400Kbps #define I_32_RN_400_3 29 #define I_32_I0_400_3 30 #define I_32_I1_400_3 31 -#define I_32_BB_400_3 32 // bitbangging on ESP32 not recommended +#define I_32_BB_400_3 32 // bitbanging on ESP32 not recommended //TM1814 (RGBW) #define I_32_RN_TM1_4 33 #define I_32_I0_TM1_4 34 @@ -374,7 +374,7 @@ class PolyBus { case I_32_I1_UCS_4: (static_cast(busPtr))->Begin(); break; #endif // case I_32_BB_UCS_4: (static_cast(busPtr))->Begin(); break; - // ESP32 can (and should, to avoid inadvertantly driving the chip select signal) specify the pins used for SPI, but only in begin() + // ESP32 can (and should, to avoid inadvertently driving the chip select signal) specify the pins used for SPI, but only in begin() case I_HS_DOT_3: beginDotStar(busPtr, pins[1], -1, pins[0], -1, clock_kHz); break; case I_HS_LPD_3: beginDotStar(busPtr, pins[1], -1, pins[0], -1, clock_kHz); break; case I_HS_LPO_3: beginDotStar(busPtr, pins[1], -1, pins[0], -1, clock_kHz); break; diff --git a/wled00/button.cpp b/wled00/button.cpp index 053d59dd..60df15eb 100644 --- a/wled00/button.cpp +++ b/wled00/button.cpp @@ -171,13 +171,12 @@ void handleAnalog(uint8_t b) // remove noise & reduce frequency of UI updates if (abs(int(aRead) - int(oldRead[b])) <= POT_SENSITIVITY) return; // no significant change in reading - // Unomment the next lines if you still see flickering related to potentiometer + // Un-comment the next lines if you still see flickering related to potentiometer // This waits until strip finishes updating (why: strip was not updating at the start of handleButton() but may have started during analogRead()?) //unsigned long wait_started = millis(); //while(strip.isUpdating() && (millis() - wait_started < STRIP_WAIT_TIME)) { // delay(1); //} - //if (strip.isUpdating()) return; // give up oldRead[b] = aRead; @@ -375,7 +374,7 @@ void handleIO() if (!offMode) { #ifdef ESP8266 // turn off built-in LED if strip is turned off - // this will break digital bus so will need to be reinitialised on On + // this will break digital bus so will need to be re-initialised on On PinOwner ledPinOwner = pinManager.getPinOwner(LED_BUILTIN); if (!strip.isOffRefreshRequired() && (ledPinOwner == PinOwner::None || ledPinOwner == PinOwner::BusDigital)) { pinMode(LED_BUILTIN, OUTPUT); @@ -392,4 +391,4 @@ void handleIO() } offMode = true; } -} \ No newline at end of file +} diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index bb2c9476..54c32f9c 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -83,7 +83,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { noWifiSleep = doc[F("wifi")][F("sleep")] | !noWifiSleep; // inverted noWifiSleep = !noWifiSleep; - //int wifi_phy = doc[F("wifi")][F("phy")]; //force phy mode n? + force802_3g = doc[F("wifi")][F("phy")] | force802_3g; //force phy mode g? JsonObject hw = doc[F("hw")]; @@ -103,10 +103,9 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { } #endif - uint8_t autoWhiteMode = RGBW_MODE_MANUAL_ONLY; CJSON(strip.ablMilliampsMax, hw_led[F("maxpwr")]); CJSON(strip.milliampsPerLed, hw_led[F("ledma")]); - Bus::setGlobalAWMode(hw_led[F("rgbwm")] | 255); + Bus::setGlobalAWMode(hw_led[F("rgbwm")] | AW_GLOBAL_DISABLED); CJSON(correctWB, hw_led["cct"]); CJSON(cctFromRgb, hw_led[F("cr")]); CJSON(strip.cctBlending, hw_led[F("cb")]); @@ -185,7 +184,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { } uint16_t length = elm["len"] | 1; - uint8_t colorOrder = (int)elm[F("order")]; + uint8_t colorOrder = (int)elm[F("order")]; // contains white channel swap option in upper nibble uint8_t skipFirst = elm[F("skip")]; uint16_t start = elm["start"] | 0; if (length==0 || start + length > MAX_LEDS) continue; // zero length or we reached max. number of LEDs, just stop @@ -194,7 +193,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { bool refresh = elm["ref"] | false; uint16_t freqkHz = elm[F("freq")] | 0; // will be in kHz for DotStar and Hz for PWM (not yet implemented fully) ledType |= refresh << 7; // hack bit 7 to indicate strip requires off refresh - uint8_t AWmode = elm[F("rgbwm")] | autoWhiteMode; + uint8_t AWmode = elm[F("rgbwm")] | RGBW_MODE_MANUAL_ONLY; if (fromFS) { BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz); mem += BusManager::memUsage(bc); @@ -338,7 +337,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { PinManagerPinType i2c[2] = { { i2c_sda, true }, { i2c_scl, true } }; if (i2c_scl >= 0 && i2c_sda >= 0 && pinManager.allocateMultiplePins(i2c, 2, PinOwner::HW_I2C)) { #ifdef ESP32 - Wire.setPins(i2c_sda, i2c_scl); // this will fail if Wire is initilised (Wire.begin() called prior) + Wire.setPins(i2c_sda, i2c_scl); // this will fail if Wire is initialised (Wire.begin() called prior) #endif // Wire.begin(); // WLEDMM moved into pinManager DEBUG_PRINTF("pinmgr success for global i2c %d %d\n", i2c_sda, i2c_scl); @@ -364,45 +363,49 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { //int hw_status_pin = hw[F("status")]["pin"]; // -1 JsonObject light = doc[F("light")]; - CJSON(briMultiplier, light[F("scale-bri")]); - CJSON(strip.paletteBlend, light[F("pal-mode")]); - CJSON(autoSegments, light[F("aseg")]); + byte prev; //WLEDMM + int tdd; //WLEDMM + if (!light.isNull()) { //WLEDMM: in case cfg string does not contain light! (solves issue that sometimes gamma correction dissappears) + CJSON(briMultiplier, light[F("scale-bri")]); + CJSON(strip.paletteBlend, light[F("pal-mode")]); + CJSON(autoSegments, light[F("aseg")]); - CJSON(gammaCorrectVal, light["gc"]["val"]); // default 2.8 - float light_gc_bri = light["gc"]["bri"]; - float light_gc_col = light["gc"]["col"]; - float light_gc_prev = light["gc"]["prev"]; // WLEDMM - if (light_gc_bri > 1.0f) gammaCorrectBri = true; - else gammaCorrectBri = false; - if (light_gc_col > 1.0f) gammaCorrectCol = true; - else gammaCorrectCol = false; - if (light_gc_prev > 1.0f) gammaCorrectPreview = true; // WLEDMM - else gammaCorrectPreview = false; // WLEDMM - if (gammaCorrectVal > 1.0f && gammaCorrectVal <= 3) { - if (gammaCorrectVal != 2.8f) calcGammaTable(gammaCorrectVal); - } else { - gammaCorrectVal = 1.0f; // no gamma correction - gammaCorrectBri = false; - gammaCorrectCol = false; - gammaCorrectPreview = false; // WLEDMM + CJSON(gammaCorrectVal, light["gc"]["val"]); // default 2.8 + float light_gc_bri = light["gc"]["bri"]; + float light_gc_col = light["gc"]["col"]; + float light_gc_prev = light["gc"]["prev"]; // WLEDMM + if (light_gc_bri > 1.0f) gammaCorrectBri = true; + else gammaCorrectBri = false; + if (light_gc_col > 1.0f) gammaCorrectCol = true; + else gammaCorrectCol = false; + if (light_gc_prev > 1.0f) gammaCorrectPreview = true; // WLEDMM + else gammaCorrectPreview = false; // WLEDMM + if (gammaCorrectVal > 1.0f && gammaCorrectVal <= 3) { + if (gammaCorrectVal != 2.8f) calcGammaTable(gammaCorrectVal); + } else { + gammaCorrectVal = 1.0f; // no gamma correction + gammaCorrectBri = false; + gammaCorrectCol = false; + gammaCorrectPreview = false; // WLEDMM + } + + JsonObject light_tr = light["tr"]; + CJSON(fadeTransition, light_tr["mode"]); + tdd = light_tr["dur"] | -1; + if (tdd >= 0) transitionDelay = transitionDelayDefault = tdd * 100; + CJSON(strip.paletteFade, light_tr["pal"]); + CJSON(randomPaletteChangeTime, light_tr[F("rpc")]); + + JsonObject light_nl = light["nl"]; + CJSON(nightlightMode, light_nl["mode"]); + prev = nightlightDelayMinsDefault; + CJSON(nightlightDelayMinsDefault, light_nl["dur"]); + if (nightlightDelayMinsDefault != prev) nightlightDelayMins = nightlightDelayMinsDefault; + + CJSON(nightlightTargetBri, light_nl[F("tbri")]); + CJSON(macroNl, light_nl["macro"]); } - JsonObject light_tr = light["tr"]; - CJSON(fadeTransition, light_tr["mode"]); - int tdd = light_tr["dur"] | -1; - if (tdd >= 0) transitionDelay = transitionDelayDefault = tdd * 100; - CJSON(strip.paletteFade, light_tr["pal"]); - CJSON(randomPaletteChangeTime, light_tr[F("rpc")]); - - JsonObject light_nl = light["nl"]; - CJSON(nightlightMode, light_nl["mode"]); - byte prev = nightlightDelayMinsDefault; - CJSON(nightlightDelayMinsDefault, light_nl["dur"]); - if (nightlightDelayMinsDefault != prev) nightlightDelayMins = nightlightDelayMinsDefault; - - CJSON(nightlightTargetBri, light_nl[F("tbri")]); - CJSON(macroNl, light_nl["macro"]); - JsonObject def = doc["def"]; CJSON(bootPreset, def["ps"]); CJSON(turnOnAtBoot, def["on"]); // true @@ -732,7 +735,7 @@ void serializeConfig() { JsonObject wifi = doc.createNestedObject("wifi"); wifi[F("sleep")] = !noWifiSleep; - //wifi[F("phy")] = 1; + wifi[F("phy")] = force802_3g; #ifdef WLED_USE_ETHERNET JsonObject ethernet = doc.createNestedObject("eth"); @@ -786,6 +789,11 @@ void serializeConfig() { matrix[F("pv")] = strip.matrix.vertical; matrix["ps"] = strip.matrix.serpentine; + matrix[F("pbl")] = strip.panelO.bottomStart; + matrix[F("prl")] = strip.panelO.rightStart; + matrix[F("pvl")] = strip.panelO.vertical; + matrix["psl"] = strip.panelO.serpentine; + JsonArray panels = matrix.createNestedArray(F("panels")); for (uint8_t i=0; i8bit) that was proposed during discussion of issue #2767 // https://github.com/Aircoookie/WLED/issues/2767#issuecomment-1310961308 -// unfortunately NepixelsBu has its own internal table, that kills low brightness values similar to the original WLED table. +// unfortunately NeoPixelBus has its own internal table, that kills low brightness values similar to the original WLED table. // see https://github.com/Makuna/NeoPixelBus/blob/master/src/internal/NeoGamma.h static const byte gammaT[256] = { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, diff --git a/wled00/const.h b/wled00/const.h index 24095e3a..bb8c7a98 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -132,7 +132,10 @@ #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_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_INTERNAL_TEMPERATURE 42 //Usermod "usermod_internal_temperature.h" +#define USERMOD_ID_LDR_DUSK_DAWN 43 //Usermod "usermod_LDR_Dusk_Dawn_v2.h" //WLEDMM #define USERMOD_ID_MCUTEMP 89 //Usermod "usermod_v2_artifx.h" #define USERMOD_ID_ARTIFX 90 //Usermod "usermod_v2_artifx.h" @@ -155,7 +158,7 @@ #define CALL_MODE_NO_NOTIFY 5 #define CALL_MODE_FX_CHANGED 6 //no longer used #define CALL_MODE_HUE 7 -#define CALL_MODE_PRESET_CYCLE 8 +#define CALL_MODE_PRESET_CYCLE 8 //no longer used #define CALL_MODE_BLYNK 9 //no longer used #define CALL_MODE_ALEXA 10 #define CALL_MODE_WS_SEND 11 //special call mode, not for notifier, updates websocket only @@ -196,8 +199,8 @@ #define DMX_MODE_MULTIPLE_RGB 4 //every LED is addressed with its own RGB (ledCount * 3 channels) #define DMX_MODE_MULTIPLE_DRGB 5 //every LED is addressed with its own RGB and share a master dimmer (ledCount * 3 + 1 channels) #define DMX_MODE_MULTIPLE_RGBW 6 //every LED is addressed with its own RGBW (ledCount * 4 channels) -#define DMX_MODE_EFFECT_SEGMENT 8 //trigger standalone effects of WLED (15 channels per segement) -#define DMX_MODE_EFFECT_SEGMENT_W 9 //trigger standalone effects of WLED (18 channels per segement) +#define DMX_MODE_EFFECT_SEGMENT 8 //trigger standalone effects of WLED (15 channels per segment) +#define DMX_MODE_EFFECT_SEGMENT_W 9 //trigger standalone effects of WLED (18 channels per segment) #define DMX_MODE_PRESET 10 //apply presets (1 channel) //Light capability byte (unused) 0bRCCCTTTT @@ -273,7 +276,7 @@ #define BTN_TYPE_ANALOG_INVERTED 8 //Ethernet board types -#define WLED_NUM_ETH_TYPES 11 +#define WLED_NUM_ETH_TYPES 12 //WLEDMM +1 for Olimex ESP32-Gateway #define WLED_ETH_NONE 0 #define WLED_ETH_WT32_ETH01 1 @@ -286,6 +289,7 @@ #define WLED_ETH_QUINLED_OCTA 8 #define WLED_ETH_ABCWLEDV43ETH 9 #define WLED_ETH_SERG74 10 +#define WLED_ETH_OLIMEX_GTW 11 //Hue error codes #define HUE_ERROR_INACTIVE 0 @@ -313,7 +317,7 @@ #define SEG_DIFFERS_OPT 0x02 // all segment options except: selected, reset & transitional #define SEG_DIFFERS_COL 0x04 // colors #define SEG_DIFFERS_FX 0x08 // effect/mode parameters -#define SEG_DIFFERS_BOUNDS 0x10 // segment start/stop ounds +#define SEG_DIFFERS_BOUNDS 0x10 // segment start/stop bounds #define SEG_DIFFERS_GSO 0x20 // grouping, spacing & offset #define SEG_DIFFERS_SEL 0x80 // selected @@ -327,26 +331,46 @@ // WLED Error modes #define ERR_NONE 0 // All good :) -#define ERR_EEP_COMMIT 2 // Could not commit to EEPROM (wrong flash layout?) +#define ERR_DENIED 1 // Permission denied +#define ERR_EEP_COMMIT 2 // Could not commit to EEPROM (wrong flash layout?) OBSOLETE #define ERR_NOBUF 3 // JSON buffer was not released in time, request cannot be handled at this time #define ERR_JSON 9 // JSON parsing failed (input too large?) #define ERR_FS_BEGIN 10 // Could not init filesystem (no partition?) #define ERR_FS_QUOTA 11 // The FS is full or the maximum file size is reached #define ERR_FS_PLOAD 12 // It was attempted to load a preset that does not exist #define ERR_FS_IRLOAD 13 // It was attempted to load an IR JSON cmd, but the "ir.json" file does not exist -#define ERR_FS_GENERAL 19 // A general unspecified filesystem error occured +#define ERR_FS_RMLOAD 14 // It was attempted to load an remote JSON cmd, but the "remote.json" file does not exist +#define ERR_FS_GENERAL 19 // A general unspecified filesystem error occurred #define ERR_OVERTEMP 30 // An attached temperature sensor has measured above threshold temperature (not implemented) #define ERR_OVERCURRENT 31 // An attached current sensor has measured a current above the threshold (not implemented) #define ERR_UNDERVOLT 32 // An attached voltmeter has measured a voltage below the threshold (not implemented) -//Timer mode types +// Timer mode types #define NL_MODE_SET 0 //After nightlight time elapsed, set to target brightness #define NL_MODE_FADE 1 //Fade to target brightness gradually #define NL_MODE_COLORFADE 2 //Fade to target brightness and secondary color gradually #define NL_MODE_SUN 3 //Sunrise/sunset. Target brightness is set immediately, then Sunrise effect is started. Max 60 min. +// Settings sub page IDs +#define SUBPAGE_MENU 0 +#define SUBPAGE_WIFI 1 +#define SUBPAGE_LEDS 2 +#define SUBPAGE_UI 3 +#define SUBPAGE_SYNC 4 +#define SUBPAGE_TIME 5 +#define SUBPAGE_SEC 6 +#define SUBPAGE_DMX 7 +#define SUBPAGE_UM 8 +#define SUBPAGE_UPDATE 9 +#define SUBPAGE_2D 10 +#define SUBPAGE_LOCK 251 +#define SUBPAGE_PINREQ 252 +#define SUBPAGE_CSS 253 +#define SUBPAGE_JS 254 +#define SUBPAGE_WELCOME 255 -#define NTP_PACKET_SIZE 48 +#define NTP_PACKET_SIZE 48 // size of NTP receive buffer +#define NTP_MIN_PACKET_SIZE 48 // min expected size - NTP v4 allows for "extended information" appended to the standard fields //maximum number of rendered LEDs - this does not have to match max. physical LEDs, e.g. if there are virtual busses #ifndef MAX_LEDS @@ -377,7 +401,11 @@ #ifdef ESP8266 #define SETTINGS_STACK_BUF_SIZE 2048 #else -#define SETTINGS_STACK_BUF_SIZE 3792 // WLEDMM added 696 bytes of margin (was 3096) for audioreactive UI + #if !defined(USERMOD_AUDIOREACTIVE) + #define SETTINGS_STACK_BUF_SIZE 3834 // WLEDMM added 696+32 bytes of margin (was 3096) + #else + #define SETTINGS_STACK_BUF_SIZE 3904 // WLEDMM more buffer for audioreactive UI (add '-D CONFIG_ASYNC_TCP_TASK_STACK_SIZE=9216' to your build_flags) + #endif #endif #ifdef WLED_USE_ETHERNET @@ -418,12 +446,12 @@ #if defined(BOARD_HAS_PSRAM) && (defined(WLED_USE_PSRAM) || defined(WLED_USE_PSRAM_JSON)) #if defined(ARDUINO_ARCH_ESP32S2) || defined(ARDUINO_ARCH_ESP32C3) #if defined(ARDUINO_ARCH_ESP32C3) - #define JSON_BUFFER_SIZE 46000 // WLEDMM - max 46KB on -C3 with PSRAM (chip has 400kb RAM) + #define JSON_BUFFER_SIZE 44000 // WLEDMM - max 44KB on -C3 with PSRAM (chip has 400kb RAM) #else - #define JSON_BUFFER_SIZE 36000 // WLEDMM - max 36KB on -S2 with PSRAM (chip has 320kb RAM) + #define JSON_BUFFER_SIZE 28000 // WLEDMM - max 28KB on -S2 with PSRAM (chip has 320kb RAM) #endif #else - #define JSON_BUFFER_SIZE 56000 // WLEDMM (was 60000) slightly reduced to avoid build error "region dram0_0_seg overflowed" + #define JSON_BUFFER_SIZE 54000 // WLEDMM (was 60000) slightly reduced to avoid build error "region dram0_0_seg overflowed" #endif #else #define JSON_BUFFER_SIZE 24576 @@ -442,8 +470,9 @@ //this is merely a default now and can be changed at runtime #ifndef LEDPIN -#if defined(ESP8266) || (defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM)) || defined(CONFIG_IDF_TARGET_ESP32C3) - #define LEDPIN 2 // GPIO2 (D4) on Wemod D1 mini compatible boards + +#if defined(ESP8266) || (defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM)) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(ARDUINO_ESP32_PICO) //WLEDMM + #define LEDPIN 2 // GPIO2 (D4) on Wemos D1 mini compatible boards, and on boards where GPIO16 is not available #else #define LEDPIN 16 // aligns with GPIO2 (D4) on Wemos D1 mini32 compatible boards #endif @@ -464,7 +493,7 @@ #define INTERFACE_UPDATE_COOLDOWN 2000 //time in ms to wait between websockets, alexa, and MQTT updates // HW_PIN_SCL & HW_PIN_SDA are used for information in usermods settings page and usermods themselves -// which GPIO pins are actually used in a hardwarea layout (controller board) +// which GPIO pins are actually used in a hardware layout (controller board) //WLEDMM: unchangeable pins are not treated here by undef them, but elsewhere in the code // defaults for 1st I2C on ESP32 (Wire global) #ifndef HW_PIN_SCL @@ -475,7 +504,7 @@ #endif // HW_PIN_SCLKSPI & HW_PIN_MOSISPI & HW_PIN_MISOSPI are used for information in usermods settings page and usermods themselves -// which GPIO pins are actually used in a hardwarea layout (controller board) +// which GPIO pins are actually used in a hardware layout (controller board) //WLEDMM: unchangeable pins are not treated here by undef them, but elsewhere in the code // defaults for VSPI on ESP32 (SPI global, SPI.cpp) as HSPI is used by WLED (bus_wrapper.h) #ifndef HW_PIN_CLOCKSPI diff --git a/wled00/data/cpal/cpal.htm b/wled00/data/cpal/cpal.htm index 5a8c801e..773c02d2 100644 --- a/wled00/data/cpal/cpal.htm +++ b/wled00/data/cpal/cpal.htm @@ -1,6 +1,7 @@ + @@ -45,6 +46,7 @@ width: 7px; top: 50%; transform: translateY(-50%); + touch-action: none; } .color-picker-marker { height: 7px; @@ -94,9 +96,14 @@ line-height: 1; } .wrap { - width: 800px; + width: 100%; margin: 0 auto; } + @media (min-width: 800px) { + .wrap { + width: 800px; + } + } .palette { height: 20px; } @@ -136,6 +143,9 @@ .sendSpan, .editSpan{ cursor: pointer; } + h1 { + font-size: 1.6rem; + } @@ -191,6 +201,7 @@ var gradientLength = rect.width; var mOffs = Math.round((gradientLength / 256) / 2) - 5; var paletteArray = []; //Holds the palettes after load. + var paletteName = []; // Holds the names of the palettes after load. var svgSave = '' var svgEdit = '' @@ -349,24 +360,31 @@ var gradientLength = maxX - minX + 1; elmnt.onmousedown = dragMouseDown; + elmnt.ontouchstart = dragMouseDown; function dragMouseDown(e) { removeTrashcan(event) e = e || window.event; - e.preventDefault(); + var isTouch = e.type.startsWith('touch'); + if (!isTouch) e.preventDefault(); // get the mouse cursor position at startup: - mousePos = e.clientX; + mousePos = isTouch ? e.touches[0].clientX : e.clientX; d.onmouseup = closeDragElement; + d.ontouchcancel = closeDragElement; + d.ontouchend = closeDragElement; // call a function whenever the cursor moves: d.onmousemove = elementDrag; + d.ontouchmove = elementDrag; } function elementDrag(e) { e = e || window.event; - e.preventDefault(); + var isTouch = e.type.startsWith('touch'); + if (!isTouch) e.preventDefault(); // calculate the new cursor position: - posNew = mousePos - e.clientX; - mousePos = e.clientX; + var clientX = isTouch ? e.touches[0].clientX : e.clientX; + posNew = mousePos - clientX; + mousePos = clientX; mousePosInGradient = mousePos - (minX + 1) truePos = Math.round((mousePosInGradient/gradientLength)*256); @@ -393,7 +411,10 @@ function closeDragElement() { /* stop moving when mouse button is released:*/ d.onmouseup = null; + d.ontouchcancel = null; + d.ontouchend = null; d.onmousemove = null; + d.ontouchmove = null; } } @@ -485,7 +506,7 @@ console.log('Error: ', e); console.log(' Status: ', this.status); //Show some error notification for some time setTimeout(()=>{ - //Remove it when time has pased + //Remove it when time has passed }, 1000); }); req.open("POST", "/upload"); @@ -500,8 +521,10 @@ if (hst.length > 0 ) { try { var arr = []; - const response = await fetch('http://'+hst+'/json/info'); - const json = await response.json(); + const responseInfo = await fetch('http://'+hst+'/json/info'); + const responsePalettes = await fetch('http://'+hst+'/json/palettes'); + const json = await responseInfo.json(); + paletteName = await responsePalettes.json(); cpalc = json.cpalcount; fetchPalettes(cpalc-1); } catch (error) { @@ -530,7 +553,7 @@ paletteArray.push({"palette":[0,70,70,70,255,70,70,70]}); } - //Get static palettes from localStorage and do some magic to reformat them into the same format as the pallete JSONs + //Get static palettes from localStorage and do some magic to reformat them into the same format as the palette JSONs //This code excludes any objects with "non valid integer colors", i.e. r, c1, c2, c3 and such //This code also fixes potentially broken palettes which doesn't end on 255 //The code finally also removes any representations of the custom palettes, since we read them from file @@ -540,6 +563,7 @@ alert("The cache of palettes are missig from your browser. You should probably return to the main page and let it load properly for the palettes cache to regenerate before returning here.","Missing cached palettes!") } else { for (const key in wledPalx.p) { + wledPalx.p[key].name = paletteName[key]; if (key > 245) { delete wledPalx.p[key]; continue; @@ -571,8 +595,11 @@ } const pArray = Object.entries(wledPalx.p).map(([key, value]) => ({ - [key]: value.flat() + [key]: value.flat(), + name: value.name })); + // Sort pArray by name + pArray.sort((a, b) => a.name.localeCompare(b.name)); paletteArray.push( ...pArray); } @@ -614,6 +641,9 @@ editSpan.id = `editSpan${i}`; editSpan.onclick = function() {loadForEdit(i)}; editSpan.setAttribute('title', `Copy slot ${i} palette to editor`); + if (paletteArray[i].name) { + editSpan.setAttribute('title', `Copy ${paletteArray[i].name} palette to editor`); + } editSpan.innerHTML = svgEdit; editSpan.classList.add("editSpan") diff --git a/wled00/data/index.css b/wled00/data/index.css index 8eac75ec..d8338d93 100644 --- a/wled00/data/index.css +++ b/wled00/data/index.css @@ -624,7 +624,12 @@ button { width: 100%; } -#info td, #nodes td { +/*WLEDMM split info and nodes table font attributes*/ +#info td { + padding-bottom: 8px; +} +#nodes td { + font-size: 12px; /*WLEDMM small table cells (nodes popup) */ padding-bottom: 8px; } @@ -1043,6 +1048,8 @@ textarea { .sbs { padding: 1px 0 1px 20px; display: var(--sgp); + width: 100%; + position: relative; } .pname { diff --git a/wled00/data/index.js b/wled00/data/index.js index fb2393a9..a5f914b3 100644 --- a/wled00/data/index.js +++ b/wled00/data/index.js @@ -33,15 +33,17 @@ var hol = [ [0,11,24,4,"https://aircoookie.github.io/xmas.png"], // christmas [0,2,17,1,"https://images.alphacoders.com/491/491123.jpg"], // st. Patrick's day [2025,3,20,2,"https://aircoookie.github.io/easter.png"], - [2023,3,9,2,"https://aircoookie.github.io/easter.png"], [2024,2,31,2,"https://aircoookie.github.io/easter.png"], - [0,6,4,1,"https://initiate.alphacoders.com/download/wallpaper/516792/images/jpg/510921363292536"], // 4th of July - [0,0,1,1,"https://initiate.alphacoders.com/download/wallpaper/1198800/images/jpg/2522807481585600"] // new year + [0,6,4,1,"https://images.alphacoders.com/516/516792.jpg"], // 4th of July + [0,0,1,1,"https://images.alphacoders.com/119/1198800.jpg"] // new year ]; var ctx = null; // WLEDMM var ledmapNr = -1; //WLEDMM var ledmapFileNames = []; //WLEDMM -let extendedNodes = []; //WLEDMM +let nodesData = []; //WLEDMM +let ibtglChecked = true; //WLEDMM +let sbtglChecked = true; //WLEDMM +let sbchkChecked = false; //WLEDMM function handleVisibilityChange() {if (!d.hidden && new Date () - lastUpdate > 3000) requestJson();} function sCol(na, col) {d.documentElement.style.setProperty(na, col);} @@ -695,6 +697,7 @@ ${inforow("Filesystem",i.fs.u + "/" + i.fs.t + " kB (" +Math.round(i.fs.u*100/i. ${theap>0?inforow("Heap ☾",((i.totalheap-i.freeheap)/1000).toFixed(0)+"/"+theap.toFixed(0)+" kB"," ("+Math.round((i.totalheap-i.freeheap)/(10*theap))+"%)"):""} ${i.minfreeheap?inforow("Max used heap ☾",((i.totalheap-i.minfreeheap)/1000).toFixed(1)+" kB"," ("+Math.round((i.totalheap-i.minfreeheap)/(10*theap))+"%)"):""} ${inforow("Free heap",heap," kB")} +${i.freestack?inforow("Free stack ☾",(i.freestack/1024).toFixed(3)," kB"):""} ${inforow("Flash Size ☾",flashsize," kB")} ${i.tpram?inforow("PSRAM ☾",(i.tpram/1024).toFixed(1)," kB"):""} ${i.psram?((i.tpram-i.psram)>16383?inforow("Used PSRAM ☾",((i.tpram-i.psram)/1024).toFixed(1)," kB"):inforow("Used PSRAM ☾",(i.tpram-i.psram)," B")):""} @@ -866,7 +869,7 @@ function populateSegments(s) } if (segCount < 2) { 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) 1) ? "block":"none"; // rsbtn parent @@ -1055,9 +1058,9 @@ function bname(o) //WLEDMM call a node with json api command function callNode(ip, type, json) { - console.log("callNode", ip, json); + console.log("callNode", ip, type, json); - fetch('http://'+ip+'/json/'+type, { + fetch('http://' + ip + '/json/' + type, { method: 'POST', headers: { 'Content-Type': 'application/json' @@ -1075,99 +1078,265 @@ function callNode(ip, type, json) { } function ddpAll() { + if (!confirm('Press Yes/OK if you know what you are doing!')) return; ins = []; start = 0; order = 0; - for (var node of extendedNodes) { - console.log(node); - output = {}; - output.start = start; //increase with count - output.len = node.count; - output.pin = node.ip.split("."); - output.order = order++; - output.rev = false; - output.skip = 0; - output.type = 80; - output.ref = false; - output.rgbm = 0; - // "ins":[{"start":0,"len":24,"pin":[2],"order":0,"rev":false,"skip":0,"type":22,"ref":false,"rgbwm":0}, - // {"start":24,"len":241,"pin":[192,168,121,57],"order":1,"rev":false,"skip":0,"type":80,"ref":false,"rgbwm":0}] - ins.push(output); - start+=node.count; + for (var node of nodesData) { + if (node.info.ip != lastinfo.ip) { //do not add to self + console.log(node); + output = {}; + output.start = start; //increase with count + output.len = node.info.leds.count; + output.pin = node.info.ip.split("."); + output.order = order++; + output.rev = false; + output.skip = 0; + output.type = 80; + output.ref = false; + output.rgbm = 0; + // "ins":[{"start":0,"len":24,"pin":[2],"order":0,"rev":false,"skip":0,"type":22,"ref":false,"rgbwm":0}, + // {"start":24,"len":241,"pin":[192,168,121,57],"order":1,"rev":false,"skip":0,"type":80,"ref":false,"rgbwm":0}] + ins.push(output); + start+=node.info.leds.count; + } + } + // console.log("ins", lastinfo.ip,JSON.stringify({"hw":{"led":{"ins":ins}}})); + + //update own cfg.json + callNode(lastinfo.ip, "cfg", {"hw":{"led":{"ins":ins}}}); //self +} + +//curl -s -F "update=@/Users/ewoudwijma/Developer/GitHub/MoonModules/WLED/build_output/release/WLEDMM_0.14.0-b28.35_esp32_4MB_M.bin" 192.168.8.105/update >nul & + +//WLEDMM +function SuperSync() { + if (!confirm('Press Yes/OK if you know what you are doing!')) return; + + for (i=0; i 2) { + errFound = true; + gId(`pnlC${nodeNr}`).style.color = "red"; + } + } + + //set the SuperSync Update needed column + gId(`ssu${nodeNr}`).innerText = errFound?"yes":"no"; + if (errFound) { + gId(`ssu${nodeNr}`).style.color = "red"; + } + } + + //fetch both cfg.json and info from a node and store in nodesData array + function fetchInfoAndCfg(ip, nodeNr, callback) { + //add td placeholders + urows += ``; + for (let nm of ["ins", "pwr", "ip", "type", "rel", "ver", "vid", "fx", "scale-bri", "gcc", "fps", "fpsr", "lpc", "lvc", "mrx", "pnl0", "pnlC", "pnlX", "ssu"]) + urows += ``; + urows += ``; + + //fetch info, state and effects + fetchAndExecute(`http://${ip}/`, "json/si", nodeNr, function(nodeNr, text) { + let info = JSON.parse(text)["info"]; + let state = JSON.parse(text)["state"]; + + //set values + let name = n.nodes[nodeNr].name; + let url = ``; + gId(`ins${nodeNr}`).innerHTML = url; + gId(`ip${nodeNr}`).innerText = ip; + gId(`pwr${nodeNr}`).innerHTML = ""; + gId(`type${nodeNr}`).innerText = info.arch; + gId(`vid${nodeNr}`).innerText = info.vid; + gId(`rel${nodeNr}`).innerText = info.rel; + gId(`ver${nodeNr}`).innerText = info.ver; + gId(`lvc${nodeNr}`).innerText = info.leds.count; + gId(`lpc${nodeNr}`).innerText = info.leds.countP; + gId(`fpsr${nodeNr}`).innerText = info.leds.fps; + gId(`fx${nodeNr}`).innerText = eJson.find((o)=>{return o.id==state.seg[0].fx}).name; + + //store data + if (!nodesData[nodeNr]) nodesData[nodeNr] = {}; + nodesData[nodeNr].info = info; + + //if the node has a matrix, show matrix info + if (info.leds.matrix) { + gId(`mrx${nodeNr}`).innerText = info.leds.matrix.w + "x" + info.leds.matrix.h; + } + + //fetch cfg.json + fetchAndExecute(`http://${ip}/`, "cfg.json", nodeNr, function(nodeNr, text) { + let cfg = JSON.parse(text); + + //set values + gId(`scale-bri${nodeNr}`).innerText = cfg.light["scale-bri"]; + gId(`gcc${nodeNr}`).innerText = cfg.light.gc.col > 1; + gId(`fps${nodeNr}`).innerText = cfg.hw.led.fps; + + //if the node has a matrix, show matrix info + if (cfg.hw.led.matrix) { + gId(`pnl0${nodeNr}`).innerText = showPanel(cfg.hw.led.matrix.panels[0]); //show the first panel + gId(`pnlC${nodeNr}`).innerText = cfg.hw.led.matrix.panels.length; //show nr of panels + + //if self, assign it's matrix details to all others + if (ip == lastinfo.ip) { + let panelIndex = 0; //loop over panels + for (let i=0; i (a.name).localeCompare(b.name)); + + n.nodes.sort((a,b) => (a.name).localeCompare(b.name)); //alphabetic on name // console.log("populateNodes",i,n); - //loop over nodes e.g. {name: "MM 32 L", type: 32, ip: "192.168.121.249", age: 1, vid: 2305080} - for (var o of n.nodes) { + + //set table header + urows += ``; + for (let nm of ["Instance", "Power", "IP", "Type", "Release", "Version", "Build", "Effect", "Bri%", "Gamma", "FPS", "FPS Real", "LedsP#", "LedsV#", "Matrix", "Panel0", "Panels", "PanelX", "SSync"]) + urows += `${nm}`; + urows += ``; + + //show other nodes e.g. {name: "MM 32 L", type: 32, ip: "192.168.121.249", age: 1, vid: 2305080} + var nodesDone = 0; + for (let o of n.nodes) { if (o.name) { - var url = ``; - // urows += inforow(url,`${btype(o.type)}
${o.vid==0?"N/A":o.vid} ${o.mode}`); - - //WLEDMM fetch json from nodes and add in table rows - urows += `${url}${btype(o.type)}
${o.vid==0?"N/A":o.vid}`; - // console.log("Node", o); if (o.ip) { //in ap mode no ip... - //fetch the rest of the nodes info - fetchAndExecute(`http://${o.ip}/`, "json", nnodes, function(nnodes,text) { - // console.log(text); - let state = JSON.parse(text)["state"]; - let info = JSON.parse(text)["info"]; - let effects = JSON.parse(text)["effects"]; - let nodeInfo = {}; - // console.log(nnodes, state, info, effects); - nodeInfo.ip = info.ip; - nodeInfo.count = info.leds.count; - //append to table row - - // gId(`node${nnodes}`).appendChild(addEl('td', ``)); - gId(`node${nnodes}`).appendChild(addEl('td', "")); - // ${i.opt&0x100?inforow("Net Print ☾",""):''} - gId(`node${nnodes}`).appendChild(addEl('td', info["ip"])); - gId(`node${nnodes}`).appendChild(addEl('td', info["rel"])); - gId(`node${nnodes}`).appendChild(addEl('td', info["ver"])); - gId(`node${nnodes}`).appendChild(addEl('td', info["leds"]["count"])); - gId(`node${nnodes}`).appendChild(addEl('td', effects[state["seg"][0]["fx"]])); - if (info["leds"]["matrix"]) - gId(`node${nnodes}`).appendChild(addEl('td', info["leds"]["matrix"]["w"] + "x" + info["leds"]["matrix"]["h"])); - if (nodeInfo.ip != thisNode.ip) - extendedNodes.push(nodeInfo); + fetchInfoAndCfg(o.ip, nnodes, function(nodeNr) { + nodesDone++; + console.log("nodesDone", nodesDone, nodeNr, n.nodes.length, nnodes, n.nodes[nodeNr].name); + //if all done + if (nodesDone == n.nodes.length ) { + for (let i=0; i - ${urows} - `; - cn += "" + else if (!n.nodes) cn += `No other instances found.`; + cn += `${urows}
`; + cn += ``; + cn += ``; gId('kn').innerHTML = cn; // ${inforow("Current instance:",i.name)} //WLEDMM current instance is now also shown as node } @@ -1196,7 +1365,7 @@ function updateTrail(e) { if (e==null) return; let sd = e.parentNode.getElementsByClassName('sliderdisplay')[0]; - if (sd && getComputedStyle(sd).getPropertyValue("--bg") !== "none") { + if (sd && getComputedStyle(sd).getPropertyValue("--bg").trim() !== "none") { // trim() for Safari var max = e.hasAttribute('max') ? e.attributes.max.value : 255; var perc = Math.round(e.value * 100 / max); if (perc < 50) perc += 2; @@ -1215,7 +1384,7 @@ function toggleBubble(e) } // updates segment length upon input of segment values -function updateLen(s, draw=true) //WLEDMM conditonally draw segment view +function updateLen(s, draw=true) //WLEDMM conditionally draw segment view { if (!gId(`seg${s}s`)) return; var start = parseInt(gId(`seg${s}s`).value); @@ -1556,7 +1725,7 @@ function updateUI() if (hasRGB) { updateTrail(gId('sliderR')); updateTrail(gId('sliderG')); - updateTrail(gId('sliderB')); + updateTrail(gId('sliderB')); } if (hasWhite) updateTrail(gId('sliderW')); @@ -1809,9 +1978,9 @@ function readState(s,command=false) // - For AC effects (id<128) 2 sliders and 3 colors and the palette will be shown // - For SR effects (id>128) 5 sliders and 3 colors and the palette will be shown // If effective (@) -// - a ; seperates slider controls (left) from color controls (middle) and palette control (right) +// - a ; separates slider controls (left) from color controls (middle) and palette control (right) // - if left, middle or right is empty no controls are shown -// - a , seperates slider controls (max 5) or color controls (max 3). Palette has only one value +// - a , separates slider controls (max 5) or color controls (max 3). Palette has only one value // - a ! means that the default is used. // - For sliders: Effect speeds, Effect intensity, Custom 1, Custom 2, Custom 3 // - For colors: Fx color, Background color, Custom @@ -2269,7 +2438,7 @@ function makeP(i,pl) end: 0 }; var rep = plJson[i].repeat ? plJson[i].repeat : 0; - content = + content = `
`; if (Array.isArray(lastinfo.maps) && lastinfo.maps.length>0) { //WLEDMM >0 instead of 1 to show also first ledmap. Attention: WLED AC has isM check, in MM Matrices are supported so do not check on isM @@ -2349,7 +2518,15 @@ function makePUtil() p.innerHTML = `
${makeP(0)}
`; let pTx = gId('p0txt'); pTx.focus(); - pTx.value = eJson.find((o)=>{return o.id==selectedFx}).name; + //WLEDMM: take the name PLUS the icons as default name + let fxName = eJson.find((o)=>{return o.id==selectedFx}).name; + + let sE = gId('fxlist').querySelector(`.lstI[data-id="${selectedFx}"]`); + if (sE) { + fxName = sE.querySelector(".lstIname").innerText; + } + + pTx.value = fxName; pTx.select(); p.scrollIntoView({ behavior: 'smooth', @@ -2737,8 +2914,11 @@ function saveP(i,pl) obj.o = true; } else { obj.ib = gId(`p${i}ibtgl`).checked; + ibtglChecked = obj.ib; //WLEDMM obj.sb = gId(`p${i}sbtgl`).checked; + sbtglChecked = obj.sb; //WLEDMM obj.sc = gId(`p${i}sbchk`).checked; + sbchkChecked = obj.sc; //WLEDMM if (gId(`p${i}lmp`) && gId(`p${i}lmp`).value!=="") obj.ledmap = parseInt(gId(`p${i}lmp`).value); } } @@ -3055,7 +3235,7 @@ function genPresets() if (!defaultString.includes("o1")) defaultString += ',"o1":0'; //Check 1 if (!defaultString.includes("o2")) defaultString += ',"o2":0'; //Check 2 if (!defaultString.includes("o3")) defaultString += ',"o3":0'; //Check 3 - if (!defaultString.includes("pal")) defaultString += ',"pal":1'; //Random palette if not set different + if (!defaultString.includes("pal")) defaultString += ',"pal":11'; //Temporary for deterministic effects test: Set to 11/Raibow instead of 1/Random smooth palette (if not set different) if (!defaultString.includes("m12") && m.includes("1") && !m.includes("1.5") && !m.includes("12")) defaultString += ',"rev":true,"mi":true,"rY":true,"mY":true,"m12":2'; //Arc expansion else { @@ -3070,7 +3250,7 @@ function genPresets() addToPlaylist("All", ef.id); if (m.includes("1")) addToPlaylist("All1", ef.id); if (m.includes("2")) addToPlaylist("All2", ef.id); - } //fxData is array + } //fxdata is array } //not RSVD } //all effects @@ -3097,13 +3277,15 @@ function genPresets() //WLEDMM: utility function to load contents of file from FS (used in draw) function fetchAndExecute(url, name, parms, callback, callError = null) { + let errorCalled = false; fetch (url+name, { method: 'get' }) .then(res => { if (!res.ok) { - callError("File " + name + " not found"); + if (!errorCalled && callError) callError(parms, "File " + name + " not found"); + errorCalled = true; return ""; } return res.text(); @@ -3112,7 +3294,8 @@ function fetchAndExecute(url, name, parms, callback, callError = null) callback(parms, text); }) .catch(function (error) { - if (callError) callError(parms, "Error getting " + name); + if (!errorCalled && callError) callError(parms, "Error getting " + name); + errorCalled = true; console.log(error); }) .finally(() => { diff --git a/wled00/data/peek.js b/wled00/data/peek.js index 5192cfec..24ee7ee7 100644 --- a/wled00/data/peek.js +++ b/wled00/data/peek.js @@ -25,7 +25,7 @@ function peek(c) { let mW = leds[2]; // matrix width let mH = leds[3]; // matrix height let pPL = Math.min(c.width / mW, c.height / mH); // pixels per LED (width of circle) - let lOf = Math.floor((c.width - pPL*mW)/2); //left offeset (to center matrix) + let lOf = Math.floor((c.width - pPL*mW)/2); //left offset (to center matrix) var i = 4; //same offset as in ws.cpp ctx.clearRect(0, 0, c.width, c.height); //WLEDMM function colorAmp(color) { diff --git a/wled00/data/pixart/getPixelValues.js b/wled00/data/pixart/getPixelValues.js index 6f68f2d2..7f4265fd 100644 --- a/wled00/data/pixart/getPixelValues.js +++ b/wled00/data/pixart/getPixelValues.js @@ -69,7 +69,7 @@ function getPixelRGBValues(base64Image) { let sizeY = szY.value; if (color != accentColor || sizeX < 1 || sizeY < 1){ - //image will not be rezised Set desitred size to original size + //image will not be resized Set desired size to original size sizeX = image.width; sizeY = image.height; //failsafe for not generating huge images automatically @@ -153,7 +153,7 @@ function getPixelRGBValues(base64Image) { let curentColorIndex = 0 let commandArray = []; - //For evry pixel in the LED array + //For every pixel in the LED array for (let i = 0; i < maxi; i++) { let pixel = ledRGBValues[i]; let r = pixel[0]; diff --git a/wled00/data/settings.htm b/wled00/data/settings.htm index b95c0d49..e52d3bd7 100644 --- a/wled00/data/settings.htm +++ b/wled00/data/settings.htm @@ -2,7 +2,7 @@ - + WLED Settings