diff --git a/CHANGELOG.md b/CHANGELOG.md
index 641568de..594fa97e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,34 @@
## WLED changelog
+#### Build 2306020
+
+- Support for segment sets (PR #3171)
+- Reduce sound simulation modes to 2 to facilitiate 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
+- new 2D effects: Soap (#3184) & Octopus & Waving cell (credit @St3P40 https://github.com/80Stepko08)
+- various fixes and enhancements
+
+#### Build 2305090
+- new ethernet board: @Wladi ABC! WLED Eth
+- Battery usermod voltage calculation (#3116)
+- custom palette editor (#3164)
+- improvements in Dancing Shadows and Tartan effects
+- UCS389x support
+- switched to NeoPixelBus 2.7.5 (replaced NeoPixelBrightnessBus with NeoPixelBusLg)
+- SPI bus clock selection (for LEDs) (#3173)
+- DMX mode preset fix (#3134)
+- iOS fix for scroll (#3182)
+- Wordclock "Norddeutsch" fix (#3161)
+- various fixes and enhancements
+
#### Build 2304090
- updated Arduino ESP8266 core to 4.1.0 (newer compiler)
- updated NeoPixelBus to 2.7.3 (with support for UCS890x chipset)
diff --git a/package-lock.json b/package-lock.json
index 7e5c29c9..711778c8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "wled",
- "version": "0.14.0-b15.25",
+ "version": "0.14.0-b15.27",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "wled",
- "version": "0.14.0-b15.25",
+ "version": "0.14.0-b15.27",
"license": "ISC",
"dependencies": {
"clean-css": "^4.2.3",
diff --git a/package.json b/package.json
index 7ea6d0ab..94f9d5ba 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "wled",
- "version": "0.14.0-b15.25",
+ "version": "0.14.0-b15.27",
"description": "Tools for WLED project",
"main": "tools/cdata.js",
"directories": {
diff --git a/platformio.ini b/platformio.ini
index 6becb27d..b71504d1 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -9,8 +9,9 @@
# (use `platformio_override.ini` when building for your own board; see `platformio_override.ini.sample` for an example)
# ------------------------------------------------------------------------------
-# Release / CI binaries
-; default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth, esp32s2_saola, esp32c3, esp32s3dev_8MB
+# 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
# Release binaries
; default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_8MB
@@ -97,18 +98,28 @@ arduino_core_2_6_3 = espressif8266@2.3.3
arduino_core_2_7_4 = espressif8266@2.6.2
arduino_core_3_0_0 = espressif8266@3.0.0
arduino_core_3_2_0 = espressif8266@3.2.0
+arduino_core_4_1_0 = espressif8266@4.1.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_3_2_0}
+platform_wled_default = ${common.arduino_core_4_1_0}
# We use 2.7.4.7 for all, includes PWM flicker fix and Wstring optimization
-platform_packages = tasmota/framework-arduinoespressif8266 @ 3.20704.7
- platformio/toolchain-xtensa @ ~2.40802.200502
- platformio/tool-esptool @ ~1.413.0
- platformio/tool-esptoolpy @ ~1.30000.0
+#platform_packages = tasmota/framework-arduinoespressif8266 @ 3.20704.7
+platform_packages = platformio/framework-arduinoespressif8266
+ platformio/toolchain-xtensa @ ~2.100300.220621 #2.40802.200502
+ platformio/tool-esptool #@ ~1.413.0
+ platformio/tool-esptoolpy #@ ~1.30000.0
+
+## previous platform for 8266, in case of problems with the new one
+## you'll need makuna/NeoPixelBus@ 2.6.9 for arduino_core_3_2_0, which does not support Ucs890x
+;; platform_wled_default = ${common.arduino_core_3_2_0}
+;; platform_packages = tasmota/framework-arduinoespressif8266 @ 3.20704.7
+;; platformio/toolchain-xtensa @ ~2.40802.200502
+;; platformio/tool-esptool @ ~1.413.0
+;; platformio/tool-esptoolpy @ ~1.30000.0
# ------------------------------------------------------------------------------
# FLAGS: DEBUG
@@ -147,6 +158,7 @@ build_flags =
-DBEARSSL_SSL_BASIC
-D CORE_DEBUG_LEVEL=0
;-D NDEBUG ;; WLEDMM espressif docs say NDEBUG is not recommended. see https://docs.espressif.com/projects/esp-idf/en/v4.4.4/esp32/api-guides/performance/speed.html#not-recommended
+ -Wno-attributes ;; silence warnings about unknown attribute 'maybe_unused' in NeoPixelBus
#build_flags for the IRremoteESP8266 library (enabled decoders have to appear here)
-D _IR_ENABLE_DEFAULT_=false
-D DECODE_HASH=true
@@ -154,7 +166,7 @@ build_flags =
-D DECODE_SONY=true
-D DECODE_SAMSUNG=true
-D DECODE_LG=true
- ; -Dregister= # remove warnings in C++17 due to use of deprecated register keyword by the FastLED library
+ ;-Dregister= # remove warnings in C++17 due to use of deprecated register keyword by the FastLED library ;; warning: this breaks framework code on ESP32-C3 and ESP32-S2
-DWLED_USE_MY_CONFIG
; -D USERMOD_SENSORSTOMQTT
#For ADS1115 sensor uncomment following
@@ -164,6 +176,7 @@ build_unflags =
build_flags_esp8266 = ${common.build_flags} ${esp8266.build_flags}
build_flags_esp32 = ${common.build_flags} ${esp32.build_flags}
+build_flags_esp32_V4= ${common.build_flags} ${esp32_idf_V4.build_flags}
ldscript_1m128k = eagle.flash.1m128.ld
ldscript_2m512k = eagle.flash.2m512.ld
@@ -198,26 +211,25 @@ upload_speed = 115200
# LIBRARIES: required dependencies
# Please note that we don't always use the latest version of a library.
#
-# The following libraries have been included (and some of them changd) in the source:
+# The following libraries have been included (and some of them changed) in the source:
# ArduinoJson@5.13.5, E131@1.0.0(changed), Time@1.5, Timezone@1.2.1
# ------------------------------------------------------------------------------
lib_compat_mode = strict
lib_deps =
- ;fastled/FastLED @ 3.6.0
- 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 ;; 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
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
https://github.com/lost-hope/ESPAsyncWebServer.git#master ;; WLEDMM to display .log and .wled files in /edit
#For use of the TTGO T-Display ESP32 Module with integrated TFT display uncomment the following line
#TFT_eSPI
- #For use SSD1306 OLED display uncomment following
- #U8g2@~2.28.8
- #U8g2@~2.32.10
- #For Dallas sensor uncomment following 2 lines
- #OneWire@~2.3.5
- #milesburton/DallasTemperature@^3.9.0
+ #For compatible OLED display uncomment following
+ #U8g2 #@ ~2.33.15
+ #For Dallas sensor uncomment following
+ #OneWire @ ~2.3.7
#For BME280 sensor uncomment following
- #BME280@~3.0.0
+ #BME280 @ ~3.0.0
; adafruit/Adafruit BMP280 Library @ 2.1.0
; adafruit/Adafruit CCS811 Library @ 1.0.4
; adafruit/Adafruit Si7021 Library @ 1.4.0
@@ -232,8 +244,9 @@ 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-misleading-indentation
+ -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)
-DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_190703
; lwIP 2 - Higher Bandwidth no Features
@@ -245,11 +258,12 @@ build_flags =
; restrict to minimal mime-types
-DMIMETYPE_MINIMAL
-lib_deps =
+lib_deps =
#https://github.com/lorol/LITTLEFS.git
ESPAsyncTCP @ 1.2.2
ESPAsyncUDP
- makuna/NeoPixelBus @ 2.6.9
+ ;; makuna/NeoPixelBus @ 2.6.9 ;; WLEDMM use if you have problems with 2.7.5
+ makuna/NeoPixelBus @ 2.7.5
${env.lib_deps}
[esp32]
@@ -259,12 +273,12 @@ platform = espressif32@3.5.0
platform_packages = framework-arduinoespressif32 @ https://github.com/Aircoookie/arduino-esp32.git#1.0.6.4
build_flags = -g
- -DARDUINO_ARCH_ESP32 -DESP32
+ -DARDUINO_ARCH_ESP32
#-DCONFIG_LITTLEFS_FOR_IDF_3_2
-D CONFIG_ASYNC_TCP_USE_WDT=0
-#use LITTLEFS library by lorol in ESP32 core 1.x.x instead of built-in in 2.x.x
+ #use LITTLEFS library by lorol in ESP32 core 1.x.x instead of built-in in 2.x.x
-D LOROL_LITTLEFS
- ; -DARDUINO_USB_CDC_ON_BOOT=0 ;; this flag is mandatory for "classic ESP32" when builing with arduino-esp32 >=2.0.3
+ ; -DARDUINO_USB_CDC_ON_BOOT=0 ;; this flag is mandatory for "classic ESP32" when building with arduino-esp32 >=2.0.3
default_partitions = tools/WLED_ESP32_4MB_1MB_FS.csv ;; 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)
@@ -274,26 +288,26 @@ lib_deps =
; https://github.com/lorol/LITTLEFS.git
; WLEDMM specific: use patched version of lorol LittleFS
https://github.com/softhack007/LITTLEFS-threadsafe.git#master
- ;;makuna/NeoPixelBus @ 2.6.9 ;; WLEDMM default
- makuna/NeoPixelBus @ 2.7.1
+ makuna/NeoPixelBus @ 2.7.5
${env.lib_deps}
+;; WLEDMM begin
+
;; ** For compiling with latest Frameworks (IDF4.4.x and arduino-esp32 v2.0.x) **
-;;; standard V4 platform
-platformV4 = espressif32@ ~5.1.1
-platformV4_packages =
+;;; previous standard V4 platform
+platformV4_pre = espressif32@ ~5.1.1
+platformV4_packages_pre =
platformio/framework-arduinoespressif32@ ~3.20004.0
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
-
-;;; newer V4 platform - may help in case you experience flash corruption and boot loops
-platformV4_new = espressif32@ ~5.2.0
-platformV4_new_packages =
+;;; standard V4 platform
+platformV4 = espressif32@5.2.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
-;;; tasmota platform
-;platformV4 = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.5.1/platform-espressif32-2.0.5.1.zip
-;platformV4_packages =
-;;; V4.4.x build flags (without LOROL_LITTLEFS)
+;;; experimental: 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_packages_xp = platformio/framework-arduinoespressif32 @ ~3.20009.0 ;; arduino-esp32 v2.0.9+
+
build_flagsV4 = -g
-DARDUINO_ARCH_ESP32 -DESP32
-DCONFIG_LITTLEFS_FOR_IDF_3_2 -DLFS_THREADSAFE
@@ -302,27 +316,59 @@ build_flagsV4 = -g
;;; 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 !!
- makuna/NeoPixelBus @ 2.7.3
+ makuna/NeoPixelBus @ 2.7.5
+ ${env.lib_deps}
+
+;; WLEDMM end
+
+[esp32_idf_V4]
+;; experimental build environment for ESP32 using ESP-IDF 4.4.x / arduino-esp32 v2.0.5
+;; very similar to the normal ESP32 flags, but omitting Lorol LittleFS, as littlefs is included in the new framework already.
+;;
+;; 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_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
+ -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 =
+ https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
+ makuna/NeoPixelBus @ 2.7.5
${env.lib_deps}
[esp32s2]
+;; 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
build_flags = -g
-DARDUINO_ARCH_ESP32 -DESP32 ;; WLEDMM
-DARDUINO_ARCH_ESP32S2
- -DCONFIG_IDF_TARGET_ESP32S2
+ -DCONFIG_IDF_TARGET_ESP32S2=1
-DCONFIG_LITTLEFS_FOR_IDF_3_2 -DLFS_THREADSAFE ;; WLEDMM
-D CONFIG_ASYNC_TCP_USE_WDT=0
+ -DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_USB_DFU_ON_BOOT=0
-DCO
-DARDUINO_USB_MODE=0 ;; this flag is mandatory for ESP32-S2 !
;; 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:
- ;; ARDUINO_USB_CDC_ON_BOOT, ARDUINO_USB_MSC_ON_BOOT, ARDUINO_USB_DFU_ON_BOOT
+ ;; ARDUINO_USB_CDC_ON_BOOT
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 !!
- makuna/NeoPixelBus @ 2.7.3 ;; WLEDMM - new version is more stable on -S2
+ https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
+ makuna/NeoPixelBus @ 2.7.5
${env.lib_deps}
[esp32c3]
+;; generic definitions for all ESP32-C3 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
build_flags = -g
-DARDUINO_ARCH_ESP32 -DESP32 ;; WLEDMM
-DARDUINO_ARCH_ESP32C3
@@ -335,20 +381,20 @@ build_flags = -g
;; ARDUINO_USB_CDC_ON_BOOT
lib_deps =
- fastled/FastLED @ 3.5.0
- IRremoteESP8266 @ ~2.8.2
https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
- ;;https://github.com/Aircoookie/ESPAsyncWebServer.git @ ~2.0.7
- https://github.com/lost-hope/ESPAsyncWebServer.git#master ;; WLEDMM to display .log and .wled files in /edit
- makuna/NeoPixelBus @ 2.7.3 ;; WLEDMM - new version is more stable on -C3
+ makuna/NeoPixelBus @ 2.7.5
+ ${env.lib_deps}
[esp32s3]
;; generic definitions for all ESP32-S3 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
build_flags = -g
-DESP32
-DARDUINO_ARCH_ESP32
-DARDUINO_ARCH_ESP32S3
- -DCONFIG_IDF_TARGET_ESP32S3
+ -DCONFIG_IDF_TARGET_ESP32S3=1
-DCONFIG_LITTLEFS_FOR_IDF_3_2 -DLFS_THREADSAFE ;; WLEDMM
-D CONFIG_ASYNC_TCP_USE_WDT=0
-DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_DFU_ON_BOOT=0
@@ -358,7 +404,7 @@ build_flags = -g
lib_deps =
https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
- makuna/NeoPixelBus @ 2.7.3
+ makuna/NeoPixelBus @ 2.7.5
${env.lib_deps}
@@ -455,6 +501,21 @@ board_build.partitions = ${esp32.default_partitions}
board_build.f_flash = 80000000L
board_build.flash_mode = qio
+[env:esp32dev_V4_dio80]
+;; experimental ESP32 env using ESP-IDF V4.4.x
+;; Warning: this build environment is not stable!!
+;; please erase your device before installing.
+board = esp32dev
+platform = ${esp32_idf_V4.platform}
+platform_packages = ${esp32_idf_V4.platform_packages}
+build_unflags = ${common.build_unflags}
+build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=ESP32_V4_qio80 #-D WLED_DISABLE_BROWNOUT_DET
+lib_deps = ${esp32_idf_V4.lib_deps}
+monitor_filters = esp32_exception_decoder
+board_build.partitions = ${esp32_idf_V4.default_partitions}
+board_build.f_flash = 80000000L
+board_build.flash_mode = dio
+
[env:esp32_eth]
board = esp32-poe
platform = ${esp32.platform}
@@ -467,51 +528,45 @@ board_build.partitions = ${esp32.default_partitions}
[env:esp32s2_saola]
board = esp32-s2-saola-1
-;platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.2.2/platform-tasmota-espressif32-2.0.2.zip
-;platform_packages =
-platform = ${esp32.platformV4}
-platform_packages = ${esp32.platformV4_packages}
+platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.2.2/platform-tasmota-espressif32-2.0.2.zip
+platform_packages =
+framework = arduino
board_build.partitions = tools/WLED_ESP32_4MB_1MB_FS.csv
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
+ -DARDUINO_USB_CDC_ON_BOOT=1
lib_deps = ${esp32s2.lib_deps}
-[env:esp32c3dev] ;WLEDMM, merged with latest change on upstream (renamed from env:esp32c3)
+[env:esp32c3dev]
+extends = esp32c3
+platform = ${esp32c3.platform}
+platform_packages = ${esp32c3.platform_packages}
+framework = arduino
board = esp32-c3-devkitm-1
-platform = ${esp32.platformV4} ;; standard platform, well-tested on -C3, good compatibility with WLED
-platform_packages = ${esp32.platformV4_packages} ;; use with standard platform
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
- ; -DARDUINO_USB_CDC_ON_BOOT=1 ;; for virtual USB
- -DARDUINO_USB_CDC_ON_BOOT=0 ;; no virtual USB
- -D CONFIG_LITTLEFS_FOR_IDF_3_2 ; WLEDMM
- -D WLED_USE_MY_CONFIG ; WLEDMM
- ; -D USERMOD_AUDIOREACTIVE ; WLEDMM
- -D USERMOD_ARTIFX ; WLEDMM
+ ; -DARDUINO_USB_CDC_ON_BOOT=1 ;; for virtual CDC USB
+ -DARDUINO_USB_CDC_ON_BOOT=0 ;; for serial-to-USB chip
upload_speed = 460800
build_unflags = ${common.build_unflags}
lib_deps = ${esp32c3.lib_deps}
- ; https://github.com/blazoncek/arduinoFFT.git
[env:esp32s3dev_8MB]
;; ESP32-S3-DevKitC-1 development board, with 8MB FLASH, no PSRAM (flash_mode: qio)
board = esp32-s3-devkitc-1
-;platform = espressif32@5.1.1
-;platform_packages = platformio/framework-arduinoespressif32@3.20004.220825
-platform = ${esp32.platformV4}
-platform_packages = ${esp32.platformV4_packages}
-upload_speed = 921600
+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} -D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0 -D ARDUINO_USB_MODE=1 -D ARDUINO_USB_CDC_ON_BOOT=0 -D ARDUINO_USB_MSC_ON_BOOT=0
- -D WLED_RELEASE_NAME=ESP32-S3
- -D WLED_USE_MY_CONFIG
- -D USERMOD_AUDIOREACTIVE
- -D USERMOD_ARTIFX
+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 WLED_DEBUG
lib_deps = ${esp32s3.lib_deps}
- https://github.com/blazoncek/arduinoFFT.git
board_build.partitions = tools/WLED_ESP32_8MB.csv
board_build.f_flash = 80000000L
board_build.flash_mode = qio
@@ -523,13 +578,14 @@ monitor_filters = esp32_exception_decoder
;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
-platform = ${esp32.platformV4_new} ;; alternative platform, might help in case you experience bootloops due to corrupted flash filesystem
-platform_packages = ${esp32.platformV4_new_packages}
+platform = ${esp32s3.platform}
+platform_packages = ${esp32s3.platform_packages}
upload_speed = 921600
build_unflags = ${common.build_unflags}
-build_flags = ${common.build_flags} ${esp32s3.build_flags}
+build_flags = ${common.build_flags} ${esp32s3.build_flags}
-D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0
- -D ARDUINO_USB_MODE=1 -D ARDUINO_USB_MSC_ON_BOOT=0 ; -D ARDUINO_USB_CDC_ON_BOOT=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 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}
@@ -601,16 +657,17 @@ build_flags = ${common.build_flags_esp8266} -D LEDPIN=12 -D IRPIN=-1 -D RLYPIN=2
lib_deps = ${esp8266.lib_deps}
[env:lolin_s2_mini]
-;platform = espressif32@5.1.1
-platform = ${esp32.platformV4}
-platform_packages = ${esp32.platformV4_packages}
+platform = ${esp32s2.platform}
+platform_packages = ${esp32s2.platform_packages}
board = lolin_s2_mini
board_build.partitions = tools/WLED_ESP32_4MB_1MB_FS.csv
-build_unflags = ${common.build_unflags}
-build_flags = ${common.build_flags} ${esp32s2.build_flags} -D WLED_RELEASE_NAME=LolinS2
+build_unflags = ${common.build_unflags} -DARDUINO_USB_CDC_ON_BOOT=1
+build_flags = ${common.build_flags} ${esp32s2.build_flags} #-D WLED_RELEASE_NAME=LolinS2
-DBOARD_HAS_PSRAM
- -D ARDUINO_USB_CDC_ON_BOOT
- ;-D ARDUINO_USB_CDC_ON_BOOT=0
+ -DARDUINO_USB_CDC_ON_BOOT=0
+ -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_WATCHDOG_TIMEOUT=0
-D CONFIG_ASYNC_TCP_USE_WDT=0
@@ -623,22 +680,36 @@ build_flags = ${common.build_flags} ${esp32s2.build_flags} -D WLED_RELEASE_NAME
-D HW_PIN_CLOCKSPI=7
-D HW_PIN_MOSISPI=11 ;WLEDMM renamed from HW_PIN_DATASPI
-D HW_PIN_MISOSPI=9
- ; -D STATUSLED=15
- -D WLED_USE_MY_CONFIG
- -D USERMOD_AUDIOREACTIVE
- -D USERMOD_ARTIFX
-
+; -D STATUSLED=15
lib_deps = ${esp32s2.lib_deps}
- https://github.com/blazoncek/arduinoFFT.git
# ------------------------------------------------------------------------------
# custom board configurations
# ------------------------------------------------------------------------------
-; WLEDMM see below
+[env:esp32c3dev_2MB]
+;; for ESP32-C3 boards with 2MB flash (instead of 4MB).
+;; this board need a specific partition file. OTA not possible.
+extends = esp32c3
+platform = ${esp32c3.platform}
+platform_packages = ${esp32c3.platform_packages}
+board = esp32-c3-devkitm-1
+build_flags = ${common.build_flags} ${esp32c3.build_flags} #-D WLED_RELEASE_NAME=ESP32-C3
+ -D WLED_WATCHDOG_TIMEOUT=0
+ -D WLED_DISABLE_OTA
+ ; -DARDUINO_USB_CDC_ON_BOOT=1 ;; for virtual CDC USB
+ -DARDUINO_USB_CDC_ON_BOOT=0 ;; for serial-to-USB chip
+build_unflags = ${common.build_unflags}
+upload_speed = 115200
+lib_deps = ${esp32c3.lib_deps}
+board_build.partitions = tools/WLED_ESP32_2MB_noOTA.csv
+board_build.flash_mode = dio
+
+;WLEDMM: see below
; [env:wemos_shield_esp32]
; board = esp32dev
-; platform = espressif32@3.2
+; platform = ${esp32.platform}
+; platform_packages = ${esp32.platform_packages}
; upload_speed = 460800
; build_unflags = ${common.build_unflags}
; build_flags = ${common.build_flags_esp32}
@@ -663,7 +734,8 @@ board = esp32dev
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp32} -D LEDPIN=27 -D BTNPIN=39
lib_deps = ${esp32.lib_deps}
-platform = espressif32@3.2
+platform = ${esp32.platform}
+platform_packages = ${esp32.platform_packages}
board_build.partitions = ${esp32.default_partitions}
[env:sp501e]
@@ -769,7 +841,8 @@ lib_deps = ${esp8266.lib_deps}
# ------------------------------------------------------------------------------
[env:elekstube_ips]
board = esp32dev
-platform = espressif32@3.2
+platform = ${esp32.platform}
+platform_packages = ${esp32.platform_packages}
upload_speed = 921600
build_flags = ${common.build_flags_esp32} -D WLED_DISABLE_BROWNOUT_DET -D WLED_DISABLE_INFRARED
-D USERMOD_RTC
@@ -1493,8 +1566,8 @@ monitor_filters = esp32_exception_decoder
;; MM environment for generic ESP32-S2, with PSRAM, 4MB flash (300kB filesystem to have more program space)
[env:esp32s2_PSRAM_M]
extends = esp32_4MB_V4_M_base
-platform = ${esp32.platformV4_new} ;; more stable on -S2 than 5.1.1
-platform_packages = ${esp32.platformV4_new_packages}
+platform = ${esp32.platformV4} ;; more stable on -S2 than 5.1.1
+platform_packages = ${esp32.platformV4_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)
@@ -1539,11 +1612,9 @@ monitor_filters = esp32_exception_decoder
;; MM environment for generic ESP32-C3 -> 4MB flash, no PSRAM
[env:esp32c3dev_4MB_M]
extends = esp32_4MB_V4_S_base
-;platform = ${esp32.platformV4} ;; standard IDF 4.4.1 platform
-;platform_packages = ${esp32.platformV4_packages}
;board_build.flash_mode = dout
-platform = ${esp32.platformV4_new} ;; alternative platform, might help in case you experience bootloops due to corrupted flash filesystem
-platform_packages = ${esp32.platformV4_new_packages}
+platform = ${esp32.platformV4} ;; alternative platform, might help in case you experience bootloops due to corrupted flash filesystem
+platform_packages = ${esp32.platformV4_packages}
board_build.flash_mode = qio
board = esp32-c3-devkitm-1
;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)
@@ -1594,8 +1665,8 @@ lib_ignore =
[env:seeed_esp32c3_4MB_S]
extends = env:esp32c3dev_4MB_M
board = seeed_xiao_esp32c3
-platform = ${esp32.platformV4} ;; standard IDF 4.4.1 platform
-platform_packages = ${esp32.platformV4_packages}
+platform = ${esp32.platformV4_pre} ;; standard IDF 4.4.1 platform
+platform_packages = ${esp32.platformV4_packages_pre}
board_build.flash_mode = qio
upload_speed = 460800
build_unflags = ${env:esp32c3dev_4MB_M.build_unflags}
diff --git a/readme.md b/readme.md
index 132fdc41..62e1c852 100644
--- a/readme.md
+++ b/readme.md
@@ -14,15 +14,19 @@
-MoonModules/WLED is a fork from Aircoookie/WLED which contains latest merge of v0.14 of WLED with additional features.
+MoonModules/WLED is a fork from [Aircoookie/WLED](https://github.com/Aircoookie/WLED) which contains latest merge of v0.14 of WLED with [additional features](https://mm.kno.wled.ge/moonmodules/what-is-moonmodules/).
-This fork is created by members of the Atuline/WLED team to make development against v0.14 possible while still preserving Atuline/WLED v0.13 as a stable and supported version. The Atuline/WLED fork is also called WLED SR (Sound Reactive).
+This fork is created by members of the [Atuline/WLED](https://github.com/atuline/WLED) team to make development against v0.14 possible while still preserving [Atuline/WLED v0.13.x](https://github.com/atuline/WLED/tree/dev) as a stable and supported version. The Atuline/WLED fork is also called WLED SR (Sound Reactive).
More info here: what-is-moonmodules
Donations will be used to buy WLED related hardware, software or drinks shared with the contributors of this repo.
-*Disclaimer:*
+## Contributing
+We welcome contributions to this project! See [contributing](https://github.com/MoonModules/WLED/blob/mdev/CONTRIBUTING.md) for more information.
+> We would like to have this repository in a polite and friendly atmosphere, so please be kind and respectful to others. For more details, look at [Code of Conduct](https://github.com/MoonModules/WLED/blob/mdev/CODE_OF_CONDUCT.md).
+
+## *Disclaimer:*
Using this software is the users responsibility as it is not bug free. Therefore contributors of this repo are not reliable for anything including but not limited to spontaneous combustion of the entire led strip, the house and the inevitable heat death of the universe
diff --git a/requirements.txt b/requirements.txt
index da65486c..bc536ed0 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -21,9 +21,7 @@ click==8.1.3
# platformio
# uvicorn
colorama==0.4.6
- # via
- # click
- # platformio
+ # via platformio
h11==0.14.0
# via
# uvicorn
@@ -42,7 +40,7 @@ pyelftools==0.29
# via platformio
pyserial==3.5
# via platformio
-requests==2.28.2
+requests==2.31.0
# via platformio
semantic-version==2.10.0
# via platformio
@@ -52,8 +50,6 @@ starlette==0.23.1
# via platformio
tabulate==0.9.0
# via platformio
-typing-extensions==4.5.0
- # via starlette
urllib3==1.26.15
# via requests
uvicorn==0.20.0
diff --git a/usermods/EleksTube_IPS/TFTs.h b/usermods/EleksTube_IPS/TFTs.h
index e614704f..030ec23a 100644
--- a/usermods/EleksTube_IPS/TFTs.h
+++ b/usermods/EleksTube_IPS/TFTs.h
@@ -133,13 +133,13 @@ private:
return false;
}
- read32(bmpFS); // filesize in bytes
- read32(bmpFS); // reserved
+ (void) read32(bmpFS); // filesize in bytes
+ (void) read32(bmpFS); // reserved
seekOffset = read32(bmpFS); // start of bitmap
headerSize = read32(bmpFS); // header size
w = read32(bmpFS); // width
h = read32(bmpFS); // height
- read16(bmpFS); // color planes (must be 1)
+ (void) read16(bmpFS); // color planes (must be 1)
bitDepth = read16(bmpFS);
if (read32(bmpFS) != 0 || (bitDepth != 24 && bitDepth != 1 && bitDepth != 4 && bitDepth != 8)) {
@@ -151,9 +151,9 @@ private:
uint32_t palette[256];
if (bitDepth <= 8) // 1,4,8 bit bitmap: read color palette
{
- read32(bmpFS); read32(bmpFS); read32(bmpFS); // size, w resolution, h resolution
+ (void) read32(bmpFS); (void) read32(bmpFS); (void) read32(bmpFS); // size, w resolution, h resolution
paletteSize = read32(bmpFS);
- if (paletteSize == 0) paletteSize = bitDepth * bitDepth; //if 0, size is 2^bitDepth
+ if (paletteSize == 0) paletteSize = 1 << bitDepth; //if 0, size is 2^bitDepth
bmpFS.seek(14 + headerSize); // start of color palette
for (uint16_t i = 0; i < paletteSize; i++) {
palette[i] = read32(bmpFS);
@@ -198,7 +198,7 @@ private:
}
b = c; g = c >> 8; r = c >> 16;
}
- if (dimming != 255) { // only dimm when needed
+ if (dimming != 255) { // only dim when needed
r *= dimming; g *= dimming; b *= dimming;
r = r >> 8; g = g >> 8; b = b >> 8;
}
diff --git a/usermods/mcu_temp/mcuTemp.h b/usermods/mcu_temp/mcuTemp.h
new file mode 100644
index 00000000..d38bac2b
--- /dev/null
+++ b/usermods/mcu_temp/mcuTemp.h
@@ -0,0 +1,122 @@
+#pragma once
+
+#include "wled.h"
+
+// class name. Use something descriptive and leave the ": public Usermod" part :)
+class mcuTemp : public Usermod
+{
+
+private:
+ float mcutemp = 0;
+
+ // any private methods should go here (non-inline methosd should be defined out of class)
+ void publishMqtt(const char *state, bool retain = false); // example for publishing MQTT message
+
+public:
+ mcuTemp(const char *name, bool enabled) : Usermod(name, enabled) {} // WLEDMM
+
+ void setup()
+ {
+ }
+
+ void connected()
+ {
+ }
+
+ void loop()
+ {
+ // if usermod is disabled or called during strip updating just exit
+ // NOTE: on very long strips strip.isUpdating() may always return true so update accordingly
+ if (!enabled || strip.isUpdating())
+ return;
+
+#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;
+#endif
+
+ if (millis() - lastTime > 10000)
+ {
+ char array[10];
+ snprintf(array, sizeof(array), "%f", mcutemp);
+ publishMqtt(array);
+ lastTime = millis();
+ }
+ }
+ /*
+ * addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
+ * Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI.
+ * Below it is shown how this could be used for e.g. a light sensor
+ */
+ void addToJsonInfo(JsonObject &root)
+ {
+ // if "u" object does not exist yet wee need to create it
+ JsonObject user = root["u"];
+ if (user.isNull())
+ user = root.createNestedObject("u");
+
+ // this code adds "u":{"ExampleUsermod":[20," lux"]} to the info object
+ // int reading = 20;
+ JsonArray lightArr = user.createNestedArray(FPSTR(_name)); // name
+ lightArr.add(mcutemp); // value
+ lightArr.add(F(" °C")); // unit
+
+ // if you are implementing a sensor usermod, you may publish sensor data
+ // JsonObject sensor = root[F("sensor")];
+ // if (sensor.isNull()) sensor = root.createNestedObject(F("sensor"));
+ // temp = sensor.createNestedArray(F("light"));
+ // temp.add(reading);
+ // temp.add(F("lux"));
+ }
+
+ void addToJsonState(JsonObject &root)
+ {
+ }
+ void readFromJsonState(JsonObject &root)
+ {
+ }
+
+ void addToConfig(JsonObject &root)
+ {
+ }
+
+ bool readFromConfig(JsonObject &root)
+ {
+ return true;
+ }
+
+ void appendConfigData()
+ {
+ }
+
+ 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.
+ */
+ uint16_t getId()
+ {
+ return USERMOD_ID_MCUTEMP;
+ }
+};
+
+void mcuTemp::publishMqtt(const char *state, bool retain)
+{
+#ifndef WLED_DISABLE_MQTT
+ // Check if MQTT Connected, otherwise it will crash the 8266
+ if (WLED_MQTT_CONNECTED)
+ {
+ char subuf[64];
+ strcpy(subuf, mqttDeviceTopic);
+ strcat_P(subuf, PSTR("/mcutemp"));
+ mqtt->publish(subuf, 0, retain, state);
+ }
+#endif
+}
diff --git a/usermods/mcu_temp/readme.md b/usermods/mcu_temp/readme.md
new file mode 100644
index 00000000..c284613e
--- /dev/null
+++ b/usermods/mcu_temp/readme.md
@@ -0,0 +1,11 @@
+# MCU Temp Usermod
+This usermod adds the temperature readout to the Info tab and also publishes that over the topic `mcutemp` topic.
+
+
+A shown temp of 53,33°C might indicate that the internal temp is not supported.
+
+ESP8266 does not have a internal temp sensor
+
+ESP32S2 seems to crash on reading the sensor -> disabled
+
+Buildflag: `-D USERMOD_MCUTEMP`
diff --git a/usermods/multi_relay/readme.md b/usermods/multi_relay/readme.md
index 2906b860..71a54070 100644
--- a/usermods/multi_relay/readme.md
+++ b/usermods/multi_relay/readme.md
@@ -1,6 +1,9 @@
# Multi Relay
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.
+(**NOTE:** Will require Wire library and global I2C pins defined.)
## HTTP API
All responses are returned in JSON format.
@@ -81,13 +84,15 @@ void registerUsermods()
Usermod can be configured via the Usermods settings page.
* `enabled` - enable/disable usermod
+* `use-PCF8574` - use PCF8574 port expander instead of GPIO pins
+* `first-PCF8574` - I2C address of first expander (WARNING: enter *decimal* value)
+* `broadcast`- time in seconds between MQTT relay-state broadcasts
+* `HA-discovery`- enable Home Assistant auto discovery
* `pin` - ESP GPIO pin the relay is connected to (can be configured at compile time `-D MULTI_RELAY_PINS=xx,xx,...`)
* `delay-s` - delay in seconds after on/off command is received
* `active-high` - assign high/low activation of relay (can be used to reverse relay states)
* `external` - if enabled, WLED does not control relay, it can only be triggered by an external command (MQTT, HTTP, JSON or button)
* `button` - button (from LED Settings) that controls this relay
-* `broadcast`- time in seconds between MQTT relay-state broadcasts
-* `HA-discovery`- enable Home Assistant auto discovery
If there is no MultiRelay section, just save current configuration and re-open Usermods settings page.
@@ -100,3 +105,6 @@ Have fun - @blazoncek
2021-11
* Added information about dynamic configuration options
* Added button support.
+
+2023-05
+* Added support for PCF8574 I2C port expander (multiple)
\ No newline at end of file
diff --git a/usermods/multi_relay/usermod_multi_relay.h b/usermods/multi_relay/usermod_multi_relay.h
index 749b9c75..b8cabebb 100644
--- a/usermods/multi_relay/usermod_multi_relay.h
+++ b/usermods/multi_relay/usermod_multi_relay.h
@@ -4,6 +4,11 @@
#ifndef MULTI_RELAY_MAX_RELAYS
#define MULTI_RELAY_MAX_RELAYS 4
+#else
+ #if MULTI_RELAY_MAX_RELAYS>16
+ #undef MULTI_RELAY_MAX_RELAYS
+ #define MULTI_RELAY_MAX_RELAYS 16
+ #endif
#endif
#ifndef MULTI_RELAY_PINS
@@ -15,21 +20,29 @@
#define ON true
#define OFF false
+#ifndef PCF8574_ADDRESS
+ #define PCF8574_ADDRESS 0x20 // some may start at 0x38
+#endif
+
/*
* This usermod handles multiple relay outputs.
* These outputs complement built-in relay output in a way that the activation can be delayed.
* They can also activate/deactivate in reverse logic independently.
+ *
+ * Written and maintained by @blazoncek
*/
typedef struct relay_t {
int8_t pin;
- bool active;
- bool mode;
- bool state;
- bool external;
- uint16_t delay;
- int8_t button;
+ struct { // reduces memory footprint
+ bool active : 1; // is the relay waiting to be switched
+ bool mode : 1; // does On mean 1 or 0 (inverted output)
+ bool state : 1; // 1 relay is On, 0 relay is Off
+ bool external : 1; // is the relay externally controlled
+ int8_t button : 4; // which button triggers relay
+ };
+ uint16_t delay; // amount of ms to wait after it is activated
} Relay;
@@ -48,7 +61,8 @@ class MultiRelay : public Usermod {
bool enabled = false; // needs to be configured (no default config)
// status of initialisation
bool initDone = false;
-
+ bool usePcf8574 = false;
+ uint8_t addrPcf8574 = PCF8574_ADDRESS;
bool HAautodiscovery = false;
uint16_t periodicBroadcastSec = 60;
@@ -64,136 +78,28 @@ class MultiRelay : public Usermod {
static const char _button[];
static const char _broadcast[];
static const char _HAautodiscovery[];
+ static const char _pcf8574[];
+ static const char _pcfAddress[];
- void publishMqtt(int relay) {
+ void handleOffTimer();
+ void InitHtmlAPIHandle();
+ int getValue(String data, char separator, int index);
+ uint8_t getActiveRelayCount();
+
+ byte IOexpanderWrite(byte address, byte _data);
+ byte IOexpanderRead(int address);
+
+ void publishMqtt(int relay);
#ifndef WLED_DISABLE_MQTT
- //Check if MQTT Connected, otherwise it will crash the 8266
- if (WLED_MQTT_CONNECTED){
- char subuf[64];
- sprintf_P(subuf, PSTR("%s/relay/%d"), mqttDeviceTopic, relay);
- mqtt->publish(subuf, 0, false, _relay[relay].state ? "on" : "off");
- }
+ void publishHomeAssistantAutodiscovery();
#endif
- }
-
- /**
- * switch off the strip if the delay has elapsed
- */
- void handleOffTimer() {
- unsigned long now = millis();
- bool activeRelays = false;
- for (int i=0; i 0 && now - _switchTimerStart > (_relay[i].delay*1000)) {
- if (!_relay[i].external) toggleRelay(i);
- _relay[i].active = false;
- } else if (periodicBroadcastSec && now - lastBroadcast > (periodicBroadcastSec*1000)) {
- if (_relay[i].pin>=0) publishMqtt(i);
- }
- activeRelays = activeRelays || _relay[i].active;
- }
- if (!activeRelays) _switchTimerStart = 0;
- if (periodicBroadcastSec && now - lastBroadcast > (periodicBroadcastSec*1000)) lastBroadcast = now;
- }
-
- /**
- * HTTP API handler
- * borrowed from:
- * https://github.com/gsieben/WLED/blob/master/usermods/GeoGab-Relays/usermod_GeoGab.h
- */
- #define GEOGABVERSION "0.1.3"
- void InitHtmlAPIHandle() { // https://github.com/me-no-dev/ESPAsyncWebServer
- DEBUG_PRINTLN(F("Relays: Initialize HTML API"));
-
- server.on("/relays", HTTP_GET, [this](AsyncWebServerRequest *request) {
- DEBUG_PRINTLN("Relays: HTML API");
- String janswer;
- String error = "";
- //int params = request->params();
- janswer = F("{\"NoOfRelays\":");
- janswer += String(MULTI_RELAY_MAX_RELAYS) + ",";
-
- if (getActiveRelayCount()) {
- // Commands
- if(request->hasParam("switch")) {
- /**** Switch ****/
- AsyncWebParameter* p = request->getParam("switch");
- // Get Values
- for (int i=0; ivalue(), ',', i);
- if (value==-1) {
- error = F("There must be as many arguments as relays");
- } else {
- // Switch
- if (_relay[i].external) switchRelay(i, (bool)value);
- }
- }
- } else if(request->hasParam("toggle")) {
- /**** Toggle ****/
- AsyncWebParameter* p = request->getParam("toggle");
- // Get Values
- for (int i=0;ivalue(), ',', i);
- if (value==-1) {
- error = F("There must be as many arguments as relays");
- } else {
- // Toggle
- if (value && _relay[i].external) toggleRelay(i);
- }
- }
- } else {
- error = F("No valid command found");
- }
- } else {
- error = F("No active relays");
- }
-
- // Status response
- char sbuf[16];
- for (int i=0; isend(200, "application/json", janswer);
- });
- }
-
- int getValue(String data, char separator, int index) {
- int found = 0;
- int strIndex[] = {0, -1};
- int maxIndex = data.length()-1;
-
- for(int i=0; i<=maxIndex && found<=index; i++){
- if(data.charAt(i)==separator || i==maxIndex){
- found++;
- strIndex[0] = strIndex[1]+1;
- strIndex[1] = (i == maxIndex) ? i+1 : i;
- }
- }
- return found>index ? data.substring(strIndex[0], strIndex[1]).toInt() : -1;
- }
public:
/**
* constructor
*/
- MultiRelay() {
- const int8_t defPins[] = {MULTI_RELAY_PINS};
- for (size_t i=0; i=MULTI_RELAY_MAX_RELAYS || _relay[relay].pin<0) return;
- _relay[relay].state = mode;
- pinMode(_relay[relay].pin, OUTPUT);
- digitalWrite(_relay[relay].pin, mode ? !_relay[relay].mode : _relay[relay].mode);
- publishMqtt(relay);
- }
+ void switchRelay(uint8_t relay, bool mode);
/**
* toggle relay
@@ -226,359 +133,58 @@ class MultiRelay : public Usermod {
switchRelay(relay, !_relay[relay].state);
}
- uint8_t getActiveRelayCount() {
- uint8_t count = 0;
- for (int i=0; i=0) count++;
- return count;
- }
-
- //Functions called by WLED
-
-#ifndef WLED_DISABLE_MQTT
- /**
- * handling of MQTT message
- * topic only contains stripped topic (part after /wled/MAC)
- * topic should look like: /relay/X/command; where X is relay number, 0 based
- */
- bool onMqttMessage(char* topic, char* payload) {
- if (strlen(topic) > 8 && strncmp_P(topic, PSTR("/relay/"), 7) == 0 && strncmp_P(topic+8, PSTR("/command"), 8) == 0) {
- uint8_t relay = strtoul(topic+7, NULL, 10);
- if (relaysubscribe(subuf, 0);
- if (HAautodiscovery) publishHomeAssistantAutodiscovery();
- for (int i=0; i= 0 && _relay[i].external) {
- StaticJsonDocument<1024> json;
- sprintf_P(buf, PSTR("%s Switch %d"), serverDescription, i); //max length: 33 + 8 + 3 = 44
- json[F("name")] = buf;
-
- sprintf_P(buf, PSTR("%s/relay/%d"), mqttDeviceTopic, i); //max length: 33 + 7 + 3 = 43
- json["~"] = buf;
- strcat_P(buf, PSTR("/command"));
- mqtt->subscribe(buf, 0);
-
- json[F("stat_t")] = "~";
- json[F("cmd_t")] = F("~/command");
- json[F("pl_off")] = "off";
- json[F("pl_on")] = "on";
- json[F("uniq_id")] = uid;
-
- strcpy(buf, mqttDeviceTopic); //max length: 33 + 7 = 40
- strcat_P(buf, PSTR("/status"));
- json[F("avty_t")] = buf;
- json[F("pl_avail")] = F("online");
- json[F("pl_not_avail")] = F("offline");
- //TODO: dev
- payload_size = serializeJson(json, json_str);
- } else {
- //Unpublish disabled or internal relays
- json_str[0] = 0;
- payload_size = 0;
- }
- sprintf_P(buf, PSTR("homeassistant/switch/%s/config"), uid);
- mqtt->publish(buf, 0, true, json_str, payload_size);
- }
- }
-#endif
-
/**
* setup() is called once at boot. WiFi is not yet connected at this point.
* You can use it to initialize variables, sensors or similar.
*/
- void setup() {
- // pins retrieved from cfg.json (readFromConfig()) prior to running setup()
- for (int i=0; i=0 && !_relay[i].external) _relay[i].active = true;
- }
- }
-
- handleOffTimer();
- }
+#ifndef WLED_DISABLE_MQTT
+ bool onMqttMessage(char* topic, char* payload);
+ void onMqttConnect(bool sessionPresent);
+#endif
/**
* handleButton() can be used to override default button behaviour. Returning true
* will prevent button working in a default way.
* Replicating button.cpp
*/
- bool handleButton(uint8_t b) {
- yield();
- if (!enabled
- || buttonType[b] == BTN_TYPE_NONE
- || buttonType[b] == BTN_TYPE_RESERVED
- || buttonType[b] == BTN_TYPE_PIR_SENSOR
- || buttonType[b] == BTN_TYPE_ANALOG
- || buttonType[b] == BTN_TYPE_ANALOG_INVERTED) {
- return false;
- }
+ bool handleButton(uint8_t b);
- bool handled = false;
- for (int i=0; i WLED_DEBOUNCE_THRESHOLD) { //fire edge event only after 50ms without change (debounce)
- for (int i=0; i 600) { //long press
- //longPressAction(b); //not exposed
- //handled = false; //use if you want to pass to default behaviour
- buttonLongPressed[b] = true;
- }
-
- } else if (!isButtonPressed(b) && buttonPressedBefore[b]) { //released
-
- long dur = now - buttonPressedTime[b];
- if (dur < WLED_DEBOUNCE_THRESHOLD) {
- buttonPressedBefore[b] = false;
- return handled;
- } //too short "press", debounce
- bool doublePress = buttonWaitTime[b]; //did we have short press before?
- buttonWaitTime[b] = 0;
-
- if (!buttonLongPressed[b]) { //short press
- // if this is second release within 350ms it is a double press (buttonWaitTime!=0)
- if (doublePress) {
- //doublePressAction(b); //not exposed
- //handled = false; //use if you want to pass to default behaviour
- } else {
- buttonWaitTime[b] = now;
- }
- }
- buttonPressedBefore[b] = false;
- buttonLongPressed[b] = false;
- }
- // if 350ms elapsed since last press/release it is a short press
- if (buttonWaitTime[b] && now - buttonWaitTime[b] > 350 && !buttonPressedBefore[b]) {
- buttonWaitTime[b] = 0;
- //shortPressAction(b); //not exposed
- for (int i=0; i");
- uiDomString += F("");
- infoArr.add(uiDomString);
- }
- }
- }
+ void addToJsonInfo(JsonObject &root);
/**
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
* Values in the state object may be modified by connected clients
*/
- void addToJsonState(JsonObject &root) {
- if (!initDone || !enabled) return; // prevent crash on boot applyPreset()
- JsonObject multiRelay = root[FPSTR(_name)];
- if (multiRelay.isNull()) {
- multiRelay = root.createNestedObject(FPSTR(_name));
- }
- #if MULTI_RELAY_MAX_RELAYS > 1
- JsonArray rel_arr = multiRelay.createNestedArray(F("relays"));
- for (int i=0; i() && usermod[FPSTR(_relay_str)].as()>=0) {
- int rly = usermod[FPSTR(_relay_str)].as();
- if (usermod["on"].is()) {
- switchRelay(rly, usermod["on"].as());
- } else if (usermod["on"].is() && usermod["on"].as()[0] == 't') {
- toggleRelay(rly);
- }
- }
- } else if (root[FPSTR(_name)].is()) {
- JsonArray relays = root[FPSTR(_name)].as();
- for (JsonVariant r : relays) {
- if (r[FPSTR(_relay_str)].is() && r[FPSTR(_relay_str)].as()>=0) {
- int rly = r[FPSTR(_relay_str)].as();
- if (r["on"].is()) {
- switchRelay(rly, r["on"].as());
- } else if (r["on"].is() && r["on"].as()[0] == 't') {
- toggleRelay(rly);
- }
- }
- }
- }
- }
+ void readFromJsonState(JsonObject &root);
/**
* provide the changeable values
*/
- void addToConfig(JsonObject &root) {
- JsonObject top = root.createNestedObject(FPSTR(_name));
+ void addToConfig(JsonObject &root);
- top[FPSTR(_enabled)] = enabled;
- top[FPSTR(_broadcast)] = periodicBroadcastSec;
- for (int i=0; i=0) {
- pinManager.deallocatePin(oldPin[i], PinOwner::UM_MultiRelay);
- }
- // allocate new pins
- for (int i=0; i=0 && pinManager.allocatePin(_relay[i].pin, true, PinOwner::UM_MultiRelay)) {
- if (!_relay[i].external) {
- _relay[i].state = !offMode;
- switchRelay(i, _relay[i].state);
- _oldMode = offMode;
- }
- } else {
- _relay[i].pin = -1;
- }
- _relay[i].active = false;
- }
- DEBUG_PRINTLN(F(" config (re)loaded."));
- }
- // use "return !top["newestParameter"].isNull();" when updating Usermod with new features
- return !top[FPSTR(_HAautodiscovery)].isNull();
- }
-
- /**
- * 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.
- */
- uint16_t getId()
- {
- return USERMOD_ID_MULTI_RELAY;
- }
+ bool readFromConfig(JsonObject &root);
};
+
+// class implementetion
+
+void MultiRelay::publishMqtt(int relay) {
+#ifndef WLED_DISABLE_MQTT
+ //Check if MQTT Connected, otherwise it will crash the 8266
+ if (WLED_MQTT_CONNECTED){
+ char subuf[64];
+ sprintf_P(subuf, PSTR("%s/relay/%d"), mqttDeviceTopic, relay);
+ mqtt->publish(subuf, 0, false, _relay[relay].state ? "on" : "off");
+ }
+#endif
+}
+
+/**
+ * switch off the strip if the delay has elapsed
+ */
+void MultiRelay::handleOffTimer() {
+ unsigned long now = millis();
+ bool activeRelays = false;
+ for (int i=0; i 0 && now - _switchTimerStart > (_relay[i].delay*1000)) {
+ if (!_relay[i].external) switchRelay(i, !offMode);
+ _relay[i].active = false;
+ } else if (periodicBroadcastSec && now - lastBroadcast > (periodicBroadcastSec*1000)) {
+ if (_relay[i].pin>=0) publishMqtt(i);
+ }
+ activeRelays = activeRelays || _relay[i].active;
+ }
+ if (!activeRelays) _switchTimerStart = 0;
+ if (periodicBroadcastSec && now - lastBroadcast > (periodicBroadcastSec*1000)) lastBroadcast = now;
+}
+
+/**
+ * HTTP API handler
+ * borrowed from:
+ * https://github.com/gsieben/WLED/blob/master/usermods/GeoGab-Relays/usermod_GeoGab.h
+ */
+#define GEOGABVERSION "0.1.3"
+void MultiRelay::InitHtmlAPIHandle() { // https://github.com/me-no-dev/ESPAsyncWebServer
+ DEBUG_PRINTLN(F("Relays: Initialize HTML API"));
+
+ server.on("/relays", HTTP_GET, [this](AsyncWebServerRequest *request) {
+ DEBUG_PRINTLN("Relays: HTML API");
+ String janswer;
+ String error = "";
+ //int params = request->params();
+ janswer = F("{\"NoOfRelays\":");
+ janswer += String(MULTI_RELAY_MAX_RELAYS) + ",";
+
+ if (getActiveRelayCount()) {
+ // Commands
+ if(request->hasParam("switch")) {
+ /**** Switch ****/
+ AsyncWebParameter* p = request->getParam("switch");
+ // Get Values
+ for (int i=0; ivalue(), ',', i);
+ if (value==-1) {
+ error = F("There must be as many arguments as relays");
+ } else {
+ // Switch
+ if (_relay[i].external) switchRelay(i, (bool)value);
+ }
+ }
+ } else if(request->hasParam("toggle")) {
+ /**** Toggle ****/
+ AsyncWebParameter* p = request->getParam("toggle");
+ // Get Values
+ for (int i=0;ivalue(), ',', i);
+ if (value==-1) {
+ error = F("There must be as many arguments as relays");
+ } else {
+ // Toggle
+ if (value && _relay[i].external) toggleRelay(i);
+ }
+ }
+ } else {
+ error = F("No valid command found");
+ }
+ } else {
+ error = F("No active relays");
+ }
+
+ // Status response
+ char sbuf[16];
+ for (int i=0; isend(200, "application/json", janswer);
+ });
+}
+
+int MultiRelay::getValue(String data, char separator, int index) {
+ int found = 0;
+ int strIndex[] = {0, -1};
+ int maxIndex = data.length()-1;
+
+ for(int i=0; i<=maxIndex && found<=index; i++){
+ if(data.charAt(i)==separator || i==maxIndex){
+ found++;
+ strIndex[0] = strIndex[1]+1;
+ strIndex[1] = (i == maxIndex) ? i+1 : i;
+ }
+ }
+ return found>index ? data.substring(strIndex[0], strIndex[1]).toInt() : -1;
+}
+
+//Write a byte to the IO expander
+byte MultiRelay::IOexpanderWrite(byte address, byte _data ) {
+ Wire.beginTransmission(addrPcf8574 + address);
+ Wire.write(_data);
+ return Wire.endTransmission();
+}
+
+//Read a byte from the IO expander
+byte MultiRelay::IOexpanderRead(int address) {
+ byte _data = 0;
+ Wire.requestFrom(addrPcf8574 + address, 1);
+ if (Wire.available()) {
+ _data = Wire.read();
+ }
+ return _data;
+}
+
+
+// public methods
+
+MultiRelay::MultiRelay() {
+ const int8_t defPins[] = {MULTI_RELAY_PINS};
+ for (size_t i=0; i=MULTI_RELAY_MAX_RELAYS || (_relay[relay].pin<0 && !usePcf8574)) return;
+ _relay[relay].state = mode;
+ if (usePcf8574) {
+ byte expander = relay/8;
+ uint16_t state = 0;
+ for (int i=0; i>(8*expander));
+ DEBUG_PRINT(F("PCF8574 Writing to ")); DEBUG_PRINT(addrPcf8574 + expander); DEBUG_PRINT(F(" with data ")); DEBUG_PRINTLN(state>>(8*expander));
+ } else {
+ pinMode(_relay[relay].pin, OUTPUT);
+ digitalWrite(_relay[relay].pin, mode ? !_relay[relay].mode : _relay[relay].mode);
+ }
+ publishMqtt(relay);
+}
+
+uint8_t MultiRelay::getActiveRelayCount() {
+ uint8_t count = 0;
+ if (usePcf8574) return MULTI_RELAY_MAX_RELAYS; // we don't know how many there are
+ for (int i=0; i=0) count++;
+ return count;
+}
+
+
+//Functions called by WLED
+
+#ifndef WLED_DISABLE_MQTT
+/**
+ * handling of MQTT message
+ * topic only contains stripped topic (part after /wled/MAC)
+ * topic should look like: /relay/X/command; where X is relay number, 0 based
+ */
+bool MultiRelay::onMqttMessage(char* topic, char* payload) {
+ if (strlen(topic) > 8 && strncmp_P(topic, PSTR("/relay/"), 7) == 0 && strncmp_P(topic+8, PSTR("/command"), 8) == 0) {
+ uint8_t relay = strtoul(topic+7, NULL, 10);
+ if (relaysubscribe(subuf, 0);
+ if (HAautodiscovery) publishHomeAssistantAutodiscovery();
+ for (int i=0; i= 0 && _relay[i].external) {
+ StaticJsonDocument<1024> json;
+ sprintf_P(buf, PSTR("%s Switch %d"), serverDescription, i); //max length: 33 + 8 + 3 = 44
+ json[F("name")] = buf;
+
+ sprintf_P(buf, PSTR("%s/relay/%d"), mqttDeviceTopic, i); //max length: 33 + 7 + 3 = 43
+ json["~"] = buf;
+ strcat_P(buf, PSTR("/command"));
+ mqtt->subscribe(buf, 0);
+
+ json[F("stat_t")] = "~";
+ json[F("cmd_t")] = F("~/command");
+ json[F("pl_off")] = "off";
+ json[F("pl_on")] = "on";
+ json[F("uniq_id")] = uid;
+
+ strcpy(buf, mqttDeviceTopic); //max length: 33 + 7 = 40
+ strcat_P(buf, PSTR("/status"));
+ json[F("avty_t")] = buf;
+ json[F("pl_avail")] = F("online");
+ json[F("pl_not_avail")] = F("offline");
+ //TODO: dev
+ payload_size = serializeJson(json, json_str);
+ } else {
+ //Unpublish disabled or internal relays
+ json_str[0] = 0;
+ payload_size = 0;
+ }
+ sprintf_P(buf, PSTR("homeassistant/switch/%s/config"), uid);
+ mqtt->publish(buf, 0, true, json_str, payload_size);
+ }
+}
+#endif
+
+/**
+ * setup() is called once at boot. WiFi is not yet connected at this point.
+ * You can use it to initialize variables, sensors or similar.
+ */
+void MultiRelay::setup() {
+ // pins retrieved from cfg.json (readFromConfig()) prior to running setup()
+ // if we want PCF8574 expander I2C pins need to be valid
+ if (i2c_sda == i2c_scl && i2c_sda == -1) usePcf8574 = false;
+
+ if (usePcf8574) {
+ uint16_t state = 0;
+ for (int i=0; i>(8*expander)); // init expander (set all outputs)
+ delay(1);
+ }
+ DEBUG_PRINTLN(F("PCF8574(s) inited."));
+ } else {
+ for (int i=0; i=0 || usePcf8574) && !_relay[i].external) _relay[i].active = true;
+ }
+ }
+
+ handleOffTimer();
+}
+
+/**
+ * handleButton() can be used to override default button behaviour. Returning true
+ * will prevent button working in a default way.
+ * Replicating button.cpp
+ */
+bool MultiRelay::handleButton(uint8_t b) {
+ yield();
+ if (!enabled
+ || buttonType[b] == BTN_TYPE_NONE
+ || buttonType[b] == BTN_TYPE_RESERVED
+ || buttonType[b] == BTN_TYPE_PIR_SENSOR
+ || buttonType[b] == BTN_TYPE_ANALOG
+ || buttonType[b] == BTN_TYPE_ANALOG_INVERTED) {
+ return false;
+ }
+
+ bool handled = false;
+ for (int i=0; i WLED_DEBOUNCE_THRESHOLD) { //fire edge event only after 50ms without change (debounce)
+ for (int i=0; i 600) { //long press
+ //longPressAction(b); //not exposed
+ //handled = false; //use if you want to pass to default behaviour
+ buttonLongPressed[b] = true;
+ }
+
+ } else if (!isButtonPressed(b) && buttonPressedBefore[b]) { //released
+
+ long dur = now - buttonPressedTime[b];
+ if (dur < WLED_DEBOUNCE_THRESHOLD) {
+ buttonPressedBefore[b] = false;
+ return handled;
+ } //too short "press", debounce
+ bool doublePress = buttonWaitTime[b]; //did we have short press before?
+ buttonWaitTime[b] = 0;
+
+ if (!buttonLongPressed[b]) { //short press
+ // if this is second release within 350ms it is a double press (buttonWaitTime!=0)
+ if (doublePress) {
+ //doublePressAction(b); //not exposed
+ //handled = false; //use if you want to pass to default behaviour
+ } else {
+ buttonWaitTime[b] = now;
+ }
+ }
+ buttonPressedBefore[b] = false;
+ buttonLongPressed[b] = false;
+ }
+ // if 350ms elapsed since last press/release it is a short press
+ if (buttonWaitTime[b] && now - buttonWaitTime[b] > 350 && !buttonPressedBefore[b]) {
+ buttonWaitTime[b] = 0;
+ //shortPressAction(b); //not exposed
+ for (int i=0; i");
+ uiDomString += F("");
+ infoArr.add(uiDomString);
+ }
+ }
+}
+
+/**
+ * addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
+ * Values in the state object may be modified by connected clients
+ */
+void MultiRelay::addToJsonState(JsonObject &root) {
+ if (!initDone || !enabled) return; // prevent crash on boot applyPreset()
+ JsonObject multiRelay = root[FPSTR(_name)];
+ if (multiRelay.isNull()) {
+ multiRelay = root.createNestedObject(FPSTR(_name));
+ }
+ #if MULTI_RELAY_MAX_RELAYS > 1
+ JsonArray rel_arr = multiRelay.createNestedArray(F("relays"));
+ for (int i=0; i() && usermod[FPSTR(_relay_str)].as()>=0) {
+ int rly = usermod[FPSTR(_relay_str)].as();
+ if (usermod["on"].is()) {
+ switchRelay(rly, usermod["on"].as());
+ } else if (usermod["on"].is() && usermod["on"].as()[0] == 't') {
+ toggleRelay(rly);
+ }
+ }
+ } else if (root[FPSTR(_name)].is()) {
+ JsonArray relays = root[FPSTR(_name)].as();
+ for (JsonVariant r : relays) {
+ if (r[FPSTR(_relay_str)].is() && r[FPSTR(_relay_str)].as()>=0) {
+ int rly = r[FPSTR(_relay_str)].as();
+ if (r["on"].is()) {
+ switchRelay(rly, r["on"].as());
+ } else if (r["on"].is() && r["on"].as()[0] == 't') {
+ toggleRelay(rly);
+ }
+ }
+ }
+ }
+}
+
+/**
+ * provide the changeable values
+ */
+void MultiRelay::addToConfig(JsonObject &root) {
+ JsonObject top = root.createNestedObject(FPSTR(_name));
+
+ top[FPSTR(_enabled)] = enabled;
+ top[FPSTR(_pcf8574)] = usePcf8574;
+ top[FPSTR(_pcfAddress)] = addrPcf8574;
+ top[FPSTR(_broadcast)] = periodicBroadcastSec;
+ top[FPSTR(_HAautodiscovery)] = HAautodiscovery;
+ for (int i=0; i(not hex!)','address');"));
+ oappend(SET_F("addInfo('MultiRelay:broadcast-sec',1,'(MQTT message)');"));
+ oappend(SET_F("addInfo('MultiRelay:relay-0:pin',1,'(use -1 for PCF8574)');"));
+}
+
+/**
+ * restore the changeable values
+ * readFromConfig() is called before setup() to populate properties from values stored in cfg.json
+ *
+ * The function should return true if configuration was successfully loaded or false if there was no configuration.
+ */
+bool MultiRelay::readFromConfig(JsonObject &root) {
+ int8_t oldPin[MULTI_RELAY_MAX_RELAYS];
+
+ JsonObject top = root[FPSTR(_name)];
+ if (top.isNull()) {
+ DEBUG_PRINT(FPSTR(_name));
+ DEBUG_PRINTLN(F(": No config found. (Using defaults.)"));
+ return false;
+ }
+
+ //bool configComplete = !top.isNull();
+ //configComplete &= getJsonValue(top[FPSTR(_enabled)], enabled);
+ enabled = top[FPSTR(_enabled)] | enabled;
+ usePcf8574 = top[FPSTR(_pcf8574)] | usePcf8574;
+ addrPcf8574 = top[FPSTR(_pcfAddress)] | addrPcf8574;
+ // if I2C is not globally initialised just ignore
+ if (i2c_sda == i2c_scl && i2c_sda == -1) usePcf8574 = false;
+ periodicBroadcastSec = top[FPSTR(_broadcast)] | periodicBroadcastSec;
+ periodicBroadcastSec = min(900,max(0,(int)periodicBroadcastSec));
+ HAautodiscovery = top[FPSTR(_HAautodiscovery)] | HAautodiscovery;
+
+ for (int i=0; i=0) {
+ pinManager.deallocatePin(oldPin[i], PinOwner::UM_MultiRelay);
+ }
+ // allocate new pins
+ for (int i=0; i=0 && pinManager.allocatePin(_relay[i].pin, true, PinOwner::UM_MultiRelay)) {
+ if (!_relay[i].external) {
+ _relay[i].state = !offMode;
+ switchRelay(i, _relay[i].state);
+ _oldMode = offMode;
+ }
+ } else {
+ _relay[i].pin = -1;
+ }
+ _relay[i].active = false;
+ }
+ DEBUG_PRINTLN(F(" config (re)loaded."));
+ }
+ // use "return !top["newestParameter"].isNull();" when updating Usermod with new features
+ return !top[FPSTR(_pcf8574)].isNull();
+}
+
// strings to reduce flash memory usage (used more than twice)
-const char MultiRelay::_name[] PROGMEM = "MultiRelay";
-const char MultiRelay::_enabled[] PROGMEM = "enabled";
-const char MultiRelay::_relay_str[] PROGMEM = "relay";
-const char MultiRelay::_delay_str[] PROGMEM = "delay-s";
-const char MultiRelay::_activeHigh[] PROGMEM = "active-high";
-const char MultiRelay::_external[] PROGMEM = "external";
-const char MultiRelay::_button[] PROGMEM = "button";
-const char MultiRelay::_broadcast[] PROGMEM = "broadcast-sec";
+const char MultiRelay::_name[] PROGMEM = "MultiRelay";
+const char MultiRelay::_enabled[] PROGMEM = "enabled";
+const char MultiRelay::_relay_str[] PROGMEM = "relay";
+const char MultiRelay::_delay_str[] PROGMEM = "delay-s";
+const char MultiRelay::_activeHigh[] PROGMEM = "active-high";
+const char MultiRelay::_external[] PROGMEM = "external";
+const char MultiRelay::_button[] PROGMEM = "button";
+const char MultiRelay::_broadcast[] PROGMEM = "broadcast-sec";
const char MultiRelay::_HAautodiscovery[] PROGMEM = "HA-autodiscovery";
+const char MultiRelay::_pcf8574[] PROGMEM = "use-PCF8574";
+const char MultiRelay::_pcfAddress[] PROGMEM = "first-PCF8574";
diff --git a/wled00/FX.cpp b/wled00/FX.cpp
index 04208d6f..487db7e4 100644
--- a/wled00/FX.cpp
+++ b/wled00/FX.cpp
@@ -2805,7 +2805,7 @@ uint16_t mode_bouncing_balls(void) {
// number of balls based on intensity setting to max of 7 (cycles colors)
// non-chosen color is a random color
uint16_t numBalls = (SEGMENT.intensity * (maxNumBalls - 1)) / 255 + 1; // minimum 1 ball
- constexpr float gravity = -9.81; // standard value of gravity
+ const float gravity = -9.81f; // standard value of gravity
const bool hasCol2 = SEGCOLOR(2);
const unsigned long time = millis();
@@ -4177,11 +4177,9 @@ static const char _data_FX_MODE_DANCING_SHADOWS[] PROGMEM = "Dancing Shadows@!,#
By Stefan Seegel
*/
uint16_t mode_washing_machine(void) {
- float speed = tristate_square8(strip.now >> 7, 90, 15);
- float quot = 32.0f - ((float)SEGMENT.speed / 16.0f);
- speed /= quot;
+ int speed = tristate_square8(strip.now >> 7, 90, 15);
- SEGENV.step += (speed * 128.0f);
+ SEGENV.step += (speed * 2048) / (512 - SEGMENT.speed);
for (int i = 0; i < SEGLEN; i++) {
uint8_t col = sin8(((SEGMENT.intensity / 25 + 1) * 255 * i / SEGLEN) + (SEGENV.step >> 7));
@@ -4595,7 +4593,7 @@ uint16_t mode_2DBlackHole(void) { // By: Stepko https://editor.soulma
}
SEGMENT.fadeToBlackBy(16 + (SEGMENT.speed>>3)); // create fading trails
- float t = (float)(millis())/128; // timebase
+ unsigned long t = millis()/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);
@@ -5098,7 +5096,9 @@ uint16_t mode_2DLissajous(void) { // By: Andrew Tuline
const uint16_t cols = SEGMENT.virtualWidth();
const uint16_t rows = SEGMENT.virtualHeight();
+ if (SEGENV.call == 0) { SEGMENT.setUpLeds(); SEGMENT.fill(BLACK);} // WLEDMM fadeToBlackBy() needs previous setUpLeds()
SEGMENT.fadeToBlackBy(SEGMENT.intensity);
+
uint_fast16_t phase = (strip.now * (1 + SEGENV.custom3)) /32; // allow user to control rotation speed
if (SEGENV.check3) { // WLEDMM: this is the original "float" code featuring anti-aliasing
diff --git a/wled00/FX.h b/wled00/FX.h
index b2eb474a..732af8ff 100644
--- a/wled00/FX.h
+++ b/wled00/FX.h
@@ -371,7 +371,8 @@ typedef struct Segment {
bool mirror_y : 1; // 8 : mirrored Y (2D)
bool transpose : 1; // 9 : transposed (2D, swapped X & Y)
uint8_t map1D2D : 3; // 10-12 : mapping for 1D effect on 2D (0-use as strip, 1-expand vertically, 2-circular/arc, 3-rectangular/corner, ...)
- uint8_t soundSim : 3; // 13-15 : 0-7 sound simulation types
+ uint8_t soundSim : 1; // 13 : 0-1 sound simulation types ("soft" & "hard" or "on"/"off")
+ uint8_t set : 2; // 14-15 : 0-3 UI segment sets/groups
};
};
uint8_t grouping, spacing;
@@ -544,7 +545,7 @@ typedef struct Segment {
void allocLeds(); //WLEDMM
- void set(uint16_t i1, uint16_t i2, uint8_t grp=1, uint8_t spc=0, uint16_t ofs=UINT16_MAX, uint16_t i1Y=0, uint16_t i2Y=1);
+ void setUp(uint16_t i1, uint16_t i2, uint8_t grp=1, uint8_t spc=0, uint16_t ofs=UINT16_MAX, uint16_t i1Y=0, uint16_t i2Y=1);
bool setColor(uint8_t slot, uint32_t c); //returns true if changed
void setCCT(uint16_t k);
void setOpacity(uint8_t o);
@@ -831,6 +832,7 @@ class WS2812FX { // 96 bytes
getActiveSegmentsNum(void),
getFirstSelectedSegId(void),
getLastActiveSegmentId(void),
+ getActiveSegsLightCapabilities(bool selectedOnly = false),
setPixelSegment(uint8_t n);
inline uint8_t getBrightness(void) { return _brightness; }
diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp
index d675af30..f746a1bf 100644
--- a/wled00/FX_2Dfcn.cpp
+++ b/wled00/FX_2Dfcn.cpp
@@ -63,11 +63,12 @@ void WS2812FX::setUpMatrix() {
return;
}
+ USER_PRINTF("setUpMatrix %d x %d\n", Segment::maxWidth, Segment::maxHeight);
+
//WLEDMM recreate customMappingTable if more space needed
if (Segment::maxWidth * Segment::maxHeight > customMappingTableSize) {
uint32_t size = MAX(ledmapMaxSize, Segment::maxWidth * Segment::maxHeight);//TroyHack
USER_PRINTF("setupmatrix customMappingTable alloc %d from %d\n", size, customMappingTableSize);
-
//if (customMappingTable != nullptr) delete[] customMappingTable;
//customMappingTable = new uint16_t[size];
diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp
index 4ec9aafd..c170f31d 100644
--- a/wled00/FX_fcn.cpp
+++ b/wled00/FX_fcn.cpp
@@ -186,12 +186,12 @@ bool Segment::allocateData(size_t len) {
if (data && _dataLen == len) return true; //already allocated
deallocateData();
if (Segment::getUsedSegmentData() + len > MAX_SEGMENT_DATA) return false; //not enough memory
- // if possible use SPI RAM on ESP32
- #if defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM) && defined(WLED_USE_PSRAM)
- if (psramFound())
- data = (byte*) ps_malloc(len);
- else
- #endif
+ // do not use SPI RAM on ESP32 since it is slow
+ //#if defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM) && defined(WLED_USE_PSRAM)
+ //if (psramFound())
+ // data = (byte*) ps_malloc(len);
+ //else
+ //#endif
data = (byte*) malloc(len);
if (!data) return false; //allocation failed
Segment::addUsedSegmentData(len);
@@ -438,7 +438,7 @@ void Segment::handleTransition() {
}
}
-void Segment::set(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t ofs, uint16_t i1Y, uint16_t i2Y) {
+void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t ofs, uint16_t i1Y, uint16_t i2Y) {
//return if neither bounds nor grouping have changed
bool boundsUnchanged = (start == i1 && stop == i2);
#ifndef WLED_DISABLE_2D
@@ -542,7 +542,7 @@ void Segment::setMode(uint8_t fx, bool loadDefaults) {
sOpt = extractModeDefaults(fx, "o3"); check3 = (sOpt >= 0) ? (bool)sOpt : false;
//WLEDMM: return to old setting if not explicitly set
sOpt = extractModeDefaults(fx, "m12"); if (sOpt >= 0) {if (oldMap==-1) oldMap = map1D2D; map1D2D = constrain(sOpt, 0, 7);} else {if (oldMap!=-1) map1D2D = oldMap; oldMap = -1;}
- sOpt = extractModeDefaults(fx, "si"); if (sOpt >= 0) {if (oldSim==-1) oldSim = soundSim; soundSim = constrain(sOpt, 0, 7);} else {if (oldSim!=-1) soundSim = oldSim; oldSim = -1;}
+ sOpt = extractModeDefaults(fx, "si"); if (sOpt >= 0) {if (oldSim==-1) oldSim = soundSim; soundSim = constrain(sOpt, 0, 1);} else {if (oldSim!=-1) soundSim = oldSim; oldSim = -1;}
sOpt = extractModeDefaults(fx, "rev"); if (sOpt >= 0) {if (oldReverse==-1) oldReverse = reverse; reverse = (bool)sOpt;} else {if (oldReverse!=-1) reverse = oldReverse==1; oldReverse = -1;}
sOpt = extractModeDefaults(fx, "mi"); if (sOpt >= 0) {if (oldMirror==-1) oldMirror = mirror; mirror = (bool)sOpt;} else {if (oldMirror!=-1) mirror = oldMirror==1; oldMirror = -1;} // NOTE: setting this option is a risky business
sOpt = extractModeDefaults(fx, "rY"); if (sOpt >= 0) {if (oldReverse_y==-1) oldReverse_y = reverse_y; reverse_y = (bool)sOpt;} else {if (oldReverse_y!=-1) reverse_y = oldReverse_y==1; oldReverse_y = -1;}
@@ -1064,7 +1064,7 @@ uint8_t Segment::differs(Segment& b) const {
if (startY != b.startY) d |= SEG_DIFFERS_BOUNDS;
if (stopY != b.stopY) d |= SEG_DIFFERS_BOUNDS;
- //bit pattern: (msb first) sound:3, mapping:3, transposed, mirrorY, reverseY, [transitional, reset,] paused, mirrored, on, reverse, [selected]
+ //bit pattern: (msb first) set:2, sound:1, mapping:3, transposed, mirrorY, reverseY, [transitional, reset,] paused, mirrored, on, reverse, [selected]
if ((options & 0b1111111110011110U) != (b.options & 0b1111111110011110U)) d |= SEG_DIFFERS_OPT;
if ((options & 0x0001U) != (b.options & 0x0001U)) d |= SEG_DIFFERS_SEL;
for (uint8_t i = 0; i < NUM_COLORS; i++) if (colors[i] != b.colors[i]) d |= SEG_DIFFERS_COL;
@@ -1411,18 +1411,27 @@ void WS2812FX::enumerateLedmaps() {
if (ledmapNames[i-1]) strlcpy(ledmapNames[i-1], tmp, 33);
}
- //WLEDMM calc ledmapMaxSize (TroyHack)
- char dim[34] = { '\0' };
- f.find("\"width\":");
- f.readBytesUntil('\n', dim, sizeof(dim)-1); //hack: use fileName as we have this allocated already
- uint16_t maxWidth = atoi(cleanUpName(dim));
- f.find("\"height\":");
- memset(dim, 0, sizeof(dim)); // clear buffer before reading
- f.readBytesUntil('\n', dim, sizeof(dim)-1);
- uint16_t maxHeight = atoi(cleanUpName(dim));
- ledmapMaxSize = MAX(ledmapMaxSize, maxWidth * maxHeight);
+ USER_PRINTF("enumerateLedmaps %s \"%s\"", fileName, name);
+ if (isMatrix) {
+ //WLEDMM calc ledmapMaxSize (TroyHack)
+ char dim[34] = { '\0' };
+ f.find("\"width\":");
+ f.readBytesUntil('\n', dim, sizeof(dim)-1); //hack: use fileName as we have this allocated already
+ uint16_t maxWidth = atoi(cleanUpName(dim));
+ f.find("\"height\":");
+ memset(dim, 0, sizeof(dim)); // clear buffer before reading
+ f.readBytesUntil('\n', dim, sizeof(dim)-1);
+ uint16_t maxHeight = atoi(cleanUpName(dim));
+ ledmapMaxSize = MAX(ledmapMaxSize, maxWidth * maxHeight);
- USER_PRINTF("enumerateLedmaps %s \"%s\" (%dx%d -> %d)\n", fileName, name, maxWidth, maxHeight, ledmapMaxSize);
+ if (maxWidth*maxHeight>0) {
+ USER_PRINTF(" (%dx%d -> %d)\n", maxWidth, maxHeight, ledmapMaxSize);
+ } else {
+ USER_PRINTLN();
+ }
+ }
+ else
+ USER_PRINTLN();
}
f.close();
USER_FLUSH();
@@ -1822,6 +1831,14 @@ void WS2812FX::setBrightness(uint8_t b, bool direct) {
}
}
+uint8_t WS2812FX::getActiveSegsLightCapabilities(bool selectedOnly) {
+ uint8_t totalLC = 0;
+ for (segment &seg : _segments) {
+ if (seg.isActive() && (!selectedOnly || seg.isSelected())) totalLC |= seg.getLightCapabilities();
+ }
+ return totalLC;
+}
+
uint8_t WS2812FX::getFirstSelectedSegId(void)
{
size_t i = 0;
@@ -1919,7 +1936,7 @@ Segment& WS2812FX::getSegment(uint8_t id) {
void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping, uint8_t spacing, uint16_t offset, uint16_t startY, uint16_t stopY) {
if (n >= _segments.size()) return;
- _segments[n].set(i1, i2, grouping, spacing, offset, startY, stopY);
+ _segments[n].setUp(i1, i2, grouping, spacing, offset, startY, stopY);
}
void WS2812FX::restartRuntime() {
@@ -2208,31 +2225,32 @@ bool WS2812FX::deserializeMap(uint8_t n) {
USER_PRINT(F("Reading LED map from ")); //WLEDMM use USER_PRINT
USER_PRINTLN(fileName);
- //WLEDMM: read width and height (mandatory in file!!)
- f.find("\"width\":");
- f.readBytesUntil('\n', fileName, sizeof(fileName)); //hack: use fileName as we have this allocated already
- uint16_t maxWidth = atoi(fileName);
+ if (isMatrix) {
+ //WLEDMM: read width and height
+ f.find("\"width\":");
+ f.readBytesUntil('\n', fileName, sizeof(fileName)); //hack: use fileName as we have this allocated already
+ uint16_t maxWidth = atoi(fileName);
- f.find("\"height\":");
- f.readBytesUntil('\n', fileName, sizeof(fileName));
- uint16_t maxHeight = atoi(fileName);
+ f.find("\"height\":");
+ f.readBytesUntil('\n', fileName, sizeof(fileName));
+ uint16_t maxHeight = atoi(fileName);
- USER_PRINTF("deserializeMap %d x %d\n", maxWidth, maxHeight);
- if (maxWidth * maxHeight <= 0) {
- releaseJSONBufferLock();
- return false;
+ //WLEDMM: support ledmap file properties width and height: if found change segment
+ if (maxWidth * maxHeight > 0) {
+ Segment::maxWidth = maxWidth;
+ Segment::maxHeight = maxHeight;
+ resetSegments(true); //WLEDMM not makeAutoSegments() as we only want to change bounds
+ }
+ else
+ setUpMatrix(); //reset segment sizes to panels
}
- //WLEDMM: support ledmap file properties width and height
- Segment::maxWidth = maxWidth;
- Segment::maxHeight = maxHeight;
- resetSegments(true); //WLEDMM not makeAutoSegments() as we only want to change bounds
+ USER_PRINTF("deserializeMap %d x %d\n", Segment::maxWidth, Segment::maxHeight);
//WLEDMM recreate customMappingTable if more space needed
if (Segment::maxWidth * Segment::maxHeight > customMappingTableSize) {
uint32_t size = MAX(ledmapMaxSize, Segment::maxWidth * Segment::maxHeight);//TroyHack
USER_PRINTF("deserializemap customMappingTable alloc %d from %d\n", size, customMappingTableSize);
-
//if (customMappingTable != nullptr) delete[] customMappingTable;
//customMappingTable = new uint16_t[size];
@@ -2249,7 +2267,7 @@ bool WS2812FX::deserializeMap(uint8_t n) {
}
if (customMappingTable != nullptr) {
- customMappingSize = maxWidth * maxHeight;
+ customMappingSize = Segment::maxWidth * Segment::maxHeight;
//WLEDMM: find the map values
f.find("\"map\":[");
diff --git a/wled00/alexa.cpp b/wled00/alexa.cpp
index c122402a..179a522c 100644
--- a/wled00/alexa.cpp
+++ b/wled00/alexa.cpp
@@ -101,20 +101,27 @@ void onAlexaChange(EspalexaDevice* dev)
{
byte rgbw[4];
uint16_t ct = dev->getCt();
- if (!ct) return;
- uint16_t k = 1000000 / ct; //mireds to kelvin
-
- if (strip.hasCCTBus()) {
- strip.setCCT(k);
- rgbw[0]= 0; rgbw[1]= 0; rgbw[2]= 0; rgbw[3]= 255;
- } else if (strip.hasWhiteChannel()) {
+ if (!ct) return;
+ uint16_t k = 1000000 / ct; //mireds to kelvin
+
+ if (strip.hasCCTBus()) {
+ bool hasManualWhite = strip.getActiveSegsLightCapabilities(true) & SEG_CAPABILITY_W;
+
+ strip.setCCT(k);
+ if (hasManualWhite) {
+ rgbw[0] = 0; rgbw[1] = 0; rgbw[2] = 0; rgbw[3] = 255;
+ } else {
+ rgbw[0] = 255; rgbw[1] = 255; rgbw[2] = 255; rgbw[3] = 0;
+ dev->setValue(255);
+ }
+ } else if (strip.hasWhiteChannel()) {
switch (ct) { //these values empirically look good on RGBW
case 199: rgbw[0]=255; rgbw[1]=255; rgbw[2]=255; rgbw[3]=255; break;
case 234: rgbw[0]=127; rgbw[1]=127; rgbw[2]=127; rgbw[3]=255; break;
case 284: rgbw[0]= 0; rgbw[1]= 0; rgbw[2]= 0; rgbw[3]=255; break;
case 350: rgbw[0]=130; rgbw[1]= 90; rgbw[2]= 0; rgbw[3]=255; break;
case 383: rgbw[0]=255; rgbw[1]=153; rgbw[2]= 0; rgbw[3]=255; break;
- default : colorKtoRGB(k, rgbw);
+ default : colorKtoRGB(k, rgbw);
}
} else {
colorKtoRGB(k, rgbw);
diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp
index 8f5e1403..1fe48032 100644
--- a/wled00/bus_manager.cpp
+++ b/wled00/bus_manager.cpp
@@ -101,12 +101,14 @@ uint32_t Bus::autoWhiteCalc(uint32_t c) {
BusDigital::BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com) : Bus(bc.type, bc.start, bc.autoWhite), _colorOrderMap(com) {
if (!IS_DIGITAL(bc.type) || !bc.count) return;
if (!pinManager.allocatePin(bc.pins[0], true, PinOwner::BusDigital)) return;
+ _frequencykHz = 0U;
_pins[0] = bc.pins[0];
if (IS_2PIN(bc.type)) {
if (!pinManager.allocatePin(bc.pins[1], true, PinOwner::BusDigital)) {
cleanup(); return;
}
_pins[1] = bc.pins[1];
+ _frequencykHz = bc.frequency ? bc.frequency : 2000U; // 2MHz clock if undefined
}
reversed = bc.reversed;
_needsRefresh = bc.refreshReq || bc.type == TYPE_TM1814;
@@ -116,7 +118,7 @@ BusDigital::BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com) : Bu
if (_iType == I_NONE) return;
uint16_t lenToCreate = _len;
if (bc.type == TYPE_WS2812_1CH_X3) lenToCreate = NUM_ICS_WS2812_1CH_3X(_len); // only needs a third of "RGB" LEDs for NeoPixelBus
- _busPtr = PolyBus::create(_iType, _pins, lenToCreate, nr);
+ _busPtr = PolyBus::create(_iType, _pins, lenToCreate, nr, _frequencykHz);
_valid = (_busPtr != nullptr);
_colorOrder = bc.colorOrder;
if (_pins[1] != 255) { // WLEDMM USER_PRINTF
@@ -222,10 +224,11 @@ BusPwm::BusPwm(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) {
_valid = false;
if (!IS_PWM(bc.type)) return;
uint8_t numPins = NUM_PWM_PINS(bc.type);
+ _frequency = bc.frequency ? bc.frequency : WLED_PWM_FREQ;
#ifdef ESP8266
analogWriteRange(255); //same range as one RGB channel
- analogWriteFreq(WLED_PWM_FREQ);
+ analogWriteFreq(_frequency);
#else
_ledcStart = pinManager.allocateLedc(numPins);
if (_ledcStart == 255) { //no more free LEDC channels
@@ -242,7 +245,7 @@ BusPwm::BusPwm(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) {
#ifdef ESP8266
pinMode(_pins[i], OUTPUT);
#else
- ledcSetup(_ledcStart + i, WLED_PWM_FREQ, 8);
+ ledcSetup(_ledcStart + i, _frequency, 8);
ledcAttachPin(_pins[i], _ledcStart + i);
#endif
}
@@ -462,21 +465,21 @@ void BusNetwork::cleanup() {
uint32_t BusManager::memUsage(BusConfig &bc) {
uint8_t type = bc.type;
uint16_t len = bc.count + bc.skipAmount;
- if (type > 15 && type < 32) {
+ if (type > 15 && type < 32) { // digital types
+ if (type == TYPE_UCS8903 || type == TYPE_UCS8904) len *= 2; // 16-bit LEDs
#ifdef ESP8266
if (bc.pins[0] == 3) { //8266 DMA uses 5x the mem
- if (type > 29) return len*20; //RGBW
+ if (type > 28) return len*20; //RGBW
return len*15;
}
- if (type > 29) return len*4; //RGBW
+ if (type > 28) return len*4; //RGBW
return len*3;
#else //ESP32 RMT uses double buffer?
- if (type > 29) return len*8; //RGBW
+ if (type > 28) return len*8; //RGBW
return len*6;
#endif
}
if (type > 31 && type < 48) return 5;
- if (type == 44 || type == 45) return len*4; //RGBW
return len*3; //RGB
}
diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h
index b39f0d43..945720b2 100644
--- a/wled00/bus_manager.h
+++ b/wled00/bus_manager.h
@@ -29,10 +29,11 @@ struct BusConfig {
bool refreshReq;
uint8_t autoWhite;
uint8_t pins[5] = {LEDPIN, 255, 255, 255, 255};
- BusConfig(uint8_t busType, uint8_t* ppins, uint16_t pstart, uint16_t len = 1, uint8_t pcolorOrder = COL_ORDER_GRB, bool rev = false, uint8_t skip = 0, byte aw=RGBW_MODE_MANUAL_ONLY) {
+ uint16_t frequency;
+ BusConfig(uint8_t busType, uint8_t* ppins, uint16_t pstart, uint16_t len = 1, uint8_t pcolorOrder = COL_ORDER_GRB, bool rev = false, uint8_t skip = 0, byte aw=RGBW_MODE_MANUAL_ONLY, uint16_t clock_kHz=0U) {
refreshReq = (bool) GET_BIT(busType,7);
type = busType & 0x7F; // bit 7 may be/is hacked to include refresh info (1=refresh in off state, 0=no refresh)
- count = len; start = pstart; colorOrder = pcolorOrder; reversed = rev; skipAmount = skip; autoWhite = aw;
+ count = len; start = pstart; colorOrder = pcolorOrder; reversed = rev; skipAmount = skip; autoWhite = aw; frequency = clock_kHz;
uint8_t nPins = 1;
if (type >= TYPE_NET_DDP_RGB && type < 96) nPins = 4; //virtual network bus. 4 "pins" store IP address
else if (type > 47) nPins = 2;
@@ -114,6 +115,7 @@ class Bus {
virtual void setColorOrder() {}
virtual uint8_t getColorOrder() { return COL_ORDER_RGB; }
virtual uint8_t skippedLeds() { return 0; }
+ virtual uint16_t getFrequency() { return 0U; }
inline uint16_t getStart() { return _start; }
inline void setStart(uint16_t start) { _start = start; }
inline uint8_t getType() { return _type; }
@@ -203,6 +205,8 @@ class BusDigital : public Bus {
return _skip;
}
+ uint16_t getFrequency() { return _frequencykHz; }
+
void reinit();
void cleanup();
@@ -216,6 +220,7 @@ class BusDigital : public Bus {
uint8_t _pins[2] = {255, 255};
uint8_t _iType = 0; //I_NONE;
uint8_t _skip = 0;
+ uint16_t _frequencykHz = 0U;
void * _busPtr = nullptr;
const ColorOrderMap &_colorOrderMap;
};
@@ -234,6 +239,8 @@ class BusPwm : public Bus {
uint8_t getPins(uint8_t* pinArray);
+ uint16_t getFrequency() { return _frequency; }
+
void cleanup() {
deallocatePins();
}
@@ -248,6 +255,7 @@ class BusPwm : public Bus {
#ifdef ARDUINO_ARCH_ESP32
uint8_t _ledcStart = 255;
#endif
+ uint16_t _frequency = 0U;
void deallocatePins();
};
@@ -335,7 +343,7 @@ class BusManager {
void setStatusPixel(uint32_t c);
- void IRAM_ATTR setPixelColor(uint16_t pix, uint32_t c, int16_t cct=-1);
+ void setPixelColor(uint16_t pix, uint32_t c, int16_t cct=-1);
void setBrightness(uint8_t b);
diff --git a/wled00/bus_wrapper.h b/wled00/bus_wrapper.h
index aada5eb7..047e7dfa 100644
--- a/wled00/bus_wrapper.h
+++ b/wled00/bus_wrapper.h
@@ -1,7 +1,7 @@
#ifndef BusWrapper_h
#define BusWrapper_h
-#include "NeoPixelBrightnessBus.h"
+#include "NeoPixelBusLg.h"
// temporary - these defines should actually be set in platformio.ini
// C3: I2S0 and I2S1 methods not supported (has one I2S bus)
@@ -53,6 +53,16 @@
#define I_8266_U1_TM2_3 18
#define I_8266_DM_TM2_3 19
#define I_8266_BB_TM2_3 20
+//UCS8903 (RGB)
+#define I_8266_U0_UCS_3 49
+#define I_8266_U1_UCS_3 50
+#define I_8266_DM_UCS_3 51
+#define I_8266_BB_UCS_3 52
+//UCS8904 (RGBW)
+#define I_8266_U0_UCS_4 53
+#define I_8266_U1_UCS_4 54
+#define I_8266_DM_UCS_4 55
+#define I_8266_BB_UCS_4 56
/*** ESP32 Neopixel methods ***/
//RGB
@@ -80,6 +90,16 @@
#define I_32_I0_TM2_3 37
#define I_32_I1_TM2_3 38
//Bit Bang theoratically possible, but very undesirable and not needed (no pin restrictions on RMT and I2S)
+//UCS8903 (RGB)
+#define I_32_RN_UCS_3 57
+#define I_32_I0_UCS_3 58
+#define I_32_I1_UCS_3 59
+//Bit Bang theoratically possible, but very undesirable and not needed (no pin restrictions on RMT and I2S)
+//UCS8904 (RGBW)
+#define I_32_RN_UCS_4 60
+#define I_32_I0_UCS_4 61
+#define I_32_I1_UCS_4 62
+//Bit Bang theoratically possible, but very undesirable and not needed (no pin restrictions on RMT and I2S)
//APA102
#define I_HS_DOT_3 39 //hardware SPI
@@ -105,77 +125,105 @@
/*** ESP8266 Neopixel methods ***/
#ifdef ESP8266
//RGB
-#define B_8266_U0_NEO_3 NeoPixelBrightnessBus //3 chan, esp8266, gpio1
-#define B_8266_U1_NEO_3 NeoPixelBrightnessBus //3 chan, esp8266, gpio2
-#define B_8266_DM_NEO_3 NeoPixelBrightnessBus //3 chan, esp8266, gpio3
-#define B_8266_BB_NEO_3 NeoPixelBrightnessBus //3 chan, esp8266, bb (any pin but 16)
+#define B_8266_U0_NEO_3 NeoPixelBusLg //3 chan, esp8266, gpio1
+#define B_8266_U1_NEO_3 NeoPixelBusLg //3 chan, esp8266, gpio2
+#define B_8266_DM_NEO_3 NeoPixelBusLg //3 chan, esp8266, gpio3
+#define B_8266_BB_NEO_3 NeoPixelBusLg //3 chan, esp8266, bb (any pin but 16)
//RGBW
-#define B_8266_U0_NEO_4 NeoPixelBrightnessBus //4 chan, esp8266, gpio1
-#define B_8266_U1_NEO_4 NeoPixelBrightnessBus //4 chan, esp8266, gpio2
-#define B_8266_DM_NEO_4 NeoPixelBrightnessBus //4 chan, esp8266, gpio3
-#define B_8266_BB_NEO_4 NeoPixelBrightnessBus //4 chan, esp8266, bb (any pin)
+#define B_8266_U0_NEO_4 NeoPixelBusLg //4 chan, esp8266, gpio1
+#define B_8266_U1_NEO_4 NeoPixelBusLg //4 chan, esp8266, gpio2
+#define B_8266_DM_NEO_4 NeoPixelBusLg //4 chan, esp8266, gpio3
+#define B_8266_BB_NEO_4 NeoPixelBusLg //4 chan, esp8266, bb (any pin)
//400Kbps
-#define B_8266_U0_400_3 NeoPixelBrightnessBus //3 chan, esp8266, gpio1
-#define B_8266_U1_400_3 NeoPixelBrightnessBus //3 chan, esp8266, gpio2
-#define B_8266_DM_400_3 NeoPixelBrightnessBus //3 chan, esp8266, gpio3
-#define B_8266_BB_400_3 NeoPixelBrightnessBus //3 chan, esp8266, bb (any pin)
+#define B_8266_U0_400_3 NeoPixelBusLg //3 chan, esp8266, gpio1
+#define B_8266_U1_400_3 NeoPixelBusLg //3 chan, esp8266, gpio2
+#define B_8266_DM_400_3 NeoPixelBusLg //3 chan, esp8266, gpio3
+#define B_8266_BB_400_3 NeoPixelBusLg //3 chan, esp8266, bb (any pin)
//TM1814 (RGBW)
-#define B_8266_U0_TM1_4 NeoPixelBrightnessBus
-#define B_8266_U1_TM1_4 NeoPixelBrightnessBus
-#define B_8266_DM_TM1_4 NeoPixelBrightnessBus
-#define B_8266_BB_TM1_4 NeoPixelBrightnessBus
+#define B_8266_U0_TM1_4 NeoPixelBusLg
+#define B_8266_U1_TM1_4 NeoPixelBusLg
+#define B_8266_DM_TM1_4 NeoPixelBusLg
+#define B_8266_BB_TM1_4 NeoPixelBusLg
//TM1829 (RGB)
-#define B_8266_U0_TM2_4 NeoPixelBrightnessBus
-#define B_8266_U1_TM2_4 NeoPixelBrightnessBus
-#define B_8266_DM_TM2_4 NeoPixelBrightnessBus
-#define B_8266_BB_TM2_4 NeoPixelBrightnessBus
+#define B_8266_U0_TM2_4 NeoPixelBusLg
+#define B_8266_U1_TM2_4 NeoPixelBusLg
+#define B_8266_DM_TM2_4 NeoPixelBusLg
+#define B_8266_BB_TM2_4 NeoPixelBusLg
+//UCS8903
+#define B_8266_U0_UCS_3 NeoPixelBusLg //3 chan, esp8266, gpio1
+#define B_8266_U1_UCS_3 NeoPixelBusLg //3 chan, esp8266, gpio2
+#define B_8266_DM_UCS_3 NeoPixelBusLg //3 chan, esp8266, gpio3
+#define B_8266_BB_UCS_3 NeoPixelBusLg //3 chan, esp8266, bb (any pin but 16)
+//UCS8904 RGBW
+#define B_8266_U0_UCS_4 NeoPixelBusLg //4 chan, esp8266, gpio1
+#define B_8266_U1_UCS_4 NeoPixelBusLg //4 chan, esp8266, gpio2
+#define B_8266_DM_UCS_4 NeoPixelBusLg //4 chan, esp8266, gpio3
+#define B_8266_BB_UCS_4 NeoPixelBusLg //4 chan, esp8266, bb (any pin)
#endif
/*** ESP32 Neopixel methods ***/
#ifdef ARDUINO_ARCH_ESP32
//RGB
-#define B_32_RN_NEO_3 NeoPixelBrightnessBus
+#define B_32_RN_NEO_3 NeoPixelBusLg
#ifndef WLED_NO_I2S0_PIXELBUS
-#define B_32_I0_NEO_3 NeoPixelBrightnessBus
+#define B_32_I0_NEO_3 NeoPixelBusLg
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
-#define B_32_I1_NEO_3 NeoPixelBrightnessBus
+#define B_32_I1_NEO_3 NeoPixelBusLg
#endif
//#define B_32_BB_NEO_3 NeoPixelBrightnessBus // NeoEsp8266BitBang800KbpsMethod
//RGBW
-#define B_32_RN_NEO_4 NeoPixelBrightnessBus
+#define B_32_RN_NEO_4 NeoPixelBusLg
#ifndef WLED_NO_I2S0_PIXELBUS
-#define B_32_I0_NEO_4 NeoPixelBrightnessBus
+#define B_32_I0_NEO_4 NeoPixelBusLg
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
-#define B_32_I1_NEO_4 NeoPixelBrightnessBus
+#define B_32_I1_NEO_4 NeoPixelBusLg
#endif
//#define B_32_BB_NEO_4 NeoPixelBrightnessBus // NeoEsp8266BitBang800KbpsMethod
//400Kbps
-#define B_32_RN_400_3 NeoPixelBrightnessBus
+#define B_32_RN_400_3 NeoPixelBusLg
#ifndef WLED_NO_I2S0_PIXELBUS
-#define B_32_I0_400_3 NeoPixelBrightnessBus
+#define B_32_I0_400_3 NeoPixelBusLg
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
-#define B_32_I1_400_3 NeoPixelBrightnessBus
+#define B_32_I1_400_3 NeoPixelBusLg
#endif
//#define B_32_BB_400_3 NeoPixelBrightnessBus // NeoEsp8266BitBang400KbpsMethod
//TM1814 (RGBW)
-#define B_32_RN_TM1_4 NeoPixelBrightnessBus
+#define B_32_RN_TM1_4 NeoPixelBusLg
#ifndef WLED_NO_I2S0_PIXELBUS
-#define B_32_I0_TM1_4 NeoPixelBrightnessBus
+#define B_32_I0_TM1_4 NeoPixelBusLg
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
-#define B_32_I1_TM1_4 NeoPixelBrightnessBus
+#define B_32_I1_TM1_4 NeoPixelBusLg
#endif
//Bit Bang theoratically possible, but very undesirable and not needed (no pin restrictions on RMT and I2S)
//TM1829 (RGB)
-#define B_32_RN_TM2_3 NeoPixelBrightnessBus
+#define B_32_RN_TM2_3 NeoPixelBusLg
#ifndef WLED_NO_I2S0_PIXELBUS
-#define B_32_I0_TM2_3 NeoPixelBrightnessBus
+#define B_32_I0_TM2_3 NeoPixelBusLg
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
-#define B_32_I1_TM2_3 NeoPixelBrightnessBus
+#define B_32_I1_TM2_3 NeoPixelBusLg
+#endif
+//Bit Bang theoratically possible, but very undesirable and not needed (no pin restrictions on RMT and I2S)
+//UCS8903
+#define B_32_RN_UCS_3 NeoPixelBusLg
+#ifndef WLED_NO_I2S0_PIXELBUS
+#define B_32_I0_UCS_3 NeoPixelBusLg
+#endif
+#ifndef WLED_NO_I2S1_PIXELBUS
+#define B_32_I1_UCS_3 NeoPixelBusLg
+#endif
+//Bit Bang theoratically possible, but very undesirable and not needed (no pin restrictions on RMT and I2S)
+//UCS8904
+#define B_32_RN_UCS_4 NeoPixelBusLg
+#ifndef WLED_NO_I2S0_PIXELBUS
+#define B_32_I0_UCS_4 NeoPixelBusLg
+#endif
+#ifndef WLED_NO_I2S1_PIXELBUS
+#define B_32_I1_UCS_4 NeoPixelBusLg
#endif
//Bit Bang theoratically possible, but very undesirable and not needed (no pin restrictions on RMT and I2S)
@@ -184,45 +232,51 @@
//APA102
#ifdef WLED_USE_ETHERNET
// fix for #2542 (by @BlackBird77)
-#define B_HS_DOT_3 NeoPixelBrightnessBus //hardware HSPI with DMA (ESP32 only)
+#define B_HS_DOT_3 NeoPixelBusLg //hardware HSPI (was DotStarEsp32DmaHspi5MhzMethod in NPB @ 2.6.9)
#else
-#define B_HS_DOT_3 NeoPixelBrightnessBus //hardware VSPI
+#define B_HS_DOT_3 NeoPixelBusLg //hardware VSPI
#endif
-#define B_SS_DOT_3 NeoPixelBrightnessBus //soft SPI
+#define B_SS_DOT_3 NeoPixelBusLg //soft SPI
//LPD8806
-#define B_HS_LPD_3 NeoPixelBrightnessBus
-#define B_SS_LPD_3 NeoPixelBrightnessBus
+#define B_HS_LPD_3 NeoPixelBusLg
+#define B_SS_LPD_3 NeoPixelBusLg
//LPD6803
-#define B_HS_LPO_3 NeoPixelBrightnessBus
-#define B_SS_LPO_3 NeoPixelBrightnessBus
+#define B_HS_LPO_3 NeoPixelBusLg
+#define B_SS_LPO_3 NeoPixelBusLg
//WS2801
-#if defined(WLED_WS2801_SPEED_KHZ) && WLED_WS2801_SPEED_KHZ==40000
-#define B_HS_WS1_3 NeoPixelBrightnessBus // fastest bus speed (not existing method?)
-#elif defined(WLED_WS2801_SPEED_KHZ) && WLED_WS2801_SPEED_KHZ==20000
-#define B_HS_WS1_3 NeoPixelBrightnessBus // 20MHz
-#elif defined(WLED_WS2801_SPEED_KHZ) && WLED_WS2801_SPEED_KHZ==10000
-#define B_HS_WS1_3 NeoPixelBrightnessBus // 10MHz
-#elif defined(WLED_WS2801_SPEED_KHZ) && WLED_WS2801_SPEED_KHZ==2000
-#define B_HS_WS1_3 NeoPixelBrightnessBus //slower, more compatible
-#elif defined(WLED_WS2801_SPEED_KHZ) && WLED_WS2801_SPEED_KHZ==1000
-#define B_HS_WS1_3 NeoPixelBrightnessBus //slower, more compatible
-#elif defined(WLED_WS2801_SPEED_KHZ) && WLED_WS2801_SPEED_KHZ==500
-#define B_HS_WS1_3 NeoPixelBrightnessBus //slower, more compatible
+#ifdef WLED_USE_ETHERNET
+#define B_HS_WS1_3 NeoPixelBusLg>, NeoGammaNullMethod>
#else
-#define B_HS_WS1_3 NeoPixelBrightnessBus // 2MHz; slower, more compatible
+#define B_HS_WS1_3 NeoPixelBusLg
#endif
-#define B_SS_WS1_3 NeoPixelBrightnessBus
+#define B_SS_WS1_3 NeoPixelBusLg
//P9813
-#define B_HS_P98_3 NeoPixelBrightnessBus
-#define B_SS_P98_3 NeoPixelBrightnessBus
+#define B_HS_P98_3 NeoPixelBusLg
+#define B_SS_P98_3 NeoPixelBusLg
+
+// 48bit & 64bit to 24bit & 32bit RGB(W) conversion
+#define toRGBW32(c) (RGBW32((c>>40)&0xFF, (c>>24)&0xFF, (c>>8)&0xFF, (c>>56)&0xFF))
+#define RGBW32(r,g,b,w) (uint32_t((byte(w) << 24) | (byte(r) << 16) | (byte(g) << 8) | (byte(b))))
//handles pointer type conversion for all possible bus types
class PolyBus {
public:
+ // initialize SPI bus speed for DotStar methods
+ template
+ static void beginDotStar(void* busPtr, int8_t sck, int8_t miso, int8_t mosi, int8_t ss, uint16_t clock_kHz = 0U) {
+ T dotStar_strip = static_cast(busPtr);
+ #ifdef ESP8266
+ dotStar_strip->Begin();
+ #else
+ if (sck == -1 && mosi == -1) dotStar_strip->Begin();
+ else dotStar_strip->Begin(sck, miso, mosi, ss);
+ #endif
+ if (clock_kHz) dotStar_strip->SetMethodSettings(NeoSpiSettings((uint32_t)clock_kHz*1000));
+ }
// Begin & initialize the PixelSettings for TM1814 strips.
template
static void beginTM1814(void* busPtr) {
@@ -231,7 +285,7 @@ class PolyBus {
// Max current for each LED (22.5 mA).
tm1814_strip->SetPixelSettings(NeoTm1814Settings(/*R*/225, /*G*/225, /*B*/225, /*W*/225));
}
- static void begin(void* busPtr, uint8_t busType, uint8_t* pins) {
+ static void begin(void* busPtr, uint8_t busType, uint8_t* pins, uint16_t clock_kHz = 0U) {
switch (busType) {
case I_NONE: break;
#ifdef ESP8266
@@ -255,11 +309,19 @@ class PolyBus {
case I_8266_U1_TM2_3: (static_cast(busPtr))->Begin(); break;
case I_8266_DM_TM2_3: (static_cast(busPtr))->Begin(); break;
case I_8266_BB_TM2_3: (static_cast(busPtr))->Begin(); break;
- case I_HS_DOT_3: (static_cast(busPtr))->Begin(); break;
- case I_HS_LPD_3: (static_cast(busPtr))->Begin(); break;
- case I_HS_LPO_3: (static_cast(busPtr))->Begin(); break;
- case I_HS_WS1_3: (static_cast(busPtr))->Begin(); break;
- case I_HS_P98_3: (static_cast(busPtr))->Begin(); break;
+ case I_HS_DOT_3: beginDotStar(busPtr, -1, -1, -1, -1, clock_kHz); break;
+ case I_HS_LPD_3: beginDotStar(busPtr, -1, -1, -1, -1, clock_kHz); break;
+ case I_HS_LPO_3: beginDotStar(busPtr, -1, -1, -1, -1, clock_kHz); break;
+ case I_HS_WS1_3: beginDotStar(busPtr, -1, -1, -1, -1, clock_kHz); break;
+ case I_HS_P98_3: beginDotStar(busPtr, -1, -1, -1, -1, clock_kHz); break;
+ case I_8266_U0_UCS_3: (static_cast(busPtr))->Begin(); break;
+ case I_8266_U1_UCS_3: (static_cast(busPtr))->Begin(); break;
+ case I_8266_DM_UCS_3: (static_cast(busPtr))->Begin(); break;
+ case I_8266_BB_UCS_3: (static_cast(busPtr))->Begin(); break;
+ case I_8266_U0_UCS_4: (static_cast(busPtr))->Begin(); break;
+ case I_8266_U1_UCS_4: (static_cast(busPtr))->Begin(); break;
+ case I_8266_DM_UCS_4: (static_cast(busPtr))->Begin(); break;
+ case I_8266_BB_UCS_4: (static_cast(busPtr))->Begin(); break;
#endif
#ifdef ARDUINO_ARCH_ESP32
case I_32_RN_NEO_3: (static_cast(busPtr))->Begin(); break;
@@ -296,12 +358,28 @@ class PolyBus {
case I_32_I1_TM1_4: beginTM1814(busPtr); break;
case I_32_I1_TM2_3: (static_cast(busPtr))->Begin(); break;
#endif
+ case I_32_RN_UCS_3: (static_cast(busPtr))->Begin(); break;
+ #ifndef WLED_NO_I2S0_PIXELBUS
+ case I_32_I0_UCS_3: (static_cast(busPtr))->Begin(); break;
+ #endif
+ #ifndef WLED_NO_I2S1_PIXELBUS
+ case I_32_I1_UCS_3: (static_cast(busPtr))->Begin(); break;
+ #endif
+// case I_32_BB_UCS_3: (static_cast(busPtr))->Begin(); break;
+ case I_32_RN_UCS_4: (static_cast(busPtr))->Begin(); break;
+ #ifndef WLED_NO_I2S0_PIXELBUS
+ case I_32_I0_UCS_4: (static_cast(busPtr))->Begin(); break;
+ #endif
+ #ifndef WLED_NO_I2S1_PIXELBUS
+ 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()
- case I_HS_DOT_3: (static_cast(busPtr))->Begin(pins[1], -1, pins[0], -1); break;
- case I_HS_LPD_3: (static_cast(busPtr))->Begin(pins[1], -1, pins[0], -1); break;
- case I_HS_LPO_3: (static_cast(busPtr))->Begin(pins[1], -1, pins[0], -1); break;
- case I_HS_WS1_3: (static_cast(busPtr))->Begin(pins[1], -1, pins[0], -1); break;
- case I_HS_P98_3: (static_cast(busPtr))->Begin(pins[1], -1, pins[0], -1); break;
+ 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;
+ case I_HS_WS1_3: beginDotStar(busPtr, pins[1], -1, pins[0], -1, clock_kHz); break;
+ case I_HS_P98_3: beginDotStar(busPtr, pins[1], -1, pins[0], -1, clock_kHz); break;
#endif
case I_SS_DOT_3: (static_cast(busPtr))->Begin(); break;
case I_SS_LPD_3: (static_cast(busPtr))->Begin(); break;
@@ -310,7 +388,7 @@ class PolyBus {
case I_SS_P98_3: (static_cast(busPtr))->Begin(); break;
}
};
- static void* create(uint8_t busType, uint8_t* pins, uint16_t len, uint8_t channel) {
+ static void* create(uint8_t busType, uint8_t* pins, uint16_t len, uint8_t channel, uint16_t clock_kHz = 0U) {
void* busPtr = nullptr;
switch (busType) {
case I_NONE: break;
@@ -335,6 +413,14 @@ class PolyBus {
case I_8266_U1_TM2_3: busPtr = new B_8266_U1_TM2_4(len, pins[0]); break;
case I_8266_DM_TM2_3: busPtr = new B_8266_DM_TM2_4(len, pins[0]); break;
case I_8266_BB_TM2_3: busPtr = new B_8266_BB_TM2_4(len, pins[0]); break;
+ case I_8266_U0_UCS_3: busPtr = new B_8266_U0_UCS_3(len, pins[0]); break;
+ case I_8266_U1_UCS_3: busPtr = new B_8266_U1_UCS_3(len, pins[0]); break;
+ case I_8266_DM_UCS_3: busPtr = new B_8266_DM_UCS_3(len, pins[0]); break;
+ case I_8266_BB_UCS_3: busPtr = new B_8266_BB_UCS_3(len, pins[0]); break;
+ case I_8266_U0_UCS_4: busPtr = new B_8266_U0_UCS_4(len, pins[0]); break;
+ case I_8266_U1_UCS_4: busPtr = new B_8266_U1_UCS_4(len, pins[0]); break;
+ case I_8266_DM_UCS_4: busPtr = new B_8266_DM_UCS_4(len, pins[0]); break;
+ case I_8266_BB_UCS_4: busPtr = new B_8266_BB_UCS_4(len, pins[0]); break;
#endif
#ifdef ARDUINO_ARCH_ESP32
case I_32_RN_NEO_3: busPtr = new B_32_RN_NEO_3(len, pins[0], (NeoBusChannel)channel); break;
@@ -371,6 +457,22 @@ class PolyBus {
case I_32_I1_TM1_4: busPtr = new B_32_I1_TM1_4(len, pins[0]); break;
case I_32_I1_TM2_3: busPtr = new B_32_I1_TM2_3(len, pins[0]); break;
#endif
+ case I_32_RN_UCS_3: busPtr = new B_32_RN_UCS_3(len, pins[0], (NeoBusChannel)channel); break;
+ #ifndef WLED_NO_I2S0_PIXELBUS
+ case I_32_I0_UCS_3: busPtr = new B_32_I0_UCS_3(len, pins[0]); break;
+ #endif
+ #ifndef WLED_NO_I2S1_PIXELBUS
+ case I_32_I1_UCS_3: busPtr = new B_32_I1_UCS_3(len, pins[0]); break;
+ #endif
+// case I_32_BB_UCS_3: busPtr = new B_32_BB_UCS_3(len, pins[0], (NeoBusChannel)channel); break;
+ case I_32_RN_UCS_4: busPtr = new B_32_RN_UCS_4(len, pins[0], (NeoBusChannel)channel); break;
+ #ifndef WLED_NO_I2S0_PIXELBUS
+ case I_32_I0_UCS_4: busPtr = new B_32_I0_UCS_4(len, pins[0]); break;
+ #endif
+ #ifndef WLED_NO_I2S1_PIXELBUS
+ case I_32_I1_UCS_4: busPtr = new B_32_I1_UCS_4(len, pins[0]); break;
+ #endif
+// case I_32_BB_UCS_4: busPtr = new B_32_BB_UCS_4(len, pins[0], (NeoBusChannel)channel); break;
#endif
// for 2-wire: pins[1] is clk, pins[0] is dat. begin expects (len, clk, dat)
case I_HS_DOT_3: busPtr = new B_HS_DOT_3(len, pins[1], pins[0]); break;
@@ -384,7 +486,7 @@ class PolyBus {
case I_HS_P98_3: busPtr = new B_HS_P98_3(len, pins[1], pins[0]); break;
case I_SS_P98_3: busPtr = new B_SS_P98_3(len, pins[1], pins[0]); break;
}
- begin(busPtr, busType, pins);
+ begin(busPtr, busType, pins, clock_kHz);
return busPtr;
};
static void show(void* busPtr, uint8_t busType) {
@@ -411,6 +513,14 @@ class PolyBus {
case I_8266_U1_TM2_3: (static_cast(busPtr))->Show(); break;
case I_8266_DM_TM2_3: (static_cast(busPtr))->Show(); break;
case I_8266_BB_TM2_3: (static_cast(busPtr))->Show(); break;
+ case I_8266_U0_UCS_3: (static_cast(busPtr))->Show(); break;
+ case I_8266_U1_UCS_3: (static_cast(busPtr))->Show(); break;
+ case I_8266_DM_UCS_3: (static_cast(busPtr))->Show(); break;
+ case I_8266_BB_UCS_3: (static_cast(busPtr))->Show(); break;
+ case I_8266_U0_UCS_4: (static_cast(busPtr))->Show(); break;
+ case I_8266_U1_UCS_4: (static_cast(busPtr))->Show(); break;
+ case I_8266_DM_UCS_4: (static_cast(busPtr))->Show(); break;
+ case I_8266_BB_UCS_4: (static_cast(busPtr))->Show(); break;
#endif
#ifdef ARDUINO_ARCH_ESP32
case I_32_RN_NEO_3: (static_cast(busPtr))->Show(); break;
@@ -447,6 +557,22 @@ class PolyBus {
case I_32_I1_TM1_4: (static_cast(busPtr))->Show(); break;
case I_32_I1_TM2_3: (static_cast(busPtr))->Show(); break;
#endif
+ case I_32_RN_UCS_3: (static_cast(busPtr))->Show(); break;
+ #ifndef WLED_NO_I2S0_PIXELBUS
+ case I_32_I0_UCS_3: (static_cast(busPtr))->Show(); break;
+ #endif
+ #ifndef WLED_NO_I2S1_PIXELBUS
+ case I_32_I1_UCS_3: (static_cast(busPtr))->Show(); break;
+ #endif
+// case I_32_BB_UCS_3: (static_cast(busPtr))->Show(); break;
+ case I_32_RN_UCS_4: (static_cast(busPtr))->Show(); break;
+ #ifndef WLED_NO_I2S0_PIXELBUS
+ case I_32_I0_UCS_4: (static_cast(busPtr))->Show(); break;
+ #endif
+ #ifndef WLED_NO_I2S1_PIXELBUS
+ case I_32_I1_UCS_4: (static_cast(busPtr))->Show(); break;
+ #endif
+// case I_32_BB_UCS_4: (static_cast(busPtr))->Show(); break;
#endif
case I_HS_DOT_3: (static_cast(busPtr))->Show(); break;
case I_SS_DOT_3: (static_cast(busPtr))->Show(); break;
@@ -484,6 +610,13 @@ class PolyBus {
case I_8266_U1_TM2_3: return (static_cast(busPtr))->CanShow(); break;
case I_8266_DM_TM2_3: return (static_cast(busPtr))->CanShow(); break;
case I_8266_BB_TM2_3: return (static_cast(busPtr))->CanShow(); break;
+ case I_8266_U0_UCS_3: return (static_cast