Merge branch 'Aircoookie:main' into pr_fxsegs
@ -1,5 +1,12 @@
|
|||||||
## WLED changelog
|
## WLED changelog
|
||||||
|
|
||||||
|
### WLED release 0.14.0-b1
|
||||||
|
|
||||||
|
#### Build 2212222
|
||||||
|
|
||||||
|
- Version bump to v0.14.0-b1 "Hoshi"
|
||||||
|
- Full changelog TBD
|
||||||
|
|
||||||
### WLED release 0.13.3
|
### WLED release 0.13.3
|
||||||
|
|
||||||
- Version bump to v0.13.3 "Toki"
|
- Version bump to v0.13.3 "Toki"
|
||||||
|
2
package-lock.json
generated
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "wled",
|
"name": "wled",
|
||||||
"version": "0.14.0-b0",
|
"version": "0.14.0-b1",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "wled",
|
"name": "wled",
|
||||||
"version": "0.14.0-b0",
|
"version": "0.14.0-b1",
|
||||||
"description": "Tools for WLED project",
|
"description": "Tools for WLED project",
|
||||||
"main": "tools/cdata.js",
|
"main": "tools/cdata.js",
|
||||||
"directories": {
|
"directories": {
|
||||||
|
@ -214,6 +214,7 @@ build_flags = -g
|
|||||||
-D CONFIG_ASYNC_TCP_USE_WDT=0
|
-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
|
-D LOROL_LITTLEFS
|
||||||
|
; -DARDUINO_USB_CDC_ON_BOOT=0 ;; this flag is mandatory for "classic ESP32" when builing with arduino-esp32 >=2.0.3
|
||||||
|
|
||||||
default_partitions = tools/WLED_ESP32_4MB_1MB_FS.csv
|
default_partitions = tools/WLED_ESP32_4MB_1MB_FS.csv
|
||||||
|
|
||||||
@ -230,6 +231,9 @@ build_flags = -g
|
|||||||
-DCONFIG_IDF_TARGET_ESP32S2
|
-DCONFIG_IDF_TARGET_ESP32S2
|
||||||
-D CONFIG_ASYNC_TCP_USE_WDT=0
|
-D CONFIG_ASYNC_TCP_USE_WDT=0
|
||||||
-DCO
|
-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
|
||||||
|
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${env.lib_deps}
|
${env.lib_deps}
|
||||||
@ -243,6 +247,9 @@ build_flags = -g
|
|||||||
-DCONFIG_IDF_TARGET_ESP32C3
|
-DCONFIG_IDF_TARGET_ESP32C3
|
||||||
-D CONFIG_ASYNC_TCP_USE_WDT=0
|
-D CONFIG_ASYNC_TCP_USE_WDT=0
|
||||||
-DCO
|
-DCO
|
||||||
|
-DARDUINO_USB_MODE=1 ;; this flag is mandatory for ESP32-C3
|
||||||
|
;; please make sure that the following flags are properly set (to 0 or 1) by your board.json, or included in your custom platformio_override.ini entry:
|
||||||
|
;; ARDUINO_USB_CDC_ON_BOOT
|
||||||
|
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${env.lib_deps}
|
${env.lib_deps}
|
||||||
@ -258,6 +265,8 @@ build_flags = -g
|
|||||||
-DCONFIG_IDF_TARGET_ESP32S3
|
-DCONFIG_IDF_TARGET_ESP32S3
|
||||||
-D CONFIG_ASYNC_TCP_USE_WDT=0
|
-D CONFIG_ASYNC_TCP_USE_WDT=0
|
||||||
-DCO
|
-DCO
|
||||||
|
;; please make sure that the following flags are properly set (to 0 or 1) by your board.json, or included in your custom platformio_override.ini entry:
|
||||||
|
;; ARDUINO_USB_MODE, ARDUINO_USB_CDC_ON_BOOT, ARDUINO_USB_MSC_ON_BOOT, ARDUINO_USB_DFU_ON_BOOT
|
||||||
|
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${env.lib_deps}
|
${env.lib_deps}
|
||||||
@ -276,7 +285,7 @@ platform = ${common.platform_wled_default}
|
|||||||
platform_packages = ${common.platform_packages}
|
platform_packages = ${common.platform_packages}
|
||||||
board_build.ldscript = ${common.ldscript_4m1m}
|
board_build.ldscript = ${common.ldscript_4m1m}
|
||||||
build_unflags = ${common.build_unflags}
|
build_unflags = ${common.build_unflags}
|
||||||
build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=ESP8266 #-DWLED_DISABLE_2D
|
build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=ESP8266 -D WLED_DISABLE_BLYNK #-DWLED_DISABLE_2D
|
||||||
lib_deps = ${esp8266.lib_deps}
|
lib_deps = ${esp8266.lib_deps}
|
||||||
monitor_filters = esp8266_exception_decoder
|
monitor_filters = esp8266_exception_decoder
|
||||||
|
|
||||||
@ -286,7 +295,7 @@ platform = ${common.platform_wled_default}
|
|||||||
platform_packages = ${common.platform_packages}
|
platform_packages = ${common.platform_packages}
|
||||||
board_build.ldscript = ${common.ldscript_2m512k}
|
board_build.ldscript = ${common.ldscript_2m512k}
|
||||||
build_unflags = ${common.build_unflags}
|
build_unflags = ${common.build_unflags}
|
||||||
build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=ESP02
|
build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=ESP02 -D WLED_DISABLE_BLYNK
|
||||||
lib_deps = ${esp8266.lib_deps}
|
lib_deps = ${esp8266.lib_deps}
|
||||||
|
|
||||||
[env:esp01_1m_full]
|
[env:esp01_1m_full]
|
||||||
@ -295,7 +304,7 @@ platform = ${common.platform_wled_default}
|
|||||||
platform_packages = ${common.platform_packages}
|
platform_packages = ${common.platform_packages}
|
||||||
board_build.ldscript = ${common.ldscript_1m128k}
|
board_build.ldscript = ${common.ldscript_1m128k}
|
||||||
build_unflags = ${common.build_unflags}
|
build_unflags = ${common.build_unflags}
|
||||||
build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=ESP01 -D WLED_DISABLE_OTA
|
build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=ESP01 -D WLED_DISABLE_OTA -D WLED_DISABLE_BLYNK
|
||||||
lib_deps = ${esp8266.lib_deps}
|
lib_deps = ${esp8266.lib_deps}
|
||||||
|
|
||||||
[env:esp07]
|
[env:esp07]
|
||||||
@ -341,7 +350,7 @@ board = esp32dev
|
|||||||
platform = ${esp32.platform}
|
platform = ${esp32.platform}
|
||||||
platform_packages = ${esp32.platform_packages}
|
platform_packages = ${esp32.platform_packages}
|
||||||
build_unflags = ${common.build_unflags}
|
build_unflags = ${common.build_unflags}
|
||||||
build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32 #-D WLED_DISABLE_BLYNK #-D WLED_DISABLE_BROWNOUT_DET
|
build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32 -D WLED_DISABLE_BLYNK #-D WLED_DISABLE_BROWNOUT_DET
|
||||||
lib_deps = ${esp32.lib_deps}
|
lib_deps = ${esp32.lib_deps}
|
||||||
monitor_filters = esp32_exception_decoder
|
monitor_filters = esp32_exception_decoder
|
||||||
board_build.partitions = ${esp32.default_partitions}
|
board_build.partitions = ${esp32.default_partitions}
|
||||||
@ -351,7 +360,7 @@ board = esp32dev
|
|||||||
platform = ${esp32.platform}
|
platform = ${esp32.platform}
|
||||||
platform_packages = ${esp32.platform_packages}
|
platform_packages = ${esp32.platform_packages}
|
||||||
build_unflags = ${common.build_unflags}
|
build_unflags = ${common.build_unflags}
|
||||||
build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32_qio80 #-D WLED_DISABLE_BLYNK #-D WLED_DISABLE_BROWNOUT_DET
|
build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32_qio80 -D WLED_DISABLE_BLYNK #-D WLED_DISABLE_BROWNOUT_DET
|
||||||
lib_deps = ${esp32.lib_deps}
|
lib_deps = ${esp32.lib_deps}
|
||||||
monitor_filters = esp32_exception_decoder
|
monitor_filters = esp32_exception_decoder
|
||||||
board_build.partitions = ${esp32.default_partitions}
|
board_build.partitions = ${esp32.default_partitions}
|
||||||
@ -381,12 +390,14 @@ build_flags = ${common.build_flags} ${esp32s2.build_flags} #-D WLED_RELEASE_NAME
|
|||||||
lib_deps = ${esp32s2.lib_deps}
|
lib_deps = ${esp32s2.lib_deps}
|
||||||
|
|
||||||
[env:esp32c3]
|
[env:esp32c3]
|
||||||
platform = espressif32@5.1.1
|
platform = espressif32@5.1.1 ;; well-tested on -C3, good compatibility with WLED
|
||||||
|
; platform = espressif32@~5.2.0 ;; might help in case you experience bootloops due to corrupted flash filesystem
|
||||||
framework = arduino
|
framework = arduino
|
||||||
board = esp32-c3-devkitm-1
|
board = esp32-c3-devkitm-1
|
||||||
board_build.partitions = tools/WLED_ESP32_4MB_1MB_FS.csv
|
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
|
-D WLED_WATCHDOG_TIMEOUT=0
|
||||||
|
; -DARDUINO_USB_CDC_ON_BOOT=1 ;; for virtual USB
|
||||||
upload_speed = 460800
|
upload_speed = 460800
|
||||||
build_unflags = ${common.build_unflags}
|
build_unflags = ${common.build_unflags}
|
||||||
lib_deps = ${esp32c3.lib_deps}
|
lib_deps = ${esp32c3.lib_deps}
|
||||||
|
@ -203,45 +203,45 @@ public:
|
|||||||
void addToConfig(JsonObject& root) override {
|
void addToConfig(JsonObject& root) override {
|
||||||
validateAndUpdate();
|
validateAndUpdate();
|
||||||
|
|
||||||
JsonObject top = root.createNestedObject("Analog Clock");
|
JsonObject top = root.createNestedObject(F("Analog Clock"));
|
||||||
top["Overlay Enabled"] = enabled;
|
top[F("Overlay Enabled")] = enabled;
|
||||||
top["First LED (Main Ring)"] = mainSegment.firstLed;
|
top[F("First LED (Main Ring)")] = mainSegment.firstLed;
|
||||||
top["Last LED (Main Ring)"] = mainSegment.lastLed;
|
top[F("Last LED (Main Ring)")] = mainSegment.lastLed;
|
||||||
top["Center/12h LED (Main Ring)"] = mainSegment.centerLed;
|
top[F("Center/12h LED (Main Ring)")] = mainSegment.centerLed;
|
||||||
top["Hour Marks Enabled"] = hourMarksEnabled;
|
top[F("Hour Marks Enabled")] = hourMarksEnabled;
|
||||||
top["Hour Mark Color (RRGGBB)"] = colorToHexString(hourMarkColor);
|
top[F("Hour Mark Color (RRGGBB)")] = colorToHexString(hourMarkColor);
|
||||||
top["Hour Color (RRGGBB)"] = colorToHexString(hourColor);
|
top[F("Hour Color (RRGGBB)")] = colorToHexString(hourColor);
|
||||||
top["Minute Color (RRGGBB)"] = colorToHexString(minuteColor);
|
top[F("Minute Color (RRGGBB)")] = colorToHexString(minuteColor);
|
||||||
top["Show Seconds"] = secondsEnabled;
|
top[F("Show Seconds")] = secondsEnabled;
|
||||||
top["First LED (Seconds Ring)"] = secondsSegment.firstLed;
|
top[F("First LED (Seconds Ring)")] = secondsSegment.firstLed;
|
||||||
top["Last LED (Seconds Ring)"] = secondsSegment.lastLed;
|
top[F("Last LED (Seconds Ring)")] = secondsSegment.lastLed;
|
||||||
top["Center/12h LED (Seconds Ring)"] = secondsSegment.centerLed;
|
top[F("Center/12h LED (Seconds Ring)")] = secondsSegment.centerLed;
|
||||||
top["Second Color (RRGGBB)"] = colorToHexString(secondColor);
|
top[F("Second Color (RRGGBB)")] = colorToHexString(secondColor);
|
||||||
top["Seconds Effect (0-1)"] = secondsEffect;
|
top[F("Seconds Effect (0-1)")] = secondsEffect;
|
||||||
top["Blend Colors"] = blendColors;
|
top[F("Blend Colors")] = blendColors;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool readFromConfig(JsonObject& root) override {
|
bool readFromConfig(JsonObject& root) override {
|
||||||
JsonObject top = root["Analog Clock"];
|
JsonObject top = root[F("Analog Clock")];
|
||||||
|
|
||||||
bool configComplete = !top.isNull();
|
bool configComplete = !top.isNull();
|
||||||
|
|
||||||
String color;
|
String color;
|
||||||
configComplete &= getJsonValue(top["Overlay Enabled"], enabled, false);
|
configComplete &= getJsonValue(top[F("Overlay Enabled")], enabled, false);
|
||||||
configComplete &= getJsonValue(top["First LED (Main Ring)"], mainSegment.firstLed, 0);
|
configComplete &= getJsonValue(top[F("First LED (Main Ring)")], mainSegment.firstLed, 0);
|
||||||
configComplete &= getJsonValue(top["Last LED (Main Ring)"], mainSegment.lastLed, 59);
|
configComplete &= getJsonValue(top[F("Last LED (Main Ring)")], mainSegment.lastLed, 59);
|
||||||
configComplete &= getJsonValue(top["Center/12h LED (Main Ring)"], mainSegment.centerLed, 0);
|
configComplete &= getJsonValue(top[F("Center/12h LED (Main Ring)")], mainSegment.centerLed, 0);
|
||||||
configComplete &= getJsonValue(top["Hour marks Enabled"], hourMarksEnabled, false);
|
configComplete &= getJsonValue(top[F("Hour Marks Enabled")], hourMarksEnabled, false);
|
||||||
configComplete &= getJsonValue(top["Hour mark Color (RRGGBB)"], color, "FF0000") && hexStringToColor(color, hourMarkColor, 0x0000FF);
|
configComplete &= getJsonValue(top[F("Hour Mark Color (RRGGBB)")], color, F("161616")) && hexStringToColor(color, hourMarkColor, 0x161616);
|
||||||
configComplete &= getJsonValue(top["Hour Color (RRGGBB)"], color, "0000FF") && hexStringToColor(color, hourColor, 0x0000FF);
|
configComplete &= getJsonValue(top[F("Hour Color (RRGGBB)")], color, F("0000FF")) && hexStringToColor(color, hourColor, 0x0000FF);
|
||||||
configComplete &= getJsonValue(top["Minute Color (RRGGBB)"], color, "00FF00") && hexStringToColor(color, minuteColor, 0x00FF00);
|
configComplete &= getJsonValue(top[F("Minute Color (RRGGBB)")], color, F("00FF00")) && hexStringToColor(color, minuteColor, 0x00FF00);
|
||||||
configComplete &= getJsonValue(top["Show Seconds"], secondsEnabled, true);
|
configComplete &= getJsonValue(top[F("Show Seconds")], secondsEnabled, true);
|
||||||
configComplete &= getJsonValue(top["First LED (Seconds Ring)"], secondsSegment.firstLed, 0);
|
configComplete &= getJsonValue(top[F("First LED (Seconds Ring)")], secondsSegment.firstLed, 0);
|
||||||
configComplete &= getJsonValue(top["Last LED (Seconds Ring)"], secondsSegment.lastLed, 59);
|
configComplete &= getJsonValue(top[F("Last LED (Seconds Ring)")], secondsSegment.lastLed, 59);
|
||||||
configComplete &= getJsonValue(top["Center/12h LED (Seconds Ring)"], secondsSegment.centerLed, 0);
|
configComplete &= getJsonValue(top[F("Center/12h LED (Seconds Ring)")], secondsSegment.centerLed, 0);
|
||||||
configComplete &= getJsonValue(top["Second Color (RRGGBB)"], color, "FF0000") && hexStringToColor(color, secondColor, 0xFF0000);
|
configComplete &= getJsonValue(top[F("Second Color (RRGGBB)")], color, F("FF0000")) && hexStringToColor(color, secondColor, 0xFF0000);
|
||||||
configComplete &= getJsonValue(top["Seconds Effect (0-1)"], secondsEffect, 0);
|
configComplete &= getJsonValue(top[F("Seconds Effect (0-1)")], secondsEffect, 0);
|
||||||
configComplete &= getJsonValue(top["Blend Colors"], blendColors, true);
|
configComplete &= getJsonValue(top[F("Blend Colors")], blendColors, true);
|
||||||
|
|
||||||
if (initDone) {
|
if (initDone) {
|
||||||
validateAndUpdate();
|
validateAndUpdate();
|
||||||
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
BIN
usermods/Battery/assets/battery_info_screen.png
Normal file
After Width: | Height: | Size: 122 KiB |
BIN
usermods/Battery/assets/battery_usermod_logo.png
Normal file
After Width: | Height: | Size: 23 KiB |
72
usermods/Battery/battery_defaults.h
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
// pin defaults
|
||||||
|
// for the esp32 it is best to use the ADC1: GPIO32 - GPIO39
|
||||||
|
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/adc.html
|
||||||
|
#ifndef USERMOD_BATTERY_MEASUREMENT_PIN
|
||||||
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
|
#define USERMOD_BATTERY_MEASUREMENT_PIN 35
|
||||||
|
#else //ESP8266 boards
|
||||||
|
#define USERMOD_BATTERY_MEASUREMENT_PIN A0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// the frequency to check the battery, 30 sec
|
||||||
|
#ifndef USERMOD_BATTERY_MEASUREMENT_INTERVAL
|
||||||
|
#define USERMOD_BATTERY_MEASUREMENT_INTERVAL 30000
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// default for 18650 battery
|
||||||
|
// https://batterybro.com/blogs/18650-wholesale-battery-reviews/18852515-when-to-recycle-18650-batteries-and-how-to-start-a-collection-center-in-your-vape-shop
|
||||||
|
// Discharge voltage: 2.5 volt + .1 for personal safety
|
||||||
|
#ifndef USERMOD_BATTERY_MIN_VOLTAGE
|
||||||
|
#ifdef USERMOD_BATTERY_USE_LIPO
|
||||||
|
// LiPo "1S" Batteries should not be dischared below 3V !!
|
||||||
|
#define USERMOD_BATTERY_MIN_VOLTAGE 3.2f
|
||||||
|
#else
|
||||||
|
#define USERMOD_BATTERY_MIN_VOLTAGE 2.6f
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef USERMOD_BATTERY_MAX_VOLTAGE
|
||||||
|
#define USERMOD_BATTERY_MAX_VOLTAGE 4.2f
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// a common capacity for single 18650 battery cells is between 2500 and 3600 mAh
|
||||||
|
#ifndef USERMOD_BATTERY_TOTAL_CAPACITY
|
||||||
|
#define USERMOD_BATTERY_TOTAL_CAPACITY 3100
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// offset or calibration value to fine tune the calculated voltage
|
||||||
|
#ifndef USERMOD_BATTERY_CALIBRATION
|
||||||
|
#define USERMOD_BATTERY_CALIBRATION 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// calculate remaining time / the time that is left before the battery runs out of power
|
||||||
|
// #ifndef USERMOD_BATTERY_CALCULATE_TIME_LEFT_ENABLED
|
||||||
|
// #define USERMOD_BATTERY_CALCULATE_TIME_LEFT_ENABLED false
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// auto-off feature
|
||||||
|
#ifndef USERMOD_BATTERY_AUTO_OFF_ENABLED
|
||||||
|
#define USERMOD_BATTERY_AUTO_OFF_ENABLED true
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef USERMOD_BATTERY_AUTO_OFF_THRESHOLD
|
||||||
|
#define USERMOD_BATTERY_AUTO_OFF_THRESHOLD 10
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// low power indication feature
|
||||||
|
#ifndef USERMOD_BATTERY_LOW_POWER_INDICATOR_ENABLED
|
||||||
|
#define USERMOD_BATTERY_LOW_POWER_INDICATOR_ENABLED true
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef USERMOD_BATTERY_LOW_POWER_INDICATOR_PRESET
|
||||||
|
#define USERMOD_BATTERY_LOW_POWER_INDICATOR_PRESET 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef USERMOD_BATTERY_LOW_POWER_INDICATOR_THRESHOLD
|
||||||
|
#define USERMOD_BATTERY_LOW_POWER_INDICATOR_THRESHOLD 20
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef USERMOD_BATTERY_LOW_POWER_INDICATOR_DURATION
|
||||||
|
#define USERMOD_BATTERY_LOW_POWER_INDICATOR_DURATION 5
|
||||||
|
#endif
|
112
usermods/Battery/readme.md
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
<p align="center">
|
||||||
|
<img width="700" src="assets/battery_usermod_logo.png">
|
||||||
|
</p>
|
||||||
|
|
||||||
|
# Welcome to the battery usermod! 🔋
|
||||||
|
|
||||||
|
Enables battery level monitoring of your project.
|
||||||
|
|
||||||
|
For this to work, the positive side of the (18650) battery must be connected to pin `A0` of the d1 mini/esp8266 with a 100k Ohm resistor (see [Useful Links](#useful-links)).
|
||||||
|
|
||||||
|
If you have an ESP32 board, connect the positive side of the battery to ADC1 (GPIO32 - GPIO39)
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img width="500" src="assets/battery_info_screen.png">
|
||||||
|
</p>
|
||||||
|
|
||||||
|
## ⚙️ Features
|
||||||
|
|
||||||
|
- 💯 Displays current battery voltage
|
||||||
|
- 🚥 Displays battery level
|
||||||
|
- 🚫 Auto-off with configurable Threshold
|
||||||
|
- 🚨 Low power indicator with many configuration posibilities
|
||||||
|
|
||||||
|
## 🎈 Installation
|
||||||
|
|
||||||
|
define `USERMOD_BATTERY` in `wled00/my_config.h`
|
||||||
|
|
||||||
|
### Example wiring
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img width="300" src="assets/battery_connection_schematic_01.png">
|
||||||
|
</p>
|
||||||
|
|
||||||
|
### Define Your Options
|
||||||
|
|
||||||
|
| Name | Unit | Description |
|
||||||
|
| ----------------------------------------------- | ----------- |-------------------------------------------------------------------------------------- |
|
||||||
|
| `USERMOD_BATTERY` | | define this (in `my_config.h`) to have this usermod included wled00\usermods_list.cpp |
|
||||||
|
| `USERMOD_BATTERY_USE_LIPO` | | define this (in `my_config.h`) if you use LiPo rechargeables (1S) |
|
||||||
|
| `USERMOD_BATTERY_MEASUREMENT_PIN` | | defaults to A0 on ESP8266 and GPIO35 on ESP32 |
|
||||||
|
| `USERMOD_BATTERY_MEASUREMENT_INTERVAL` | ms | battery check interval. defaults to 30 seconds |
|
||||||
|
| `USERMOD_BATTERY_MIN_VOLTAGE` | v | minimum battery voltage. default is 2.6 (18650 battery standard) |
|
||||||
|
| `USERMOD_BATTERY_MAX_VOLTAGE` | v | maximum battery voltage. default is 4.2 (18650 battery standard) |
|
||||||
|
| `USERMOD_BATTERY_TOTAL_CAPACITY` | mAh | the capacity of all cells in parralel sumed up |
|
||||||
|
| `USERMOD_BATTERY_CALIBRATION` | | offset / calibration number, fine tune the measured voltage by the microcontroller |
|
||||||
|
| Auto-Off | --- | --- |
|
||||||
|
| `USERMOD_BATTERY_AUTO_OFF_ENABLED` | true/false | enables auto-off |
|
||||||
|
| `USERMOD_BATTERY_AUTO_OFF_THRESHOLD` | % (0-100) | when this threshold is reached master power turns off |
|
||||||
|
| Low-Power-Indicator | --- | --- |
|
||||||
|
| `USERMOD_BATTERY_LOW_POWER_INDICATOR_ENABLED` | true/false | enables low power indication |
|
||||||
|
| `USERMOD_BATTERY_LOW_POWER_INDICATOR_PRESET` | preset id | when low power is detected then use this preset to indicate low power |
|
||||||
|
| `USERMOD_BATTERY_LOW_POWER_INDICATOR_THRESHOLD` | % (0-100) | when this threshold is reached low power gets indicated |
|
||||||
|
| `USERMOD_BATTERY_LOW_POWER_INDICATOR_DURATION` | seconds | for this long the configured preset is played |
|
||||||
|
|
||||||
|
All parameters can be configured at runtime via the Usermods settings page.
|
||||||
|
|
||||||
|
## ⚠️ Important
|
||||||
|
|
||||||
|
- Make sure you know your battery specifications! All batteries are **NOT** the same!
|
||||||
|
- Example:
|
||||||
|
|
||||||
|
| Your battery specification table | | Options you can define |
|
||||||
|
| :-------------------------------- |:--------------- | :---------------------------- |
|
||||||
|
| Capacity | 3500mAh 12,5 Wh | |
|
||||||
|
| Minimum capacity | 3350mAh 11,9 Wh | |
|
||||||
|
| Rated voltage | 3.6V - 3.7V | |
|
||||||
|
| **Charging end voltage** | **4,2V ± 0,05** | `USERMOD_BATTERY_MAX_VOLTAGE` |
|
||||||
|
| **Discharge voltage** | **2,5V** | `USERMOD_BATTERY_MIN_VOLTAGE` |
|
||||||
|
| Max. discharge current (constant) | 10A (10000mA) | |
|
||||||
|
| max. charging current | 1.7A (1700mA) | |
|
||||||
|
| ... | ... | ... |
|
||||||
|
| .. | .. | .. |
|
||||||
|
|
||||||
|
Specification from: [Molicel INR18650-M35A, 3500mAh 10A Lithium-ion battery, 3.6V - 3.7V](https://www.akkuteile.de/lithium-ionen-akkus/18650/molicel/molicel-inr18650-m35a-3500mah-10a-lithium-ionen-akku-3-6v-3-7v_100833)
|
||||||
|
|
||||||
|
## 🌐 Useful Links
|
||||||
|
|
||||||
|
- https://lazyzero.de/elektronik/esp8266/wemos_d1_mini_a0/start
|
||||||
|
- https://arduinodiy.wordpress.com/2016/12/25/monitoring-lipo-battery-voltage-with-wemos-d1-minibattery-shield-and-thingspeak/
|
||||||
|
|
||||||
|
## 📝 Change Log
|
||||||
|
|
||||||
|
2023-01-04
|
||||||
|
|
||||||
|
- basic support for LiPo rechargeable batteries ( `-D USERMOD_BATTERY_USE_LIPO`)
|
||||||
|
- improved support for esp32 (read calibrated voltage)
|
||||||
|
- corrected config saving (measurement pin, and battery min/max were lost)
|
||||||
|
- various bugfixes
|
||||||
|
|
||||||
|
2022-12-25
|
||||||
|
|
||||||
|
- added "auto-off" feature
|
||||||
|
- added "low-power-indication" feature
|
||||||
|
- added "calibration/offset" field to configuration page
|
||||||
|
- added getter and setter, so that user usermods could interact with this one
|
||||||
|
- update readme (added new options, made it markdownlint compliant)
|
||||||
|
|
||||||
|
2021-09-02
|
||||||
|
|
||||||
|
- added "Battery voltage" to info
|
||||||
|
- added circuit diagram to readme
|
||||||
|
- added MQTT support, sending battery voltage
|
||||||
|
- minor fixes
|
||||||
|
|
||||||
|
2021-08-15
|
||||||
|
|
||||||
|
- changed `USERMOD_BATTERY_MIN_VOLTAGE` to 2.6 volt as default for 18650 batteries
|
||||||
|
- Updated readme, added specification table
|
||||||
|
|
||||||
|
2021-08-10
|
||||||
|
|
||||||
|
- Created
|
771
usermods/Battery/usermod_v2_Battery.h
Normal file
@ -0,0 +1,771 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "wled.h"
|
||||||
|
#include "battery_defaults.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Usermod by Maximilian Mewes
|
||||||
|
* Mail: mewes.maximilian@gmx.de
|
||||||
|
* GitHub: itCarl
|
||||||
|
* Date: 25.12.2022
|
||||||
|
* If you have any questions, please feel free to contact me.
|
||||||
|
*/
|
||||||
|
class UsermodBattery : public Usermod
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
// battery pin can be defined in my_config.h
|
||||||
|
int8_t batteryPin = USERMOD_BATTERY_MEASUREMENT_PIN;
|
||||||
|
// how often to read the battery voltage
|
||||||
|
unsigned long readingInterval = USERMOD_BATTERY_MEASUREMENT_INTERVAL;
|
||||||
|
unsigned long nextReadTime = 0;
|
||||||
|
unsigned long lastReadTime = 0;
|
||||||
|
// battery min. voltage
|
||||||
|
float minBatteryVoltage = USERMOD_BATTERY_MIN_VOLTAGE;
|
||||||
|
// battery max. voltage
|
||||||
|
float maxBatteryVoltage = USERMOD_BATTERY_MAX_VOLTAGE;
|
||||||
|
// all battery cells summed up
|
||||||
|
unsigned int totalBatteryCapacity = USERMOD_BATTERY_TOTAL_CAPACITY;
|
||||||
|
// raw analog reading
|
||||||
|
float rawValue = 0.0f;
|
||||||
|
// calculated voltage
|
||||||
|
float voltage = maxBatteryVoltage;
|
||||||
|
// mapped battery level based on voltage
|
||||||
|
int8_t batteryLevel = 100;
|
||||||
|
// offset or calibration value to fine tune the calculated voltage
|
||||||
|
float calibration = USERMOD_BATTERY_CALIBRATION;
|
||||||
|
|
||||||
|
// time left estimation feature
|
||||||
|
// bool calculateTimeLeftEnabled = USERMOD_BATTERY_CALCULATE_TIME_LEFT_ENABLED;
|
||||||
|
// float estimatedTimeLeft = 0.0;
|
||||||
|
|
||||||
|
// auto shutdown/shutoff/master off feature
|
||||||
|
bool autoOffEnabled = USERMOD_BATTERY_AUTO_OFF_ENABLED;
|
||||||
|
int8_t autoOffThreshold = USERMOD_BATTERY_AUTO_OFF_THRESHOLD;
|
||||||
|
|
||||||
|
// low power indicator feature
|
||||||
|
bool lowPowerIndicatorEnabled = USERMOD_BATTERY_LOW_POWER_INDICATOR_ENABLED;
|
||||||
|
int8_t lowPowerIndicatorPreset = USERMOD_BATTERY_LOW_POWER_INDICATOR_PRESET;
|
||||||
|
int8_t lowPowerIndicatorThreshold = USERMOD_BATTERY_LOW_POWER_INDICATOR_THRESHOLD;
|
||||||
|
int8_t lowPowerIndicatorReactivationThreshold = lowPowerIndicatorThreshold+10;
|
||||||
|
int8_t lowPowerIndicatorDuration = USERMOD_BATTERY_LOW_POWER_INDICATOR_DURATION;
|
||||||
|
bool lowPowerIndicationDone = false;
|
||||||
|
unsigned long lowPowerActivationTime = 0; // used temporary during active time
|
||||||
|
int8_t lastPreset = 0;
|
||||||
|
|
||||||
|
bool initDone = false;
|
||||||
|
bool initializing = true;
|
||||||
|
|
||||||
|
// strings to reduce flash memory usage (used more than twice)
|
||||||
|
static const char _name[];
|
||||||
|
static const char _readInterval[];
|
||||||
|
static const char _enabled[];
|
||||||
|
static const char _threshold[];
|
||||||
|
static const char _preset[];
|
||||||
|
static const char _duration[];
|
||||||
|
static const char _init[];
|
||||||
|
|
||||||
|
|
||||||
|
// custom map function
|
||||||
|
// https://forum.arduino.cc/t/floating-point-using-map-function/348113/2
|
||||||
|
double mapf(double x, double in_min, double in_max, double out_min, double out_max)
|
||||||
|
{
|
||||||
|
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||||
|
}
|
||||||
|
|
||||||
|
float dot2round(float x)
|
||||||
|
{
|
||||||
|
float nx = (int)(x * 100 + .5);
|
||||||
|
return (float)(nx / 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Turn off all leds
|
||||||
|
*/
|
||||||
|
void turnOff()
|
||||||
|
{
|
||||||
|
bri = 0;
|
||||||
|
stateUpdated(CALL_MODE_DIRECT_CHANGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Indicate low power by activating a configured preset for a given time and then switching back to the preset that was selected previously
|
||||||
|
*/
|
||||||
|
void lowPowerIndicator()
|
||||||
|
{
|
||||||
|
if (!lowPowerIndicatorEnabled) return;
|
||||||
|
if (batteryPin < 0) return; // no measurement
|
||||||
|
if (lowPowerIndicationDone && lowPowerIndicatorReactivationThreshold <= batteryLevel) lowPowerIndicationDone = false;
|
||||||
|
if (lowPowerIndicatorThreshold <= batteryLevel) return;
|
||||||
|
if (lowPowerIndicationDone) return;
|
||||||
|
if (lowPowerActivationTime <= 1) {
|
||||||
|
lowPowerActivationTime = millis();
|
||||||
|
lastPreset = currentPreset;
|
||||||
|
applyPreset(lowPowerIndicatorPreset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lowPowerActivationTime+(lowPowerIndicatorDuration*1000) <= millis()) {
|
||||||
|
lowPowerIndicationDone = true;
|
||||||
|
lowPowerActivationTime = 0;
|
||||||
|
applyPreset(lastPreset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
//Functions called by WLED
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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()
|
||||||
|
{
|
||||||
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
|
bool success = false;
|
||||||
|
DEBUG_PRINTLN(F("Allocating battery pin..."));
|
||||||
|
if (batteryPin >= 0 && digitalPinToAnalogChannel(batteryPin) >= 0)
|
||||||
|
if (pinManager.allocatePin(batteryPin, false, PinOwner::UM_Battery)) {
|
||||||
|
DEBUG_PRINTLN(F("Battery pin allocation succeeded."));
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
DEBUG_PRINTLN(F("Battery pin allocation failed."));
|
||||||
|
batteryPin = -1; // allocation failed
|
||||||
|
} else {
|
||||||
|
pinMode(batteryPin, INPUT);
|
||||||
|
}
|
||||||
|
#else //ESP8266 boards have only one analog input pin A0
|
||||||
|
|
||||||
|
pinMode(batteryPin, INPUT);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
nextReadTime = millis() + readingInterval;
|
||||||
|
lastReadTime = millis();
|
||||||
|
|
||||||
|
initDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* connected() is called every time the WiFi is (re)connected
|
||||||
|
* Use it to initialize network interfaces
|
||||||
|
*/
|
||||||
|
void connected()
|
||||||
|
{
|
||||||
|
//Serial.println("Connected to WiFi!");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* loop() is called continuously. Here you can check for events, read sensors, etc.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
if(strip.isUpdating()) return;
|
||||||
|
|
||||||
|
lowPowerIndicator();
|
||||||
|
|
||||||
|
// check the battery level every USERMOD_BATTERY_MEASUREMENT_INTERVAL (ms)
|
||||||
|
if (millis() < nextReadTime) return;
|
||||||
|
|
||||||
|
nextReadTime = millis() + readingInterval;
|
||||||
|
lastReadTime = millis();
|
||||||
|
|
||||||
|
if (batteryPin < 0) return; // nothing to read
|
||||||
|
|
||||||
|
initializing = false;
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
|
// use calibrated millivolts analogread on esp32 (150 mV ~ 2450 mV)
|
||||||
|
rawValue = analogReadMilliVolts(batteryPin);
|
||||||
|
// calculate the voltage
|
||||||
|
voltage = (rawValue / 1000.0f) + calibration;
|
||||||
|
// usually a voltage divider (50%) is used on ESP32, so we need to multiply by 2
|
||||||
|
voltage *= 2.0f;
|
||||||
|
#else
|
||||||
|
// read battery raw input
|
||||||
|
rawValue = analogRead(batteryPin);
|
||||||
|
|
||||||
|
// calculate the voltage
|
||||||
|
voltage = ((rawValue / getAdcPrecision()) * maxBatteryVoltage) + calibration;
|
||||||
|
#endif
|
||||||
|
// check if voltage is within specified voltage range, allow 10% over/under voltage
|
||||||
|
voltage = ((voltage < minBatteryVoltage * 0.85f) || (voltage > maxBatteryVoltage * 1.1f)) ? -1.0f : voltage;
|
||||||
|
|
||||||
|
// translate battery voltage into percentage
|
||||||
|
/*
|
||||||
|
the standard "map" function doesn't work
|
||||||
|
https://www.arduino.cc/reference/en/language/functions/math/map/ notes and warnings at the bottom
|
||||||
|
*/
|
||||||
|
#ifdef USERMOD_BATTERY_USE_LIPO
|
||||||
|
batteryLevel = mapf(voltage, minBatteryVoltage, maxBatteryVoltage, 0, 100); // basic mapping
|
||||||
|
// LiPo batteries have a differnt dischargin curve, see
|
||||||
|
// https://blog.ampow.com/lipo-voltage-chart/
|
||||||
|
if (batteryLevel < 40.0f)
|
||||||
|
batteryLevel = mapf(batteryLevel, 0, 40, 0, 12); // last 45% -> drops very quickly
|
||||||
|
else {
|
||||||
|
if (batteryLevel < 90.0f)
|
||||||
|
batteryLevel = mapf(batteryLevel, 40, 90, 12, 95); // 90% ... 40% -> almost linear drop
|
||||||
|
else // level > 90%
|
||||||
|
batteryLevel = mapf(batteryLevel, 90, 105, 95, 100); // highest 15% -> drop slowly
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
batteryLevel = mapf(voltage, minBatteryVoltage, maxBatteryVoltage, 0, 100);
|
||||||
|
#endif
|
||||||
|
if (voltage > -1.0f) batteryLevel = constrain(batteryLevel, 0.0f, 110.0f);
|
||||||
|
|
||||||
|
// if (calculateTimeLeftEnabled) {
|
||||||
|
// float currentBatteryCapacity = totalBatteryCapacity;
|
||||||
|
// estimatedTimeLeft = (currentBatteryCapacity/strip.currentMilliamps)*60;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Auto off -- Master power off
|
||||||
|
if (autoOffEnabled && (autoOffThreshold >= batteryLevel))
|
||||||
|
turnOff();
|
||||||
|
|
||||||
|
// SmartHome stuff
|
||||||
|
// still don't know much about MQTT and/or HA
|
||||||
|
if (WLED_MQTT_CONNECTED) {
|
||||||
|
char buf[64]; // buffer for snprintf()
|
||||||
|
snprintf_P(buf, 63, PSTR("%s/voltage"), mqttDeviceTopic);
|
||||||
|
mqtt->publish(buf, 0, false, String(voltage).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
JsonObject user = root["u"];
|
||||||
|
if (user.isNull()) user = root.createNestedObject("u");
|
||||||
|
|
||||||
|
if (batteryPin < 0) {
|
||||||
|
JsonArray infoVoltage = user.createNestedArray(F("Battery voltage"));
|
||||||
|
infoVoltage.add(F("n/a"));
|
||||||
|
infoVoltage.add(F(" invalid GPIO"));
|
||||||
|
return; // no GPIO - nothing to report
|
||||||
|
}
|
||||||
|
|
||||||
|
// info modal display names
|
||||||
|
JsonArray infoPercentage = user.createNestedArray(F("Battery level"));
|
||||||
|
JsonArray infoVoltage = user.createNestedArray(F("Battery voltage"));
|
||||||
|
// if (calculateTimeLeftEnabled)
|
||||||
|
// {
|
||||||
|
// JsonArray infoEstimatedTimeLeft = user.createNestedArray(F("Estimated time left"));
|
||||||
|
// if (initializing) {
|
||||||
|
// infoEstimatedTimeLeft.add(FPSTR(_init));
|
||||||
|
// } else {
|
||||||
|
// infoEstimatedTimeLeft.add(estimatedTimeLeft);
|
||||||
|
// infoEstimatedTimeLeft.add(F(" min"));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
JsonArray infoNextUpdate = user.createNestedArray(F("Next update"));
|
||||||
|
|
||||||
|
infoNextUpdate.add((nextReadTime - millis()) / 1000);
|
||||||
|
infoNextUpdate.add(F(" sec"));
|
||||||
|
|
||||||
|
if (initializing) {
|
||||||
|
infoPercentage.add(FPSTR(_init));
|
||||||
|
infoVoltage.add(FPSTR(_init));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (batteryLevel < 0) {
|
||||||
|
infoPercentage.add(F("invalid"));
|
||||||
|
} else {
|
||||||
|
infoPercentage.add(batteryLevel);
|
||||||
|
}
|
||||||
|
infoPercentage.add(F(" %"));
|
||||||
|
|
||||||
|
if (voltage < 0) {
|
||||||
|
infoVoltage.add(F("invalid"));
|
||||||
|
} else {
|
||||||
|
infoVoltage.add(dot2round(voltage));
|
||||||
|
}
|
||||||
|
infoVoltage.add(F(" V"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
|
||||||
|
* Values in the state object may be modified by connected clients
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
void readFromJsonState(JsonObject& root)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* addToConfig() can be used to add custom persistent settings to the cfg.json file in the "um" (usermod) object.
|
||||||
|
* It will be called by WLED when settings are actually saved (for example, LED settings are saved)
|
||||||
|
* If you want to force saving the current state, use serializeConfig() in your loop().
|
||||||
|
*
|
||||||
|
* CAUTION: serializeConfig() will initiate a filesystem write operation.
|
||||||
|
* It might cause the LEDs to stutter and will cause flash wear if called too often.
|
||||||
|
* Use it sparingly and always in the loop, never in network callbacks!
|
||||||
|
*
|
||||||
|
* addToConfig() will make your settings editable through the Usermod Settings page automatically.
|
||||||
|
*
|
||||||
|
* Usermod Settings Overview:
|
||||||
|
* - Numeric values are treated as floats in the browser.
|
||||||
|
* - If the numeric value entered into the browser contains a decimal point, it will be parsed as a C float
|
||||||
|
* before being returned to the Usermod. The float data type has only 6-7 decimal digits of precision, and
|
||||||
|
* doubles are not supported, numbers will be rounded to the nearest float value when being parsed.
|
||||||
|
* The range accepted by the input field is +/- 1.175494351e-38 to +/- 3.402823466e+38.
|
||||||
|
* - If the numeric value entered into the browser doesn't contain a decimal point, it will be parsed as a
|
||||||
|
* C int32_t (range: -2147483648 to 2147483647) before being returned to the usermod.
|
||||||
|
* Overflows or underflows are truncated to the max/min value for an int32_t, and again truncated to the type
|
||||||
|
* used in the Usermod when reading the value from ArduinoJson.
|
||||||
|
* - Pin values can be treated differently from an integer value by using the key name "pin"
|
||||||
|
* - "pin" can contain a single or array of integer values
|
||||||
|
* - On the Usermod Settings page there is simple checking for pin conflicts and warnings for special pins
|
||||||
|
* - Red color indicates a conflict. Yellow color indicates a pin with a warning (e.g. an input-only pin)
|
||||||
|
* - Tip: use int8_t to store the pin value in the Usermod, so a -1 value (pin not set) can be used
|
||||||
|
*
|
||||||
|
* See usermod_v2_auto_save.h for an example that saves Flash space by reusing ArduinoJson key name strings
|
||||||
|
*
|
||||||
|
* If you need a dedicated settings page with custom layout for your Usermod, that takes a lot more work.
|
||||||
|
* You will have to add the setting to the HTML, xml.cpp and set.cpp manually.
|
||||||
|
* See the WLED Soundreactive fork (code and wiki) for reference. https://github.com/atuline/WLED
|
||||||
|
*
|
||||||
|
* I highly recommend checking out the basics of ArduinoJson serialization and deserialization in order to use custom settings!
|
||||||
|
*/
|
||||||
|
void addToConfig(JsonObject& root)
|
||||||
|
{
|
||||||
|
JsonObject battery = root.createNestedObject(FPSTR(_name)); // usermodname
|
||||||
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
|
battery[F("pin")] = batteryPin;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// battery[F("time-left")] = calculateTimeLeftEnabled;
|
||||||
|
battery[F("min-voltage")] = minBatteryVoltage;
|
||||||
|
battery[F("max-voltage")] = maxBatteryVoltage;
|
||||||
|
battery[F("capacity")] = totalBatteryCapacity;
|
||||||
|
battery[F("calibration")] = calibration;
|
||||||
|
battery[FPSTR(_readInterval)] = readingInterval;
|
||||||
|
|
||||||
|
JsonObject ao = battery.createNestedObject(F("auto-off")); // auto off section
|
||||||
|
ao[FPSTR(_enabled)] = autoOffEnabled;
|
||||||
|
ao[FPSTR(_threshold)] = autoOffThreshold;
|
||||||
|
|
||||||
|
JsonObject lp = battery.createNestedObject(F("indicator")); // low power section
|
||||||
|
lp[FPSTR(_enabled)] = lowPowerIndicatorEnabled;
|
||||||
|
lp[FPSTR(_preset)] = lowPowerIndicatorPreset; // dropdown trickery (String)lowPowerIndicatorPreset;
|
||||||
|
lp[FPSTR(_threshold)] = lowPowerIndicatorThreshold;
|
||||||
|
lp[FPSTR(_duration)] = lowPowerIndicatorDuration;
|
||||||
|
|
||||||
|
DEBUG_PRINTLN(F("Battery config saved."));
|
||||||
|
}
|
||||||
|
|
||||||
|
void appendConfigData()
|
||||||
|
{
|
||||||
|
oappend(SET_F("addInfo('Battery:min-voltage', 1, 'v');"));
|
||||||
|
oappend(SET_F("addInfo('Battery:max-voltage', 1, 'v');"));
|
||||||
|
oappend(SET_F("addInfo('Battery:capacity', 1, 'mAh');"));
|
||||||
|
oappend(SET_F("addInfo('Battery:interval', 1, 'ms');"));
|
||||||
|
oappend(SET_F("addInfo('Battery:auto-off:threshold', 1, '%');"));
|
||||||
|
oappend(SET_F("addInfo('Battery:indicator:threshold', 1, '%');"));
|
||||||
|
oappend(SET_F("addInfo('Battery:indicator:duration', 1, 's');"));
|
||||||
|
|
||||||
|
// cannot quite get this mf to work. its exeeding some buffer limit i think
|
||||||
|
// what i wanted is a list of all presets to select one from
|
||||||
|
// oappend(SET_F("bd=addDropdown('Battery:low-power-indicator', 'preset');"));
|
||||||
|
// the loop generates: oappend(SET_F("addOption(bd, 'preset name', preset id);"));
|
||||||
|
// for(int8_t i=1; i < 42; i++) {
|
||||||
|
// oappend(SET_F("addOption(bd, 'Preset#"));
|
||||||
|
// oappendi(i);
|
||||||
|
// oappend(SET_F("',"));
|
||||||
|
// oappendi(i);
|
||||||
|
// oappend(SET_F(");"));
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* readFromConfig() can be used to read back the custom settings you added with addToConfig().
|
||||||
|
* This is called by WLED when settings are loaded (currently this only happens immediately after boot, or after saving on the Usermod Settings page)
|
||||||
|
*
|
||||||
|
* readFromConfig() is called BEFORE setup(). This means you can use your persistent values in setup() (e.g. pin assignments, buffer sizes),
|
||||||
|
* but also that if you want to write persistent values to a dynamic buffer, you'd need to allocate it here instead of in setup.
|
||||||
|
* If you don't know what that is, don't fret. It most likely doesn't affect your use case :)
|
||||||
|
*
|
||||||
|
* Return true in case the config values returned from Usermod Settings were complete, or false if you'd like WLED to save your defaults to disk (so any missing values are editable in Usermod Settings)
|
||||||
|
*
|
||||||
|
* getJsonValue() returns false if the value is missing, or copies the value into the variable provided and returns true if the value is present
|
||||||
|
* The configComplete variable is true only if the "exampleUsermod" object and all values are present. If any values are missing, WLED will know to call addToConfig() to save them
|
||||||
|
*
|
||||||
|
* This function is guaranteed to be called on boot, but could also be called every time settings are updated
|
||||||
|
*/
|
||||||
|
bool readFromConfig(JsonObject& root)
|
||||||
|
{
|
||||||
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
|
int8_t newBatteryPin = batteryPin;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
JsonObject battery = root[FPSTR(_name)];
|
||||||
|
if (battery.isNull())
|
||||||
|
{
|
||||||
|
DEBUG_PRINT(FPSTR(_name));
|
||||||
|
DEBUG_PRINTLN(F(": No config found. (Using defaults.)"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
|
newBatteryPin = battery[F("pin")] | newBatteryPin;
|
||||||
|
#endif
|
||||||
|
// calculateTimeLeftEnabled = battery[F("time-left")] | calculateTimeLeftEnabled;
|
||||||
|
setMinBatteryVoltage(battery[F("min-voltage")] | minBatteryVoltage);
|
||||||
|
setMaxBatteryVoltage(battery[F("max-voltage")] | maxBatteryVoltage);
|
||||||
|
setTotalBatteryCapacity(battery[F("capacity")] | totalBatteryCapacity);
|
||||||
|
setCalibration(battery[F("calibration")] | calibration);
|
||||||
|
setReadingInterval(battery[FPSTR(_readInterval)] | readingInterval);
|
||||||
|
|
||||||
|
JsonObject ao = battery[F("auto-off")];
|
||||||
|
setAutoOffEnabled(ao[FPSTR(_enabled)] | autoOffEnabled);
|
||||||
|
setAutoOffThreshold(ao[FPSTR(_threshold)] | autoOffThreshold);
|
||||||
|
|
||||||
|
JsonObject lp = battery[F("indicator")];
|
||||||
|
setLowPowerIndicatorEnabled(lp[FPSTR(_enabled)] | lowPowerIndicatorEnabled);
|
||||||
|
setLowPowerIndicatorPreset(lp[FPSTR(_preset)] | lowPowerIndicatorPreset); // dropdown trickery (int)lp["preset"]
|
||||||
|
setLowPowerIndicatorThreshold(lp[FPSTR(_threshold)] | lowPowerIndicatorThreshold);
|
||||||
|
lowPowerIndicatorReactivationThreshold = lowPowerIndicatorThreshold+10;
|
||||||
|
setLowPowerIndicatorDuration(lp[FPSTR(_duration)] | lowPowerIndicatorDuration);
|
||||||
|
|
||||||
|
DEBUG_PRINT(FPSTR(_name));
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
|
if (!initDone)
|
||||||
|
{
|
||||||
|
// first run: reading from cfg.json
|
||||||
|
batteryPin = newBatteryPin;
|
||||||
|
DEBUG_PRINTLN(F(" config loaded."));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DEBUG_PRINTLN(F(" config (re)loaded."));
|
||||||
|
|
||||||
|
// changing parameters from settings page
|
||||||
|
if (newBatteryPin != batteryPin)
|
||||||
|
{
|
||||||
|
// deallocate pin
|
||||||
|
pinManager.deallocatePin(batteryPin, PinOwner::UM_Battery);
|
||||||
|
batteryPin = newBatteryPin;
|
||||||
|
// initialise
|
||||||
|
setup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return !battery[FPSTR(_readInterval)].isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generate a preset sample for low power indication
|
||||||
|
*/
|
||||||
|
void generateExamplePreset()
|
||||||
|
{
|
||||||
|
// StaticJsonDocument<300> j;
|
||||||
|
// JsonObject preset = j.createNestedObject();
|
||||||
|
// preset["mainseg"] = 0;
|
||||||
|
// JsonArray seg = preset.createNestedArray("seg");
|
||||||
|
// JsonObject seg0 = seg.createNestedObject();
|
||||||
|
// seg0["id"] = 0;
|
||||||
|
// seg0["start"] = 0;
|
||||||
|
// seg0["stop"] = 60;
|
||||||
|
// seg0["grp"] = 0;
|
||||||
|
// seg0["spc"] = 0;
|
||||||
|
// seg0["on"] = true;
|
||||||
|
// seg0["bri"] = 255;
|
||||||
|
|
||||||
|
// JsonArray col0 = seg0.createNestedArray("col");
|
||||||
|
// JsonArray col00 = col0.createNestedArray();
|
||||||
|
// col00.add(255);
|
||||||
|
// col00.add(0);
|
||||||
|
// col00.add(0);
|
||||||
|
|
||||||
|
// seg0["fx"] = 1;
|
||||||
|
// seg0["sx"] = 128;
|
||||||
|
// seg0["ix"] = 128;
|
||||||
|
|
||||||
|
// savePreset(199, "Low power Indicator", preset);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Getter and Setter. Just in case some other usermod wants to interact with this in the future
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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_BATTERY;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned long getReadingInterval()
|
||||||
|
{
|
||||||
|
return readingInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* minimum repetition is 3000ms (3s)
|
||||||
|
*/
|
||||||
|
void setReadingInterval(unsigned long newReadingInterval)
|
||||||
|
{
|
||||||
|
readingInterval = max((unsigned long)3000, newReadingInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get lowest configured battery voltage
|
||||||
|
*/
|
||||||
|
float getMinBatteryVoltage()
|
||||||
|
{
|
||||||
|
return minBatteryVoltage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set lowest battery voltage
|
||||||
|
* can't be below 0 volt
|
||||||
|
*/
|
||||||
|
void setMinBatteryVoltage(float voltage)
|
||||||
|
{
|
||||||
|
minBatteryVoltage = max(0.0f, voltage);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get highest configured battery voltage
|
||||||
|
*/
|
||||||
|
float getMaxBatteryVoltage()
|
||||||
|
{
|
||||||
|
return maxBatteryVoltage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set highest battery voltage
|
||||||
|
* can't be below minBatteryVoltage
|
||||||
|
*/
|
||||||
|
void setMaxBatteryVoltage(float voltage)
|
||||||
|
{
|
||||||
|
#ifdef USERMOD_BATTERY_USE_LIPO
|
||||||
|
maxBatteryVoltage = max(getMinBatteryVoltage()+0.7f, voltage);
|
||||||
|
#else
|
||||||
|
maxBatteryVoltage = max(getMinBatteryVoltage()+1.0f, voltage);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the capacity of all cells in parralel sumed up
|
||||||
|
* unit: mAh
|
||||||
|
*/
|
||||||
|
unsigned int getTotalBatteryCapacity()
|
||||||
|
{
|
||||||
|
return totalBatteryCapacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTotalBatteryCapacity(unsigned int capacity)
|
||||||
|
{
|
||||||
|
totalBatteryCapacity = capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the choosen adc precision
|
||||||
|
* esp8266 = 10bit resolution = 1024.0f
|
||||||
|
* esp32 = 12bit resolution = 4095.0f
|
||||||
|
*/
|
||||||
|
float getAdcPrecision()
|
||||||
|
{
|
||||||
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
|
// esp32
|
||||||
|
return 4096.0f;
|
||||||
|
#else
|
||||||
|
// esp8266
|
||||||
|
return 1024.0f;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the calculated voltage
|
||||||
|
* formula: (adc pin value / adc precision * max voltage) + calibration
|
||||||
|
*/
|
||||||
|
float getVoltage()
|
||||||
|
{
|
||||||
|
return voltage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the mapped battery level (0 - 100) based on voltage
|
||||||
|
* important: voltage can drop when a load is applied, so its only an estimate
|
||||||
|
*/
|
||||||
|
int8_t getBatteryLevel()
|
||||||
|
{
|
||||||
|
return batteryLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the configured calibration value
|
||||||
|
* a offset value to fine-tune the calculated voltage.
|
||||||
|
*/
|
||||||
|
float getCalibration()
|
||||||
|
{
|
||||||
|
return calibration;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the voltage calibration offset value
|
||||||
|
* a offset value to fine-tune the calculated voltage.
|
||||||
|
*/
|
||||||
|
void setCalibration(float offset)
|
||||||
|
{
|
||||||
|
calibration = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get auto-off feature enabled status
|
||||||
|
* is auto-off enabled, true/false
|
||||||
|
*/
|
||||||
|
bool getAutoOffEnabled()
|
||||||
|
{
|
||||||
|
return autoOffEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set auto-off feature status
|
||||||
|
*/
|
||||||
|
void setAutoOffEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
autoOffEnabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get auto-off threshold in percent (0-100)
|
||||||
|
*/
|
||||||
|
int8_t getAutoOffThreshold()
|
||||||
|
{
|
||||||
|
return autoOffThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set auto-off threshold in percent (0-100)
|
||||||
|
*/
|
||||||
|
void setAutoOffThreshold(int8_t threshold)
|
||||||
|
{
|
||||||
|
autoOffThreshold = min((int8_t)100, max((int8_t)0, threshold));
|
||||||
|
// when low power indicator is enabled the auto-off threshold cannot be above indicator threshold
|
||||||
|
autoOffThreshold = lowPowerIndicatorEnabled /*&& autoOffEnabled*/ ? min(lowPowerIndicatorThreshold-1, (int)autoOffThreshold) : autoOffThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get low-power-indicator feature enabled status
|
||||||
|
* is the low-power-indicator enabled, true/false
|
||||||
|
*/
|
||||||
|
bool getLowPowerIndicatorEnabled()
|
||||||
|
{
|
||||||
|
return lowPowerIndicatorEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set low-power-indicator feature status
|
||||||
|
*/
|
||||||
|
void setLowPowerIndicatorEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
lowPowerIndicatorEnabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get low-power-indicator preset to activate when low power is detected
|
||||||
|
*/
|
||||||
|
int8_t getLowPowerIndicatorPreset()
|
||||||
|
{
|
||||||
|
return lowPowerIndicatorPreset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set low-power-indicator preset to activate when low power is detected
|
||||||
|
*/
|
||||||
|
void setLowPowerIndicatorPreset(int8_t presetId)
|
||||||
|
{
|
||||||
|
// String tmp = ""; For what ever reason this doesn't work :(
|
||||||
|
// lowPowerIndicatorPreset = getPresetName(presetId, tmp) ? presetId : lowPowerIndicatorPreset;
|
||||||
|
lowPowerIndicatorPreset = presetId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get low-power-indicator threshold in percent (0-100)
|
||||||
|
*/
|
||||||
|
int8_t getLowPowerIndicatorThreshold()
|
||||||
|
{
|
||||||
|
return lowPowerIndicatorThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set low-power-indicator threshold in percent (0-100)
|
||||||
|
*/
|
||||||
|
void setLowPowerIndicatorThreshold(int8_t threshold)
|
||||||
|
{
|
||||||
|
lowPowerIndicatorThreshold = threshold;
|
||||||
|
// when auto-off is enabled the indicator threshold cannot be below auto-off threshold
|
||||||
|
lowPowerIndicatorThreshold = autoOffEnabled /*&& lowPowerIndicatorEnabled*/ ? max(autoOffThreshold+1, (int)lowPowerIndicatorThreshold) : max(5, (int)lowPowerIndicatorThreshold);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get low-power-indicator duration in seconds
|
||||||
|
*/
|
||||||
|
int8_t getLowPowerIndicatorDuration()
|
||||||
|
{
|
||||||
|
return lowPowerIndicatorDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set low-power-indicator duration in seconds
|
||||||
|
*/
|
||||||
|
void setLowPowerIndicatorDuration(int8_t duration)
|
||||||
|
{
|
||||||
|
lowPowerIndicatorDuration = duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get low-power-indicator status when the indication is done thsi returns true
|
||||||
|
*/
|
||||||
|
bool getLowPowerIndicatorDone()
|
||||||
|
{
|
||||||
|
return lowPowerIndicationDone;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// strings to reduce flash memory usage (used more than twice)
|
||||||
|
const char UsermodBattery::_name[] PROGMEM = "Battery";
|
||||||
|
const char UsermodBattery::_readInterval[] PROGMEM = "interval";
|
||||||
|
const char UsermodBattery::_enabled[] PROGMEM = "enabled";
|
||||||
|
const char UsermodBattery::_threshold[] PROGMEM = "threshold";
|
||||||
|
const char UsermodBattery::_preset[] PROGMEM = "preset";
|
||||||
|
const char UsermodBattery::_duration[] PROGMEM = "duration";
|
||||||
|
const char UsermodBattery::_init[] PROGMEM = "init";
|
@ -271,6 +271,7 @@ class UsermodCronixie : public Usermod {
|
|||||||
{
|
{
|
||||||
if (root["nx"].is<const char*>()) {
|
if (root["nx"].is<const char*>()) {
|
||||||
strncpy(cronixieDisplay, root["nx"], 6);
|
strncpy(cronixieDisplay, root["nx"], 6);
|
||||||
|
setCronixie();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,7 +136,7 @@ private:
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (m_offPreset) {
|
if (m_offPreset) {
|
||||||
if (currentPreset==m_onPreset || currentPlaylist==m_onPreset) applyPreset(m_offPreset, NotifyUpdateMode);
|
applyPreset(m_offPreset, NotifyUpdateMode);
|
||||||
return;
|
return;
|
||||||
} else if (prevPlaylist) {
|
} else if (prevPlaylist) {
|
||||||
if (currentPreset==m_onPreset || currentPlaylist==m_onPreset) applyPreset(prevPlaylist, NotifyUpdateMode);
|
if (currentPreset==m_onPreset || currentPlaylist==m_onPreset) applyPreset(prevPlaylist, NotifyUpdateMode);
|
||||||
|
@ -14,7 +14,7 @@ Copy the example `platformio_override.ini` to the root directory. This file sho
|
|||||||
### Define Your Options
|
### Define Your Options
|
||||||
|
|
||||||
* `USERMOD_DALLASTEMPERATURE` - enables this user mod wled00/usermods_list.cpp
|
* `USERMOD_DALLASTEMPERATURE` - enables this user mod wled00/usermods_list.cpp
|
||||||
* `USERMOD_DALLASTEMPERATURE_FIRST_MEASUREMENT_AT` - umber of milliseconds after boot to take first measurement, defaults to 20000 ms
|
* `USERMOD_DALLASTEMPERATURE_FIRST_MEASUREMENT_AT` - number of milliseconds after boot to take first measurement, defaults to 20000 ms
|
||||||
|
|
||||||
All parameters can be configured at runtime via the Usermods settings page, including pin, temperature in degrees Celsius or Farenheit and measurement interval.
|
All parameters can be configured at runtime via the Usermods settings page, including pin, temperature in degrees Celsius or Farenheit and measurement interval.
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 68 KiB |
@ -1,68 +0,0 @@
|
|||||||
# :battery: Battery status/level Usermod :battery:
|
|
||||||
Enables battery level monitoring of your project.
|
|
||||||
|
|
||||||
You can see the battery level and voltage in the `info modal`.
|
|
||||||
|
|
||||||
For this to work, the positive side of the (18650) battery must be connected to pin `A0` of the d1 mini/esp8266 with a 100k Ohm resistor (see [Useful Links](#useful-links)).
|
|
||||||
|
|
||||||
If you have an ESP32 board, connect the positive side of the battery to ADC1 (GPIO32 - GPIO39)
|
|
||||||
|
|
||||||
<p align="center">
|
|
||||||
<img width="300" src="assets/battery_info_screen.png">
|
|
||||||
</p>
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
define `USERMOD_BATTERY_STATUS_BASIC` in `my_config.h`
|
|
||||||
|
|
||||||
### Basic wiring diagram
|
|
||||||
<p align="center">
|
|
||||||
<img width="300" src="assets/battery_connection_schematic_01.png">
|
|
||||||
</p>
|
|
||||||
|
|
||||||
### Define Your Options
|
|
||||||
|
|
||||||
* `USERMOD_BATTERY_STATUS_BASIC` - define this (in `my_config.h`) to have this usermod included wled00\usermods_list.cpp
|
|
||||||
* `USERMOD_BATTERY_MEASUREMENT_PIN` - defaults to A0 on ESP8266 and GPIO32 on ESP32
|
|
||||||
* `USERMOD_BATTERY_MEASUREMENT_INTERVAL` - battery check interval. defaults to 30 seconds
|
|
||||||
* `USERMOD_BATTERY_MIN_VOLTAGE` - minimum battery voltage. default is 2.6 (18650 battery standard)
|
|
||||||
* `USERMOD_BATTERY_MAX_VOLTAGE` - maximum battery voltage. default is 4.2 (18650 battery standard)
|
|
||||||
|
|
||||||
All parameters can be configured at runtime via the Usermods settings page.
|
|
||||||
|
|
||||||
## Important :warning:
|
|
||||||
* Make sure you know your battery specifications! All batteries are **NOT** the same!
|
|
||||||
* Example:
|
|
||||||
|
|
||||||
| Your battery specification table | | Options you can define |
|
|
||||||
| :-------------------------------- |:--------------- | :---------------------------- |
|
|
||||||
| Capacity | 3500mAh 12,5 Wh | |
|
|
||||||
| Minimum capacity | 3350mAh 11,9 Wh | |
|
|
||||||
| Rated voltage | 3.6V - 3.7V | |
|
|
||||||
| **Charging end voltage** | **4,2V ± 0,05** | `USERMOD_BATTERY_MAX_VOLTAGE` |
|
|
||||||
| **Discharge voltage** | **2,5V** | `USERMOD_BATTERY_MIN_VOLTAGE` |
|
|
||||||
| Max. discharge current (constant) | 10A (10000mA) | |
|
|
||||||
| max. charging current | 1.7A (1700mA) | |
|
|
||||||
| ... | ... | ... |
|
|
||||||
| .. | .. | .. |
|
|
||||||
|
|
||||||
Specification from: [Molicel INR18650-M35A, 3500mAh 10A Lithium-ion battery, 3.6V - 3.7V](https://www.akkuteile.de/lithium-ionen-akkus/18650/molicel/molicel-inr18650-m35a-3500mah-10a-lithium-ionen-akku-3-6v-3-7v_100833)
|
|
||||||
|
|
||||||
## Useful Links
|
|
||||||
* https://lazyzero.de/elektronik/esp8266/wemos_d1_mini_a0/start
|
|
||||||
* https://arduinodiy.wordpress.com/2016/12/25/monitoring-lipo-battery-voltage-with-wemos-d1-minibattery-shield-and-thingspeak/
|
|
||||||
|
|
||||||
## Change Log
|
|
||||||
2021-09-02
|
|
||||||
* added "Battery voltage" to info
|
|
||||||
* added circuit diagram to readme
|
|
||||||
* added MQTT support, sending battery voltage
|
|
||||||
* minor fixes
|
|
||||||
|
|
||||||
2021-08-15
|
|
||||||
* changed `USERMOD_BATTERY_MIN_VOLTAGE` to 2.6 volt as default for 18650 batteries
|
|
||||||
* Updated readme, added specification table
|
|
||||||
|
|
||||||
2021-08-10
|
|
||||||
* Created
|
|
||||||
|
|
@ -1,398 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "wled.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// pin defaults
|
|
||||||
// for the esp32 it is best to use the ADC1: GPIO32 - GPIO39
|
|
||||||
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/adc.html
|
|
||||||
#ifndef USERMOD_BATTERY_MEASUREMENT_PIN
|
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
|
||||||
#define USERMOD_BATTERY_MEASUREMENT_PIN 32
|
|
||||||
#else //ESP8266 boards
|
|
||||||
#define USERMOD_BATTERY_MEASUREMENT_PIN A0
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// esp32 has a 12bit adc resolution
|
|
||||||
// esp8266 only 10bit
|
|
||||||
#ifndef USERMOD_BATTERY_ADC_PRECISION
|
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
|
||||||
// 12 bits
|
|
||||||
#define USERMOD_BATTERY_ADC_PRECISION 4095.0f
|
|
||||||
#else
|
|
||||||
// 10 bits
|
|
||||||
#define USERMOD_BATTERY_ADC_PRECISION 1024.0f
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// the frequency to check the battery, 30 sec
|
|
||||||
#ifndef USERMOD_BATTERY_MEASUREMENT_INTERVAL
|
|
||||||
#define USERMOD_BATTERY_MEASUREMENT_INTERVAL 30000
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// default for 18650 battery
|
|
||||||
// https://batterybro.com/blogs/18650-wholesale-battery-reviews/18852515-when-to-recycle-18650-batteries-and-how-to-start-a-collection-center-in-your-vape-shop
|
|
||||||
// Discharge voltage: 2.5 volt + .1 for personal safety
|
|
||||||
#ifndef USERMOD_BATTERY_MIN_VOLTAGE
|
|
||||||
#define USERMOD_BATTERY_MIN_VOLTAGE 2.6f
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef USERMOD_BATTERY_MAX_VOLTAGE
|
|
||||||
#define USERMOD_BATTERY_MAX_VOLTAGE 4.2f
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class UsermodBatteryBasic : public Usermod
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
// battery pin can be defined in my_config.h
|
|
||||||
int8_t batteryPin = USERMOD_BATTERY_MEASUREMENT_PIN;
|
|
||||||
// how often to read the battery voltage
|
|
||||||
unsigned long readingInterval = USERMOD_BATTERY_MEASUREMENT_INTERVAL;
|
|
||||||
unsigned long nextReadTime = 0;
|
|
||||||
unsigned long lastReadTime = 0;
|
|
||||||
// battery min. voltage
|
|
||||||
float minBatteryVoltage = USERMOD_BATTERY_MIN_VOLTAGE;
|
|
||||||
// battery max. voltage
|
|
||||||
float maxBatteryVoltage = USERMOD_BATTERY_MAX_VOLTAGE;
|
|
||||||
// 0 - 1024 for esp8266 (10-bit resolution)
|
|
||||||
// 0 - 4095 for esp32 (Default is 12-bit resolution)
|
|
||||||
float adcPrecision = USERMOD_BATTERY_ADC_PRECISION;
|
|
||||||
// raw analog reading
|
|
||||||
float rawValue = 0.0;
|
|
||||||
// calculated voltage
|
|
||||||
float voltage = 0.0;
|
|
||||||
// mapped battery level based on voltage
|
|
||||||
long batteryLevel = 0;
|
|
||||||
bool initDone = false;
|
|
||||||
bool initializing = true;
|
|
||||||
|
|
||||||
|
|
||||||
// strings to reduce flash memory usage (used more than twice)
|
|
||||||
static const char _name[];
|
|
||||||
static const char _readInterval[];
|
|
||||||
|
|
||||||
|
|
||||||
// custom map function
|
|
||||||
// https://forum.arduino.cc/t/floating-point-using-map-function/348113/2
|
|
||||||
double mapf(double x, double in_min, double in_max, double out_min, double out_max)
|
|
||||||
{
|
|
||||||
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
|
||||||
}
|
|
||||||
|
|
||||||
float truncate(float val, byte dec)
|
|
||||||
{
|
|
||||||
float x = val * pow(10, dec);
|
|
||||||
float y = round(x);
|
|
||||||
float z = x - y;
|
|
||||||
if ((int)z == 5)
|
|
||||||
{
|
|
||||||
y++;
|
|
||||||
}
|
|
||||||
x = y / pow(10, dec);
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
//Functions called by WLED
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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()
|
|
||||||
{
|
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
|
||||||
DEBUG_PRINTLN(F("Allocating battery pin..."));
|
|
||||||
if (batteryPin >= 0 && pinManager.allocatePin(batteryPin, false))
|
|
||||||
{
|
|
||||||
DEBUG_PRINTLN(F("Battery pin allocation succeeded."));
|
|
||||||
} else {
|
|
||||||
if (batteryPin >= 0) DEBUG_PRINTLN(F("Battery pin allocation failed."));
|
|
||||||
batteryPin = -1; // allocation failed
|
|
||||||
}
|
|
||||||
#else //ESP8266 boards have only one analog input pin A0
|
|
||||||
|
|
||||||
pinMode(batteryPin, INPUT);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
nextReadTime = millis() + readingInterval;
|
|
||||||
lastReadTime = millis();
|
|
||||||
|
|
||||||
initDone = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* connected() is called every time the WiFi is (re)connected
|
|
||||||
* Use it to initialize network interfaces
|
|
||||||
*/
|
|
||||||
void connected()
|
|
||||||
{
|
|
||||||
//Serial.println("Connected to WiFi!");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* loop() is called continuously. Here you can check for events, read sensors, etc.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void loop()
|
|
||||||
{
|
|
||||||
if(strip.isUpdating()) return;
|
|
||||||
|
|
||||||
// check the battery level every USERMOD_BATTERY_MEASUREMENT_INTERVAL (ms)
|
|
||||||
if (millis() < nextReadTime) return;
|
|
||||||
|
|
||||||
|
|
||||||
nextReadTime = millis() + readingInterval;
|
|
||||||
lastReadTime = millis();
|
|
||||||
initializing = false;
|
|
||||||
|
|
||||||
// read battery raw input
|
|
||||||
rawValue = analogRead(batteryPin);
|
|
||||||
|
|
||||||
// calculate the voltage
|
|
||||||
voltage = (rawValue / adcPrecision) * maxBatteryVoltage ;
|
|
||||||
// check if voltage is within specified voltage range
|
|
||||||
voltage = voltage<minBatteryVoltage||voltage>maxBatteryVoltage?-1.0f:voltage;
|
|
||||||
|
|
||||||
// translate battery voltage into percentage
|
|
||||||
/*
|
|
||||||
the standard "map" function doesn't work
|
|
||||||
https://www.arduino.cc/reference/en/language/functions/math/map/ notes and warnings at the bottom
|
|
||||||
*/
|
|
||||||
batteryLevel = mapf(voltage, minBatteryVoltage, maxBatteryVoltage, 0, 100);
|
|
||||||
|
|
||||||
|
|
||||||
// SmartHome stuff
|
|
||||||
if (WLED_MQTT_CONNECTED) {
|
|
||||||
char subuf[64];
|
|
||||||
strcpy(subuf, mqttDeviceTopic);
|
|
||||||
strcat_P(subuf, PSTR("/voltage"));
|
|
||||||
mqtt->publish(subuf, 0, false, String(voltage).c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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)
|
|
||||||
{
|
|
||||||
|
|
||||||
JsonObject user = root["u"];
|
|
||||||
if (user.isNull()) user = root.createNestedObject("u");
|
|
||||||
|
|
||||||
// info modal display names
|
|
||||||
JsonArray batteryPercentage = user.createNestedArray("Battery level");
|
|
||||||
JsonArray batteryVoltage = user.createNestedArray("Battery voltage");
|
|
||||||
|
|
||||||
if (initializing) {
|
|
||||||
batteryPercentage.add((nextReadTime - millis()) / 1000);
|
|
||||||
batteryPercentage.add(" sec");
|
|
||||||
batteryVoltage.add((nextReadTime - millis()) / 1000);
|
|
||||||
batteryVoltage.add(" sec");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(batteryLevel < 0) {
|
|
||||||
batteryPercentage.add(F("invalid"));
|
|
||||||
} else {
|
|
||||||
batteryPercentage.add(batteryLevel);
|
|
||||||
}
|
|
||||||
batteryPercentage.add(F(" %"));
|
|
||||||
|
|
||||||
if(voltage < 0) {
|
|
||||||
batteryVoltage.add(F("invalid"));
|
|
||||||
} else {
|
|
||||||
batteryVoltage.add(truncate(voltage, 2));
|
|
||||||
}
|
|
||||||
batteryVoltage.add(F(" V"));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
|
|
||||||
* Values in the state object may be modified by connected clients
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
void readFromJsonState(JsonObject& root)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* addToConfig() can be used to add custom persistent settings to the cfg.json file in the "um" (usermod) object.
|
|
||||||
* It will be called by WLED when settings are actually saved (for example, LED settings are saved)
|
|
||||||
* If you want to force saving the current state, use serializeConfig() in your loop().
|
|
||||||
*
|
|
||||||
* CAUTION: serializeConfig() will initiate a filesystem write operation.
|
|
||||||
* It might cause the LEDs to stutter and will cause flash wear if called too often.
|
|
||||||
* Use it sparingly and always in the loop, never in network callbacks!
|
|
||||||
*
|
|
||||||
* addToConfig() will make your settings editable through the Usermod Settings page automatically.
|
|
||||||
*
|
|
||||||
* Usermod Settings Overview:
|
|
||||||
* - Numeric values are treated as floats in the browser.
|
|
||||||
* - If the numeric value entered into the browser contains a decimal point, it will be parsed as a C float
|
|
||||||
* before being returned to the Usermod. The float data type has only 6-7 decimal digits of precision, and
|
|
||||||
* doubles are not supported, numbers will be rounded to the nearest float value when being parsed.
|
|
||||||
* The range accepted by the input field is +/- 1.175494351e-38 to +/- 3.402823466e+38.
|
|
||||||
* - If the numeric value entered into the browser doesn't contain a decimal point, it will be parsed as a
|
|
||||||
* C int32_t (range: -2147483648 to 2147483647) before being returned to the usermod.
|
|
||||||
* Overflows or underflows are truncated to the max/min value for an int32_t, and again truncated to the type
|
|
||||||
* used in the Usermod when reading the value from ArduinoJson.
|
|
||||||
* - Pin values can be treated differently from an integer value by using the key name "pin"
|
|
||||||
* - "pin" can contain a single or array of integer values
|
|
||||||
* - On the Usermod Settings page there is simple checking for pin conflicts and warnings for special pins
|
|
||||||
* - Red color indicates a conflict. Yellow color indicates a pin with a warning (e.g. an input-only pin)
|
|
||||||
* - Tip: use int8_t to store the pin value in the Usermod, so a -1 value (pin not set) can be used
|
|
||||||
*
|
|
||||||
* See usermod_v2_auto_save.h for an example that saves Flash space by reusing ArduinoJson key name strings
|
|
||||||
*
|
|
||||||
* If you need a dedicated settings page with custom layout for your Usermod, that takes a lot more work.
|
|
||||||
* You will have to add the setting to the HTML, xml.cpp and set.cpp manually.
|
|
||||||
* See the WLED Soundreactive fork (code and wiki) for reference. https://github.com/atuline/WLED
|
|
||||||
*
|
|
||||||
* I highly recommend checking out the basics of ArduinoJson serialization and deserialization in order to use custom settings!
|
|
||||||
*/
|
|
||||||
void addToConfig(JsonObject& root)
|
|
||||||
{
|
|
||||||
// created JSON object:
|
|
||||||
/*
|
|
||||||
{
|
|
||||||
"Battery-Level": {
|
|
||||||
"pin": "A0", <--- only when using esp32 boards
|
|
||||||
"minBatteryVoltage": 2.6,
|
|
||||||
"maxBatteryVoltage": 4.2,
|
|
||||||
"read-interval-ms": 30000
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
JsonObject battery = root.createNestedObject(FPSTR(_name)); // usermodname
|
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
|
||||||
battery["pin"] = batteryPin; // usermodparam
|
|
||||||
#endif
|
|
||||||
battery["minBatteryVoltage"] = minBatteryVoltage; // usermodparam
|
|
||||||
battery["maxBatteryVoltage"] = maxBatteryVoltage; // usermodparam
|
|
||||||
battery[FPSTR(_readInterval)] = readingInterval;
|
|
||||||
|
|
||||||
DEBUG_PRINTLN(F("Battery config saved."));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* readFromConfig() can be used to read back the custom settings you added with addToConfig().
|
|
||||||
* This is called by WLED when settings are loaded (currently this only happens immediately after boot, or after saving on the Usermod Settings page)
|
|
||||||
*
|
|
||||||
* readFromConfig() is called BEFORE setup(). This means you can use your persistent values in setup() (e.g. pin assignments, buffer sizes),
|
|
||||||
* but also that if you want to write persistent values to a dynamic buffer, you'd need to allocate it here instead of in setup.
|
|
||||||
* If you don't know what that is, don't fret. It most likely doesn't affect your use case :)
|
|
||||||
*
|
|
||||||
* Return true in case the config values returned from Usermod Settings were complete, or false if you'd like WLED to save your defaults to disk (so any missing values are editable in Usermod Settings)
|
|
||||||
*
|
|
||||||
* getJsonValue() returns false if the value is missing, or copies the value into the variable provided and returns true if the value is present
|
|
||||||
* The configComplete variable is true only if the "exampleUsermod" object and all values are present. If any values are missing, WLED will know to call addToConfig() to save them
|
|
||||||
*
|
|
||||||
* This function is guaranteed to be called on boot, but could also be called every time settings are updated
|
|
||||||
*/
|
|
||||||
bool readFromConfig(JsonObject& root)
|
|
||||||
{
|
|
||||||
// looking for JSON object:
|
|
||||||
/*
|
|
||||||
{
|
|
||||||
"BatteryLevel": {
|
|
||||||
"pin": "A0", <--- only when using esp32 boards
|
|
||||||
"minBatteryVoltage": 2.6,
|
|
||||||
"maxBatteryVoltage": 4.2,
|
|
||||||
"read-interval-ms": 30000
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
|
||||||
int8_t newBatteryPin = batteryPin;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
JsonObject battery = root[FPSTR(_name)];
|
|
||||||
if (battery.isNull())
|
|
||||||
{
|
|
||||||
DEBUG_PRINT(FPSTR(_name));
|
|
||||||
DEBUG_PRINTLN(F(": No config found. (Using defaults.)"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
|
||||||
newBatteryPin = battery["pin"] | newBatteryPin;
|
|
||||||
#endif
|
|
||||||
minBatteryVoltage = battery["minBatteryVoltage"] | minBatteryVoltage;
|
|
||||||
//minBatteryVoltage = min(12.0f, (int)readingInterval);
|
|
||||||
maxBatteryVoltage = battery["maxBatteryVoltage"] | maxBatteryVoltage;
|
|
||||||
//maxBatteryVoltage = min(14.4f, max(3.3f,(int)readingInterval));
|
|
||||||
readingInterval = battery["read-interval-ms"] | readingInterval;
|
|
||||||
readingInterval = max(3000, (int)readingInterval); // minimum repetition is >5000ms (5s)
|
|
||||||
|
|
||||||
DEBUG_PRINT(FPSTR(_name));
|
|
||||||
|
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
|
||||||
if (!initDone)
|
|
||||||
{
|
|
||||||
// first run: reading from cfg.json
|
|
||||||
newBatteryPin = batteryPin;
|
|
||||||
DEBUG_PRINTLN(F(" config loaded."));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DEBUG_PRINTLN(F(" config (re)loaded."));
|
|
||||||
|
|
||||||
// changing paramters from settings page
|
|
||||||
if (newBatteryPin != batteryPin)
|
|
||||||
{
|
|
||||||
// deallocate pin
|
|
||||||
pinManager.deallocatePin(batteryPin);
|
|
||||||
batteryPin = newBatteryPin;
|
|
||||||
// initialise
|
|
||||||
setup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return !battery[FPSTR(_readInterval)].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_BATTERY_STATUS_BASIC;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// strings to reduce flash memory usage (used more than twice)
|
|
||||||
const char UsermodBatteryBasic::_name[] PROGMEM = "Battery-level";
|
|
||||||
const char UsermodBatteryBasic::_readInterval[] PROGMEM = "read-interval-ms";
|
|
@ -138,7 +138,7 @@ class MPU6050Driver : public Usermod {
|
|||||||
// (if it's going to break, usually the code will be 1)
|
// (if it's going to break, usually the code will be 1)
|
||||||
DEBUG_PRINT(F("DMP Initialization failed (code "));
|
DEBUG_PRINT(F("DMP Initialization failed (code "));
|
||||||
DEBUG_PRINT(devStatus);
|
DEBUG_PRINT(devStatus);
|
||||||
DEBUG_PRINTLN(F(")"));
|
DEBUG_PRINTLN(")");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,9 +26,8 @@ class ShtUsermod : public Usermod
|
|||||||
const byte shtI2cAddress = 0x44; // i2c address of the sensor. 0x44 is the default for all SHT sensors. Change this, if needed
|
const byte shtI2cAddress = 0x44; // i2c address of the sensor. 0x44 is the default for all SHT sensors. Change this, if needed
|
||||||
unsigned long shtLastTimeUpdated = 0; // Remembers when we read data the last time
|
unsigned long shtLastTimeUpdated = 0; // Remembers when we read data the last time
|
||||||
bool shtDataRequested = false; // Reading data is done async. This remembers if we asked the sensor to read data
|
bool shtDataRequested = false; // Reading data is done async. This remembers if we asked the sensor to read data
|
||||||
float shtCurrentTempC = 0; // Last read temperature in Celsius
|
float shtCurrentTempC = 0.0f; // Last read temperature in Celsius
|
||||||
float shtCurrentTempF = 0; // Last read temperature in Fahrenheit
|
float shtCurrentHumidity = 0.0f; // Last read humidity in RH%
|
||||||
float shtCurrentHumidity = 0; // Last read humidity in RH%
|
|
||||||
|
|
||||||
|
|
||||||
void initShtTempHumiditySensor();
|
void initShtTempHumiditySensor();
|
||||||
@ -56,9 +55,13 @@ class ShtUsermod : public Usermod
|
|||||||
bool readFromConfig(JsonObject &root);
|
bool readFromConfig(JsonObject &root);
|
||||||
void addToJsonInfo(JsonObject& root);
|
void addToJsonInfo(JsonObject& root);
|
||||||
|
|
||||||
float getTemperatureC();
|
bool isEnabled() { return enabled; }
|
||||||
float getTemperatureF();
|
|
||||||
float getHumidity();
|
float getTemperature();
|
||||||
|
float getTemperatureC() { return shtCurrentTempC; }
|
||||||
|
float getTemperatureF() { return (shtCurrentTempC * 1.8f) + 32.0f; }
|
||||||
|
float getHumidity() { return shtCurrentHumidity; }
|
||||||
|
const char* getUnitString();
|
||||||
|
|
||||||
uint16_t getId() { return USERMOD_ID_SHT; }
|
uint16_t getId() { return USERMOD_ID_SHT; }
|
||||||
};
|
};
|
||||||
@ -90,7 +93,6 @@ void ShtUsermod::initShtTempHumiditySensor()
|
|||||||
shtTempHumidSensor->begin(shtI2cAddress, i2c_sda, i2c_scl);
|
shtTempHumidSensor->begin(shtI2cAddress, i2c_sda, i2c_scl);
|
||||||
if (shtTempHumidSensor->readStatus() == 0xFFFF) {
|
if (shtTempHumidSensor->readStatus() == 0xFFFF) {
|
||||||
DEBUG_PRINTF("[%s] SHT init failed!\n", _name);
|
DEBUG_PRINTF("[%s] SHT init failed!\n", _name);
|
||||||
cleanupShtTempHumiditySensor();
|
|
||||||
cleanup();
|
cleanup();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -107,12 +109,8 @@ void ShtUsermod::initShtTempHumiditySensor()
|
|||||||
*/
|
*/
|
||||||
void ShtUsermod::cleanupShtTempHumiditySensor()
|
void ShtUsermod::cleanupShtTempHumiditySensor()
|
||||||
{
|
{
|
||||||
if (isShtReady()) {
|
if (isShtReady()) shtTempHumidSensor->reset();
|
||||||
shtTempHumidSensor->reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
delete shtTempHumidSensor;
|
delete shtTempHumidSensor;
|
||||||
|
|
||||||
shtInitDone = false;
|
shtInitDone = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,9 +124,7 @@ void ShtUsermod::cleanupShtTempHumiditySensor()
|
|||||||
*/
|
*/
|
||||||
void ShtUsermod::cleanup()
|
void ShtUsermod::cleanup()
|
||||||
{
|
{
|
||||||
if (isShtReady()) {
|
|
||||||
cleanupShtTempHumiditySensor();
|
cleanupShtTempHumiditySensor();
|
||||||
}
|
|
||||||
|
|
||||||
if (pinAllocDone) {
|
if (pinAllocDone) {
|
||||||
PinManagerPinType pins[2] = { { i2c_sda, true }, { i2c_scl, true } };
|
PinManagerPinType pins[2] = { { i2c_sda, true }, { i2c_scl, true } };
|
||||||
@ -162,9 +158,9 @@ void ShtUsermod::publishTemperatureAndHumidityViaMqtt() {
|
|||||||
char buf[128];
|
char buf[128];
|
||||||
|
|
||||||
snprintf_P(buf, 127, PSTR("%s/temperature"), mqttDeviceTopic);
|
snprintf_P(buf, 127, PSTR("%s/temperature"), mqttDeviceTopic);
|
||||||
mqtt->publish(buf, 0, false, String((unitOfTemp ? getTemperatureF() : getTemperatureC())).c_str());
|
mqtt->publish(buf, 0, false, String(getTemperature()).c_str());
|
||||||
snprintf_P(buf, 127, PSTR("%s/humidity"), mqttDeviceTopic);
|
snprintf_P(buf, 127, PSTR("%s/humidity"), mqttDeviceTopic);
|
||||||
mqtt->publish(buf, 0, false, String(shtCurrentHumidity).c_str());
|
mqtt->publish(buf, 0, false, String(getHumidity()).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -191,7 +187,7 @@ void ShtUsermod::publishHomeAssistantAutodiscovery() {
|
|||||||
json[F("stat_cla")] = F("measurement");
|
json[F("stat_cla")] = F("measurement");
|
||||||
snprintf_P(buf, 127, PSTR("%s-temperature"), escapedMac.c_str());
|
snprintf_P(buf, 127, PSTR("%s-temperature"), escapedMac.c_str());
|
||||||
json[F("uniq_id")] = buf;
|
json[F("uniq_id")] = buf;
|
||||||
json[F("unit_of_meas")] = F("°C");
|
json[F("unit_of_meas")] = unitOfTemp ? F("°F") : F("°C");
|
||||||
appendDeviceToMqttDiscoveryMessage(json);
|
appendDeviceToMqttDiscoveryMessage(json);
|
||||||
payload_size = serializeJson(json, json_str);
|
payload_size = serializeJson(json, json_str);
|
||||||
snprintf_P(buf, 127, PSTR("homeassistant/sensor/%s/%s-temperature/config"), escapedMac.c_str(), escapedMac.c_str());
|
snprintf_P(buf, 127, PSTR("homeassistant/sensor/%s/%s-temperature/config"), escapedMac.c_str(), escapedMac.c_str());
|
||||||
@ -222,7 +218,7 @@ void ShtUsermod::publishHomeAssistantAutodiscovery() {
|
|||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
void ShtUsermod::appendDeviceToMqttDiscoveryMessage(JsonDocument& root) {
|
void ShtUsermod::appendDeviceToMqttDiscoveryMessage(JsonDocument& root) {
|
||||||
JsonObject device = root.createNestedObject("dev");
|
JsonObject device = root.createNestedObject(F("dev"));
|
||||||
device[F("ids")] = escapedMac.c_str();
|
device[F("ids")] = escapedMac.c_str();
|
||||||
device[F("name")] = serverDescription;
|
device[F("name")] = serverDescription;
|
||||||
device[F("sw")] = versionString;
|
device[F("sw")] = versionString;
|
||||||
@ -290,13 +286,11 @@ void ShtUsermod::loop()
|
|||||||
if (shtTempHumidSensor->dataReady()) {
|
if (shtTempHumidSensor->dataReady()) {
|
||||||
if (shtTempHumidSensor->readData(false)) {
|
if (shtTempHumidSensor->readData(false)) {
|
||||||
shtCurrentTempC = shtTempHumidSensor->getTemperature();
|
shtCurrentTempC = shtTempHumidSensor->getTemperature();
|
||||||
shtCurrentTempF = shtTempHumidSensor->getFahrenheit();
|
|
||||||
shtCurrentHumidity = shtTempHumidSensor->getHumidity();
|
shtCurrentHumidity = shtTempHumidSensor->getHumidity();
|
||||||
|
|
||||||
publishTemperatureAndHumidityViaMqtt();
|
publishTemperatureAndHumidityViaMqtt();
|
||||||
shtReadDataSuccess = true;
|
shtReadDataSuccess = true;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
shtReadDataSuccess = false;
|
shtReadDataSuccess = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -387,6 +381,7 @@ bool ShtUsermod::readFromConfig(JsonObject &root)
|
|||||||
|
|
||||||
bool oldEnabled = enabled;
|
bool oldEnabled = enabled;
|
||||||
byte oldShtType = shtType;
|
byte oldShtType = shtType;
|
||||||
|
byte oldUnitOfTemp = unitOfTemp;
|
||||||
bool oldHaMqttDiscovery = haMqttDiscovery;
|
bool oldHaMqttDiscovery = haMqttDiscovery;
|
||||||
|
|
||||||
getJsonValue(top[FPSTR(_enabled)], enabled);
|
getJsonValue(top[FPSTR(_enabled)], enabled);
|
||||||
@ -410,6 +405,11 @@ bool ShtUsermod::readFromConfig(JsonObject &root)
|
|||||||
initShtTempHumiditySensor();
|
initShtTempHumiditySensor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (oldUnitOfTemp != unitOfTemp) {
|
||||||
|
publishTemperatureAndHumidityViaMqtt();
|
||||||
|
publishHomeAssistantAutodiscovery();
|
||||||
|
}
|
||||||
|
|
||||||
if (oldHaMqttDiscovery != haMqttDiscovery && haMqttDiscovery) {
|
if (oldHaMqttDiscovery != haMqttDiscovery && haMqttDiscovery) {
|
||||||
publishHomeAssistantAutodiscovery();
|
publishHomeAssistantAutodiscovery();
|
||||||
}
|
}
|
||||||
@ -448,45 +448,34 @@ void ShtUsermod::addToJsonInfo(JsonObject& root)
|
|||||||
if (shtLastTimeUpdated == 0) {
|
if (shtLastTimeUpdated == 0) {
|
||||||
jsonTemp.add(F(" Not read yet"));
|
jsonTemp.add(F(" Not read yet"));
|
||||||
jsonHumidity.add(F(" Not read yet"));
|
jsonHumidity.add(F(" Not read yet"));
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
jsonTemp.add(F(" Error"));
|
jsonTemp.add(F(" Error"));
|
||||||
jsonHumidity.add(F(" Error"));
|
jsonHumidity.add(F(" Error"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonHumidity.add(shtCurrentHumidity);
|
jsonHumidity.add(getHumidity());
|
||||||
jsonHumidity.add(F(" RH"));
|
jsonHumidity.add(F(" RH"));
|
||||||
|
|
||||||
unitOfTemp ? jsonTemp.add(getTemperatureF()) : jsonTemp.add(getTemperatureC());
|
jsonTemp.add(getTemperature());
|
||||||
unitOfTemp ? jsonTemp.add(F(" °F")) : jsonTemp.add(F(" °C"));
|
jsonTemp.add(unitOfTemp ? "°F" : "°C");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Getter for last read temperature in Celsius.
|
* Getter for last read temperature for configured unit.
|
||||||
*
|
*
|
||||||
* @return float
|
* @return float
|
||||||
*/
|
*/
|
||||||
float ShtUsermod::getTemperatureC() {
|
float ShtUsermod::getTemperature() {
|
||||||
return shtCurrentTempC;
|
return unitOfTemp ? getTemperatureF() : getTemperatureC();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Getter for last read temperature in Fahrenheit.
|
* Returns the current configured unit as human readable string.
|
||||||
*
|
*
|
||||||
* @return float
|
* @return const char*
|
||||||
*/
|
*/
|
||||||
float ShtUsermod::getTemperatureF() {
|
const char* ShtUsermod::getUnitString() {
|
||||||
return shtCurrentTempF;
|
return unitOfTemp ? "°F" : "°C";
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Getter for last read humidity in RH%.
|
|
||||||
*
|
|
||||||
* @return float
|
|
||||||
*/
|
|
||||||
float ShtUsermod::getHumidity() {
|
|
||||||
return shtCurrentHumidity;
|
|
||||||
}
|
}
|
339
wled00/FX.cpp
@ -378,7 +378,7 @@ uint16_t scan(bool dual)
|
|||||||
uint16_t size = 1 + ((SEGMENT.intensity * SEGLEN) >> 9);
|
uint16_t size = 1 + ((SEGMENT.intensity * SEGLEN) >> 9);
|
||||||
uint16_t ledIndex = (prog * ((SEGLEN *2) - size *2)) >> 16;
|
uint16_t ledIndex = (prog * ((SEGLEN *2) - size *2)) >> 16;
|
||||||
|
|
||||||
SEGMENT.fill(SEGCOLOR(1));
|
if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1));
|
||||||
|
|
||||||
int led_offset = ledIndex - (SEGLEN - size);
|
int led_offset = ledIndex - (SEGLEN - size);
|
||||||
led_offset = abs(led_offset);
|
led_offset = abs(led_offset);
|
||||||
@ -404,7 +404,7 @@ uint16_t scan(bool dual)
|
|||||||
uint16_t mode_scan(void) {
|
uint16_t mode_scan(void) {
|
||||||
return scan(false);
|
return scan(false);
|
||||||
}
|
}
|
||||||
static const char _data_FX_MODE_SCAN[] PROGMEM = "Scan@!,# of dots;!,!,!;!";
|
static const char _data_FX_MODE_SCAN[] PROGMEM = "Scan@!,# of dots,,,,,Overlay;!,!,!;!";
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -413,7 +413,7 @@ static const char _data_FX_MODE_SCAN[] PROGMEM = "Scan@!,# of dots;!,!,!;!";
|
|||||||
uint16_t mode_dual_scan(void) {
|
uint16_t mode_dual_scan(void) {
|
||||||
return scan(true);
|
return scan(true);
|
||||||
}
|
}
|
||||||
static const char _data_FX_MODE_DUAL_SCAN[] PROGMEM = "Scan Dual@!,# of dots;!,!,!;!";
|
static const char _data_FX_MODE_DUAL_SCAN[] PROGMEM = "Scan Dual@!,# of dots,,,,,Overlay;!,!,!;!";
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -530,6 +530,7 @@ uint16_t running_base(bool saw, bool dual=false) {
|
|||||||
}
|
}
|
||||||
SEGMENT.setPixelColor(i, ca);
|
SEGMENT.setPixelColor(i, ca);
|
||||||
}
|
}
|
||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -567,7 +568,6 @@ static const char _data_FX_MODE_SAW[] PROGMEM = "Saw@!,Width;!,!;!";
|
|||||||
* Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
|
* Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
|
||||||
*/
|
*/
|
||||||
uint16_t mode_twinkle(void) {
|
uint16_t mode_twinkle(void) {
|
||||||
//SEGMENT.fill(SEGCOLOR(1));
|
|
||||||
SEGMENT.fade_out(224);
|
SEGMENT.fade_out(224);
|
||||||
|
|
||||||
uint32_t cycleTime = 20 + (255 - SEGMENT.speed)*5;
|
uint32_t cycleTime = 20 + (255 - SEGMENT.speed)*5;
|
||||||
@ -659,7 +659,7 @@ static const char _data_FX_MODE_DISSOLVE_RANDOM[] PROGMEM = "Dissolve Rnd@Repeat
|
|||||||
* Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
|
* Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
|
||||||
*/
|
*/
|
||||||
uint16_t mode_sparkle(void) {
|
uint16_t mode_sparkle(void) {
|
||||||
for(int i = 0; i < SEGLEN; i++) {
|
if (!SEGMENT.check2) for(int i = 0; i < SEGLEN; i++) {
|
||||||
SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1));
|
SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1));
|
||||||
}
|
}
|
||||||
uint32_t cycleTime = 10 + (255 - SEGMENT.speed)*2;
|
uint32_t cycleTime = 10 + (255 - SEGMENT.speed)*2;
|
||||||
@ -673,7 +673,7 @@ uint16_t mode_sparkle(void) {
|
|||||||
SEGMENT.setPixelColor(SEGENV.aux0, SEGCOLOR(0));
|
SEGMENT.setPixelColor(SEGENV.aux0, SEGCOLOR(0));
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
static const char _data_FX_MODE_SPARKLE[] PROGMEM = "Sparkle@!;!,!;!;;m12=0";
|
static const char _data_FX_MODE_SPARKLE[] PROGMEM = "Sparkle@!,,,,,,Overlay;!,!;!;;m12=0";
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -681,7 +681,7 @@ static const char _data_FX_MODE_SPARKLE[] PROGMEM = "Sparkle@!;!,!;!;;m12=0";
|
|||||||
* Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
|
* Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
|
||||||
*/
|
*/
|
||||||
uint16_t mode_flash_sparkle(void) {
|
uint16_t mode_flash_sparkle(void) {
|
||||||
for(uint16_t i = 0; i < SEGLEN; i++) {
|
if (!SEGMENT.check2) for(uint16_t i = 0; i < SEGLEN; i++) {
|
||||||
SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
|
SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -694,7 +694,7 @@ uint16_t mode_flash_sparkle(void) {
|
|||||||
}
|
}
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
static const char _data_FX_MODE_FLASH_SPARKLE[] PROGMEM = "Sparkle Dark@!,!;Bg,Fx;!;;m12=0";
|
static const char _data_FX_MODE_FLASH_SPARKLE[] PROGMEM = "Sparkle Dark@!,!,,,,,Overlay;Bg,Fx;!;;m12=0";
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -702,7 +702,7 @@ static const char _data_FX_MODE_FLASH_SPARKLE[] PROGMEM = "Sparkle Dark@!,!;Bg,F
|
|||||||
* Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
|
* Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
|
||||||
*/
|
*/
|
||||||
uint16_t mode_hyper_sparkle(void) {
|
uint16_t mode_hyper_sparkle(void) {
|
||||||
for (int i = 0; i < SEGLEN; i++) {
|
if (!SEGMENT.check2) for (int i = 0; i < SEGLEN; i++) {
|
||||||
SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
|
SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -717,7 +717,7 @@ uint16_t mode_hyper_sparkle(void) {
|
|||||||
}
|
}
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
static const char _data_FX_MODE_HYPER_SPARKLE[] PROGMEM = "Sparkle+@!,!;Bg,Fx;!;;m12=0";
|
static const char _data_FX_MODE_HYPER_SPARKLE[] PROGMEM = "Sparkle+@!,!,,,,,Overlay;Bg,Fx;!;;m12=0";
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1366,12 +1366,11 @@ uint16_t police_base(uint32_t color1, uint32_t color2)
|
|||||||
//Police Lights with custom colors
|
//Police Lights with custom colors
|
||||||
uint16_t mode_two_dots()
|
uint16_t mode_two_dots()
|
||||||
{
|
{
|
||||||
SEGMENT.fill(SEGCOLOR(2));
|
if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(2));
|
||||||
uint32_t color2 = (SEGCOLOR(1) == SEGCOLOR(2)) ? SEGCOLOR(0) : SEGCOLOR(1);
|
uint32_t color2 = (SEGCOLOR(1) == SEGCOLOR(2)) ? SEGCOLOR(0) : SEGCOLOR(1);
|
||||||
|
|
||||||
return police_base(SEGCOLOR(0), color2);
|
return police_base(SEGCOLOR(0), color2);
|
||||||
}
|
}
|
||||||
static const char _data_FX_MODE_TWO_DOTS[] PROGMEM = "Two Dots@!,Dot size;1,2,Bg;!";
|
static const char _data_FX_MODE_TWO_DOTS[] PROGMEM = "Two Dots@!,Dot size,,,,,Overlay;1,2,Bg;!";
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1549,7 +1548,7 @@ uint16_t mode_icu(void) {
|
|||||||
uint16_t dest = SEGENV.step & 0xFFFF;
|
uint16_t dest = SEGENV.step & 0xFFFF;
|
||||||
uint8_t space = (SEGMENT.intensity >> 3) +2;
|
uint8_t space = (SEGMENT.intensity >> 3) +2;
|
||||||
|
|
||||||
SEGMENT.fill(SEGCOLOR(1));
|
if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1));
|
||||||
|
|
||||||
byte pindex = map(dest, 0, SEGLEN-SEGLEN/space, 0, 255);
|
byte pindex = map(dest, 0, SEGLEN-SEGLEN/space, 0, 255);
|
||||||
uint32_t col = SEGMENT.color_from_palette(pindex, false, false, 0);
|
uint32_t col = SEGMENT.color_from_palette(pindex, false, false, 0);
|
||||||
@ -1580,7 +1579,7 @@ uint16_t mode_icu(void) {
|
|||||||
|
|
||||||
return SPEED_FORMULA_L;
|
return SPEED_FORMULA_L;
|
||||||
}
|
}
|
||||||
static const char _data_FX_MODE_ICU[] PROGMEM = "ICU@!,!;!,!;!";
|
static const char _data_FX_MODE_ICU[] PROGMEM = "ICU@!,!,,,,,Overlay;!,!;!";
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1823,7 +1822,7 @@ uint16_t mode_lightning(void)
|
|||||||
SEGENV.aux0 = 200; //200ms delay after leader
|
SEGENV.aux0 = 200; //200ms delay after leader
|
||||||
}
|
}
|
||||||
|
|
||||||
SEGMENT.fill(SEGCOLOR(1));
|
if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1));
|
||||||
|
|
||||||
if (SEGENV.aux1 > 3 && !(SEGENV.aux1 & 0x01)) { //flash on even number >2
|
if (SEGENV.aux1 > 3 && !(SEGENV.aux1 & 0x01)) { //flash on even number >2
|
||||||
for (int i = ledstart; i < ledstart + ledlen; i++)
|
for (int i = ledstart; i < ledstart + ledlen; i++)
|
||||||
@ -1848,7 +1847,7 @@ uint16_t mode_lightning(void)
|
|||||||
}
|
}
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
static const char _data_FX_MODE_LIGHTNING[] PROGMEM = "Lightning@!,!;!,!;!";
|
static const char _data_FX_MODE_LIGHTNING[] PROGMEM = "Lightning@!,!,,,,,Overlay;!,!;!";
|
||||||
|
|
||||||
|
|
||||||
// Pride2015
|
// Pride2015
|
||||||
@ -1892,6 +1891,7 @@ uint16_t mode_pride_2015(void)
|
|||||||
}
|
}
|
||||||
SEGENV.step = sPseudotime;
|
SEGENV.step = sPseudotime;
|
||||||
SEGENV.aux0 = sHue16;
|
SEGENV.aux0 = sHue16;
|
||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
static const char _data_FX_MODE_PRIDE_2015[] PROGMEM = "Pride 2015@!;;";
|
static const char _data_FX_MODE_PRIDE_2015[] PROGMEM = "Pride 2015@!;;";
|
||||||
@ -1929,9 +1929,10 @@ uint16_t mode_palette()
|
|||||||
uint8_t colorIndex = (i * 255 / SEGLEN) - counter;
|
uint8_t colorIndex = (i * 255 / SEGLEN) - counter;
|
||||||
SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(colorIndex, false, noWrap, 255));
|
SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(colorIndex, false, noWrap, 255));
|
||||||
}
|
}
|
||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
static const char _data_FX_MODE_PALETTE[] PROGMEM = "Palette@Cycle speed;;!";
|
static const char _data_FX_MODE_PALETTE[] PROGMEM = "Palette@Cycle speed;;!;;c3=0,o2=0";
|
||||||
|
|
||||||
|
|
||||||
// WLED limitation: Analog Clock overlay will NOT work when Fire2012 is active
|
// WLED limitation: Analog Clock overlay will NOT work when Fire2012 is active
|
||||||
@ -2069,6 +2070,7 @@ uint16_t mode_colorwaves()
|
|||||||
}
|
}
|
||||||
SEGENV.step = sPseudotime;
|
SEGENV.step = sPseudotime;
|
||||||
SEGENV.aux0 = sHue16;
|
SEGENV.aux0 = sHue16;
|
||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
static const char _data_FX_MODE_COLORWAVES[] PROGMEM = "Colorwaves@!,Hue;!;!";
|
static const char _data_FX_MODE_COLORWAVES[] PROGMEM = "Colorwaves@!,Hue;!;!";
|
||||||
@ -2085,6 +2087,7 @@ uint16_t mode_bpm()
|
|||||||
//SEGMENT.setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
|
//SEGMENT.setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
|
||||||
SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(stp + (i * 2), false, PALETTE_SOLID_WRAP, 0, beat - stp + (i * 10)));
|
SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(stp + (i * 2), false, PALETTE_SOLID_WRAP, 0, beat - stp + (i * 10)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
static const char _data_FX_MODE_BPM[] PROGMEM = "Bpm@!;!;!;;sx=64";
|
static const char _data_FX_MODE_BPM[] PROGMEM = "Bpm@!;!;!;;sx=64";
|
||||||
@ -2267,6 +2270,7 @@ uint16_t mode_lake() {
|
|||||||
//SEGMENT.setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
|
//SEGMENT.setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
|
||||||
SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, false, 0, lum));
|
SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, false, 0, lum));
|
||||||
}
|
}
|
||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
static const char _data_FX_MODE_LAKE[] PROGMEM = "Lake@!;Fx;!";
|
static const char _data_FX_MODE_LAKE[] PROGMEM = "Lake@!;Fx;!";
|
||||||
@ -2351,7 +2355,7 @@ static const char _data_FX_MODE_METEOR_SMOOTH[] PROGMEM = "Meteor Smooth@!,Trail
|
|||||||
//Railway Crossing / Christmas Fairy lights
|
//Railway Crossing / Christmas Fairy lights
|
||||||
uint16_t mode_railway()
|
uint16_t mode_railway()
|
||||||
{
|
{
|
||||||
uint16_t dur = 40 + (255 - SEGMENT.speed) * 10;
|
uint16_t dur = (256 - SEGMENT.speed) * 40;
|
||||||
uint16_t rampdur = (dur * SEGMENT.intensity) >> 8;
|
uint16_t rampdur = (dur * SEGMENT.intensity) >> 8;
|
||||||
if (SEGENV.step > dur)
|
if (SEGENV.step > dur)
|
||||||
{
|
{
|
||||||
@ -2368,16 +2372,16 @@ uint16_t mode_railway()
|
|||||||
if (SEGENV.aux0) pos = 255 - pos;
|
if (SEGENV.aux0) pos = 255 - pos;
|
||||||
for (int i = 0; i < SEGLEN; i += 2)
|
for (int i = 0; i < SEGLEN; i += 2)
|
||||||
{
|
{
|
||||||
SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(255 - pos, false, false, 255));
|
SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(255 - pos, false, false, 255)); // do not use color 1 or 2, always use palette
|
||||||
if (i < SEGLEN -1)
|
if (i < SEGLEN -1)
|
||||||
{
|
{
|
||||||
SEGMENT.setPixelColor(i + 1, SEGMENT.color_from_palette(pos, false, false, 255));
|
SEGMENT.setPixelColor(i + 1, SEGMENT.color_from_palette(pos, false, false, 255)); // do not use color 1 or 2, always use palette
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SEGENV.step += FRAMETIME;
|
SEGENV.step += FRAMETIME;
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
static const char _data_FX_MODE_RAILWAY[] PROGMEM = "Railway@!,Smoothness;;!";
|
static const char _data_FX_MODE_RAILWAY[] PROGMEM = "Railway@!,Smoothness;1,2;!";
|
||||||
|
|
||||||
|
|
||||||
//Water ripple
|
//Water ripple
|
||||||
@ -2396,7 +2400,7 @@ typedef struct Ripple {
|
|||||||
#else
|
#else
|
||||||
#define MAX_RIPPLES 100
|
#define MAX_RIPPLES 100
|
||||||
#endif
|
#endif
|
||||||
uint16_t ripple_base(bool rainbow)
|
uint16_t ripple_base()
|
||||||
{
|
{
|
||||||
uint16_t maxRipples = min(1 + (SEGLEN >> 2), MAX_RIPPLES); // 56 max for 16 segment ESP8266
|
uint16_t maxRipples = min(1 + (SEGLEN >> 2), MAX_RIPPLES); // 56 max for 16 segment ESP8266
|
||||||
uint16_t dataSize = sizeof(ripple) * maxRipples;
|
uint16_t dataSize = sizeof(ripple) * maxRipples;
|
||||||
@ -2405,80 +2409,74 @@ uint16_t ripple_base(bool rainbow)
|
|||||||
|
|
||||||
Ripple* ripples = reinterpret_cast<Ripple*>(SEGENV.data);
|
Ripple* ripples = reinterpret_cast<Ripple*>(SEGENV.data);
|
||||||
|
|
||||||
// ranbow background or chosen background, all very dim.
|
|
||||||
if (rainbow) {
|
|
||||||
if (SEGENV.call ==0) {
|
|
||||||
SEGENV.aux0 = random8();
|
|
||||||
SEGENV.aux1 = random8();
|
|
||||||
}
|
|
||||||
if (SEGENV.aux0 == SEGENV.aux1) {
|
|
||||||
SEGENV.aux1 = random8();
|
|
||||||
}
|
|
||||||
else if (SEGENV.aux1 > SEGENV.aux0) {
|
|
||||||
SEGENV.aux0++;
|
|
||||||
} else {
|
|
||||||
SEGENV.aux0--;
|
|
||||||
}
|
|
||||||
SEGMENT.fill(color_blend(SEGMENT.color_wheel(SEGENV.aux0),BLACK,235));
|
|
||||||
} else {
|
|
||||||
SEGMENT.fill(SEGCOLOR(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
//draw wave
|
//draw wave
|
||||||
for (int i = 0; i < maxRipples; i++)
|
for (int i = 0; i < maxRipples; i++) {
|
||||||
{
|
|
||||||
uint16_t ripplestate = ripples[i].state;
|
uint16_t ripplestate = ripples[i].state;
|
||||||
if (ripplestate)
|
if (ripplestate) {
|
||||||
{
|
|
||||||
uint8_t rippledecay = (SEGMENT.speed >> 4) +1; //faster decay if faster propagation
|
uint8_t rippledecay = (SEGMENT.speed >> 4) +1; //faster decay if faster propagation
|
||||||
uint16_t rippleorigin = ripples[i].pos;
|
uint16_t rippleorigin = ripples[i].pos;
|
||||||
uint32_t col = SEGMENT.color_from_palette(ripples[i].color, false, false, 255);
|
uint32_t col = SEGMENT.color_from_palette(ripples[i].color, false, false, 255);
|
||||||
uint16_t propagation = ((ripplestate/rippledecay -1) * SEGMENT.speed);
|
uint16_t propagation = ((ripplestate/rippledecay - 1) * (SEGMENT.speed + 1));
|
||||||
int16_t propI = propagation >> 8;
|
int16_t propI = propagation >> 8;
|
||||||
uint8_t propF = propagation & 0xFF;
|
uint8_t propF = propagation & 0xFF;
|
||||||
int16_t left = rippleorigin - propI -1;
|
|
||||||
uint8_t amp = (ripplestate < 17) ? triwave8((ripplestate-1)*8) : map(ripplestate,17,255,255,2);
|
uint8_t amp = (ripplestate < 17) ? triwave8((ripplestate-1)*8) : map(ripplestate,17,255,255,2);
|
||||||
|
|
||||||
for (int16_t v = left; v < left +4; v++)
|
#ifndef WLED_DISABLE_2D
|
||||||
|
if (SEGMENT.is2D()) {
|
||||||
|
uint16_t cx = rippleorigin >> 8;
|
||||||
|
uint16_t cy = rippleorigin & 0xFF;
|
||||||
|
uint8_t mag = scale8(cubicwave8((propF>>2)), amp);
|
||||||
|
if (propI > 0) SEGMENT.draw_circle(cx, cy, propI, color_blend(SEGMENT.getPixelColorXY(cx + propI, cy), col, mag));
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
|
int16_t left = rippleorigin - propI -1;
|
||||||
|
for (int16_t v = left; v < left +4; v++) {
|
||||||
uint8_t mag = scale8(cubicwave8((propF>>2)+(v-left)*64), amp);
|
uint8_t mag = scale8(cubicwave8((propF>>2)+(v-left)*64), amp);
|
||||||
if (v < SEGLEN && v >= 0)
|
|
||||||
{
|
|
||||||
SEGMENT.setPixelColor(v, color_blend(SEGMENT.getPixelColor(v), col, mag)); // TODO
|
SEGMENT.setPixelColor(v, color_blend(SEGMENT.getPixelColor(v), col, mag)); // TODO
|
||||||
}
|
|
||||||
int16_t w = left + propI*2 + 3 -(v-left);
|
int16_t w = left + propI*2 + 3 -(v-left);
|
||||||
if (w < SEGLEN && w >= 0)
|
|
||||||
{
|
|
||||||
SEGMENT.setPixelColor(w, color_blend(SEGMENT.getPixelColor(w), col, mag)); // TODO
|
SEGMENT.setPixelColor(w, color_blend(SEGMENT.getPixelColor(w), col, mag)); // TODO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ripplestate += rippledecay;
|
ripplestate += rippledecay;
|
||||||
ripples[i].state = (ripplestate > 254) ? 0 : ripplestate;
|
ripples[i].state = (ripplestate > 254) ? 0 : ripplestate;
|
||||||
} else //randomly create new wave
|
} else {//randomly create new wave
|
||||||
{
|
if (random16(IBN + 10000) <= SEGMENT.intensity) {
|
||||||
if (random16(IBN + 10000) <= SEGMENT.intensity)
|
|
||||||
{
|
|
||||||
ripples[i].state = 1;
|
ripples[i].state = 1;
|
||||||
ripples[i].pos = random16(SEGLEN);
|
ripples[i].pos = SEGMENT.is2D() ? ((random8(SEGENV.virtualWidth())<<8) | (random8(SEGENV.virtualHeight()))) : random16(SEGLEN);
|
||||||
ripples[i].color = random8(); //color
|
ripples[i].color = random8(); //color
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
#undef MAX_RIPPLES
|
#undef MAX_RIPPLES
|
||||||
|
|
||||||
|
|
||||||
uint16_t mode_ripple(void) {
|
uint16_t mode_ripple(void) {
|
||||||
return ripple_base(false);
|
if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1));
|
||||||
|
return ripple_base();
|
||||||
}
|
}
|
||||||
static const char _data_FX_MODE_RIPPLE[] PROGMEM = "Ripple@!,Wave #;,!;!";
|
static const char _data_FX_MODE_RIPPLE[] PROGMEM = "Ripple@!,Wave #,,,,,Overlay;,!;!;12";
|
||||||
|
|
||||||
|
|
||||||
uint16_t mode_ripple_rainbow(void) {
|
uint16_t mode_ripple_rainbow(void) {
|
||||||
return ripple_base(true);
|
if (SEGENV.call ==0) {
|
||||||
|
SEGENV.aux0 = random8();
|
||||||
|
SEGENV.aux1 = random8();
|
||||||
}
|
}
|
||||||
static const char _data_FX_MODE_RIPPLE_RAINBOW[] PROGMEM = "Ripple Rainbow@!,Wave #;;!";
|
if (SEGENV.aux0 == SEGENV.aux1) {
|
||||||
|
SEGENV.aux1 = random8();
|
||||||
|
} else if (SEGENV.aux1 > SEGENV.aux0) {
|
||||||
|
SEGENV.aux0++;
|
||||||
|
} else {
|
||||||
|
SEGENV.aux0--;
|
||||||
|
}
|
||||||
|
SEGMENT.fill(color_blend(SEGMENT.color_wheel(SEGENV.aux0),BLACK,235));
|
||||||
|
return ripple_base();
|
||||||
|
}
|
||||||
|
static const char _data_FX_MODE_RIPPLE_RAINBOW[] PROGMEM = "Ripple Rainbow@!,Wave #;;!;12";
|
||||||
|
|
||||||
|
|
||||||
// TwinkleFOX by Mark Kriegsman: https://gist.github.com/kriegsman/756ea6dcae8e30845b5a
|
// TwinkleFOX by Mark Kriegsman: https://gist.github.com/kriegsman/756ea6dcae8e30845b5a
|
||||||
@ -2634,7 +2632,7 @@ uint16_t mode_halloween_eyes()
|
|||||||
uint16_t eyeLength = (2*HALLOWEEN_EYE_WIDTH) + HALLOWEEN_EYE_SPACE;
|
uint16_t eyeLength = (2*HALLOWEEN_EYE_WIDTH) + HALLOWEEN_EYE_SPACE;
|
||||||
if (eyeLength >= maxWidth) return mode_static(); //bail if segment too short
|
if (eyeLength >= maxWidth) return mode_static(); //bail if segment too short
|
||||||
|
|
||||||
SEGMENT.fill(SEGCOLOR(1)); //fill background
|
if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1)); //fill background
|
||||||
|
|
||||||
uint8_t state = SEGENV.aux1 >> 8;
|
uint8_t state = SEGENV.aux1 >> 8;
|
||||||
uint16_t stateTime = SEGENV.call;
|
uint16_t stateTime = SEGENV.call;
|
||||||
@ -2684,7 +2682,7 @@ uint16_t mode_halloween_eyes()
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
static const char _data_FX_MODE_HALLOWEEN_EYES[] PROGMEM = "Halloween Eyes@Duration,Eye fade time;!,!;!;12";
|
static const char _data_FX_MODE_HALLOWEEN_EYES[] PROGMEM = "Halloween Eyes@Duration,Eye fade time,,,,,Overlay;!,!;!;12";
|
||||||
|
|
||||||
|
|
||||||
//Speed slider sets amount of LEDs lit, intensity sets unlit
|
//Speed slider sets amount of LEDs lit, intensity sets unlit
|
||||||
@ -2737,7 +2735,7 @@ static const char _data_FX_MODE_TRI_STATIC_PATTERN[] PROGMEM = "Solid Pattern Tr
|
|||||||
|
|
||||||
uint16_t spots_base(uint16_t threshold)
|
uint16_t spots_base(uint16_t threshold)
|
||||||
{
|
{
|
||||||
SEGMENT.fill(SEGCOLOR(1));
|
if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1));
|
||||||
|
|
||||||
uint16_t maxZones = SEGLEN >> 2;
|
uint16_t maxZones = SEGLEN >> 2;
|
||||||
uint16_t zones = 1 + ((SEGMENT.intensity * maxZones) >> 8);
|
uint16_t zones = 1 + ((SEGMENT.intensity * maxZones) >> 8);
|
||||||
@ -2767,7 +2765,7 @@ uint16_t mode_spots()
|
|||||||
{
|
{
|
||||||
return spots_base((255 - SEGMENT.speed) << 8);
|
return spots_base((255 - SEGMENT.speed) << 8);
|
||||||
}
|
}
|
||||||
static const char _data_FX_MODE_SPOTS[] PROGMEM = "Spots@,Width;!,!;!";
|
static const char _data_FX_MODE_SPOTS[] PROGMEM = "Spots@,Width,,,,,Overlay;!,!;!";
|
||||||
|
|
||||||
|
|
||||||
//Intensity slider sets number of "lights", LEDs per light fade in and out
|
//Intensity slider sets number of "lights", LEDs per light fade in and out
|
||||||
@ -2778,7 +2776,7 @@ uint16_t mode_spots_fade()
|
|||||||
uint16_t tr = (t >> 1) + (t >> 2);
|
uint16_t tr = (t >> 1) + (t >> 2);
|
||||||
return spots_base(tr);
|
return spots_base(tr);
|
||||||
}
|
}
|
||||||
static const char _data_FX_MODE_SPOTS_FADE[] PROGMEM = "Spots Fade@Spread,Width;!,!;!";
|
static const char _data_FX_MODE_SPOTS_FADE[] PROGMEM = "Spots Fade@Spread,Width,,,,,Overlay;!,!;!";
|
||||||
|
|
||||||
|
|
||||||
//each needs 12 bytes
|
//each needs 12 bytes
|
||||||
@ -2800,7 +2798,7 @@ uint16_t mode_bouncing_balls(void) {
|
|||||||
|
|
||||||
Ball* balls = reinterpret_cast<Ball*>(SEGENV.data);
|
Ball* balls = reinterpret_cast<Ball*>(SEGENV.data);
|
||||||
|
|
||||||
SEGMENT.fill(SEGCOLOR(2) ? BLACK : SEGCOLOR(1));
|
if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(2) ? BLACK : SEGCOLOR(1));
|
||||||
|
|
||||||
// virtualStrip idea by @ewowi (Ewoud Wijma)
|
// virtualStrip idea by @ewowi (Ewoud Wijma)
|
||||||
// requires virtual strip # to be embedded into upper 16 bits of index in setPixelColor()
|
// requires virtual strip # to be embedded into upper 16 bits of index in setPixelColor()
|
||||||
@ -2857,7 +2855,7 @@ uint16_t mode_bouncing_balls(void) {
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
static const char _data_FX_MODE_BOUNCINGBALLS[] PROGMEM = "Bouncing Balls@Gravity,# of balls;!,!,!;!;1;m12=1"; //bar
|
static const char _data_FX_MODE_BOUNCINGBALLS[] PROGMEM = "Bouncing Balls@Gravity,# of balls,,,,,Overlay;!,!,!;!;1;m12=1"; //bar
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2915,19 +2913,35 @@ uint16_t mode_sinelon_rainbow(void) {
|
|||||||
static const char _data_FX_MODE_SINELON_RAINBOW[] PROGMEM = "Sinelon Rainbow@!,Trail;,,!;!";
|
static const char _data_FX_MODE_SINELON_RAINBOW[] PROGMEM = "Sinelon Rainbow@!,Trail;,,!;!";
|
||||||
|
|
||||||
|
|
||||||
//Rainbow with glitter, inspired by https://gist.github.com/kriegsman/062e10f7f07ba8518af6
|
// utility function that will add random glitter to SEGMENT
|
||||||
|
void glitter_base(uint8_t intensity, uint32_t col = ULTRAWHITE) {
|
||||||
|
if (intensity > random8()) {
|
||||||
|
if (SEGMENT.is2D()) {
|
||||||
|
SEGMENT.setPixelColorXY(random16(SEGMENT.virtualWidth()),random16(SEGMENT.virtualHeight()), col);
|
||||||
|
} else {
|
||||||
|
SEGMENT.setPixelColor(random16(SEGLEN), col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Glitter with palette background, inspired by https://gist.github.com/kriegsman/062e10f7f07ba8518af6
|
||||||
uint16_t mode_glitter()
|
uint16_t mode_glitter()
|
||||||
{
|
{
|
||||||
mode_palette();
|
if (!SEGMENT.check2) mode_palette(); // use "* Color 1" palette for solid background (replacing "Solid glitter")
|
||||||
|
glitter_base(SEGMENT.intensity, SEGCOLOR(2) ? SEGCOLOR(2) : ULTRAWHITE);
|
||||||
if (SEGMENT.intensity > random8())
|
|
||||||
{
|
|
||||||
SEGMENT.setPixelColor(random16(SEGLEN), ULTRAWHITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
static const char _data_FX_MODE_GLITTER[] PROGMEM = "Glitter@!,!;;!;;m12=0"; //pixels
|
static const char _data_FX_MODE_GLITTER[] PROGMEM = "Glitter@!,!,,,,,Overlay;1,2,Glitter color;!;;pal=0,m12=0"; //pixels
|
||||||
|
|
||||||
|
|
||||||
|
//Solid colour background with glitter
|
||||||
|
uint16_t mode_solid_glitter()
|
||||||
|
{
|
||||||
|
SEGMENT.fill(SEGCOLOR(0));
|
||||||
|
glitter_base(SEGMENT.intensity, SEGCOLOR(2) ? SEGCOLOR(2) : ULTRAWHITE);
|
||||||
|
return FRAMETIME;
|
||||||
|
}
|
||||||
|
static const char _data_FX_MODE_SOLID_GLITTER[] PROGMEM = "Solid Glitter@,!;Bg,,Glitter color;;;m12=0";
|
||||||
|
|
||||||
|
|
||||||
//each needs 19 bytes
|
//each needs 19 bytes
|
||||||
@ -2953,7 +2967,7 @@ uint16_t mode_popcorn(void) {
|
|||||||
Spark* popcorn = reinterpret_cast<Spark*>(SEGENV.data);
|
Spark* popcorn = reinterpret_cast<Spark*>(SEGENV.data);
|
||||||
|
|
||||||
bool hasCol2 = SEGCOLOR(2);
|
bool hasCol2 = SEGCOLOR(2);
|
||||||
SEGMENT.fill(hasCol2 ? BLACK : SEGCOLOR(1));
|
if (!SEGMENT.check2) SEGMENT.fill(hasCol2 ? BLACK : SEGCOLOR(1));
|
||||||
|
|
||||||
struct virtualStrip {
|
struct virtualStrip {
|
||||||
static void runStrip(uint16_t stripNr, Spark* popcorn) {
|
static void runStrip(uint16_t stripNr, Spark* popcorn) {
|
||||||
@ -3000,7 +3014,7 @@ uint16_t mode_popcorn(void) {
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
static const char _data_FX_MODE_POPCORN[] PROGMEM = "Popcorn@!,!;!,!,!;!;;m12=1"; //bar
|
static const char _data_FX_MODE_POPCORN[] PROGMEM = "Popcorn@!,!,,,,,Overlay;!,!,!;!;;m12=1"; //bar
|
||||||
|
|
||||||
|
|
||||||
//values close to 100 produce 5Hz flicker, which looks very candle-y
|
//values close to 100 produce 5Hz flicker, which looks very candle-y
|
||||||
@ -3162,7 +3176,7 @@ uint16_t mode_starburst(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SEGMENT.fill(SEGCOLOR(1));
|
if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1));
|
||||||
|
|
||||||
for (int j=0; j<numStars; j++)
|
for (int j=0; j<numStars; j++)
|
||||||
{
|
{
|
||||||
@ -3227,7 +3241,7 @@ uint16_t mode_starburst(void) {
|
|||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
#undef STARBURST_MAX_FRAG
|
#undef STARBURST_MAX_FRAG
|
||||||
static const char _data_FX_MODE_STARBURST[] PROGMEM = "Fireworks Starburst@Chance,Fragments;,!;!;;pal=11,m12=0";
|
static const char _data_FX_MODE_STARBURST[] PROGMEM = "Fireworks Starburst@Chance,Fragments,,,,,Overlay;,!;!;;pal=11,m12=0";
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3258,7 +3272,6 @@ uint16_t mode_exploding_fireworks(void)
|
|||||||
SEGENV.aux1 = dataSize;
|
SEGENV.aux1 = dataSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
//SEGMENT.fill(BLACK);
|
|
||||||
SEGMENT.fade_out(252);
|
SEGMENT.fade_out(252);
|
||||||
|
|
||||||
Spark* sparks = reinterpret_cast<Spark*>(SEGENV.data);
|
Spark* sparks = reinterpret_cast<Spark*>(SEGENV.data);
|
||||||
@ -3379,7 +3392,7 @@ uint16_t mode_drip(void)
|
|||||||
if (!SEGENV.allocateData(dataSize * strips)) return mode_static(); //allocation failed
|
if (!SEGENV.allocateData(dataSize * strips)) return mode_static(); //allocation failed
|
||||||
Spark* drops = reinterpret_cast<Spark*>(SEGENV.data);
|
Spark* drops = reinterpret_cast<Spark*>(SEGENV.data);
|
||||||
|
|
||||||
SEGMENT.fill(SEGCOLOR(1));
|
if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1));
|
||||||
|
|
||||||
struct virtualStrip {
|
struct virtualStrip {
|
||||||
static void runStrip(uint16_t stripNr, Spark* drops) {
|
static void runStrip(uint16_t stripNr, Spark* drops) {
|
||||||
@ -3449,7 +3462,7 @@ uint16_t mode_drip(void)
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
static const char _data_FX_MODE_DRIP[] PROGMEM = "Drip@Gravity,# of drips;!,!;!;;m12=1"; //bar
|
static const char _data_FX_MODE_DRIP[] PROGMEM = "Drip@Gravity,# of drips,,,,,Overlay;!,!;!;;m12=1"; //bar
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3472,7 +3485,7 @@ uint16_t mode_tetrix(void) {
|
|||||||
if (!SEGENV.allocateData(dataSize * strips)) return mode_static(); //allocation failed
|
if (!SEGENV.allocateData(dataSize * strips)) return mode_static(); //allocation failed
|
||||||
Tetris* drops = reinterpret_cast<Tetris*>(SEGENV.data);
|
Tetris* drops = reinterpret_cast<Tetris*>(SEGENV.data);
|
||||||
|
|
||||||
if (SEGENV.call == 0) SEGMENT.fill(SEGCOLOR(1)); // will fill entire segment (1D or 2D)
|
//if (SEGENV.call == 0) SEGMENT.fill(SEGCOLOR(1)); // will fill entire segment (1D or 2D), then use drop->step = 0 below
|
||||||
|
|
||||||
// virtualStrip idea by @ewowi (Ewoud Wijma)
|
// virtualStrip idea by @ewowi (Ewoud Wijma)
|
||||||
// requires virtual strip # to be embedded into upper 16 bits of index in setPixelcolor()
|
// requires virtual strip # to be embedded into upper 16 bits of index in setPixelcolor()
|
||||||
@ -3482,9 +3495,8 @@ uint16_t mode_tetrix(void) {
|
|||||||
// initialize dropping on first call or segment full
|
// initialize dropping on first call or segment full
|
||||||
if (SEGENV.call == 0) {
|
if (SEGENV.call == 0) {
|
||||||
drop->stack = 0; // reset brick stack size
|
drop->stack = 0; // reset brick stack size
|
||||||
drop->step = 0;
|
drop->step = millis() + 2000; // start by fading out strip
|
||||||
if (SEGMENT.check1) drop->col = 0;// use only one color from palette
|
if (SEGMENT.check1) drop->col = 0;// use only one color from palette
|
||||||
//for (int i=0; i<SEGLEN; i++) SEGMENT.setPixelColor(indexToVStrip(i, stripNr), SEGCOLOR(1)); // will fill virtual strip only
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (drop->step == 0) { // init brick
|
if (drop->step == 0) { // init brick
|
||||||
@ -3772,21 +3784,6 @@ uint16_t mode_pacifica()
|
|||||||
static const char _data_FX_MODE_PACIFICA[] PROGMEM = "Pacifica@!,Angle;;!;;pal=51";
|
static const char _data_FX_MODE_PACIFICA[] PROGMEM = "Pacifica@!,Angle;;!;;pal=51";
|
||||||
|
|
||||||
|
|
||||||
//Solid colour background with glitter
|
|
||||||
uint16_t mode_solid_glitter()
|
|
||||||
{
|
|
||||||
SEGMENT.fill(SEGCOLOR(0));
|
|
||||||
|
|
||||||
if (SEGMENT.intensity > random8())
|
|
||||||
{
|
|
||||||
SEGMENT.setPixelColor(random16(SEGLEN), ULTRAWHITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
return FRAMETIME;
|
|
||||||
}
|
|
||||||
static const char _data_FX_MODE_SOLID_GLITTER[] PROGMEM = "Solid Glitter@,!;!;;;m12=0";
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Mode simulates a gradual sunrise
|
* Mode simulates a gradual sunrise
|
||||||
*/
|
*/
|
||||||
@ -3800,7 +3797,7 @@ uint16_t mode_sunrise() {
|
|||||||
SEGENV.aux0 = SEGMENT.speed;
|
SEGENV.aux0 = SEGMENT.speed;
|
||||||
}
|
}
|
||||||
|
|
||||||
SEGMENT.fill(0);
|
SEGMENT.fill(BLACK);
|
||||||
uint16_t stage = 0xFFFF;
|
uint16_t stage = 0xFFFF;
|
||||||
|
|
||||||
uint32_t s10SinceStart = (millis() - SEGENV.step) /100; //tenths of seconds
|
uint32_t s10SinceStart = (millis() - SEGENV.step) /100; //tenths of seconds
|
||||||
@ -4001,7 +3998,6 @@ static const char _data_FX_MODE_FLOW[] PROGMEM = "Flow@!,Zones;;!;;m12=1"; //ver
|
|||||||
*/
|
*/
|
||||||
uint16_t mode_chunchun(void)
|
uint16_t mode_chunchun(void)
|
||||||
{
|
{
|
||||||
//SEGMENT.fill(SEGCOLOR(1));
|
|
||||||
SEGMENT.fade_out(254); // add a bit of trail
|
SEGMENT.fade_out(254); // add a bit of trail
|
||||||
uint16_t counter = strip.now * (6 + (SEGMENT.speed >> 4));
|
uint16_t counter = strip.now * (6 + (SEGMENT.speed >> 4));
|
||||||
uint16_t numBirds = 2 + (SEGLEN >> 3); // 2 + 1/8 of a segment
|
uint16_t numBirds = 2 + (SEGLEN >> 3); // 2 + 1/8 of a segment
|
||||||
@ -4629,8 +4625,8 @@ uint16_t mode_2DColoredBursts() { // By: ldirko https://editor.so
|
|||||||
SEGENV.aux0 = 0; // start with red hue
|
SEGENV.aux0 = 0; // start with red hue
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dot = false;
|
bool dot = SEGMENT.check3;
|
||||||
bool grad = true;
|
bool grad = SEGMENT.check1;
|
||||||
|
|
||||||
byte numLines = SEGMENT.intensity/16 + 1;
|
byte numLines = SEGMENT.intensity/16 + 1;
|
||||||
|
|
||||||
@ -4646,24 +4642,26 @@ uint16_t mode_2DColoredBursts() { // By: ldirko https://editor.so
|
|||||||
byte xsteps = abs8(x1 - y1) + 1;
|
byte xsteps = abs8(x1 - y1) + 1;
|
||||||
byte ysteps = abs8(x2 - y2) + 1;
|
byte ysteps = abs8(x2 - y2) + 1;
|
||||||
byte steps = xsteps >= ysteps ? xsteps : ysteps;
|
byte steps = xsteps >= ysteps ? xsteps : ysteps;
|
||||||
|
//Draw gradient line
|
||||||
for (size_t i = 1; i <= steps; i++) {
|
for (size_t i = 1; i <= steps; i++) {
|
||||||
byte dx = lerp8by8(x1, y1, i * 255 / steps);
|
uint8_t rate = i * 255 / steps;
|
||||||
byte dy = lerp8by8(x2, y2, i * 255 / steps);
|
byte dx = lerp8by8(x1, y1, rate);
|
||||||
|
byte dy = lerp8by8(x2, y2, rate);
|
||||||
|
//SEGMENT.setPixelColorXY(dx, dy, grad ? color.nscale8_video(255-rate) : color); // use addPixelColorXY for different look
|
||||||
SEGMENT.addPixelColorXY(dx, dy, color); // use setPixelColorXY for different look
|
SEGMENT.addPixelColorXY(dx, dy, color); // use setPixelColorXY for different look
|
||||||
if (grad) SEGMENT.fadePixelColorXY(dx, dy, (i * 255 / steps)); //Draw gradient line
|
if (grad) SEGMENT.fadePixelColorXY(dx, dy, rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dot) { //add white point at the ends of line
|
if (dot) { //add white point at the ends of line
|
||||||
SEGMENT.addPixelColorXY(x1, x2, WHITE);
|
SEGMENT.setPixelColorXY(x1, x2, WHITE);
|
||||||
SEGMENT.addPixelColorXY(y1, y2, WHITE);
|
SEGMENT.setPixelColorXY(y1, y2, DARKSLATEGRAY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SEGMENT.blur(4);
|
if (SEGMENT.custom3) SEGMENT.blur(SEGMENT.custom3/2);
|
||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
} // mode_2DColoredBursts()
|
} // mode_2DColoredBursts()
|
||||||
static const char _data_FX_MODE_2DCOLOREDBURSTS[] PROGMEM = "Colored Bursts@Speed,# of lines;;!;2";
|
static const char _data_FX_MODE_2DCOLOREDBURSTS[] PROGMEM = "Colored Bursts@Speed,# of lines,,,Blur,Gradient,,Dots;;!;2;c3=16";
|
||||||
|
|
||||||
|
|
||||||
/////////////////////
|
/////////////////////
|
||||||
@ -4705,10 +4703,9 @@ uint16_t mode_2DDNASpiral() { // By: ldirko https://editor.soulma
|
|||||||
if (SEGENV.call == 0) {
|
if (SEGENV.call == 0) {
|
||||||
SEGMENT.setUpLeds();
|
SEGMENT.setUpLeds();
|
||||||
SEGMENT.fill(BLACK);
|
SEGMENT.fill(BLACK);
|
||||||
SEGENV.aux0 = 0; // hue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t speeds = SEGMENT.speed/2;
|
uint8_t speeds = SEGMENT.speed/2 + 1;
|
||||||
uint8_t freq = SEGMENT.intensity/8;
|
uint8_t freq = SEGMENT.intensity/8;
|
||||||
|
|
||||||
uint32_t ms = millis() / 20;
|
uint32_t ms = millis() / 20;
|
||||||
@ -4717,17 +4714,21 @@ uint16_t mode_2DDNASpiral() { // By: ldirko https://editor.soulma
|
|||||||
for (int i = 0; i < rows; i++) {
|
for (int i = 0; i < rows; i++) {
|
||||||
uint16_t x = beatsin8(speeds, 0, cols - 1, 0, i * freq) + beatsin8(speeds - 7, 0, cols - 1, 0, i * freq + 128);
|
uint16_t x = beatsin8(speeds, 0, cols - 1, 0, i * freq) + beatsin8(speeds - 7, 0, cols - 1, 0, i * freq + 128);
|
||||||
uint16_t x1 = beatsin8(speeds, 0, cols - 1, 0, 128 + i * freq) + beatsin8(speeds - 7, 0, cols - 1, 0, 128 + 64 + i * freq);
|
uint16_t x1 = beatsin8(speeds, 0, cols - 1, 0, 128 + i * freq) + beatsin8(speeds - 7, 0, cols - 1, 0, 128 + 64 + i * freq);
|
||||||
SEGENV.aux0 = i * 128 / cols + ms; //ewowi20210629: not width - 1 to avoid crash if width = 1
|
uint8_t hue = (i * 128 / rows) + ms;
|
||||||
|
// skip every 4th row every now and then (fade it more)
|
||||||
if ((i + ms / 8) & 3) {
|
if ((i + ms / 8) & 3) {
|
||||||
|
// draw a gradient line between x and x1
|
||||||
x = x / 2; x1 = x1 / 2;
|
x = x / 2; x1 = x1 / 2;
|
||||||
byte steps = abs8(x - x1) + 1;
|
uint8_t steps = abs8(x - x1) + 1;
|
||||||
for (size_t k = 1; k <= steps; k++) {
|
for (size_t k = 1; k <= steps; k++) {
|
||||||
byte dx = lerp8by8(x, x1, k * 255 / steps);
|
uint8_t rate = k * 255 / steps;
|
||||||
SEGMENT.addPixelColorXY(dx, i, ColorFromPalette(SEGPALETTE, SEGENV.aux0, 255, LINEARBLEND));
|
uint8_t dx = lerp8by8(x, x1, rate);
|
||||||
SEGMENT.fadePixelColorXY(dx, i, (k * 255 / steps));
|
//SEGMENT.setPixelColorXY(dx, i, ColorFromPalette(SEGPALETTE, hue, 255, LINEARBLEND).nscale8_video(rate));
|
||||||
|
SEGMENT.addPixelColorXY(dx, i, ColorFromPalette(SEGPALETTE, hue, 255, LINEARBLEND)); // use setPixelColorXY for different look
|
||||||
|
SEGMENT.fadePixelColorXY(dx, i, rate);
|
||||||
}
|
}
|
||||||
SEGMENT.addPixelColorXY(x, i, DARKSLATEGRAY);
|
SEGMENT.setPixelColorXY(x, i, DARKSLATEGRAY);
|
||||||
SEGMENT.addPixelColorXY(x1, i, WHITE);
|
SEGMENT.setPixelColorXY(x1, i, WHITE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5086,11 +5087,11 @@ uint16_t mode_2DLissajous(void) { // By: Andrew Tuline
|
|||||||
for (int i=0; i < 256; i ++) {
|
for (int i=0; i < 256; i ++) {
|
||||||
//float xlocn = float(sin8(now/4+i*(SEGMENT.speed>>5))) / 255.0f;
|
//float xlocn = float(sin8(now/4+i*(SEGMENT.speed>>5))) / 255.0f;
|
||||||
//float ylocn = float(cos8(now/4+i*2)) / 255.0f;
|
//float ylocn = float(cos8(now/4+i*2)) / 255.0f;
|
||||||
uint8_t xlocn = sin8(strip.now/2+i*(SEGMENT.speed>>5));
|
uint8_t xlocn = sin8(millis()/4+i*(SEGMENT.speed>>5));
|
||||||
uint8_t ylocn = cos8(strip.now/2+i*2);
|
uint8_t ylocn = cos8(millis()/4+i*2);
|
||||||
xlocn = map(xlocn,0,255,0,cols-1);
|
xlocn = map(xlocn,0,255,0,cols-1);
|
||||||
ylocn = map(ylocn,0,255,0,rows-1);
|
ylocn = map(ylocn,0,255,0,rows-1);
|
||||||
SEGMENT.setPixelColorXY(xlocn, ylocn, SEGMENT.color_from_palette(strip.now/100+i, false, PALETTE_SOLID_WRAP, 0));
|
SEGMENT.setPixelColorXY(xlocn, ylocn, SEGMENT.color_from_palette(millis()/100+i, false, PALETTE_SOLID_WRAP, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
@ -5173,15 +5174,15 @@ uint16_t mode_2Dmetaballs(void) { // Metaballs by Stefan Petrick. Cannot have
|
|||||||
float speed = 0.25f * (1+(SEGMENT.speed>>6));
|
float speed = 0.25f * (1+(SEGMENT.speed>>6));
|
||||||
|
|
||||||
// get some 2 random moving points
|
// get some 2 random moving points
|
||||||
uint8_t x2 = inoise8(strip.now * speed, 25355, 685 ) / 16;
|
uint8_t x2 = map(inoise8(strip.now * speed, 25355, 685), 0, 255, 0, cols-1);
|
||||||
uint8_t y2 = inoise8(strip.now * speed, 355, 11685 ) / 16;
|
uint8_t y2 = map(inoise8(strip.now * speed, 355, 11685), 0, 255, 0, rows-1);
|
||||||
|
|
||||||
uint8_t x3 = inoise8(strip.now * speed, 55355, 6685 ) / 16;
|
uint8_t x3 = map(inoise8(strip.now * speed, 55355, 6685), 0, 255, 0, cols-1);
|
||||||
uint8_t y3 = inoise8(strip.now * speed, 25355, 22685 ) / 16;
|
uint8_t y3 = map(inoise8(strip.now * speed, 25355, 22685), 0, 255, 0, rows-1);
|
||||||
|
|
||||||
// and one Lissajou function
|
// and one Lissajou function
|
||||||
uint8_t x1 = beatsin8(23 * speed, 0, 15);
|
uint8_t x1 = beatsin8(23 * speed, 0, cols-1);
|
||||||
uint8_t y1 = beatsin8(28 * speed, 0, 15);
|
uint8_t y1 = beatsin8(28 * speed, 0, rows-1);
|
||||||
|
|
||||||
for (int y = 0; y < rows; y++) {
|
for (int y = 0; y < rows; y++) {
|
||||||
for (int x = 0; x < cols; x++) {
|
for (int x = 0; x < cols; x++) {
|
||||||
@ -5200,7 +5201,7 @@ uint16_t mode_2Dmetaballs(void) { // Metaballs by Stefan Petrick. Cannot have
|
|||||||
dist += sqrt16((dx * dx) + (dy * dy));
|
dist += sqrt16((dx * dx) + (dy * dy));
|
||||||
|
|
||||||
// inverse result
|
// inverse result
|
||||||
byte color = 1000 / dist;
|
byte color = dist ? 1000 / dist : 255;
|
||||||
|
|
||||||
// map color between thresholds
|
// map color between thresholds
|
||||||
if (color > 0 and color < 60) {
|
if (color > 0 and color < 60) {
|
||||||
@ -5858,7 +5859,7 @@ uint16_t mode_2Dscrollingtext(void) {
|
|||||||
char text[33] = {'\0'};
|
char text[33] = {'\0'};
|
||||||
if (SEGMENT.name) for (size_t i=0,j=0; i<strlen(SEGMENT.name); i++) if (SEGMENT.name[i]>31 && SEGMENT.name[i]<128) text[j++] = SEGMENT.name[i];
|
if (SEGMENT.name) for (size_t i=0,j=0; i<strlen(SEGMENT.name); i++) if (SEGMENT.name[i]>31 && SEGMENT.name[i]<128) text[j++] = SEGMENT.name[i];
|
||||||
|
|
||||||
if (!strlen(text) || !strncmp_P(text,PSTR("#DATE"),5) || !strncmp_P(text,PSTR("#TIME"),5)) { // fallback if empty segment name: display date and time
|
if (!strlen(text) || !strncmp_P(text,PSTR("#DATE"),5) || !strncmp_P(text,PSTR("#DDMM"),5) || !strncmp_P(text,PSTR("#MMDD"),5) || !strncmp_P(text,PSTR("#TIME"),5) || !strncmp_P(text,PSTR("#HHMM"),5)) { // fallback if empty segment name: display date and time
|
||||||
char sec[5];
|
char sec[5];
|
||||||
byte AmPmHour = hour(localTime);
|
byte AmPmHour = hour(localTime);
|
||||||
boolean isitAM = true;
|
boolean isitAM = true;
|
||||||
@ -5869,7 +5870,10 @@ uint16_t mode_2Dscrollingtext(void) {
|
|||||||
if (useAMPM) sprintf_P(sec, PSTR(" %2s"), (isitAM ? "AM" : "PM"));
|
if (useAMPM) sprintf_P(sec, PSTR(" %2s"), (isitAM ? "AM" : "PM"));
|
||||||
else sprintf_P(sec, PSTR(":%02d"), second(localTime));
|
else sprintf_P(sec, PSTR(":%02d"), second(localTime));
|
||||||
if (!strncmp_P(text,PSTR("#DATE"),5)) sprintf_P(text, PSTR("%d.%d.%d"), day(localTime), month(localTime), year(localTime));
|
if (!strncmp_P(text,PSTR("#DATE"),5)) sprintf_P(text, PSTR("%d.%d.%d"), day(localTime), month(localTime), year(localTime));
|
||||||
|
else if (!strncmp_P(text,PSTR("#DDMM"),5)) sprintf_P(text, PSTR("%d.%d"), day(localTime), month(localTime));
|
||||||
|
else if (!strncmp_P(text,PSTR("#MMDD"),5)) sprintf_P(text, PSTR("%d/%d"), month(localTime), day(localTime));
|
||||||
else if (!strncmp_P(text,PSTR("#TIME"),5)) sprintf_P(text, PSTR("%2d:%02d%s"), AmPmHour, minute(localTime), sec);
|
else if (!strncmp_P(text,PSTR("#TIME"),5)) sprintf_P(text, PSTR("%2d:%02d%s"), AmPmHour, minute(localTime), sec);
|
||||||
|
else if (!strncmp_P(text,PSTR("#HHMM"),5)) sprintf_P(text, PSTR("%2d:%02d"), AmPmHour, minute(localTime));
|
||||||
else sprintf_P(text, PSTR("%s %d, %d %2d:%02d%s"), monthShortStr(month(localTime)), day(localTime), year(localTime), AmPmHour, minute(localTime), sec);
|
else sprintf_P(text, PSTR("%s %d, %d %2d:%02d%s"), monthShortStr(month(localTime)), day(localTime), year(localTime), AmPmHour, minute(localTime), sec);
|
||||||
}
|
}
|
||||||
const int numberOfLetters = strlen(text);
|
const int numberOfLetters = strlen(text);
|
||||||
@ -5879,20 +5883,21 @@ uint16_t mode_2Dscrollingtext(void) {
|
|||||||
else SEGENV.aux0 = (cols + (numberOfLetters * letterWidth))/2;
|
else SEGENV.aux0 = (cols + (numberOfLetters * letterWidth))/2;
|
||||||
++SEGENV.aux1 &= 0xFF; // color shift
|
++SEGENV.aux1 &= 0xFF; // color shift
|
||||||
SEGENV.step = millis() + map(SEGMENT.speed, 0, 255, 10*FRAMETIME_FIXED, 2*FRAMETIME_FIXED);
|
SEGENV.step = millis() + map(SEGMENT.speed, 0, 255, 10*FRAMETIME_FIXED, 2*FRAMETIME_FIXED);
|
||||||
|
if (!SEGMENT.check2) {
|
||||||
// we need it 3 times
|
// we need it 3 times
|
||||||
SEGMENT.fade_out(255 - (SEGMENT.custom1>>5)); // fade to background color
|
SEGMENT.fade_out(255 - (SEGMENT.custom1>>5)); // fade to background color
|
||||||
SEGMENT.fade_out(255 - (SEGMENT.custom1>>5)); // fade to background color
|
SEGMENT.fade_out(255 - (SEGMENT.custom1>>5)); // fade to background color
|
||||||
SEGMENT.fade_out(255 - (SEGMENT.custom1>>5)); // fade to background color
|
SEGMENT.fade_out(255 - (SEGMENT.custom1>>5)); // fade to background color
|
||||||
|
}
|
||||||
|
}
|
||||||
for (int i = 0; i < numberOfLetters; i++) {
|
for (int i = 0; i < numberOfLetters; i++) {
|
||||||
if (int(cols) - int(SEGENV.aux0) + letterWidth*(i+1) < 0) continue; // don't draw characters off-screen
|
if (int(cols) - int(SEGENV.aux0) + letterWidth*(i+1) < 0) continue; // don't draw characters off-screen
|
||||||
SEGMENT.drawCharacter(text[i], int(cols) - int(SEGENV.aux0) + letterWidth*i, yoffset, letterWidth, letterHeight, SEGMENT.color_from_palette(SEGENV.aux1, false, PALETTE_SOLID_WRAP, 0));
|
SEGMENT.drawCharacter(text[i], int(cols) - int(SEGENV.aux0) + letterWidth*i, yoffset, letterWidth, letterHeight, SEGMENT.color_from_palette(SEGENV.aux1, false, PALETTE_SOLID_WRAP, 0));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
static const char _data_FX_MODE_2DSCROLLTEXT[] PROGMEM = "Scrolling Text@!,Y Offset,Trail,Font size;!,!;!;2;ix=128,c1=0,rev=0,mi=0,rY=0,mY=0";
|
static const char _data_FX_MODE_2DSCROLLTEXT[] PROGMEM = "Scrolling Text@!,Y Offset,Trail,Font size,,,Overlay;!,!;!;2;ix=128,c1=0,rev=0,mi=0,rY=0,mY=0";
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////
|
////////////////////////////
|
||||||
@ -7302,6 +7307,61 @@ uint16_t mode_2DAkemi(void) {
|
|||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
} // mode_2DAkemi
|
} // mode_2DAkemi
|
||||||
static const char _data_FX_MODE_2DAKEMI[] PROGMEM = "Akemi@Color speed,Dance;Head palette,Arms & Legs,Eyes & Mouth;Face palette;2f;si=0"; //beatsin
|
static const char _data_FX_MODE_2DAKEMI[] PROGMEM = "Akemi@Color speed,Dance;Head palette,Arms & Legs,Eyes & Mouth;Face palette;2f;si=0"; //beatsin
|
||||||
|
|
||||||
|
|
||||||
|
// Distortion waves - ldirko
|
||||||
|
// https://editor.soulmatelights.com/gallery/1089-distorsion-waves
|
||||||
|
// apated for WLD by @blazoncek
|
||||||
|
uint16_t mode_2Ddistortionwaves() {
|
||||||
|
if (!strip.isMatrix) return mode_static(); // not a 2D set-up
|
||||||
|
|
||||||
|
const uint16_t cols = SEGMENT.virtualWidth();
|
||||||
|
const uint16_t rows = SEGMENT.virtualHeight();
|
||||||
|
|
||||||
|
uint8_t speed = SEGMENT.speed/32;
|
||||||
|
uint8_t scale = SEGMENT.intensity/32;
|
||||||
|
|
||||||
|
uint8_t w = 2;
|
||||||
|
|
||||||
|
uint16_t a = millis()/32;
|
||||||
|
uint16_t a2 = a/2;
|
||||||
|
uint16_t a3 = a/3;
|
||||||
|
|
||||||
|
uint16_t cx = beatsin8(10-speed,0,cols-1)*scale;
|
||||||
|
uint16_t cy = beatsin8(12-speed,0,rows-1)*scale;
|
||||||
|
uint16_t cx1 = beatsin8(13-speed,0,cols-1)*scale;
|
||||||
|
uint16_t cy1 = beatsin8(15-speed,0,rows-1)*scale;
|
||||||
|
uint16_t cx2 = beatsin8(17-speed,0,cols-1)*scale;
|
||||||
|
uint16_t cy2 = beatsin8(14-speed,0,rows-1)*scale;
|
||||||
|
|
||||||
|
uint16_t xoffs = 0;
|
||||||
|
for (int x = 0; x < cols; x++) {
|
||||||
|
xoffs += scale;
|
||||||
|
uint16_t yoffs = 0;
|
||||||
|
|
||||||
|
for (int y = 0; y < rows; y++) {
|
||||||
|
yoffs += scale;
|
||||||
|
|
||||||
|
byte rdistort = cos8((cos8(((x<<3)+a )&255)+cos8(((y<<3)-a2)&255)+a3 )&255)>>1;
|
||||||
|
byte gdistort = cos8((cos8(((x<<3)-a2)&255)+cos8(((y<<3)+a3)&255)+a+32 )&255)>>1;
|
||||||
|
byte bdistort = cos8((cos8(((x<<3)+a3)&255)+cos8(((y<<3)-a) &255)+a2+64)&255)>>1;
|
||||||
|
|
||||||
|
byte valueR = rdistort+ w* (a- ( ((xoffs - cx) * (xoffs - cx) + (yoffs - cy) * (yoffs - cy))>>7 ));
|
||||||
|
byte valueG = gdistort+ w* (a2-( ((xoffs - cx1) * (xoffs - cx1) + (yoffs - cy1) * (yoffs - cy1))>>7 ));
|
||||||
|
byte valueB = bdistort+ w* (a3-( ((xoffs - cx2) * (xoffs - cx2) + (yoffs - cy2) * (yoffs - cy2))>>7 ));
|
||||||
|
|
||||||
|
valueR = gamma8(cos8(valueR));
|
||||||
|
valueG = gamma8(cos8(valueG));
|
||||||
|
valueB = gamma8(cos8(valueB));
|
||||||
|
|
||||||
|
SEGMENT.setPixelColorXY(x, y, RGBW32(valueR, valueG, valueB, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FRAMETIME;
|
||||||
|
}
|
||||||
|
static const char _data_FX_MODE_2DDISTORTIONWAVES[] PROGMEM = "Distortion Waves@!,Scale;;;2;";
|
||||||
|
|
||||||
#endif // WLED_DISABLE_2D
|
#endif // WLED_DISABLE_2D
|
||||||
|
|
||||||
|
|
||||||
@ -7500,6 +7560,7 @@ void WS2812FX::setupEffectData() {
|
|||||||
addEffect(FX_MODE_2DBLOBS, &mode_2Dfloatingblobs, _data_FX_MODE_2DBLOBS);
|
addEffect(FX_MODE_2DBLOBS, &mode_2Dfloatingblobs, _data_FX_MODE_2DBLOBS);
|
||||||
addEffect(FX_MODE_2DSCROLLTEXT, &mode_2Dscrollingtext, _data_FX_MODE_2DSCROLLTEXT);
|
addEffect(FX_MODE_2DSCROLLTEXT, &mode_2Dscrollingtext, _data_FX_MODE_2DSCROLLTEXT);
|
||||||
addEffect(FX_MODE_2DDRIFTROSE, &mode_2Ddriftrose, _data_FX_MODE_2DDRIFTROSE);
|
addEffect(FX_MODE_2DDRIFTROSE, &mode_2Ddriftrose, _data_FX_MODE_2DDRIFTROSE);
|
||||||
|
addEffect(FX_MODE_2DDISTORTIONWAVES, &mode_2Ddistortionwaves, _data_FX_MODE_2DDISTORTIONWAVES);
|
||||||
|
|
||||||
addEffect(FX_MODE_2DGEQ, &mode_2DGEQ, _data_FX_MODE_2DGEQ); // audio
|
addEffect(FX_MODE_2DGEQ, &mode_2DGEQ, _data_FX_MODE_2DGEQ); // audio
|
||||||
|
|
||||||
|
39
wled00/FX.h
@ -250,6 +250,7 @@
|
|||||||
#define FX_MODE_2DBLOBS 121 //gap fill
|
#define FX_MODE_2DBLOBS 121 //gap fill
|
||||||
#define FX_MODE_2DSCROLLTEXT 122 //gap fill
|
#define FX_MODE_2DSCROLLTEXT 122 //gap fill
|
||||||
#define FX_MODE_2DDRIFTROSE 123 //gap fill
|
#define FX_MODE_2DDRIFTROSE 123 //gap fill
|
||||||
|
#define FX_MODE_2DDISTORTIONWAVES 124
|
||||||
|
|
||||||
// WLED-SR effects (SR compatible IDs !!!)
|
// WLED-SR effects (SR compatible IDs !!!)
|
||||||
#define FX_MODE_PIXELS 128
|
#define FX_MODE_PIXELS 128
|
||||||
@ -504,6 +505,7 @@ typedef struct Segment {
|
|||||||
static uint16_t getUsedSegmentData(void) { return _usedSegmentData; }
|
static uint16_t getUsedSegmentData(void) { return _usedSegmentData; }
|
||||||
static void addUsedSegmentData(int len) { _usedSegmentData += len; }
|
static void addUsedSegmentData(int len) { _usedSegmentData += len; }
|
||||||
|
|
||||||
|
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);
|
||||||
bool setColor(uint8_t slot, uint32_t c); //returns true if changed
|
bool setColor(uint8_t slot, uint32_t c); //returns true if changed
|
||||||
void setCCT(uint16_t k);
|
void setCCT(uint16_t k);
|
||||||
void setOpacity(uint8_t o);
|
void setOpacity(uint8_t o);
|
||||||
@ -587,6 +589,7 @@ typedef struct Segment {
|
|||||||
void moveX(int8_t delta);
|
void moveX(int8_t delta);
|
||||||
void moveY(int8_t delta);
|
void moveY(int8_t delta);
|
||||||
void move(uint8_t dir, uint8_t delta);
|
void move(uint8_t dir, uint8_t delta);
|
||||||
|
void draw_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c);
|
||||||
void fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c);
|
void fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c);
|
||||||
void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c);
|
void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c);
|
||||||
void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c) { drawLine(x0, y0, x1, y1, RGBW32(c.r,c.g,c.b,0)); } // automatic inline
|
void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c) { drawLine(x0, y0, x1, y1, RGBW32(c.r,c.g,c.b,0)); } // automatic inline
|
||||||
@ -654,12 +657,8 @@ class WS2812FX { // 96 bytes
|
|||||||
timebase(0),
|
timebase(0),
|
||||||
isMatrix(false),
|
isMatrix(false),
|
||||||
#ifndef WLED_DISABLE_2D
|
#ifndef WLED_DISABLE_2D
|
||||||
hPanels(1),
|
panels(1),
|
||||||
vPanels(1),
|
|
||||||
panelH(8),
|
|
||||||
panelW(8),
|
|
||||||
matrix{0,0,0,0},
|
matrix{0,0,0,0},
|
||||||
panel{{0,0,0,0}},
|
|
||||||
#endif
|
#endif
|
||||||
// semi-private (just obscured) used in effect functions through macros
|
// semi-private (just obscured) used in effect functions through macros
|
||||||
_currentPalette(CRGBPalette16(CRGB::Black)),
|
_currentPalette(CRGBPalette16(CRGB::Black)),
|
||||||
@ -696,6 +695,9 @@ class WS2812FX { // 96 bytes
|
|||||||
_mode.clear();
|
_mode.clear();
|
||||||
_modeData.clear();
|
_modeData.clear();
|
||||||
_segments.clear();
|
_segments.clear();
|
||||||
|
#ifndef WLED_DISABLE_2D
|
||||||
|
panel.clear();
|
||||||
|
#endif
|
||||||
customPalettes.clear();
|
customPalettes.clear();
|
||||||
if (useLedsArray && Segment::_globalLeds) free(Segment::_globalLeds);
|
if (useLedsArray && Segment::_globalLeds) free(Segment::_globalLeds);
|
||||||
}
|
}
|
||||||
@ -808,22 +810,31 @@ class WS2812FX { // 96 bytes
|
|||||||
#ifndef WLED_DISABLE_2D
|
#ifndef WLED_DISABLE_2D
|
||||||
#define WLED_MAX_PANELS 64
|
#define WLED_MAX_PANELS 64
|
||||||
uint8_t
|
uint8_t
|
||||||
hPanels,
|
panels;
|
||||||
vPanels;
|
|
||||||
|
|
||||||
uint16_t
|
struct {
|
||||||
panelH,
|
bool bottomStart : 1;
|
||||||
panelW;
|
bool rightStart : 1;
|
||||||
|
bool vertical : 1;
|
||||||
|
bool serpentine : 1;
|
||||||
|
} matrix;
|
||||||
|
|
||||||
typedef struct panel_bitfield_t {
|
typedef struct panel_t {
|
||||||
|
uint16_t xOffset; // x offset relative to the top left of matrix in LEDs
|
||||||
|
uint16_t yOffset; // y offset relative to the top left of matrix in LEDs
|
||||||
|
uint8_t width; // width of the panel
|
||||||
|
uint8_t height; // height of the panel
|
||||||
|
union {
|
||||||
|
uint8_t options;
|
||||||
|
struct {
|
||||||
bool bottomStart : 1; // starts at bottom?
|
bool bottomStart : 1; // starts at bottom?
|
||||||
bool rightStart : 1; // starts on right?
|
bool rightStart : 1; // starts on right?
|
||||||
bool vertical : 1; // is vertical?
|
bool vertical : 1; // is vertical?
|
||||||
bool serpentine : 1; // is serpentine?
|
bool serpentine : 1; // is serpentine?
|
||||||
|
};
|
||||||
|
};
|
||||||
} Panel;
|
} Panel;
|
||||||
Panel
|
std::vector<Panel> panel;
|
||||||
matrix,
|
|
||||||
panel[WLED_MAX_PANELS];
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -43,49 +43,55 @@ void WS2812FX::setUpMatrix() {
|
|||||||
|
|
||||||
// isMatrix is set in cfg.cpp or set.cpp
|
// isMatrix is set in cfg.cpp or set.cpp
|
||||||
if (isMatrix) {
|
if (isMatrix) {
|
||||||
Segment::maxWidth = hPanels * panelW;
|
// calculate width dynamically because it will have gaps
|
||||||
Segment::maxHeight = vPanels * panelH;
|
Segment::maxWidth = 1;
|
||||||
|
Segment::maxHeight = 1;
|
||||||
|
for (size_t i = 0; i < panel.size(); i++) {
|
||||||
|
Panel &p = panel[i];
|
||||||
|
if (p.xOffset + p.width > Segment::maxWidth) {
|
||||||
|
Segment::maxWidth = p.xOffset + p.width;
|
||||||
|
}
|
||||||
|
if (p.yOffset + p.height > Segment::maxHeight) {
|
||||||
|
Segment::maxHeight = p.yOffset + p.height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// safety check
|
// safety check
|
||||||
if (Segment::maxWidth * Segment::maxHeight > MAX_LEDS || Segment::maxWidth == 1 || Segment::maxHeight == 1) {
|
if (Segment::maxWidth * Segment::maxHeight > MAX_LEDS || Segment::maxWidth <= 1 || Segment::maxHeight <= 1) {
|
||||||
|
DEBUG_PRINTLN(F("2D Bounds error."));
|
||||||
|
isMatrix = false;
|
||||||
Segment::maxWidth = _length;
|
Segment::maxWidth = _length;
|
||||||
Segment::maxHeight = 1;
|
Segment::maxHeight = 1;
|
||||||
isMatrix = false;
|
panels = 0;
|
||||||
|
panel.clear(); // release memory allocated by panels
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
customMappingSize = Segment::maxWidth * Segment::maxHeight;
|
customMappingTable = new uint16_t[Segment::maxWidth * Segment::maxHeight];
|
||||||
customMappingTable = new uint16_t[customMappingSize];
|
|
||||||
|
|
||||||
if (customMappingTable != nullptr) {
|
if (customMappingTable != nullptr) {
|
||||||
uint16_t startL; // index in custom mapping array (logical strip)
|
customMappingSize = Segment::maxWidth * Segment::maxHeight;
|
||||||
uint16_t startP; // position of 1st pixel of panel on (virtual) strip
|
|
||||||
uint16_t x, y, offset;
|
|
||||||
uint8_t h = matrix.vertical ? vPanels : hPanels;
|
|
||||||
uint8_t v = matrix.vertical ? hPanels : vPanels;
|
|
||||||
|
|
||||||
for (uint8_t j=0, p=0; j<v; j++) {
|
// fill with empty in case we don't fill the entire matrix
|
||||||
for (uint8_t i=0; i<h; i++, p++) {
|
for (size_t i = 0; i< customMappingSize; i++) {
|
||||||
y = (matrix.vertical ? matrix.rightStart : matrix.bottomStart) ? v - j - 1 : j;
|
customMappingTable[i] = (uint16_t)-1;
|
||||||
x = (matrix.vertical ? matrix.bottomStart : matrix.rightStart) ? h - i - 1 : i;
|
}
|
||||||
x = matrix.serpentine && j%2 ? h - x - 1 : x;
|
|
||||||
|
|
||||||
startL = (matrix.vertical ? y : x) * panelW + (matrix.vertical ? x : y) * Segment::maxWidth * panelH; // logical index (top-left corner)
|
uint16_t x, y, pix=0; //pixel
|
||||||
startP = p * panelW * panelH; // physical index (top-left corner)
|
for (size_t pan = 0; pan < panel.size(); pan++) {
|
||||||
|
Panel &p = panel[pan];
|
||||||
|
uint16_t h = p.vertical ? p.height : p.width;
|
||||||
|
uint16_t v = p.vertical ? p.width : p.height;
|
||||||
|
for (size_t j = 0; j < v; j++){
|
||||||
|
for(size_t i = 0; i < h; i++, pix++) {
|
||||||
|
y = (p.vertical?p.rightStart:p.bottomStart) ? v-j-1 : j;
|
||||||
|
x = (p.vertical?p.bottomStart:p.rightStart) ? h-i-1 : i;
|
||||||
|
x = p.serpentine && j%2 ? h-x-1 : x;
|
||||||
|
customMappingTable[(p.yOffset + (p.vertical?x:y)) * Segment::maxWidth + p.xOffset + (p.vertical?y:x)] = pix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t H = panel[h*j + i].vertical ? panelW : panelH;
|
|
||||||
uint8_t W = panel[h*j + i].vertical ? panelH : panelW;
|
|
||||||
for (uint16_t l=0, q=0; l<H; l++) {
|
|
||||||
for (uint16_t k=0; k<W; k++, q++) {
|
|
||||||
y = (panel[h*j + i].vertical ? panel[h*j + i].rightStart : panel[h*j + i].bottomStart) ? H - l - 1 : l;
|
|
||||||
x = (panel[h*j + i].vertical ? panel[h*j + i].bottomStart : panel[h*j + i].rightStart) ? W - k - 1 : k;
|
|
||||||
x = (panel[h*j + i].serpentine && l%2) ? (W - x - 1) : x;
|
|
||||||
offset = (panel[h*j + i].vertical ? y : x) + (panel[h*j + i].vertical ? x : y) * Segment::maxWidth;
|
|
||||||
customMappingTable[startL + offset] = startP + q;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifdef WLED_DEBUG
|
#ifdef WLED_DEBUG
|
||||||
DEBUG_PRINT(F("Matrix ledmap:"));
|
DEBUG_PRINT(F("Matrix ledmap:"));
|
||||||
for (uint16_t i=0; i<customMappingSize; i++) {
|
for (uint16_t i=0; i<customMappingSize; i++) {
|
||||||
@ -94,18 +100,18 @@ void WS2812FX::setUpMatrix() {
|
|||||||
}
|
}
|
||||||
DEBUG_PRINTLN();
|
DEBUG_PRINTLN();
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else { // memory allocation error
|
||||||
// memory allocation error
|
DEBUG_PRINTLN(F("Ledmap alloc error."));
|
||||||
|
isMatrix = false;
|
||||||
|
panels = 0;
|
||||||
|
panel.clear();
|
||||||
Segment::maxWidth = _length;
|
Segment::maxWidth = _length;
|
||||||
Segment::maxHeight = 1;
|
Segment::maxHeight = 1;
|
||||||
isMatrix = false;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// not a matrix set up
|
|
||||||
Segment::maxWidth = _length;
|
|
||||||
Segment::maxHeight = 1;
|
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
isMatrix = false; // no matter what config says
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,7 +121,7 @@ void IRAM_ATTR WS2812FX::setPixelColorXY(int x, int y, uint32_t col)
|
|||||||
#ifndef WLED_DISABLE_2D
|
#ifndef WLED_DISABLE_2D
|
||||||
if (!isMatrix) return; // not a matrix set-up
|
if (!isMatrix) return; // not a matrix set-up
|
||||||
uint16_t index = y * Segment::maxWidth + x;
|
uint16_t index = y * Segment::maxWidth + x;
|
||||||
if (index >= customMappingSize) return; // customMappingSize is always W * H of matrix in 2D setup
|
if (index >= customMappingSize) return;
|
||||||
#else
|
#else
|
||||||
uint16_t index = x;
|
uint16_t index = x;
|
||||||
if (index >= _length) return;
|
if (index >= _length) return;
|
||||||
@ -158,6 +164,7 @@ void IRAM_ATTR Segment::setPixelColorXY(int x, int y, uint32_t col)
|
|||||||
if (leds) leds[XY(x,y)] = col;
|
if (leds) leds[XY(x,y)] = col;
|
||||||
|
|
||||||
uint8_t _bri_t = currentBri(on ? opacity : 0);
|
uint8_t _bri_t = currentBri(on ? opacity : 0);
|
||||||
|
if (!_bri_t && !transitional) return;
|
||||||
if (_bri_t < 255) {
|
if (_bri_t < 255) {
|
||||||
byte r = scale8(R(col), _bri_t);
|
byte r = scale8(R(col), _bri_t);
|
||||||
byte g = scale8(G(col), _bri_t);
|
byte g = scale8(G(col), _bri_t);
|
||||||
@ -265,7 +272,7 @@ void Segment::addPixelColorXY(int x, int y, uint32_t color) {
|
|||||||
|
|
||||||
void Segment::fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) {
|
void Segment::fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) {
|
||||||
CRGB pix = CRGB(getPixelColorXY(x,y)).nscale8_video(fade);
|
CRGB pix = CRGB(getPixelColorXY(x,y)).nscale8_video(fade);
|
||||||
setPixelColor(x, y, pix);
|
setPixelColorXY(x, y, pix);
|
||||||
}
|
}
|
||||||
|
|
||||||
// blurRow: perform a blur on a row of a rectangular matrix
|
// blurRow: perform a blur on a row of a rectangular matrix
|
||||||
@ -422,6 +429,29 @@ void Segment::move(uint8_t dir, uint8_t delta) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Segment::draw_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) {
|
||||||
|
// Bresenham’s Algorithm
|
||||||
|
int d = 3 - (2*radius);
|
||||||
|
int y = radius, x = 0;
|
||||||
|
while (y >= x) {
|
||||||
|
setPixelColorXY(cx+x, cy+y, col);
|
||||||
|
setPixelColorXY(cx-x, cy+y, col);
|
||||||
|
setPixelColorXY(cx+x, cy-y, col);
|
||||||
|
setPixelColorXY(cx-x, cy-y, col);
|
||||||
|
setPixelColorXY(cx+y, cy+x, col);
|
||||||
|
setPixelColorXY(cx-y, cy+x, col);
|
||||||
|
setPixelColorXY(cx+y, cy-x, col);
|
||||||
|
setPixelColorXY(cx-y, cy-x, col);
|
||||||
|
x++;
|
||||||
|
if (d > 0) {
|
||||||
|
y--;
|
||||||
|
d += 4 * (x - y) + 10;
|
||||||
|
} else {
|
||||||
|
d += 4 * x + 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// by stepko, taken from https://editor.soulmatelights.com/gallery/573-blobs
|
// by stepko, taken from https://editor.soulmatelights.com/gallery/573-blobs
|
||||||
void Segment::fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) {
|
void Segment::fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) {
|
||||||
const uint16_t cols = virtualWidth();
|
const uint16_t cols = virtualWidth();
|
||||||
@ -431,7 +461,7 @@ void Segment::fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) {
|
|||||||
if (x * x + y * y <= radius * radius &&
|
if (x * x + y * y <= radius * radius &&
|
||||||
int16_t(cx)+x>=0 && int16_t(cy)+y>=0 &&
|
int16_t(cx)+x>=0 && int16_t(cy)+y>=0 &&
|
||||||
int16_t(cx)+x<cols && int16_t(cy)+y<rows)
|
int16_t(cx)+x<cols && int16_t(cy)+y<rows)
|
||||||
addPixelColorXY(cx + x, cy + y, col);
|
setPixelColorXY(cx + x, cy + y, col);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -453,7 +483,7 @@ void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint3
|
|||||||
const int16_t dy = abs(y1-y0), sy = y0<y1 ? 1 : -1;
|
const int16_t dy = abs(y1-y0), sy = y0<y1 ? 1 : -1;
|
||||||
int16_t err = (dx>dy ? dx : -dy)/2, e2;
|
int16_t err = (dx>dy ? dx : -dy)/2, e2;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
addPixelColorXY(x0,y0,c);
|
setPixelColorXY(x0,y0,c);
|
||||||
if (x0==x1 && y0==y1) break;
|
if (x0==x1 && y0==y1) break;
|
||||||
e2 = err;
|
e2 = err;
|
||||||
if (e2 >-dx) { err -= dy; x0 += sx; }
|
if (e2 >-dx) { err -= dy; x0 += sx; }
|
||||||
|
@ -211,6 +211,7 @@ void Segment::setUpLeds() {
|
|||||||
CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) {
|
CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) {
|
||||||
static unsigned long _lastPaletteChange = 0; // perhaps it should be per segment
|
static unsigned long _lastPaletteChange = 0; // perhaps it should be per segment
|
||||||
static CRGBPalette16 randomPalette = CRGBPalette16(DEFAULT_COLOR);
|
static CRGBPalette16 randomPalette = CRGBPalette16(DEFAULT_COLOR);
|
||||||
|
static CRGBPalette16 prevRandomPalette = CRGBPalette16(CRGB(BLACK));
|
||||||
byte tcp[72];
|
byte tcp[72];
|
||||||
if (pal < 245 && pal > GRADIENT_PALETTE_COUNT+13) pal = 0;
|
if (pal < 245 && pal > GRADIENT_PALETTE_COUNT+13) pal = 0;
|
||||||
if (pal > 245 && (strip.customPalettes.size() == 0 || 255U-pal > strip.customPalettes.size()-1)) pal = 0;
|
if (pal > 245 && (strip.customPalettes.size() == 0 || 255U-pal > strip.customPalettes.size()-1)) pal = 0;
|
||||||
@ -230,16 +231,29 @@ CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) {
|
|||||||
switch (pal) {
|
switch (pal) {
|
||||||
case 0: //default palette. Exceptions for specific effects above
|
case 0: //default palette. Exceptions for specific effects above
|
||||||
targetPalette = PartyColors_p; break;
|
targetPalette = PartyColors_p; break;
|
||||||
case 1: //periodically replace palette with a random one. Doesn't work with multiple FastLED segments
|
case 1: {//periodically replace palette with a random one. Transition palette change in 500ms
|
||||||
if (millis() - _lastPaletteChange > 5000 /*+ ((uint32_t)(255-intensity))*100*/) {
|
uint32_t timeSinceLastChange = millis() - _lastPaletteChange;
|
||||||
|
if (timeSinceLastChange > 5000 /*+ ((uint32_t)(255-intensity))*100*/) {
|
||||||
|
prevRandomPalette = randomPalette;
|
||||||
randomPalette = CRGBPalette16(
|
randomPalette = CRGBPalette16(
|
||||||
CHSV(random8(), random8(160, 255), random8(128, 255)),
|
CHSV(random8(), random8(160, 255), random8(128, 255)),
|
||||||
CHSV(random8(), random8(160, 255), random8(128, 255)),
|
CHSV(random8(), random8(160, 255), random8(128, 255)),
|
||||||
CHSV(random8(), random8(160, 255), random8(128, 255)),
|
CHSV(random8(), random8(160, 255), random8(128, 255)),
|
||||||
CHSV(random8(), random8(160, 255), random8(128, 255)));
|
CHSV(random8(), random8(160, 255), random8(128, 255)));
|
||||||
_lastPaletteChange = millis();
|
_lastPaletteChange = millis();
|
||||||
|
timeSinceLastChange = 0;
|
||||||
}
|
}
|
||||||
targetPalette = randomPalette; break;
|
if (timeSinceLastChange <= 250) {
|
||||||
|
targetPalette = prevRandomPalette;
|
||||||
|
// there needs to be 255 palette blends (48) for full blend but that is too resource intensive
|
||||||
|
// so 128 is a compromise (we need to perform full blend of the two palettes as each segment can have random
|
||||||
|
// palette selected but only 2 static palettes are used)
|
||||||
|
size_t noOfBlends = ((128U * timeSinceLastChange) / 250U);
|
||||||
|
for (size_t i=0; i<noOfBlends; i++) nblendPaletteTowardPalette(targetPalette, randomPalette, 48);
|
||||||
|
} else {
|
||||||
|
targetPalette = randomPalette;
|
||||||
|
}
|
||||||
|
break;}
|
||||||
case 2: {//primary color only
|
case 2: {//primary color only
|
||||||
CRGB prim = gamma32(colors[0]);
|
CRGB prim = gamma32(colors[0]);
|
||||||
targetPalette = CRGBPalette16(prim); break;}
|
targetPalette = CRGBPalette16(prim); break;}
|
||||||
@ -294,7 +308,7 @@ void Segment::startTransition(uint16_t dur) {
|
|||||||
// starting a transition has to occur before change so we get current values 1st
|
// starting a transition has to occur before change so we get current values 1st
|
||||||
uint8_t _briT = currentBri(on ? opacity : 0);
|
uint8_t _briT = currentBri(on ? opacity : 0);
|
||||||
uint8_t _cctT = currentBri(cct, true);
|
uint8_t _cctT = currentBri(cct, true);
|
||||||
CRGBPalette16 _palT; loadPalette(_palT, palette);
|
CRGBPalette16 _palT = CRGBPalette16(DEFAULT_COLOR); loadPalette(_palT, palette);
|
||||||
uint8_t _modeP = mode;
|
uint8_t _modeP = mode;
|
||||||
uint32_t _colorT[NUM_COLORS];
|
uint32_t _colorT[NUM_COLORS];
|
||||||
for (size_t i=0; i<NUM_COLORS; i++) _colorT[i] = currentColor(i, colors[i]);
|
for (size_t i=0; i<NUM_COLORS; i++) _colorT[i] = currentColor(i, colors[i]);
|
||||||
@ -363,6 +377,42 @@ 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) {
|
||||||
|
//return if neither bounds nor grouping have changed
|
||||||
|
bool boundsUnchanged = (start == i1 && stop == i2);
|
||||||
|
#ifndef WLED_DISABLE_2D
|
||||||
|
if (Segment::maxHeight>1) boundsUnchanged &= (startY == i1Y && stopY == i2Y); // 2D
|
||||||
|
#endif
|
||||||
|
if (boundsUnchanged
|
||||||
|
&& (!grp || (grouping == grp && spacing == spc))
|
||||||
|
&& (ofs == UINT16_MAX || ofs == offset)) return;
|
||||||
|
|
||||||
|
if (stop) fill(BLACK); //turn old segment range off
|
||||||
|
if (i2 <= i1) { //disable segment
|
||||||
|
stop = 0;
|
||||||
|
markForReset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (i1 < Segment::maxWidth) start = i1; // Segment::maxWidth equals strip.getLengthTotal() for 1D
|
||||||
|
stop = i2 > Segment::maxWidth ? Segment::maxWidth : MAX(1,i2);
|
||||||
|
startY = 0;
|
||||||
|
stopY = 1;
|
||||||
|
#ifndef WLED_DISABLE_2D
|
||||||
|
if (Segment::maxHeight>1) { // 2D
|
||||||
|
if (i1Y < Segment::maxHeight) startY = i1Y;
|
||||||
|
stopY = i2Y > Segment::maxHeight ? Segment::maxHeight : MAX(1,i2Y);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (grp) {
|
||||||
|
grouping = grp;
|
||||||
|
spacing = spc;
|
||||||
|
}
|
||||||
|
if (ofs < UINT16_MAX) offset = ofs;
|
||||||
|
markForReset();
|
||||||
|
if (!boundsUnchanged) refreshLightCapabilities();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Segment::setColor(uint8_t slot, uint32_t c) { //returns true if changed
|
bool Segment::setColor(uint8_t slot, uint32_t c) { //returns true if changed
|
||||||
if (slot >= NUM_COLORS || c == colors[slot]) return false;
|
if (slot >= NUM_COLORS || c == colors[slot]) return false;
|
||||||
if (fadeTransition) startTransition(strip.getTransition()); // start transition prior to change
|
if (fadeTransition) startTransition(strip.getTransition()); // start transition prior to change
|
||||||
@ -409,18 +459,21 @@ void Segment::setMode(uint8_t fx, bool loadDefaults) {
|
|||||||
// load default values from effect string
|
// load default values from effect string
|
||||||
if (loadDefaults) {
|
if (loadDefaults) {
|
||||||
int16_t sOpt;
|
int16_t sOpt;
|
||||||
sOpt = extractModeDefaults(fx, "sx"); if (sOpt >= 0) speed = sOpt;
|
sOpt = extractModeDefaults(fx, "sx"); speed = (sOpt >= 0) ? sOpt : DEFAULT_SPEED;
|
||||||
sOpt = extractModeDefaults(fx, "ix"); if (sOpt >= 0) intensity = sOpt;
|
sOpt = extractModeDefaults(fx, "ix"); intensity = (sOpt >= 0) ? sOpt : DEFAULT_INTENSITY;
|
||||||
sOpt = extractModeDefaults(fx, "c1"); if (sOpt >= 0) custom1 = sOpt;
|
sOpt = extractModeDefaults(fx, "c1"); custom1 = (sOpt >= 0) ? sOpt : DEFAULT_C1;
|
||||||
sOpt = extractModeDefaults(fx, "c2"); if (sOpt >= 0) custom2 = sOpt;
|
sOpt = extractModeDefaults(fx, "c2"); custom2 = (sOpt >= 0) ? sOpt : DEFAULT_C2;
|
||||||
sOpt = extractModeDefaults(fx, "c3"); if (sOpt >= 0) custom3 = sOpt;
|
sOpt = extractModeDefaults(fx, "c3"); custom3 = (sOpt >= 0) ? sOpt : DEFAULT_C3;
|
||||||
|
sOpt = extractModeDefaults(fx, "o1"); check1 = (sOpt >= 0) ? (bool)sOpt : false;
|
||||||
|
sOpt = extractModeDefaults(fx, "o2"); check2 = (sOpt >= 0) ? (bool)sOpt : false;
|
||||||
|
sOpt = extractModeDefaults(fx, "o3"); check3 = (sOpt >= 0) ? (bool)sOpt : false;
|
||||||
sOpt = extractModeDefaults(fx, "m12"); if (sOpt >= 0) map1D2D = constrain(sOpt, 0, 7);
|
sOpt = extractModeDefaults(fx, "m12"); if (sOpt >= 0) map1D2D = constrain(sOpt, 0, 7);
|
||||||
sOpt = extractModeDefaults(fx, "si"); if (sOpt >= 0) soundSim = constrain(sOpt, 0, 7);
|
sOpt = extractModeDefaults(fx, "si"); if (sOpt >= 0) soundSim = constrain(sOpt, 0, 7);
|
||||||
sOpt = extractModeDefaults(fx, "rev"); if (sOpt >= 0) reverse = (bool)sOpt;
|
sOpt = extractModeDefaults(fx, "rev"); if (sOpt >= 0) reverse = (bool)sOpt;
|
||||||
sOpt = extractModeDefaults(fx, "mi"); if (sOpt >= 0) mirror = (bool)sOpt; // NOTE: setting this option is a risky business
|
sOpt = extractModeDefaults(fx, "mi"); if (sOpt >= 0) mirror = (bool)sOpt; // NOTE: setting this option is a risky business
|
||||||
sOpt = extractModeDefaults(fx, "rY"); if (sOpt >= 0) reverse_y = (bool)sOpt;
|
sOpt = extractModeDefaults(fx, "rY"); if (sOpt >= 0) reverse_y = (bool)sOpt;
|
||||||
sOpt = extractModeDefaults(fx, "mY"); if (sOpt >= 0) mirror_y = (bool)sOpt; // NOTE: setting this option is a risky business
|
sOpt = extractModeDefaults(fx, "mY"); if (sOpt >= 0) mirror_y = (bool)sOpt; // NOTE: setting this option is a risky business
|
||||||
sOpt = extractModeDefaults(fx, "pal"); if (sOpt >= 0) setPalette(sOpt);
|
sOpt = extractModeDefaults(fx, "pal"); if (sOpt >= 0) setPalette(sOpt); //else setPalette(0);
|
||||||
}
|
}
|
||||||
stateChanged = true; // send UDP/WS broadcast
|
stateChanged = true; // send UDP/WS broadcast
|
||||||
}
|
}
|
||||||
@ -524,6 +577,20 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col)
|
|||||||
int y = roundf(cos_t(rad) * i);
|
int y = roundf(cos_t(rad) * i);
|
||||||
setPixelColorXY(x, y, col);
|
setPixelColorXY(x, y, col);
|
||||||
}
|
}
|
||||||
|
// Bresenham’s Algorithm (may not fill every pixel)
|
||||||
|
//int d = 3 - (2*i);
|
||||||
|
//int y = i, x = 0;
|
||||||
|
//while (y >= x) {
|
||||||
|
// setPixelColorXY(x, y, col);
|
||||||
|
// setPixelColorXY(y, x, col);
|
||||||
|
// x++;
|
||||||
|
// if (d > 0) {
|
||||||
|
// y--;
|
||||||
|
// d += 4 * (x - y) + 10;
|
||||||
|
// } else {
|
||||||
|
// d += 4 * x + 6;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case M12_pCorner:
|
case M12_pCorner:
|
||||||
@ -546,6 +613,7 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col)
|
|||||||
|
|
||||||
uint16_t len = length();
|
uint16_t len = length();
|
||||||
uint8_t _bri_t = currentBri(on ? opacity : 0);
|
uint8_t _bri_t = currentBri(on ? opacity : 0);
|
||||||
|
if (!_bri_t && !transitional) return;
|
||||||
if (_bri_t < 255) {
|
if (_bri_t < 255) {
|
||||||
byte r = scale8(R(col), _bri_t);
|
byte r = scale8(R(col), _bri_t);
|
||||||
byte g = scale8(G(col), _bri_t);
|
byte g = scale8(G(col), _bri_t);
|
||||||
@ -689,7 +757,7 @@ void Segment::refreshLightCapabilities() {
|
|||||||
if (bus->getStart() + bus->getLength() <= start) continue;
|
if (bus->getStart() + bus->getLength() <= start) continue;
|
||||||
|
|
||||||
uint8_t type = bus->getType();
|
uint8_t type = bus->getType();
|
||||||
if (type == TYPE_ANALOG_1CH || (!cctFromRgb && type == TYPE_ANALOG_2CH)) capabilities &= 0xFE; // does not support RGB
|
if (type == TYPE_ONOFF || type == TYPE_ANALOG_1CH || (!cctFromRgb && type == TYPE_ANALOG_2CH)) capabilities &= 0xFE; // does not support RGB
|
||||||
if (bus->isRgbw()) capabilities |= 0x02; // segment supports white channel
|
if (bus->isRgbw()) capabilities |= 0x02; // segment supports white channel
|
||||||
if (!cctFromRgb) {
|
if (!cctFromRgb) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@ -698,7 +766,7 @@ void Segment::refreshLightCapabilities() {
|
|||||||
capabilities |= 0x04; //segment supports white CCT
|
capabilities |= 0x04; //segment supports white CCT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (correctWB && type != TYPE_ANALOG_1CH) capabilities |= 0x04; //white balance correction (uses CCT slider)
|
if (correctWB && !(type == TYPE_ANALOG_1CH || type == TYPE_ONOFF)) capabilities |= 0x04; //white balance correction (uses CCT slider)
|
||||||
uint8_t aWM = Bus::getAutoWhiteMode()<255 ? Bus::getAutoWhiteMode() : bus->getAWMode();
|
uint8_t aWM = Bus::getAutoWhiteMode()<255 ? Bus::getAutoWhiteMode() : bus->getAWMode();
|
||||||
bool whiteSlider = (aWM == RGBW_MODE_DUAL || aWM == RGBW_MODE_MANUAL_ONLY); // white slider allowed
|
bool whiteSlider = (aWM == RGBW_MODE_DUAL || aWM == RGBW_MODE_MANUAL_ONLY); // white slider allowed
|
||||||
if (bus->isRgbw() && (whiteSlider || !(capabilities & 0x01))) capabilities |= 0x08; // allow white channel adjustments (AWM allows or is not RGB)
|
if (bus->isRgbw() && (whiteSlider || !(capabilities & 0x01))) capabilities |= 0x08; // allow white channel adjustments (AWM allows or is not RGB)
|
||||||
@ -858,7 +926,7 @@ uint8_t Segment::get_random_wheel_index(uint8_t pos) {
|
|||||||
* Gets a single color from the currently selected palette.
|
* Gets a single color from the currently selected palette.
|
||||||
* @param i Palette Index (if mapping is true, the full palette will be _virtualSegmentLength long, if false, 255). Will wrap around automatically.
|
* @param i Palette Index (if mapping is true, the full palette will be _virtualSegmentLength long, if false, 255). Will wrap around automatically.
|
||||||
* @param mapping if true, LED position in segment is considered for color
|
* @param mapping if true, LED position in segment is considered for color
|
||||||
* @param wrap FastLED palettes will usally wrap back to the start smoothly. Set false to get a hard edge
|
* @param wrap FastLED palettes will usually wrap back to the start smoothly. Set false to get a hard edge
|
||||||
* @param mcol If the default palette 0 is selected, return the standard color 0, 1 or 2 instead. If >2, Party palette is used instead
|
* @param mcol If the default palette 0 is selected, return the standard color 0, 1 or 2 instead. If >2, Party palette is used instead
|
||||||
* @param pbri Value to scale the brightness of the returned color by. Default is 255. (no scaling)
|
* @param pbri Value to scale the brightness of the returned color by. Default is 255. (no scaling)
|
||||||
* @returns Single color from palette
|
* @returns Single color from palette
|
||||||
@ -914,13 +982,13 @@ void WS2812FX::finalizeInit(void)
|
|||||||
const uint8_t defNumBusses = ((sizeof defDataPins) / (sizeof defDataPins[0]));
|
const uint8_t defNumBusses = ((sizeof defDataPins) / (sizeof defDataPins[0]));
|
||||||
const uint8_t defNumCounts = ((sizeof defCounts) / (sizeof defCounts[0]));
|
const uint8_t defNumCounts = ((sizeof defCounts) / (sizeof defCounts[0]));
|
||||||
uint16_t prevLen = 0;
|
uint16_t prevLen = 0;
|
||||||
for (uint8_t i = 0; i < defNumBusses && i < WLED_MAX_BUSSES; i++) {
|
for (uint8_t i = 0; i < defNumBusses && i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) {
|
||||||
uint8_t defPin[] = {defDataPins[i]};
|
uint8_t defPin[] = {defDataPins[i]};
|
||||||
uint16_t start = prevLen;
|
uint16_t start = prevLen;
|
||||||
uint16_t count = defCounts[(i < defNumCounts) ? i : defNumCounts -1];
|
uint16_t count = defCounts[(i < defNumCounts) ? i : defNumCounts -1];
|
||||||
prevLen += count;
|
prevLen += count;
|
||||||
BusConfig defCfg = BusConfig(DEFAULT_LED_TYPE, defPin, start, count, DEFAULT_LED_COLOR_ORDER, false, 0, RGBW_MODE_MANUAL_ONLY);
|
BusConfig defCfg = BusConfig(DEFAULT_LED_TYPE, defPin, start, count, DEFAULT_LED_COLOR_ORDER, false, 0, RGBW_MODE_MANUAL_ONLY);
|
||||||
busses.add(defCfg);
|
if (busses.add(defCfg) == -1) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -944,6 +1012,11 @@ void WS2812FX::finalizeInit(void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isMatrix) { // if 2D then max values defined in setUpMatrix() using panel set-up
|
||||||
|
Segment::maxWidth = _length;
|
||||||
|
Segment::maxHeight = 1;
|
||||||
|
}
|
||||||
|
|
||||||
//initialize leds array. TBD: realloc if nr of leds change
|
//initialize leds array. TBD: realloc if nr of leds change
|
||||||
if (Segment::_globalLeds) {
|
if (Segment::_globalLeds) {
|
||||||
purgeSegments(true);
|
purgeSegments(true);
|
||||||
@ -1001,7 +1074,7 @@ void WS2812FX::service() {
|
|||||||
//if (seg.transitional && seg._modeP) (*_mode[seg._modeP])(progress());
|
//if (seg.transitional && seg._modeP) (*_mode[seg._modeP])(progress());
|
||||||
delay = (*_mode[seg.currentMode(seg.mode)])();
|
delay = (*_mode[seg.currentMode(seg.mode)])();
|
||||||
if (seg.mode != FX_MODE_HALLOWEEN_EYES) seg.call++;
|
if (seg.mode != FX_MODE_HALLOWEEN_EYES) seg.call++;
|
||||||
if (seg.transitional && delay > FRAMETIME) delay = FRAMETIME; // foce faster updates during transition
|
if (seg.transitional && delay > FRAMETIME) delay = FRAMETIME; // force faster updates during transition
|
||||||
|
|
||||||
seg.handleTransition();
|
seg.handleTransition();
|
||||||
}
|
}
|
||||||
@ -1306,54 +1379,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) {
|
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;
|
if (n >= _segments.size()) return;
|
||||||
Segment& seg = _segments[n];
|
_segments[n].set(i1, i2, grouping, spacing, offset, startY, stopY);
|
||||||
|
|
||||||
//return if neither bounds nor grouping have changed
|
|
||||||
bool boundsUnchanged = (seg.start == i1 && seg.stop == i2);
|
|
||||||
if (isMatrix) {
|
|
||||||
boundsUnchanged &= (seg.startY == startY && seg.stopY == stopY);
|
|
||||||
}
|
|
||||||
if (boundsUnchanged
|
|
||||||
&& (!grouping || (seg.grouping == grouping && seg.spacing == spacing))
|
|
||||||
&& (offset == UINT16_MAX || offset == seg.offset)) return;
|
|
||||||
|
|
||||||
//if (seg.stop) setRange(seg.start, seg.stop -1, BLACK); //turn old segment range off
|
|
||||||
if (seg.stop) seg.fill(BLACK); //turn old segment range off
|
|
||||||
if (i2 <= i1) //disable segment
|
|
||||||
{
|
|
||||||
// disabled segments should get removed using purgeSegments()
|
|
||||||
DEBUG_PRINT(F("-- Segment ")); DEBUG_PRINT(n); DEBUG_PRINTLN(F(" marked inactive."));
|
|
||||||
seg.stop = 0;
|
|
||||||
seg.options = 0b0000000000000101; // on & selected
|
|
||||||
//if (seg.name) {
|
|
||||||
// delete[] seg.name;
|
|
||||||
// seg.name = nullptr;
|
|
||||||
//}
|
|
||||||
// if main segment is deleted, set first active as main segment
|
|
||||||
if (n == _mainSegment) setMainSegmentId(0);
|
|
||||||
seg.markForReset();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (isMatrix) {
|
|
||||||
#ifndef WLED_DISABLE_2D
|
|
||||||
if (i1 < Segment::maxWidth) seg.start = i1;
|
|
||||||
seg.stop = i2 > Segment::maxWidth ? Segment::maxWidth : i2;
|
|
||||||
if (startY < Segment::maxHeight) seg.startY = startY;
|
|
||||||
seg.stopY = stopY > Segment::maxHeight ? Segment::maxHeight : MAX(1,stopY);
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
if (i1 < _length) seg.start = i1;
|
|
||||||
seg.stop = i2 > _length ? _length : i2;
|
|
||||||
seg.startY = 0;
|
|
||||||
seg.stopY = 1;
|
|
||||||
}
|
|
||||||
if (grouping) {
|
|
||||||
seg.grouping = grouping;
|
|
||||||
seg.spacing = spacing;
|
|
||||||
}
|
|
||||||
if (offset < UINT16_MAX) seg.offset = offset;
|
|
||||||
seg.markForReset();
|
|
||||||
if (!boundsUnchanged) seg.refreshLightCapabilities();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WS2812FX::restartRuntime() {
|
void WS2812FX::restartRuntime() {
|
||||||
@ -1511,7 +1537,19 @@ void WS2812FX::loadCustomPalettes()
|
|||||||
|
|
||||||
if (readObjectFromFile(fileName, nullptr, &pDoc)) {
|
if (readObjectFromFile(fileName, nullptr, &pDoc)) {
|
||||||
JsonArray pal = pDoc[F("palette")];
|
JsonArray pal = pDoc[F("palette")];
|
||||||
if (!pal.isNull() && pal.size()>7) { // not an empty palette (at least 2 entries)
|
if (!pal.isNull() && pal.size()>4) { // not an empty palette (at least 2 entries)
|
||||||
|
if (pal[0].is<int>() && pal[1].is<const char *>()) {
|
||||||
|
// we have an array of index & hex strings
|
||||||
|
size_t palSize = MIN(pal.size(), 36);
|
||||||
|
palSize -= palSize % 2; // make sure size is multiple of 2
|
||||||
|
for (size_t i=0, j=0; i<palSize && pal[i].as<int>()<256; i+=2, j+=4) {
|
||||||
|
uint8_t rgbw[] = {0,0,0,0};
|
||||||
|
tcp[ j ] = (uint8_t) pal[ i ].as<int>(); // index
|
||||||
|
colorFromHexString(rgbw, pal[i+1].as<const char *>()); // will catch non-string entires
|
||||||
|
for (size_t c=0; c<3; c++) tcp[j+1+c] = rgbw[c]; // only use RGB component
|
||||||
|
DEBUG_PRINTF("%d(%d) : %d %d %d\n", i, int(tcp[j]), int(tcp[j+1]), int(tcp[j+2]), int(tcp[j+3]));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
size_t palSize = MIN(pal.size(), 72);
|
size_t palSize = MIN(pal.size(), 72);
|
||||||
palSize -= palSize % 4; // make sure size is multiple of 4
|
palSize -= palSize % 4; // make sure size is multiple of 4
|
||||||
for (size_t i=0; i<palSize && pal[i].as<int>()<256; i+=4) {
|
for (size_t i=0; i<palSize && pal[i].as<int>()<256; i+=4) {
|
||||||
@ -1521,6 +1559,7 @@ void WS2812FX::loadCustomPalettes()
|
|||||||
tcp[i+3] = (uint8_t) pal[i+3].as<int>(); // B
|
tcp[i+3] = (uint8_t) pal[i+3].as<int>(); // B
|
||||||
DEBUG_PRINTF("%d(%d) : %d %d %d\n", i, int(tcp[i]), int(tcp[i+1]), int(tcp[i+2]), int(tcp[i+3]));
|
DEBUG_PRINTF("%d(%d) : %d %d %d\n", i, int(tcp[i]), int(tcp[i+1]), int(tcp[i+2]), int(tcp[i+3]));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
customPalettes.push_back(targetPalette.loadDynamicGradientPalette(tcp));
|
customPalettes.push_back(targetPalette.loadDynamicGradientPalette(tcp));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -685,8 +685,23 @@ class BusManager {
|
|||||||
return len*3; //RGB
|
return len*3; //RGB
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
int add(BusConfig &bc);
|
||||||
|
void removeAll(); //do not call this method from system context (network callback)
|
||||||
|
void setStatusPixel(uint32_t c);
|
||||||
|
void setPixelColor(uint16_t pix, uint32_t c, int16_t cct=-1);
|
||||||
|
void setBrightness(uint8_t b);
|
||||||
|
void setSegmentCCT(int16_t cct, bool allowWBCorrection = false);
|
||||||
|
uint32_t getPixelColor(uint16_t pix);
|
||||||
|
bool canAllShow();
|
||||||
|
Bus* getBus(uint8_t busNr);
|
||||||
|
void show();
|
||||||
|
uint16_t getTotalLength(); //semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit())
|
||||||
|
*/
|
||||||
|
// the following functions are inlined by compiler since they are defined within class definition
|
||||||
|
// they should be placed in cpp file instead
|
||||||
int add(BusConfig &bc) {
|
int add(BusConfig &bc) {
|
||||||
if (numBusses >= WLED_MAX_BUSSES) return -1;
|
if (getNumBusses() - getNumVirtualBusses() >= WLED_MAX_BUSSES) return -1;
|
||||||
if (bc.type >= TYPE_NET_DDP_RGB && bc.type < 96) {
|
if (bc.type >= TYPE_NET_DDP_RGB && bc.type < 96) {
|
||||||
busses[numBusses] = new BusNetwork(bc);
|
busses[numBusses] = new BusNetwork(bc);
|
||||||
} else if (IS_DIGITAL(bc.type)) {
|
} else if (IS_DIGITAL(bc.type)) {
|
||||||
@ -766,10 +781,6 @@ class BusManager {
|
|||||||
return busses[busNr];
|
return busses[busNr];
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint8_t getNumBusses() {
|
|
||||||
return numBusses;
|
|
||||||
}
|
|
||||||
|
|
||||||
//semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit())
|
//semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit())
|
||||||
uint16_t getTotalLength() {
|
uint16_t getTotalLength() {
|
||||||
uint16_t len = 0;
|
uint16_t len = 0;
|
||||||
@ -777,17 +788,27 @@ class BusManager {
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateColorOrderMap(const ColorOrderMap &com) {
|
inline void updateColorOrderMap(const ColorOrderMap &com) {
|
||||||
memcpy(&colorOrderMap, &com, sizeof(ColorOrderMap));
|
memcpy(&colorOrderMap, &com, sizeof(ColorOrderMap));
|
||||||
}
|
}
|
||||||
|
|
||||||
const ColorOrderMap& getColorOrderMap() const {
|
inline const ColorOrderMap& getColorOrderMap() const {
|
||||||
return colorOrderMap;
|
return colorOrderMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline uint8_t getNumBusses() {
|
||||||
|
return numBusses;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint8_t numBusses = 0;
|
uint8_t numBusses = 0;
|
||||||
Bus* busses[WLED_MAX_BUSSES];
|
Bus* busses[WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES];
|
||||||
ColorOrderMap colorOrderMap;
|
ColorOrderMap colorOrderMap;
|
||||||
|
|
||||||
|
inline uint8_t getNumVirtualBusses() {
|
||||||
|
int j = 0;
|
||||||
|
for (int i=0; i<numBusses; i++) if (busses[i]->getType() >= TYPE_NET_DDP_RGB && busses[i]->getType() < 96) j++;
|
||||||
|
return j;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
@ -97,32 +97,38 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
|||||||
JsonObject matrix = hw_led[F("matrix")];
|
JsonObject matrix = hw_led[F("matrix")];
|
||||||
if (!matrix.isNull()) {
|
if (!matrix.isNull()) {
|
||||||
strip.isMatrix = true;
|
strip.isMatrix = true;
|
||||||
CJSON(strip.panelH, matrix[F("ph")]);
|
CJSON(strip.panels, matrix[F("mpc")]);
|
||||||
CJSON(strip.panelW, matrix[F("pw")]);
|
|
||||||
CJSON(strip.hPanels, matrix[F("mph")]);
|
|
||||||
CJSON(strip.vPanels, matrix[F("mpv")]);
|
|
||||||
CJSON(strip.matrix.bottomStart, matrix[F("pb")]);
|
CJSON(strip.matrix.bottomStart, matrix[F("pb")]);
|
||||||
CJSON(strip.matrix.rightStart, matrix[F("pr")]);
|
CJSON(strip.matrix.rightStart, matrix[F("pr")]);
|
||||||
CJSON(strip.matrix.vertical, matrix[F("pv")]);
|
CJSON(strip.matrix.vertical, matrix[F("pv")]);
|
||||||
CJSON(strip.matrix.serpentine, matrix["ps"]);
|
CJSON(strip.matrix.serpentine, matrix["ps"]);
|
||||||
|
|
||||||
|
strip.panel.clear();
|
||||||
JsonArray panels = matrix[F("panels")];
|
JsonArray panels = matrix[F("panels")];
|
||||||
uint8_t s = 0;
|
uint8_t s = 0;
|
||||||
if (!panels.isNull()) {
|
if (!panels.isNull()) {
|
||||||
|
strip.panel.reserve(max(1U,min((size_t)strip.panels,(size_t)WLED_MAX_PANELS))); // pre-allocate memory for panels
|
||||||
for (JsonObject pnl : panels) {
|
for (JsonObject pnl : panels) {
|
||||||
CJSON(strip.panel[s].bottomStart, pnl["b"]);
|
WS2812FX::Panel p;
|
||||||
CJSON(strip.panel[s].rightStart, pnl["r"]);
|
CJSON(p.bottomStart, pnl["b"]);
|
||||||
CJSON(strip.panel[s].vertical, pnl["v"]);
|
CJSON(p.rightStart, pnl["r"]);
|
||||||
CJSON(strip.panel[s].serpentine, pnl["s"]);
|
CJSON(p.vertical, pnl["v"]);
|
||||||
if (++s >= WLED_MAX_PANELS) break; // max panels reached
|
CJSON(p.serpentine, pnl["s"]);
|
||||||
|
CJSON(p.xOffset, pnl["x"]);
|
||||||
|
CJSON(p.yOffset, pnl["y"]);
|
||||||
|
CJSON(p.height, pnl["h"]);
|
||||||
|
CJSON(p.width, pnl["w"]);
|
||||||
|
strip.panel.push_back(p);
|
||||||
|
if (++s >= WLED_MAX_PANELS || s >= strip.panels) break; // max panels reached
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
// clear remaining panels
|
// fallback
|
||||||
for (; s<WLED_MAX_PANELS; s++) {
|
WS2812FX::Panel p;
|
||||||
strip.panel[s].bottomStart = 0;
|
strip.panels = 1;
|
||||||
strip.panel[s].rightStart = 0;
|
p.height = p.width = 8;
|
||||||
strip.panel[s].vertical = 0;
|
p.xOffset = p.yOffset = 0;
|
||||||
strip.panel[s].serpentine = 0;
|
p.options = 0;
|
||||||
|
strip.panel.push_back(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
strip.setUpMatrix();
|
strip.setUpMatrix();
|
||||||
@ -137,7 +143,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
|||||||
uint32_t mem = 0;
|
uint32_t mem = 0;
|
||||||
bool busesChanged = false;
|
bool busesChanged = false;
|
||||||
for (JsonObject elm : ins) {
|
for (JsonObject elm : ins) {
|
||||||
if (s >= WLED_MAX_BUSSES) break;
|
if (s >= WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES) break;
|
||||||
uint8_t pins[5] = {255, 255, 255, 255, 255};
|
uint8_t pins[5] = {255, 255, 255, 255, 255};
|
||||||
JsonArray pinArr = elm["pin"];
|
JsonArray pinArr = elm["pin"];
|
||||||
if (pinArr.size() == 0) continue;
|
if (pinArr.size() == 0) continue;
|
||||||
@ -161,7 +167,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
|||||||
if (fromFS) {
|
if (fromFS) {
|
||||||
BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode);
|
BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode);
|
||||||
mem += BusManager::memUsage(bc);
|
mem += BusManager::memUsage(bc);
|
||||||
if (mem <= MAX_LED_MEMORY && busses.getNumBusses() <= WLED_MAX_BUSSES) busses.add(bc); // finalization will be done in WLED::beginStrip()
|
if (mem <= MAX_LED_MEMORY) if (busses.add(bc) == -1) break; // finalization will be done in WLED::beginStrip()
|
||||||
} else {
|
} else {
|
||||||
if (busConfigs[s] != nullptr) delete busConfigs[s];
|
if (busConfigs[s] != nullptr) delete busConfigs[s];
|
||||||
busConfigs[s] = new BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode);
|
busConfigs[s] = new BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode);
|
||||||
@ -192,9 +198,8 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
|||||||
|
|
||||||
// read multiple button configuration
|
// read multiple button configuration
|
||||||
JsonObject btn_obj = hw["btn"];
|
JsonObject btn_obj = hw["btn"];
|
||||||
int pull = -1; // trick for inverted setting
|
bool pull = btn_obj[F("pull")] | (!disablePullUp); // if true, pullup is enabled
|
||||||
CJSON(pull, btn_obj[F("pull")]);
|
disablePullUp = !pull;
|
||||||
if (pull>=0) disablePullUp = pull;
|
|
||||||
JsonArray hw_btn_ins = btn_obj[F("ins")];
|
JsonArray hw_btn_ins = btn_obj[F("ins")];
|
||||||
if (!hw_btn_ins.isNull()) {
|
if (!hw_btn_ins.isNull()) {
|
||||||
uint8_t s = 0;
|
uint8_t s = 0;
|
||||||
@ -702,22 +707,23 @@ void serializeConfig() {
|
|||||||
// 2D Matrix Settings
|
// 2D Matrix Settings
|
||||||
if (strip.isMatrix) {
|
if (strip.isMatrix) {
|
||||||
JsonObject matrix = hw_led.createNestedObject(F("matrix"));
|
JsonObject matrix = hw_led.createNestedObject(F("matrix"));
|
||||||
matrix[F("ph")] = strip.panelH;
|
matrix[F("mpc")] = strip.panels;
|
||||||
matrix[F("pw")] = strip.panelW;
|
|
||||||
matrix[F("mph")] = strip.hPanels;
|
|
||||||
matrix[F("mpv")] = strip.vPanels;
|
|
||||||
matrix[F("pb")] = strip.matrix.bottomStart;
|
matrix[F("pb")] = strip.matrix.bottomStart;
|
||||||
matrix[F("pr")] = strip.matrix.rightStart;
|
matrix[F("pr")] = strip.matrix.rightStart;
|
||||||
matrix[F("pv")] = strip.matrix.vertical;
|
matrix[F("pv")] = strip.matrix.vertical;
|
||||||
matrix["ps"] = strip.matrix.serpentine;
|
matrix["ps"] = strip.matrix.serpentine;
|
||||||
|
|
||||||
JsonArray panels = matrix.createNestedArray(F("panels"));
|
JsonArray panels = matrix.createNestedArray(F("panels"));
|
||||||
for (uint8_t i=0; i<strip.hPanels*strip.vPanels; i++) {
|
for (uint8_t i=0; i<strip.panel.size(); i++) {
|
||||||
JsonObject pnl = panels.createNestedObject();
|
JsonObject pnl = panels.createNestedObject();
|
||||||
pnl["b"] = strip.panel[i].bottomStart;
|
pnl["b"] = strip.panel[i].bottomStart;
|
||||||
pnl["r"] = strip.panel[i].rightStart;
|
pnl["r"] = strip.panel[i].rightStart;
|
||||||
pnl["v"] = strip.panel[i].vertical;
|
pnl["v"] = strip.panel[i].vertical;
|
||||||
pnl["s"] = strip.panel[i].serpentine;
|
pnl["s"] = strip.panel[i].serpentine;
|
||||||
|
pnl["x"] = strip.panel[i].xOffset;
|
||||||
|
pnl["y"] = strip.panel[i].yOffset;
|
||||||
|
pnl["h"] = strip.panel[i].height;
|
||||||
|
pnl["w"] = strip.panel[i].width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -25,25 +25,44 @@
|
|||||||
#ifndef WLED_MAX_BUSSES
|
#ifndef WLED_MAX_BUSSES
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
#define WLED_MAX_BUSSES 3
|
#define WLED_MAX_BUSSES 3
|
||||||
|
#define WLED_MIN_VIRTUAL_BUSSES 2
|
||||||
#else
|
#else
|
||||||
#if defined(CONFIG_IDF_TARGET_ESP32C3) // 2 RMT, 6 LEDC, only has 1 I2S but NPB does not support it ATM
|
#if defined(CONFIG_IDF_TARGET_ESP32C3) // 2 RMT, 6 LEDC, only has 1 I2S but NPB does not support it ATM
|
||||||
#define WLED_MAX_BUSSES 3 // will allow 2 digital & 1 analog (or the other way around)
|
#define WLED_MAX_BUSSES 3 // will allow 2 digital & 1 analog (or the other way around)
|
||||||
|
#define WLED_MIN_VIRTUAL_BUSSES 3
|
||||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2) // 4 RMT, 8 LEDC, only has 1 I2S bus, supported in NPB
|
#elif defined(CONFIG_IDF_TARGET_ESP32S2) // 4 RMT, 8 LEDC, only has 1 I2S bus, supported in NPB
|
||||||
#if defined(USERMOD_AUDIOREACTIVE) // requested by @softhack007 https://github.com/blazoncek/WLED/issues/33
|
#if defined(USERMOD_AUDIOREACTIVE) // requested by @softhack007 https://github.com/blazoncek/WLED/issues/33
|
||||||
#define WLED_MAX_BUSSES 6 // will allow 4 digital & 2 analog
|
#define WLED_MAX_BUSSES 6 // will allow 4 digital & 2 analog
|
||||||
|
#define WLED_MIN_VIRTUAL_BUSSES 4
|
||||||
#else
|
#else
|
||||||
#define WLED_MAX_BUSSES 7 // will allow 5 digital & 2 analog
|
#define WLED_MAX_BUSSES 7 // will allow 5 digital & 2 analog
|
||||||
|
#define WLED_MIN_VIRTUAL_BUSSES 3
|
||||||
#endif
|
#endif
|
||||||
#elif defined(CONFIG_IDF_TARGET_ESP32S3) // 4 RMT, 8 LEDC, has 2 I2S but NPB does not support them ATM
|
#elif defined(CONFIG_IDF_TARGET_ESP32S3) // 4 RMT, 8 LEDC, has 2 I2S but NPB does not support them ATM
|
||||||
#define WLED_MAX_BUSSES 6 // will allow 4 digital & 2 analog
|
#define WLED_MAX_BUSSES 6 // will allow 4 digital & 2 analog
|
||||||
|
#define WLED_MIN_VIRTUAL_BUSSES 4
|
||||||
#else
|
#else
|
||||||
#if defined(USERMOD_AUDIOREACTIVE) // requested by @softhack007 https://github.com/blazoncek/WLED/issues/33
|
#if defined(USERMOD_AUDIOREACTIVE) // requested by @softhack007 https://github.com/blazoncek/WLED/issues/33
|
||||||
#define WLED_MAX_BUSSES 8
|
#define WLED_MAX_BUSSES 8
|
||||||
|
#define WLED_MIN_VIRTUAL_BUSSES 2
|
||||||
#else
|
#else
|
||||||
#define WLED_MAX_BUSSES 10
|
#define WLED_MAX_BUSSES 10
|
||||||
|
#define WLED_MIN_VIRTUAL_BUSSES 0
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
#else
|
||||||
|
#ifdef ESP8266
|
||||||
|
#if WLED_MAX_BUSES > 5
|
||||||
|
#error Maximum number of buses is 5.
|
||||||
|
#endif
|
||||||
|
#define WLED_MIN_VIRTUAL_BUSSES (5-WLED_MAX_BUSSES)
|
||||||
|
#else
|
||||||
|
#if WLED_MAX_BUSES > 10
|
||||||
|
#error Maximum number of buses is 10.
|
||||||
|
#endif
|
||||||
|
#define WLED_MIN_VIRTUAL_BUSSES (10-WLED_MAX_BUSSES)
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef WLED_MAX_BUTTONS
|
#ifndef WLED_MAX_BUTTONS
|
||||||
@ -79,7 +98,7 @@
|
|||||||
#define USERMOD_ID_RTC 15 //Usermod "usermod_rtc.h"
|
#define USERMOD_ID_RTC 15 //Usermod "usermod_rtc.h"
|
||||||
#define USERMOD_ID_ELEKSTUBE_IPS 16 //Usermod "usermod_elekstube_ips.h"
|
#define USERMOD_ID_ELEKSTUBE_IPS 16 //Usermod "usermod_elekstube_ips.h"
|
||||||
#define USERMOD_ID_SN_PHOTORESISTOR 17 //Usermod "usermod_sn_photoresistor.h"
|
#define USERMOD_ID_SN_PHOTORESISTOR 17 //Usermod "usermod_sn_photoresistor.h"
|
||||||
#define USERMOD_ID_BATTERY_STATUS_BASIC 18 //Usermod "usermod_v2_battery_status_basic.h"
|
#define USERMOD_ID_BATTERY 18 //Usermod "usermod_v2_battery.h"
|
||||||
#define USERMOD_ID_PWM_FAN 19 //Usermod "usermod_PWM_fan.h"
|
#define USERMOD_ID_PWM_FAN 19 //Usermod "usermod_PWM_fan.h"
|
||||||
#define USERMOD_ID_BH1750 20 //Usermod "usermod_bh1750.h"
|
#define USERMOD_ID_BH1750 20 //Usermod "usermod_bh1750.h"
|
||||||
#define USERMOD_ID_SEVEN_SEGMENT_DISPLAY 21 //Usermod "usermod_v2_seven_segment_display.h"
|
#define USERMOD_ID_SEVEN_SEGMENT_DISPLAY 21 //Usermod "usermod_v2_seven_segment_display.h"
|
||||||
|
@ -436,6 +436,9 @@ button {
|
|||||||
left: 50%;
|
left: 50%;
|
||||||
margin-left: -92px;
|
margin-left: -92px;
|
||||||
|
|
||||||
|
/* Ensure tooltip goes away when mouse leaves control */
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
/* Fade in tooltip */
|
/* Fade in tooltip */
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: opacity 0.75s;
|
transition: opacity 0.75s;
|
||||||
|
@ -273,9 +273,9 @@ function onLoad()
|
|||||||
function updateTablinks(tabI)
|
function updateTablinks(tabI)
|
||||||
{
|
{
|
||||||
var tablinks = gEBCN("tablinks");
|
var tablinks = gEBCN("tablinks");
|
||||||
for (var i of tablinks) i.classList.remove("active");
|
for (var i of tablinks) i.classList.remove('active');
|
||||||
if (pcMode) return;
|
if (pcMode) return;
|
||||||
tablinks[tabI].classList.add("active");
|
tablinks[tabI].classList.add('active');
|
||||||
}
|
}
|
||||||
|
|
||||||
function openTab(tabI, force = false)
|
function openTab(tabI, force = false)
|
||||||
@ -291,13 +291,13 @@ var timeout;
|
|||||||
function showToast(text, error = false)
|
function showToast(text, error = false)
|
||||||
{
|
{
|
||||||
if (error) gId('connind').style.backgroundColor = "var(--c-r)";
|
if (error) gId('connind').style.backgroundColor = "var(--c-r)";
|
||||||
var x = gId("toast");
|
var x = gId('toast');
|
||||||
//if (error) text += '<i class="icons btn-icon" style="transform:rotate(45deg);position:absolute;top:10px;right:0px;" onclick="clearErrorToast(100);"></i>';
|
//if (error) text += '<i class="icons btn-icon" style="transform:rotate(45deg);position:absolute;top:10px;right:0px;" onclick="clearErrorToast(100);"></i>';
|
||||||
x.innerHTML = text;
|
x.innerHTML = text;
|
||||||
x.classList.add(error ? "error":"show");
|
x.classList.add(error ? 'error':'show');
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
x.style.animation = 'none';
|
x.style.animation = 'none';
|
||||||
timeout = setTimeout(()=>{ x.classList.remove("show"); }, 2900);
|
timeout = setTimeout(()=>{ x.classList.remove('show'); }, 2900);
|
||||||
if (error) console.log(text);
|
if (error) console.log(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,12 +308,12 @@ function showErrorToast()
|
|||||||
|
|
||||||
function clearErrorToast(n=5000)
|
function clearErrorToast(n=5000)
|
||||||
{
|
{
|
||||||
var x = gId("toast");
|
var x = gId('toast');
|
||||||
if (x.classList.contains("error")) {
|
if (x.classList.contains('error')) {
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
timeout = setTimeout(()=>{
|
timeout = setTimeout(()=>{
|
||||||
x.classList.remove("show");
|
x.classList.remove('show');
|
||||||
x.classList.remove("error");
|
x.classList.remove('error');
|
||||||
}, n);
|
}, n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -544,8 +544,8 @@ function populateQL()
|
|||||||
for (var key of (pQL||[])) {
|
for (var key of (pQL||[])) {
|
||||||
cn += `<button class="btn btn-xs psts" id="p${key[0]}qlb" title="${key[2]?key[2]:''}" onclick="setPreset(${key[0]});">${key[1]}</button>`;
|
cn += `<button class="btn btn-xs psts" id="p${key[0]}qlb" title="${key[2]?key[2]:''}" onclick="setPreset(${key[0]});">${key[1]}</button>`;
|
||||||
}
|
}
|
||||||
gId('pql').classList.add("expanded");
|
gId('pql').classList.add('expanded');
|
||||||
} else gId('pql').classList.remove("expanded");
|
} else gId('pql').classList.remove('expanded');
|
||||||
gId('pql').innerHTML = cn;
|
gId('pql').innerHTML = cn;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -610,8 +610,8 @@ function parseInfo(i) {
|
|||||||
mh = i.leds.matrix ? i.leds.matrix.h : 0;
|
mh = i.leds.matrix ? i.leds.matrix.h : 0;
|
||||||
isM = mw>0 && mh>0;
|
isM = mw>0 && mh>0;
|
||||||
if (!isM) {
|
if (!isM) {
|
||||||
gId("filter1D").classList.add("hide");
|
gId("filter1D").classList.add('hide');
|
||||||
//gId("filter2D").classList.add("hide");
|
//gId("filter2D").classList.add('hide');
|
||||||
hideModes("2D");
|
hideModes("2D");
|
||||||
}
|
}
|
||||||
// if (i.noaudio) {
|
// if (i.noaudio) {
|
||||||
@ -697,7 +697,7 @@ function populateSegments(s)
|
|||||||
if (i > lSeg) lSeg = i;
|
if (i > lSeg) lSeg = i;
|
||||||
|
|
||||||
let sg = gId(`seg${i}`);
|
let sg = gId(`seg${i}`);
|
||||||
let exp = sg ? (sg.classList.contains("expanded") || (i===0 && cfg.comp.segexp)) : false;
|
let exp = sg ? (sg.classList.contains('expanded') || (i===0 && cfg.comp.segexp)) : false;
|
||||||
|
|
||||||
let segp = `<div id="segp${i}" class="sbs">
|
let segp = `<div id="segp${i}" class="sbs">
|
||||||
<i class="icons e-icon pwr ${inst.on ? "act":""}" id="seg${i}pwr" onclick="setSegPwr(${i})"></i>
|
<i class="icons e-icon pwr ${inst.on ? "act":""}" id="seg${i}pwr" onclick="setSegPwr(${i})"></i>
|
||||||
@ -807,14 +807,14 @@ function populateSegments(s)
|
|||||||
if (!isM && !noNewSegs && (cfg.comp.seglen?parseInt(gId(`seg${lSeg}s`).value):0)+parseInt(gId(`seg${lSeg}e`).value)<ledCount) gId(`segr${lSeg}`).style.display = "inline";
|
if (!isM && !noNewSegs && (cfg.comp.seglen?parseInt(gId(`seg${lSeg}s`).value):0)+parseInt(gId(`seg${lSeg}e`).value)<ledCount) gId(`segr${lSeg}`).style.display = "inline";
|
||||||
gId('segutil2').style.display = (segCount > 1) ? "block":"none"; // rsbtn parent
|
gId('segutil2').style.display = (segCount > 1) ? "block":"none"; // rsbtn parent
|
||||||
|
|
||||||
if (Array.isArray(li.maps) && li.maps.length>1) {
|
if (!isM && Array.isArray(li.maps) && li.maps.length>1) {
|
||||||
let cont = `Ledmap: <select class="sel-sg" onchange="requestJson({'ledmap':parseInt(this.value)})"><option value="" selected>Unchanged</option>`;
|
let cont = `Ledmap: <select class="sel-sg" onchange="requestJson({'ledmap':parseInt(this.value)})"><option value="" selected>Unchanged</option>`;
|
||||||
for (const k of (li.maps||[])) cont += `<option value="${k}">${k==0?'Default':'ledmap'+k+'.json'}</option>`;
|
for (const k of (li.maps||[])) cont += `<option value="${k}">${k==0?'Default':'ledmap'+k+'.json'}</option>`;
|
||||||
cont += "</select></div>";
|
cont += "</select></div>";
|
||||||
gId("ledmap").innerHTML = cont;
|
gId("ledmap").innerHTML = cont;
|
||||||
gId("ledmap").classList.remove("hide");
|
gId("ledmap").classList.remove('hide');
|
||||||
} else {
|
} else {
|
||||||
gId("ledmap").classList.add("hide");
|
gId("ledmap").classList.add('hide');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -837,7 +837,7 @@ function populateEffects()
|
|||||||
});
|
});
|
||||||
|
|
||||||
for (let ef of effects) {
|
for (let ef of effects) {
|
||||||
// WLEDSR: add slider and color control to setFX (used by requestjson)
|
// add slider and color control to setFX (used by requestjson)
|
||||||
let id = ef.id;
|
let id = ef.id;
|
||||||
let nm = ef.name+" ";
|
let nm = ef.name+" ";
|
||||||
let fd = "";
|
let fd = "";
|
||||||
@ -1057,20 +1057,20 @@ function updateLen(s)
|
|||||||
let tPL = gId(`seg${s}lbtm`);
|
let tPL = gId(`seg${s}lbtm`);
|
||||||
if (stop-start>1 && stopY-startY>1) {
|
if (stop-start>1 && stopY-startY>1) {
|
||||||
// 2D segment
|
// 2D segment
|
||||||
if (tPL) tPL.classList.remove("hide"); // unhide transpose checkbox
|
if (tPL) tPL.classList.remove('hide'); // unhide transpose checkbox
|
||||||
let sE = gId('fxlist').querySelector(`.lstI[data-id="${selectedFx}"]`);
|
let sE = gId('fxlist').querySelector(`.lstI[data-id="${selectedFx}"]`);
|
||||||
if (sE) {
|
if (sE) {
|
||||||
let sN = sE.querySelector(".lstIname").innerText;
|
let sN = sE.querySelector(".lstIname").innerText;
|
||||||
let seg = gId(`seg${s}map2D`);
|
let seg = gId(`seg${s}map2D`);
|
||||||
if (seg) {
|
if (seg) {
|
||||||
if(sN.indexOf("\u25A6")<0) seg.classList.remove("hide"); // unhide mapping for 1D effects (| in name)
|
if(sN.indexOf("\u25A6")<0) seg.classList.remove('hide'); // unhide mapping for 1D effects (| in name)
|
||||||
else seg.classList.add("hide"); // hide mapping otherwise
|
else seg.classList.add('hide'); // hide mapping otherwise
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 1D segment in 2D set-up
|
// 1D segment in 2D set-up
|
||||||
if (tPL) {
|
if (tPL) {
|
||||||
tPL.classList.add("hide"); // hide transpose checkbox
|
tPL.classList.add('hide'); // hide transpose checkbox
|
||||||
gId(`seg${s}tp`).checked = false; // and uncheck it
|
gId(`seg${s}tp`).checked = false; // and uncheck it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1102,7 +1102,7 @@ function updatePA()
|
|||||||
ps = gEBCN("psts"); for (let p of ps) p.classList.remove('selected');
|
ps = gEBCN("psts"); for (let p of ps) p.classList.remove('selected');
|
||||||
if (currentPreset > 0) {
|
if (currentPreset > 0) {
|
||||||
var acv = gId(`p${currentPreset}o`);
|
var acv = gId(`p${currentPreset}o`);
|
||||||
if (acv /*&& !acv.classList.contains("expanded")*/) {
|
if (acv /*&& !acv.classList.contains('expanded')*/) {
|
||||||
acv.classList.add('selected');
|
acv.classList.add('selected');
|
||||||
/*
|
/*
|
||||||
// scroll selected preset into view (on WS refresh)
|
// scroll selected preset into view (on WS refresh)
|
||||||
@ -1119,13 +1119,13 @@ function updatePA()
|
|||||||
|
|
||||||
function updateUI()
|
function updateUI()
|
||||||
{
|
{
|
||||||
gId('buttonPower').className = (isOn) ? "active":"";
|
gId('buttonPower').className = (isOn) ? 'active':'';
|
||||||
gId('buttonNl').className = (nlA) ? "active":"";
|
gId('buttonNl').className = (nlA) ? 'active':'';
|
||||||
gId('buttonSync').className = (syncSend) ? "active":"";
|
gId('buttonSync').className = (syncSend) ? 'active':'';
|
||||||
showNodes();
|
showNodes();
|
||||||
|
|
||||||
updateSelectedPalette();
|
|
||||||
updateSelectedFx();
|
updateSelectedFx();
|
||||||
|
updateSelectedPalette(selectedPal); // must be after updateSelectedFx() to un-hide color slots for * palettes
|
||||||
|
|
||||||
updateTrail(gId('sliderBri'));
|
updateTrail(gId('sliderBri'));
|
||||||
updateTrail(gId('sliderSpeed'));
|
updateTrail(gId('sliderSpeed'));
|
||||||
@ -1159,17 +1159,27 @@ function updateUI()
|
|||||||
updatePSliders();
|
updatePSliders();
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateSelectedPalette()
|
function updateSelectedPalette(s)
|
||||||
{
|
{
|
||||||
var parent = gId('pallist');
|
var parent = gId('pallist');
|
||||||
var selPaletteInput = parent.querySelector(`input[name="palette"][value="${selectedPal}"]`);
|
var selPaletteInput = parent.querySelector(`input[name="palette"][value="${s}"]`);
|
||||||
if (selPaletteInput) selPaletteInput.checked = true;
|
if (selPaletteInput) selPaletteInput.checked = true;
|
||||||
|
|
||||||
var selElement = parent.querySelector('.selected');
|
var selElement = parent.querySelector('.selected');
|
||||||
if (selElement) selElement.classList.remove('selected');
|
if (selElement) selElement.classList.remove('selected');
|
||||||
|
|
||||||
var selectedPalette = parent.querySelector(`.lstI[data-id="${selectedPal}"]`);
|
var selectedPalette = parent.querySelector(`.lstI[data-id="${s}"]`);
|
||||||
if (selectedPalette) parent.querySelector(`.lstI[data-id="${selectedPal}"]`).classList.add('selected');
|
if (selectedPalette) parent.querySelector(`.lstI[data-id="${s}"]`).classList.add('selected');
|
||||||
|
|
||||||
|
// in case of special palettes (* Colors...), force show color selectors (if hidden by effect data)
|
||||||
|
let cd = gId('csl').children; // color selectors
|
||||||
|
if (s > 1 && s < 6) {
|
||||||
|
cd[0].classList.remove('hide'); // * Color 1
|
||||||
|
if (s > 2) cd[1].classList.remove('hide'); // * Color 1 & 2
|
||||||
|
if (s == 5) cd[2].classList.remove('hide'); // all colors
|
||||||
|
} else {
|
||||||
|
for (let i of cd) if (i.dataset.hide == '1') i.classList.add('hide');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateSelectedFx()
|
function updateSelectedFx()
|
||||||
@ -1191,9 +1201,9 @@ function updateSelectedFx()
|
|||||||
|
|
||||||
var selectedName = selectedEffect.querySelector(".lstIname").innerText;
|
var selectedName = selectedEffect.querySelector(".lstIname").innerText;
|
||||||
var segs = gId("segcont").querySelectorAll(`div[data-map="map2D"]`);
|
var segs = gId("segcont").querySelectorAll(`div[data-map="map2D"]`);
|
||||||
for (const seg of segs) if (selectedName.indexOf("\u25A6")<0) seg.classList.remove("hide"); else seg.classList.add("hide");
|
for (const seg of segs) if (selectedName.indexOf("\u25A6")<0) seg.classList.remove('hide'); else seg.classList.add('hide');
|
||||||
var segs = gId("segcont").querySelectorAll(`div[data-snd="si"]`);
|
var segs = gId("segcont").querySelectorAll(`div[data-snd="si"]`);
|
||||||
for (const seg of segs) if (selectedName.indexOf("\u266A")<0 && selectedName.indexOf("\266B")<0) seg.classList.add("hide"); else seg.classList.remove("hide"); // also "♫ "?
|
for (const seg of segs) if (selectedName.indexOf("\u266A")<0 && selectedName.indexOf("\266B")<0) seg.classList.add('hide'); else seg.classList.remove('hide'); // also "♫ "?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1352,7 +1362,7 @@ function readState(s,command=false)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// WLEDSR: control HTML elements for Slider and Color Control
|
// control HTML elements for Slider and Color Control (original ported form WLED-SR)
|
||||||
// Technical notes
|
// Technical notes
|
||||||
// ===============
|
// ===============
|
||||||
// If an effect name is followed by an @, slider and color control is effective.
|
// If an effect name is followed by an @, slider and color control is effective.
|
||||||
@ -1394,9 +1404,9 @@ function setEffectParameters(idx)
|
|||||||
else if (i==0) label.innerHTML = "Effect speed";
|
else if (i==0) label.innerHTML = "Effect speed";
|
||||||
else if (i==1) label.innerHTML = "Effect intensity";
|
else if (i==1) label.innerHTML = "Effect intensity";
|
||||||
else label.innerHTML = "Custom" + (i-1);
|
else label.innerHTML = "Custom" + (i-1);
|
||||||
slider.classList.remove("hide");
|
slider.classList.remove('hide');
|
||||||
} else {
|
} else {
|
||||||
slider.classList.add("hide");
|
slider.classList.add('hide');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (slOnOff.length>5) { // up to 3 checkboxes
|
if (slOnOff.length>5) { // up to 3 checkboxes
|
||||||
@ -1422,14 +1432,14 @@ function setEffectParameters(idx)
|
|||||||
// set html color items on/off
|
// set html color items on/off
|
||||||
var cslLabel = '';
|
var cslLabel = '';
|
||||||
var sep = '';
|
var sep = '';
|
||||||
var hide = true;
|
|
||||||
var cslCnt = 0, oCsel = csel;
|
var cslCnt = 0, oCsel = csel;
|
||||||
for (let i=0; i<gId("csl").children.length; i++) {
|
for (let i=0; i<gId("csl").children.length; i++) {
|
||||||
var btn = gId("csl" + i);
|
var btn = gId("csl" + i);
|
||||||
// if no controlDefined or coOnOff has a value
|
// if no controlDefined or coOnOff has a value
|
||||||
if (coOnOff.length>i && coOnOff[i] != "") {
|
if (coOnOff.length>i && coOnOff[i] != "") {
|
||||||
btn.style.display = "inline";
|
btn.classList.remove('hide');
|
||||||
if (coOnOff.length>i && coOnOff[i] != "!") {
|
btn.dataset.hide = 0;
|
||||||
|
if (coOnOff[i] != "!") {
|
||||||
var abbreviation = coOnOff[i].substr(0,2);
|
var abbreviation = coOnOff[i].substr(0,2);
|
||||||
btn.innerHTML = abbreviation;
|
btn.innerHTML = abbreviation;
|
||||||
if (abbreviation != coOnOff[i]) {
|
if (abbreviation != coOnOff[i]) {
|
||||||
@ -1440,17 +1450,18 @@ function setEffectParameters(idx)
|
|||||||
else if (i==0) btn.innerHTML = "Fx";
|
else if (i==0) btn.innerHTML = "Fx";
|
||||||
else if (i==1) btn.innerHTML = "Bg";
|
else if (i==1) btn.innerHTML = "Bg";
|
||||||
else btn.innerHTML = "Cs";
|
else btn.innerHTML = "Cs";
|
||||||
hide = false;
|
|
||||||
if (!cslCnt || oCsel==i) selectSlot(i); // select 1st displayed slot or old one
|
if (!cslCnt || oCsel==i) selectSlot(i); // select 1st displayed slot or old one
|
||||||
cslCnt++;
|
cslCnt++;
|
||||||
} else if (!controlDefined) { // if no controls then all buttons should be shown for color 1..3
|
} else if (!controlDefined) { // if no controls then all buttons should be shown for color 1..3
|
||||||
btn.style.display = "inline";
|
btn.classList.remove('hide');
|
||||||
|
btn.dataset.hide = 0;
|
||||||
btn.innerHTML = `${i+1}`;
|
btn.innerHTML = `${i+1}`;
|
||||||
hide = false;
|
|
||||||
if (!cslCnt || oCsel==i) selectSlot(i); // select 1st displayed slot or old one
|
if (!cslCnt || oCsel==i) selectSlot(i); // select 1st displayed slot or old one
|
||||||
cslCnt++;
|
cslCnt++;
|
||||||
} else {
|
} else {
|
||||||
btn.style.display = "none";
|
btn.classList.add('hide');
|
||||||
|
btn.dataset.hide = 1;
|
||||||
|
btn.innerHTML = `${i+1}`; // name hidden buttons 1..3 for * palettes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gId("cslLabel").innerHTML = cslLabel;
|
gId("cslLabel").innerHTML = cslLabel;
|
||||||
@ -1475,12 +1486,13 @@ function setEffectParameters(idx)
|
|||||||
palw.style.display = "none";
|
palw.style.display = "none";
|
||||||
}
|
}
|
||||||
// not all color selectors shown, hide palettes created from color selectors
|
// not all color selectors shown, hide palettes created from color selectors
|
||||||
for (let e of (gId('pallist').querySelectorAll('.lstI')||[])) {
|
// NOTE: this will disallow user to select "* Color ..." palettes which may be undesirable in some cases or for some users
|
||||||
let fltr = "* C";
|
//for (let e of (gId('pallist').querySelectorAll('.lstI')||[])) {
|
||||||
if (cslCnt==1 && csel==0) fltr = "* Colors";
|
// let fltr = "* C";
|
||||||
else if (cslCnt==2) fltr = "* Colors Only";
|
// if (cslCnt==1 && csel==0) fltr = "* Colors";
|
||||||
if (cslCnt < 3 && e.querySelector('.lstIname').innerText.indexOf(fltr)>=0) e.classList.add('hide'); else e.classList.remove('hide');
|
// else if (cslCnt==2) fltr = "* Colors Only";
|
||||||
}
|
// if (cslCnt < 3 && e.querySelector('.lstIname').innerText.indexOf(fltr)>=0) e.classList.add('hide'); else e.classList.remove('hide');
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
var jsonTimeout;
|
var jsonTimeout;
|
||||||
@ -1836,7 +1848,7 @@ ${makePlSel(plJson[i].end?plJson[i].end:0, true)}
|
|||||||
<input type="checkbox" id="p${i}sbchk">
|
<input type="checkbox" id="p${i}sbchk">
|
||||||
<span class="checkmark"></span>
|
<span class="checkmark"></span>
|
||||||
</label>`;
|
</label>`;
|
||||||
if (Array.isArray(lastinfo.maps) && lastinfo.maps.length>1) {
|
if (!isM && Array.isArray(lastinfo.maps) && lastinfo.maps.length>1) {
|
||||||
content += `<div class="lbl-l">Ledmap: <div class="sel-p"><select class="sel-p" id="p${i}lmp"><option value="">Unchanged</option>`;
|
content += `<div class="lbl-l">Ledmap: <div class="sel-p"><select class="sel-p" id="p${i}lmp"><option value="">Unchanged</option>`;
|
||||||
for (const k of (lastinfo.maps||[])) content += `<option value="${k}"${(i>0 && pJson[i].ledmap==k)?" selected":""}>${k==0?'Default':'ledmap'+k+'.json'}</option>`;
|
for (const k of (lastinfo.maps||[])) content += `<option value="${k}"${(i>0 && pJson[i].ledmap==k)?" selected":""}>${k==0?'Default':'ledmap'+k+'.json'}</option>`;
|
||||||
content += "</select></div></div>";
|
content += "</select></div></div>";
|
||||||
@ -1949,7 +1961,7 @@ function tglSegn(s)
|
|||||||
{
|
{
|
||||||
let t = gId(s<100?`seg${s}t`:`p${s-100}txt`);
|
let t = gId(s<100?`seg${s}t`:`p${s-100}txt`);
|
||||||
if (t) {
|
if (t) {
|
||||||
t.classList.toggle("show");
|
t.classList.toggle('show');
|
||||||
t.focus();
|
t.focus();
|
||||||
t.select();
|
t.select();
|
||||||
}
|
}
|
||||||
@ -1966,7 +1978,6 @@ function selSegAll(o)
|
|||||||
|
|
||||||
function selSegEx(s)
|
function selSegEx(s)
|
||||||
{
|
{
|
||||||
if (gId('selall')) gId('selall').checked = false;
|
|
||||||
var obj = {"seg":[]};
|
var obj = {"seg":[]};
|
||||||
for (let i=0; i<=lSeg; i++) obj.seg.push({"id":i,"sel":(i==s)});
|
for (let i=0; i<=lSeg; i++) obj.seg.push({"id":i,"sel":(i==s)});
|
||||||
obj.mainseg = s;
|
obj.mainseg = s;
|
||||||
@ -1975,7 +1986,6 @@ function selSegEx(s)
|
|||||||
|
|
||||||
function selSeg(s)
|
function selSeg(s)
|
||||||
{
|
{
|
||||||
if (gId('selall')) gId('selall').checked = false;
|
|
||||||
var sel = gId(`seg${s}sel`).checked;
|
var sel = gId(`seg${s}sel`).checked;
|
||||||
var obj = {"seg": {"id": s, "sel": sel}};
|
var obj = {"seg": {"id": s, "sel": sel}};
|
||||||
requestJson(obj);
|
requestJson(obj);
|
||||||
@ -1991,7 +2001,7 @@ function rptSeg(s)
|
|||||||
var rev = gId(`seg${s}rev`).checked;
|
var rev = gId(`seg${s}rev`).checked;
|
||||||
var mi = gId(`seg${s}mi`).checked;
|
var mi = gId(`seg${s}mi`).checked;
|
||||||
var sel = gId(`seg${s}sel`).checked;
|
var sel = gId(`seg${s}sel`).checked;
|
||||||
var pwr = gId(`seg${s}pwr`).classList.contains("act");
|
var pwr = gId(`seg${s}pwr`).classList.contains('act');
|
||||||
var obj = {"seg": {"id": s, "n": name, "start": start, "stop": (cfg.comp.seglen?start:0)+stop, "rev": rev, "mi": mi, "on": pwr, "bri": parseInt(gId(`seg${s}bri`).value), "sel": sel}};
|
var obj = {"seg": {"id": s, "n": name, "start": start, "stop": (cfg.comp.seglen?start:0)+stop, "rev": rev, "mi": mi, "on": pwr, "bri": parseInt(gId(`seg${s}bri`).value), "sel": sel}};
|
||||||
if (gId(`seg${s}grp`)) {
|
if (gId(`seg${s}grp`)) {
|
||||||
var grp = parseInt(gId(`seg${s}grp`).value);
|
var grp = parseInt(gId(`seg${s}grp`).value);
|
||||||
@ -2102,7 +2112,7 @@ function setTp(s)
|
|||||||
|
|
||||||
function setSegPwr(s)
|
function setSegPwr(s)
|
||||||
{
|
{
|
||||||
var pwr = gId(`seg${s}pwr`).classList.contains("act");
|
var pwr = gId(`seg${s}pwr`).classList.contains('act');
|
||||||
var obj = {"seg": {"id": s, "on": !pwr}};
|
var obj = {"seg": {"id": s, "on": !pwr}};
|
||||||
requestJson(obj);
|
requestJson(obj);
|
||||||
}
|
}
|
||||||
@ -2296,7 +2306,7 @@ function delP(i) {
|
|||||||
requestJson(obj);
|
requestJson(obj);
|
||||||
delete pJson[i];
|
delete pJson[i];
|
||||||
populatePresets();
|
populatePresets();
|
||||||
gId('putil').classList.add("staybot");
|
gId('putil').classList.add('staybot');
|
||||||
} else {
|
} else {
|
||||||
bt.style.color = "var(--c-r)";
|
bt.style.color = "var(--c-r)";
|
||||||
bt.innerHTML = "<i class='icons btn-icon'></i>Delete!";
|
bt.innerHTML = "<i class='icons btn-icon'></i>Delete!";
|
||||||
@ -2571,7 +2581,7 @@ function hideModes(txt)
|
|||||||
let f = false;
|
let f = false;
|
||||||
if (txt==="2D") f = iT.indexOf("\u25A6") >= 0 && iT.indexOf("\u22EE") < 0; // 2D && !1D
|
if (txt==="2D") f = iT.indexOf("\u25A6") >= 0 && iT.indexOf("\u22EE") < 0; // 2D && !1D
|
||||||
else f = iT.indexOf(txt) >= 0;
|
else f = iT.indexOf(txt) >= 0;
|
||||||
if (f) e.classList.add("hide"); //else e.classList.remove("hide");
|
if (f) e.classList.add('hide'); //else e.classList.remove('hide');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2642,9 +2652,9 @@ function expand(i)
|
|||||||
{
|
{
|
||||||
var seg = i<100 ? gId('seg' +i) : gId(`p${i-100}o`);
|
var seg = i<100 ? gId('seg' +i) : gId(`p${i-100}o`);
|
||||||
let ps = gId("pcont").children; // preset wrapper
|
let ps = gId("pcont").children; // preset wrapper
|
||||||
if (i>100) for (let p of ps) { p.classList.remove("selected"); if (p!==seg) p.classList.remove("expanded"); } // collapse all other presets & remove selected
|
if (i>100) for (let p of ps) { p.classList.remove('selected'); if (p!==seg) p.classList.remove('expanded'); } // collapse all other presets & remove selected
|
||||||
|
|
||||||
seg.classList.toggle("expanded");
|
seg.classList.toggle('expanded');
|
||||||
|
|
||||||
// presets
|
// presets
|
||||||
if (i >= 100) {
|
if (i >= 100) {
|
||||||
@ -2666,11 +2676,11 @@ function expand(i)
|
|||||||
gId(`p${p}api`).value = papi;
|
gId(`p${p}api`).value = papi;
|
||||||
if (papi.indexOf("Please") == 0) gId(`p${p}cstgl`).checked = false;
|
if (papi.indexOf("Please") == 0) gId(`p${p}cstgl`).checked = false;
|
||||||
tglCs(p);
|
tglCs(p);
|
||||||
gId('putil').classList.remove("staybot");
|
gId('putil').classList.remove('staybot');
|
||||||
} else {
|
} else {
|
||||||
updatePA();
|
updatePA();
|
||||||
gId('seg' +i).innerHTML = "";
|
gId('seg' +i).innerHTML = "";
|
||||||
gId('putil').classList.add("staybot");
|
gId('putil').classList.add('staybot');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
<script>
|
<script>
|
||||||
var d=document;
|
var d=document;
|
||||||
var loc = false, locip;
|
var loc = false, locip;
|
||||||
|
var maxPanels=64;
|
||||||
function H(){window.open("https://kno.wled.ge/features/2D");}
|
function H(){window.open("https://kno.wled.ge/features/2D");}
|
||||||
function B(){window.open("/settings","_self");}
|
function B(){window.open("/settings","_self");}
|
||||||
function gId(n){return d.getElementById(n);}
|
function gId(n){return d.getElementById(n);}
|
||||||
@ -23,6 +24,7 @@
|
|||||||
//console.log("File loaded");
|
//console.log("File loaded");
|
||||||
GetV();
|
GetV();
|
||||||
UI();
|
UI();
|
||||||
|
Sf.MPC.setAttribute("max",maxPanels);
|
||||||
});
|
});
|
||||||
// error event
|
// error event
|
||||||
scE.addEventListener("error", (ev) => {
|
scE.addEventListener("error", (ev) => {
|
||||||
@ -43,34 +45,29 @@
|
|||||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||||
}
|
}
|
||||||
|
|
||||||
var maxPanels=64;
|
function UI() {
|
||||||
function UI(change=false)
|
|
||||||
{
|
|
||||||
if (gId("somp").value === "0") {
|
if (gId("somp").value === "0") {
|
||||||
gId("mpdiv").style.display = "none";
|
gId("mpdiv").style.display = "none";
|
||||||
resetPanels();
|
resetPanels();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
gId("mpdiv").style.display = "block";
|
gId("mpdiv").style.display = "block";
|
||||||
maxPanels = parseInt(d.Sf.MPH.value) * parseInt(d.Sf.MPV.value);
|
|
||||||
|
|
||||||
let i = gId("panels").children.length;
|
|
||||||
if (i<maxPanels) for (let j=i; j<maxPanels; j++) addPanel(j);
|
|
||||||
if (i>maxPanels) for (let j=i; j>maxPanels; j--) remPanel();
|
|
||||||
//btnPanel(gId("panels").children.length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function addPanels() {
|
function addPanels() {
|
||||||
let h = parseInt(d.Sf.MPH.value);
|
let c = parseInt(d.Sf.MPC.value);
|
||||||
let v = parseInt(d.Sf.MPV.value);
|
let i = gId("panels").children.length;
|
||||||
for (let i=0; i<h*v; i++) addPanel(i);
|
if (i<c) for (let j=i; j<c; j++) addPanel(j);
|
||||||
|
if (i>c) for (let j=i; j>c; j--) remPanel();
|
||||||
}
|
}
|
||||||
|
|
||||||
function addPanel(i=0) {
|
function addPanel(i=0) {
|
||||||
let p = gId("panels");
|
let p = gId("panels");
|
||||||
if (p.children.length >= maxPanels) return;
|
if (p.children.length >= maxPanels) return;
|
||||||
let b = `<div id="pnl${i}">${i===0?"":'<hr class="sml">'}Panel ${i}<br>1<sup>st</sup> LED: <select name="P${i}B">
|
var pw = parseInt(d.Sf.PW.value);
|
||||||
|
var ph = parseInt(d.Sf.PH.value);
|
||||||
|
let b = `<div id="pnl${i}"><hr class="sml">Panel ${i}<br>
|
||||||
|
1<sup>st</sup> LED: <select name="P${i}B">
|
||||||
<option value="0">Top</option>
|
<option value="0">Top</option>
|
||||||
<option value="1">Bottom</option>
|
<option value="1">Bottom</option>
|
||||||
</select><select name="P${i}R">
|
</select><select name="P${i}R">
|
||||||
@ -81,7 +78,11 @@ Orientation: <select name="P${i}V">
|
|||||||
<option value="0">Horizontal</option>
|
<option value="0">Horizontal</option>
|
||||||
<option value="1">Vertical</option>
|
<option value="1">Vertical</option>
|
||||||
</select><br>
|
</select><br>
|
||||||
Serpentine: <input type="checkbox" name="P${i}S"></div>`;
|
Serpentine: <input type="checkbox" name="P${i}S"><br>
|
||||||
|
Dimensions (WxH): <input id="P${i}W" name="P${i}W" type="number" min="1" max="128" value="${pw}"> x <input id="P${i}H" name="P${i}H" type="number" min="1" max="128" value="${ph}"><br>
|
||||||
|
Offset X:<input id="P${i}X" name="P${i}X" type="number" min="0" max="256" value="0">
|
||||||
|
Y:<input id="P${i}Y" name="P${i}Y" type="number" min="0" max="256" value="0"><br><i>(offset from top-left corner in # LEDs)</i>
|
||||||
|
</div>`;
|
||||||
p.insertAdjacentHTML("beforeend", b);
|
p.insertAdjacentHTML("beforeend", b);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,15 +94,46 @@ Serpentine: <input type="checkbox" name="P${i}S"></div>`;
|
|||||||
}
|
}
|
||||||
|
|
||||||
function resetPanels() {
|
function resetPanels() {
|
||||||
d.Sf.MPH.value = 1;
|
d.Sf.MPC.value = 1;
|
||||||
d.Sf.MPV.value = 1;
|
let e = gId("panels").children
|
||||||
for (let e of gId("panels").children) e.remove();
|
for (let i = e.length; i>0; i--) e[i-1].remove();
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
function btnPanel(i) {
|
function btnPanel(i) {
|
||||||
gId("pnl_add").style.display = (i<maxPanels) ? "inline":"none";
|
gId("pnl_add").style.display = (i<maxPanels) ? "inline":"none";
|
||||||
gId("pnl_rem").style.display = (i>1) ? "inline":"none";
|
gId("pnl_rem").style.display = (i>1) ? "inline":"none";
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
function gen() {
|
||||||
|
resetPanels();
|
||||||
|
|
||||||
|
var pansH = parseInt(d.Sf.MPH.value);
|
||||||
|
var pansV = parseInt(d.Sf.MPV.value);
|
||||||
|
var c = pansH*pansV;
|
||||||
|
d.Sf.MPC.value = c; // number of panels
|
||||||
|
|
||||||
|
var ps = d.Sf.PS.checked;
|
||||||
|
var pv = d.Sf.PV.value==="1";
|
||||||
|
var pb = d.Sf.PB.value==="1";
|
||||||
|
var pr = d.Sf.PR.value==="1";
|
||||||
|
var pw = parseInt(d.Sf.PW.value);
|
||||||
|
var ph = parseInt(d.Sf.PH.value);
|
||||||
|
|
||||||
|
var h = pv ? pansV : pansH;
|
||||||
|
var v = pv ? pansH : pansV;
|
||||||
|
for (let j = 0, p = 0; j < v; j++) {
|
||||||
|
for (let i = 0; i < h; i++, p++) {
|
||||||
|
if (j*i < maxPanels) addPanel(p);
|
||||||
|
var y = (pv?pr:pb) ? v-j-1: j;
|
||||||
|
var x = (pv?pb:pr) ? h-i-1 : i;
|
||||||
|
x = ps && j%2 ? h-x-1 : x;
|
||||||
|
gId("P"+p+"X").value = (pv?y:x) * pw;
|
||||||
|
gId("P"+p+"Y").value = (pv?x:y) * ph
|
||||||
|
gId("P"+p+"W").value = pw;
|
||||||
|
gId("P"+p+"H").value = ph;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>@import url("style.css");</style>
|
<style>@import url("style.css");</style>
|
||||||
</head>
|
</head>
|
||||||
@ -118,10 +150,11 @@ Serpentine: <input type="checkbox" name="P${i}S"></div>`;
|
|||||||
<option value="1">2D Matrix</option>
|
<option value="1">2D Matrix</option>
|
||||||
</select><br>
|
</select><br>
|
||||||
<div id="mpdiv" style="display:none;">
|
<div id="mpdiv" style="display:none;">
|
||||||
<h3>Panel set-up</h3>
|
<hr class="sml">
|
||||||
|
<h3>Matrix Generator</h3>
|
||||||
Panel dimensions (WxH): <input name="PW" type="number" min="1" max="128" value="8"> x <input name="PH" type="number" min="1" max="128" value="8"><br>
|
Panel dimensions (WxH): <input name="PW" type="number" min="1" max="128" value="8"> x <input name="PH" type="number" min="1" max="128" value="8"><br>
|
||||||
Horizontal panels: <input name="MPH" type="number" min="1" max="8" value="1" oninput="UI()">
|
Horizontal panels: <input name="MPH" type="number" min="1" max="8" value="1">
|
||||||
Vertical panels: <input name="MPV" type="number" min="1" max="8" value="1" oninput="UI()"><br>
|
Vertical panels: <input name="MPV" type="number" min="1" max="8" value="1"><br>
|
||||||
1<sup>st</sup> panel: <select name="PB">
|
1<sup>st</sup> panel: <select name="PB">
|
||||||
<option value="0">Top</option>
|
<option value="0">Top</option>
|
||||||
<option value="1">Bottom</option>
|
<option value="1">Bottom</option>
|
||||||
@ -133,12 +166,15 @@ Serpentine: <input type="checkbox" name="P${i}S"></div>`;
|
|||||||
<option value="0">Horizontal</option>
|
<option value="0">Horizontal</option>
|
||||||
<option value="1">Vertical</option>
|
<option value="1">Vertical</option>
|
||||||
</select><br>
|
</select><br>
|
||||||
Serpentine: <input type="checkbox" name="PS">
|
Serpentine: <input type="checkbox" name="PS"><br>
|
||||||
<hr class="sml">
|
<i style="color:#fa0;">Can populate LED panel layout with pre-arranged matrix.<br>These values do not affect final layout.</i><br>
|
||||||
<i>A matrix is made of 1 or more physical LED panels of the same dimensions.<br>
|
<button type="button" onclick="gen()">Populate</button>
|
||||||
Panels should be arranged from top-left to bottom-right order, starting with lower panel number on the left (or top if transposed).<br>
|
|
||||||
Each panel can have different LED orientation and/or starting point and/or layout.</i><br>
|
|
||||||
<hr class="sml">
|
<hr class="sml">
|
||||||
|
<h3>Panel set-up</h3>
|
||||||
|
Number of panels: <input name="MPC" type="number" min="1" max="64" value="1" oninput="addPanels()"><br>
|
||||||
|
<i>A matrix is made of 1 or more physical LED panels.<br>
|
||||||
|
<!--Panels should be arranged from top-left to bottom-right order, starting with lower panel number on the left (or top if transposed).<br>-->
|
||||||
|
Each panel can be of different size and/or have different LED orientation and/or starting point and/or layout.</i><br>
|
||||||
<h3>LED panel layout</h3>
|
<h3>LED panel layout</h3>
|
||||||
<div id="panels">
|
<div id="panels">
|
||||||
</div>
|
</div>
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
|
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
|
||||||
<title>LED Settings</title>
|
<title>LED Settings</title>
|
||||||
<script>
|
<script>
|
||||||
var d=document,laprev=55,maxB=1,maxM=4000,maxPB=4096,maxL=1333,maxLbquot=0; //maximum bytes for LED allocation: 4kB for 8266, 32kB for 32
|
var d=document,laprev=55,maxB=1,maxV=0,maxM=4000,maxPB=4096,maxL=1333,maxLbquot=0; //maximum bytes for LED allocation: 4kB for 8266, 32kB for 32
|
||||||
var customStarts=false,startsDirty=[],maxCOOverrides=5;
|
var customStarts=false,startsDirty=[],maxCOOverrides=5;
|
||||||
var loc = false, locip;
|
var loc = false, locip;
|
||||||
function H(){window.open("https://kno.wled.ge/features/settings/#led-settings");}
|
function H(){window.open("https://kno.wled.ge/features/settings/#led-settings");}
|
||||||
@ -46,8 +46,8 @@
|
|||||||
x.style.animation = 'none';
|
x.style.animation = 'none';
|
||||||
timeout = setTimeout(function(){ x.className = x.className.replace("show", ""); }, 2900);
|
timeout = setTimeout(function(){ x.className = x.className.replace("show", ""); }, 2900);
|
||||||
}
|
}
|
||||||
function bLimits(b,p,m,l) {
|
function bLimits(b,v,p,m,l) {
|
||||||
maxB = b; maxM = m; maxPB = p; maxL = l;
|
maxB = b; maxV = v; maxM = m; maxPB = p; maxL = l;
|
||||||
}
|
}
|
||||||
function pinsOK() {
|
function pinsOK() {
|
||||||
var LCs = d.getElementsByTagName("input");
|
var LCs = d.getElementsByTagName("input");
|
||||||
@ -316,7 +316,7 @@
|
|||||||
var o = d.getElementsByClassName("iST");
|
var o = d.getElementsByClassName("iST");
|
||||||
var i = o.length;
|
var i = o.length;
|
||||||
|
|
||||||
if ((n==1 && i>=maxB) || (n==-1 && i==0)) return;
|
if ((n==1 && i>=maxB+maxV) || (n==-1 && i==0)) return;
|
||||||
|
|
||||||
var f = gId("mLC");
|
var f = gId("mLC");
|
||||||
if (n==1) {
|
if (n==1) {
|
||||||
@ -324,24 +324,24 @@
|
|||||||
var cn = `<div class="iST">
|
var cn = `<div class="iST">
|
||||||
<hr class="sml">
|
<hr class="sml">
|
||||||
${i+1}:
|
${i+1}:
|
||||||
<select name="LT${i}" onchange="UI(true)">
|
<select name="LT${i}" onchange="UI(true)">${i>=maxB ? '' :
|
||||||
<option value="22" selected>WS281x</option>
|
'<option value="22" selected>WS281x</option>\
|
||||||
<option value="30">SK6812 RGBW</option>
|
<option value="30">SK6812 RGBW</option>\
|
||||||
<option value="31">TM1814</option>
|
<option value="31">TM1814</option>\
|
||||||
<option value="24">400kHz</option>
|
<option value="24">400kHz</option>\
|
||||||
<option value="25">TM1829</option>
|
<option value="25">TM1829</option>\
|
||||||
<option value="50">WS2801</option>
|
<option value="50">WS2801</option>\
|
||||||
<option value="51">APA102</option>
|
<option value="51">APA102</option>\
|
||||||
<option value="52">LPD8806</option>
|
<option value="52">LPD8806</option>\
|
||||||
<option value="54">LPD6803</option>
|
<option value="54">LPD6803</option>\
|
||||||
<option value="53">P9813</option>
|
<option value="53">P9813</option>\
|
||||||
<option value="40">On/Off</option>
|
<option value="40">On/Off</option>\
|
||||||
<option value="41">PWM White</option>
|
<option value="41">PWM White</option>\
|
||||||
<option value="42">PWM CCT</option>
|
<option value="42">PWM CCT</option>\
|
||||||
<option value="43">PWM RGB</option>
|
<option value="43">PWM RGB</option>\
|
||||||
<option value="44">PWM RGBW</option>
|
<option value="44">PWM RGBW</option>\
|
||||||
<option value="45">PWM RGB+CCT</option>
|
<option value="45">PWM RGB+CCT</option>\
|
||||||
<!--option value="46">PWM RGB+DCCT</option-->
|
<!--option value="46">PWM RGB+DCCT</option-->'}
|
||||||
<option value="80">DDP RGB (network)</option>
|
<option value="80">DDP RGB (network)</option>
|
||||||
<!--option value="81">E1.31 RGB (network)</option-->
|
<!--option value="81">E1.31 RGB (network)</option-->
|
||||||
<!--option value="82">ArtNet RGB (network)</option-->
|
<!--option value="82">ArtNet RGB (network)</option-->
|
||||||
@ -377,7 +377,7 @@ ${i+1}:
|
|||||||
o[--i].remove();--i;
|
o[--i].remove();--i;
|
||||||
}
|
}
|
||||||
|
|
||||||
gId("+").style.display = (i<maxB-1) ? "inline":"none";
|
gId("+").style.display = (i<maxB+maxV-1) ? "inline":"none";
|
||||||
gId("-").style.display = (i>0) ? "inline":"none";
|
gId("-").style.display = (i>0) ? "inline":"none";
|
||||||
|
|
||||||
if (!init) UI();
|
if (!init) UI();
|
||||||
|
@ -89,7 +89,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<h2>Security & Update setup</h2>
|
<h2>Security & Update setup</h2>
|
||||||
Settings PIN: <input type="password" id="PIN" name="PIN" size="4" maxlength="4" minlength="4" onkeydown="checkNum(this)" pattern="[0-9]*" inputmode="numeric" title="Please enter a 4 digit number"><br>
|
Settings PIN: <input type="password" id="PIN" name="PIN" size="4" maxlength="4" minlength="4" onkeydown="checkNum(this)" pattern="[0-9]*" inputmode="numeric" title="Please enter a 4 digit number"><br>
|
||||||
<div style="color: #fa0;">⚠ Unencrypted transmission. Be prudent when selecting PIN, do NOT use your banking, door, SIM, etc. pin!</div><br><br>
|
<div style="color: #fa0;">⚠ Unencrypted transmission. Be prudent when selecting PIN, do NOT use your banking, door, SIM, etc. pin!</div><br>
|
||||||
Lock wireless (OTA) software update: <input type="checkbox" name="NO"><br>
|
Lock wireless (OTA) software update: <input type="checkbox" name="NO"><br>
|
||||||
Passphrase: <input type="password" name="OP" maxlength="32"><br>
|
Passphrase: <input type="password" name="OP" maxlength="32"><br>
|
||||||
To enable OTA, for security reasons you need to also enter the correct password!<br>
|
To enable OTA, for security reasons you need to also enter the correct password!<br>
|
||||||
@ -118,7 +118,7 @@
|
|||||||
<a href="https://github.com/Aircoookie/WLED/" target="_blank">WLED</a> version ##VERSION##<!-- Autoreplaced from package.json --><br><br>
|
<a href="https://github.com/Aircoookie/WLED/" target="_blank">WLED</a> version ##VERSION##<!-- Autoreplaced from package.json --><br><br>
|
||||||
<a href="https://github.com/Aircoookie/WLED/wiki/Contributors-and-credits" target="_blank">Contributors, dependencies and special thanks</a><br>
|
<a href="https://github.com/Aircoookie/WLED/wiki/Contributors-and-credits" target="_blank">Contributors, dependencies and special thanks</a><br>
|
||||||
A huge thank you to everyone who helped me create WLED!<br><br>
|
A huge thank you to everyone who helped me create WLED!<br><br>
|
||||||
(c) 2016-2022 Christian Schwinne <br>
|
(c) 2016-2023 Christian Schwinne <br>
|
||||||
<i>Licensed under the <a href="https://github.com/Aircoookie/WLED/blob/master/LICENSE" target="_blank">MIT license</a></i><br><br>
|
<i>Licensed under the <a href="https://github.com/Aircoookie/WLED/blob/master/LICENSE" target="_blank">MIT license</a></i><br><br>
|
||||||
Server message: <span class="sip"> Response error! </span><hr>
|
Server message: <span class="sip"> Response error! </span><hr>
|
||||||
<div id="toast"></div>
|
<div id="toast"></div>
|
||||||
|
@ -80,7 +80,7 @@
|
|||||||
<h3>WLED Broadcast</h3>
|
<h3>WLED Broadcast</h3>
|
||||||
UDP Port: <input name="UP" type="number" min="1" max="65535" class="d5" required><br>
|
UDP Port: <input name="UP" type="number" min="1" max="65535" class="d5" required><br>
|
||||||
2nd Port: <input name="U2" type="number" min="1" max="65535" class="d5" required><br>
|
2nd Port: <input name="U2" type="number" min="1" max="65535" class="d5" required><br>
|
||||||
<h3>Sync grups</h3>
|
<h3>Sync groups</h3>
|
||||||
<input name="GS" id="GS" type="number" style="display: none;"><!-- hidden inputs for bitwise group checkboxes -->
|
<input name="GS" id="GS" type="number" style="display: none;"><!-- hidden inputs for bitwise group checkboxes -->
|
||||||
<input name="GR" id="GR" type="number" style="display: none;">
|
<input name="GR" id="GR" type="number" style="display: none;">
|
||||||
<table style="margin: 0 auto;">
|
<table style="margin: 0 auto;">
|
||||||
|
@ -7,6 +7,10 @@
|
|||||||
<title>Usermod Settings</title>
|
<title>Usermod Settings</title>
|
||||||
<script>
|
<script>
|
||||||
var d = document;
|
var d = document;
|
||||||
|
d.max_gpio = 39;
|
||||||
|
d.um_p = [];
|
||||||
|
d.rsvd = [];
|
||||||
|
d.ro_pins = [];
|
||||||
var umCfg = {};
|
var umCfg = {};
|
||||||
var pins = [], pinO = [], owner;
|
var pins = [], pinO = [], owner;
|
||||||
var loc = false, locip;
|
var loc = false, locip;
|
||||||
@ -25,11 +29,6 @@
|
|||||||
d.body.appendChild(scE);
|
d.body.appendChild(scE);
|
||||||
// success event
|
// success event
|
||||||
scE.addEventListener("load", () => {
|
scE.addEventListener("load", () => {
|
||||||
//console.log("File loaded");
|
|
||||||
d.um_p = [];
|
|
||||||
d.rsvd = [];
|
|
||||||
d.ro_pins = [];
|
|
||||||
d.max_gpio = 39;
|
|
||||||
GetV();
|
GetV();
|
||||||
for (let k=0; k<d.rsvd.length; k++) { pins.push(d.rsvd[k]); pinO.push("rsvd"); }
|
for (let k=0; k<d.rsvd.length; k++) { pins.push(d.rsvd[k]); pinO.push("rsvd"); }
|
||||||
if (d.um_p[0]==-1) d.um_p.shift();
|
if (d.um_p[0]==-1) d.um_p.shift();
|
||||||
@ -38,6 +37,8 @@
|
|||||||
d.Sf.MOSI.max = d.max_gpio;
|
d.Sf.MOSI.max = d.max_gpio;
|
||||||
d.Sf.SCLK.max = d.max_gpio;
|
d.Sf.SCLK.max = d.max_gpio;
|
||||||
d.Sf.MISO.max = d.max_gpio;
|
d.Sf.MISO.max = d.max_gpio;
|
||||||
|
let inp = d.getElementsByTagName("input");
|
||||||
|
for (let i of inp) if (i.type === "number" && i.name.replace("[]","").substr(-3) === "pin") i.max = d.max_gpio;
|
||||||
});
|
});
|
||||||
// error event
|
// error event
|
||||||
scE.addEventListener("error", (ev) => {
|
scE.addEventListener("error", (ev) => {
|
||||||
|
@ -96,11 +96,11 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
|
|||||||
|
|
||||||
if (e131SkipOutOfSequence)
|
if (e131SkipOutOfSequence)
|
||||||
if (seq < e131LastSequenceNumber[previousUniverses] && seq > 20 && e131LastSequenceNumber[previousUniverses] < 250){
|
if (seq < e131LastSequenceNumber[previousUniverses] && seq > 20 && e131LastSequenceNumber[previousUniverses] < 250){
|
||||||
DEBUG_PRINT("skipping E1.31 frame (last seq=");
|
DEBUG_PRINT(F("skipping E1.31 frame (last seq="));
|
||||||
DEBUG_PRINT(e131LastSequenceNumber[previousUniverses]);
|
DEBUG_PRINT(e131LastSequenceNumber[previousUniverses]);
|
||||||
DEBUG_PRINT(", current seq=");
|
DEBUG_PRINT(F(", current seq="));
|
||||||
DEBUG_PRINT(seq);
|
DEBUG_PRINT(seq);
|
||||||
DEBUG_PRINT(", universe=");
|
DEBUG_PRINT(F(", universe="));
|
||||||
DEBUG_PRINT(uni);
|
DEBUG_PRINT(uni);
|
||||||
DEBUG_PRINTLN(")");
|
DEBUG_PRINTLN(")");
|
||||||
return;
|
return;
|
||||||
@ -487,7 +487,7 @@ void sendArtnetPollReply(ArtPollReply *reply, IPAddress ipAddress, uint16_t port
|
|||||||
reply->reply_sub_sw = (uint8_t)((portAddress >> 4) & 0x000F);
|
reply->reply_sub_sw = (uint8_t)((portAddress >> 4) & 0x000F);
|
||||||
reply->reply_sw_out[0] = (uint8_t)(portAddress & 0x000F);
|
reply->reply_sw_out[0] = (uint8_t)(portAddress & 0x000F);
|
||||||
|
|
||||||
sprintf((char *)reply->reply_node_report, "#0001 [%04u] OK - WLED v" TOSTRING(WLED_VERSION), pollReplyCount);
|
snprintf_P((char *)reply->reply_node_report, sizeof(reply->reply_node_report)-1, PSTR("#0001 [%04u] OK - WLED v" TOSTRING(WLED_VERSION)), pollReplyCount);
|
||||||
|
|
||||||
if (pollReplyCount < 9999) {
|
if (pollReplyCount < 9999) {
|
||||||
pollReplyCount++;
|
pollReplyCount++;
|
||||||
|
@ -44,44 +44,44 @@ const char PAGE_dmxmap[] PROGMEM = R"=====()=====";
|
|||||||
const uint16_t PAGE_update_length = 615;
|
const uint16_t PAGE_update_length = 615;
|
||||||
const uint8_t PAGE_update[] PROGMEM = {
|
const uint8_t PAGE_update[] PROGMEM = {
|
||||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x13, 0x75, 0x53, 0x5d, 0x6f, 0xd4, 0x30,
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x13, 0x75, 0x53, 0x5d, 0x6f, 0xd4, 0x30,
|
||||||
0x10, 0x7c, 0xcf, 0xaf, 0x70, 0xfd, 0x74, 0x27, 0x71, 0x4e, 0x41, 0xbc, 0x50, 0x92, 0x14, 0x8e,
|
0x10, 0x7c, 0xcf, 0xaf, 0x70, 0xfd, 0x74, 0x27, 0x71, 0x4e, 0x8b, 0x78, 0xa1, 0x24, 0x29, 0x1c,
|
||||||
0x56, 0xa8, 0x12, 0x52, 0x4f, 0x6a, 0x0b, 0xe2, 0x09, 0x39, 0xf6, 0x26, 0x31, 0xe7, 0xd8, 0xa9,
|
0xad, 0x50, 0x25, 0xa4, 0x56, 0x6a, 0x0b, 0xe2, 0x09, 0x39, 0xf6, 0xe6, 0x62, 0xce, 0xb1, 0x53,
|
||||||
0xbd, 0xb9, 0xd3, 0x09, 0xf5, 0xbf, 0xb3, 0x71, 0xee, 0x0a, 0xe2, 0xe3, 0x25, 0x8a, 0xb3, 0xb3,
|
0x7b, 0x73, 0xa7, 0xa8, 0xea, 0x7f, 0x67, 0xe3, 0xdc, 0x15, 0xc4, 0xc7, 0x4b, 0x14, 0x67, 0x67,
|
||||||
0xe3, 0xdd, 0x99, 0x49, 0x71, 0x76, 0x75, 0xfb, 0xe1, 0xfe, 0xeb, 0xe6, 0x9a, 0x75, 0xd8, 0xdb,
|
0xc7, 0xbb, 0x33, 0x93, 0xe2, 0xe4, 0xf2, 0xe6, 0xe3, 0xfd, 0xb7, 0xdb, 0x2b, 0xd6, 0x62, 0x67,
|
||||||
0xaa, 0x38, 0x3e, 0x41, 0xea, 0xaa, 0xe8, 0x01, 0x25, 0x53, 0xde, 0x21, 0x38, 0x2c, 0xf9, 0xde,
|
0xab, 0xe2, 0xf0, 0x04, 0xa9, 0xab, 0xa2, 0x03, 0x94, 0x4c, 0x79, 0x87, 0xe0, 0xb0, 0xe4, 0x7b,
|
||||||
0x68, 0xec, 0x4a, 0x0d, 0x3b, 0xa3, 0x60, 0x95, 0x0e, 0x9c, 0x39, 0xd9, 0x43, 0xc9, 0x77, 0x06,
|
0xa3, 0xb1, 0x2d, 0x35, 0xec, 0x8c, 0x82, 0x55, 0x3a, 0x70, 0xe6, 0x64, 0x07, 0x25, 0xdf, 0x19,
|
||||||
0xf6, 0x83, 0x0f, 0xc8, 0xab, 0xac, 0x40, 0x83, 0x16, 0xaa, 0x2f, 0x9f, 0xae, 0xaf, 0xd8, 0xc3,
|
0xd8, 0xf7, 0x3e, 0x20, 0xaf, 0xb2, 0x02, 0x0d, 0x5a, 0xa8, 0xbe, 0x7e, 0xbe, 0xba, 0x64, 0x0f,
|
||||||
0xa0, 0x25, 0x42, 0x91, 0xcf, 0x9f, 0x8a, 0xa8, 0x82, 0x19, 0xb0, 0xca, 0x9a, 0xd1, 0x29, 0x34,
|
0xbd, 0x96, 0x08, 0x45, 0x3e, 0x7f, 0x2a, 0xa2, 0x0a, 0xa6, 0xc7, 0x2a, 0x6b, 0x06, 0xa7, 0xd0,
|
||||||
0xde, 0xb1, 0xf5, 0x62, 0xf9, 0x63, 0x6f, 0x9c, 0xf6, 0x7b, 0xd1, 0x99, 0x88, 0x3e, 0x1c, 0x44,
|
0x78, 0xc7, 0xd6, 0x8b, 0xe5, 0xd3, 0xde, 0x38, 0xed, 0xf7, 0xa2, 0x35, 0x11, 0x7d, 0x18, 0x45,
|
||||||
0x2d, 0xd5, 0x76, 0xb1, 0x7c, 0x7a, 0x86, 0x3c, 0x10, 0x44, 0x7b, 0x35, 0xf6, 0x34, 0x81, 0x68,
|
0x2d, 0xd5, 0x76, 0xb1, 0x7c, 0x7e, 0x81, 0x3c, 0x10, 0x44, 0x7b, 0x35, 0x74, 0x34, 0x81, 0xd8,
|
||||||
0x01, 0xaf, 0x2d, 0x4c, 0xaf, 0xeb, 0xc3, 0x8d, 0x5e, 0xf0, 0xb1, 0xe1, 0x4b, 0x11, 0xf1, 0x60,
|
0x00, 0x5e, 0x59, 0x98, 0x5e, 0xd7, 0xe3, 0xb5, 0x5e, 0xf0, 0xa1, 0xe1, 0x4b, 0x11, 0x71, 0xb4,
|
||||||
0x41, 0x68, 0x13, 0x07, 0x2b, 0x0f, 0x25, 0x77, 0xde, 0x01, 0x7f, 0xf1, 0xdf, 0x96, 0x3e, 0xb6,
|
0x20, 0xb4, 0x89, 0xbd, 0x95, 0x63, 0xc9, 0x9d, 0x77, 0xc0, 0x5f, 0xfd, 0xb7, 0xa5, 0x8b, 0x9b,
|
||||||
0x7f, 0xf7, 0xd4, 0xd6, 0xab, 0x2d, 0x7f, 0xca, 0x8a, 0xfc, 0x38, 0xe2, 0x71, 0x54, 0x16, 0x83,
|
0xbf, 0x7b, 0x6a, 0xeb, 0xd5, 0x96, 0x3f, 0x67, 0x45, 0x7e, 0x18, 0xf1, 0x30, 0x2a, 0x8b, 0x41,
|
||||||
0x2a, 0x79, 0x1e, 0x01, 0xd1, 0xb8, 0x36, 0xe6, 0x51, 0x7c, 0x8f, 0x97, 0x43, 0xf9, 0x86, 0x57,
|
0x95, 0x3c, 0x8f, 0x80, 0x68, 0xdc, 0x26, 0xe6, 0x51, 0xfc, 0x88, 0x17, 0x7d, 0xf9, 0x96, 0x57,
|
||||||
0xbf, 0x21, 0x27, 0xaa, 0x2a, 0x7b, 0x67, 0xfa, 0x49, 0x00, 0x36, 0x06, 0xbb, 0xe0, 0x33, 0xbd,
|
0xbf, 0x21, 0x27, 0xaa, 0x2a, 0x7b, 0x6f, 0xba, 0x49, 0x00, 0x36, 0x04, 0xbb, 0xe0, 0x33, 0xbd,
|
||||||
0x8a, 0x91, 0x2f, 0xdf, 0x12, 0x32, 0x21, 0x8a, 0x7c, 0x96, 0xb4, 0xf6, 0xfa, 0xc0, 0xbc, 0xb3,
|
0x8a, 0x91, 0x2f, 0xdf, 0x11, 0x32, 0x21, 0x8a, 0x7c, 0x96, 0xb4, 0xf6, 0x7a, 0x64, 0xde, 0x59,
|
||||||
0x5e, 0xea, 0x92, 0x7f, 0x04, 0xfc, 0xbc, 0x58, 0x12, 0x5d, 0xf7, 0xaa, 0xca, 0x92, 0x64, 0x77,
|
0x2f, 0x75, 0xc9, 0x3f, 0x01, 0x7e, 0x59, 0x2c, 0x89, 0xae, 0x7d, 0x5d, 0x65, 0x49, 0xb2, 0x3b,
|
||||||
0xbe, 0xc1, 0xbd, 0x0c, 0xf0, 0xac, 0x1d, 0x55, 0x8a, 0xc6, 0x87, 0x9e, 0x91, 0x17, 0x9d, 0xa7,
|
0xdf, 0xe0, 0x5e, 0x06, 0x78, 0xd1, 0x8e, 0x2a, 0x45, 0xe3, 0x43, 0xc7, 0xc8, 0x8b, 0xd6, 0x53,
|
||||||
0x9e, 0xcd, 0xed, 0xdd, 0x3d, 0x67, 0x32, 0xc9, 0x43, 0xc3, 0x8d, 0x09, 0xc7, 0x99, 0xa1, 0x12,
|
0xcf, 0xed, 0xcd, 0xdd, 0x3d, 0x67, 0x32, 0xc9, 0x43, 0xc3, 0x0d, 0x09, 0xc7, 0x99, 0xa1, 0x12,
|
||||||
0xe9, 0xc1, 0x32, 0x20, 0xe5, 0x0e, 0x03, 0x99, 0xd2, 0x8f, 0x16, 0xcd, 0x20, 0x03, 0xe6, 0x53,
|
0xe9, 0xc1, 0x32, 0x20, 0xe5, 0xc6, 0x9e, 0x4c, 0xe9, 0x06, 0x8b, 0xa6, 0x97, 0x01, 0xf3, 0xa9,
|
||||||
0xff, 0x8a, 0x60, 0x92, 0xd3, 0xcd, 0x71, 0xac, 0x7b, 0x43, 0x6e, 0x3e, 0x4c, 0x17, 0xdf, 0xb8,
|
0x7f, 0x45, 0x30, 0xc9, 0xe9, 0xe6, 0x38, 0xd4, 0x9d, 0x21, 0x37, 0x1f, 0xa6, 0x8b, 0xaf, 0x5d,
|
||||||
0x88, 0xd2, 0x5a, 0xd0, 0x6c, 0x07, 0x21, 0x12, 0xe3, 0x05, 0x2b, 0xe2, 0x20, 0x1d, 0xcb, 0x94,
|
0x44, 0x69, 0x2d, 0x68, 0xb6, 0x83, 0x10, 0x89, 0xf1, 0x9c, 0x15, 0xb1, 0x97, 0x8e, 0x65, 0xca,
|
||||||
0x95, 0x31, 0x96, 0x3c, 0x9a, 0x81, 0x57, 0xe7, 0xe2, 0xe5, 0x6b, 0x71, 0xbe, 0xaa, 0xcf, 0x69,
|
0xca, 0x18, 0x4b, 0x1e, 0x4d, 0xcf, 0xab, 0x53, 0x71, 0xf6, 0x46, 0x9c, 0xae, 0xea, 0x33, 0x5a,
|
||||||
0x19, 0x2a, 0xd2, 0x12, 0xa1, 0xba, 0xf2, 0xfb, 0xb4, 0x04, 0xc3, 0x0e, 0x98, 0xa5, 0x11, 0x22,
|
0x86, 0x8a, 0xb4, 0x44, 0xa8, 0x2e, 0xfd, 0x3e, 0x2d, 0xc1, 0xb0, 0x05, 0x66, 0x69, 0x84, 0x88,
|
||||||
0xb2, 0xda, 0x38, 0x19, 0x0e, 0x44, 0x21, 0x59, 0xd6, 0x05, 0x68, 0x4a, 0xde, 0x21, 0x0e, 0xf1,
|
0xac, 0x36, 0x4e, 0x86, 0x91, 0x28, 0x24, 0xcb, 0xda, 0x00, 0x4d, 0xc9, 0x5b, 0xc4, 0x3e, 0x9e,
|
||||||
0x22, 0xcf, 0x5b, 0x83, 0xdd, 0x58, 0x0b, 0xe5, 0xfb, 0xfc, 0xbd, 0x09, 0xca, 0x7b, 0xbf, 0x35,
|
0xe7, 0xf9, 0xc6, 0x60, 0x3b, 0xd4, 0x42, 0xf9, 0x2e, 0xff, 0x60, 0x82, 0xf2, 0xde, 0x6f, 0x0d,
|
||||||
0x90, 0x4f, 0x1b, 0xe7, 0x01, 0x2c, 0xc8, 0x08, 0x91, 0x33, 0x94, 0x81, 0xec, 0x2a, 0xf9, 0xb7,
|
0xe4, 0xd3, 0xc6, 0x79, 0x00, 0x0b, 0x32, 0x42, 0xe4, 0x0c, 0x65, 0x20, 0xbb, 0x4a, 0xfe, 0xbd,
|
||||||
0xda, 0x4a, 0xb7, 0x25, 0x55, 0x4c, 0xdf, 0xb2, 0x2c, 0x79, 0x70, 0xe2, 0xa1, 0x2f, 0x22, 0x76,
|
0xb6, 0xd2, 0x6d, 0x49, 0x15, 0xd3, 0x6d, 0x58, 0x96, 0x3c, 0x38, 0xf2, 0xd0, 0x17, 0x11, 0x5b,
|
||||||
0x06, 0xac, 0x8e, 0xc2, 0xf8, 0x23, 0xed, 0x89, 0xe2, 0x4f, 0x6a, 0x11, 0x77, 0xed, 0x65, 0x52,
|
0x03, 0x56, 0x47, 0x61, 0xfc, 0x81, 0xf6, 0x48, 0xf1, 0x27, 0xb5, 0x88, 0xbb, 0xcd, 0x45, 0x52,
|
||||||
0xbf, 0x6c, 0x68, 0xc2, 0x55, 0x7c, 0x1c, 0x49, 0xd9, 0x29, 0xa3, 0xb9, 0x4c, 0x3b, 0x14, 0xc6,
|
0xbf, 0x6c, 0x68, 0xc2, 0x55, 0x7c, 0x1c, 0x48, 0xd9, 0x29, 0xa3, 0xb9, 0x4c, 0x3b, 0x14, 0xc6,
|
||||||
0x0d, 0x23, 0xb2, 0x59, 0xae, 0xc6, 0x58, 0x38, 0xe5, 0xf9, 0x24, 0x6a, 0x80, 0xc7, 0xd1, 0x04,
|
0xf5, 0x03, 0xb2, 0x59, 0xae, 0xc6, 0x58, 0x38, 0xe6, 0xf9, 0x28, 0x6a, 0x80, 0xc7, 0xc1, 0x04,
|
||||||
0xd0, 0x33, 0xba, 0x1e, 0x11, 0x29, 0x92, 0x33, 0x7c, 0x96, 0x91, 0xc8, 0x66, 0xa3, 0xce, 0x8a,
|
0xd0, 0x33, 0xba, 0x1e, 0x10, 0x29, 0x92, 0x33, 0x7c, 0x96, 0x91, 0xc8, 0x66, 0xa3, 0x4e, 0x8a,
|
||||||
0x7c, 0x2e, 0xff, 0x03, 0x3a, 0x1f, 0x26, 0xed, 0x95, 0x35, 0x6a, 0x5b, 0xf2, 0xf5, 0x24, 0xfd,
|
0x7c, 0x2e, 0xff, 0x03, 0x3a, 0x1f, 0x26, 0xed, 0x95, 0x35, 0x6a, 0x5b, 0xf2, 0xf5, 0x24, 0xfd,
|
||||||
0x9a, 0x92, 0xfe, 0xab, 0x29, 0x79, 0x54, 0x15, 0xda, 0xec, 0xb2, 0x64, 0xe5, 0x94, 0x53, 0xa2,
|
0x9a, 0x92, 0xfe, 0xab, 0x29, 0x79, 0x54, 0x15, 0xda, 0xec, 0xb2, 0x64, 0xe5, 0x94, 0x53, 0xa2,
|
||||||
0xa9, 0x12, 0x3b, 0x85, 0x4f, 0x08, 0x41, 0xe0, 0x44, 0xbe, 0x49, 0xcb, 0x32, 0xed, 0x99, 0xf3,
|
0xa9, 0x12, 0x3b, 0x85, 0x4f, 0x08, 0x41, 0xe0, 0x44, 0x7e, 0x9b, 0x96, 0x65, 0xda, 0x33, 0xe7,
|
||||||
0xc8, 0x94, 0xf5, 0x74, 0xf0, 0x81, 0x66, 0x6d, 0x02, 0xc4, 0x2e, 0xf9, 0x31, 0xc8, 0x16, 0xd8,
|
0x91, 0x29, 0xeb, 0xe9, 0xe0, 0x03, 0xcd, 0xda, 0x04, 0x88, 0x6d, 0xf2, 0xa3, 0x97, 0x1b, 0x60,
|
||||||
0xc5, 0xb2, 0xc8, 0x89, 0x6f, 0x5a, 0x77, 0x0a, 0xdd, 0x94, 0xc0, 0xe9, 0xd7, 0xfe, 0x09, 0x43,
|
0xe7, 0xcb, 0x22, 0x27, 0xbe, 0x69, 0xdd, 0x29, 0x74, 0x53, 0x02, 0xa7, 0x5f, 0xfb, 0x27, 0xff,
|
||||||
0x44, 0x4f, 0x48, 0xf0, 0x03, 0x00, 0x00
|
0x66, 0x0a, 0x46, 0xf0, 0x03, 0x00, 0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
3817
wled00/html_ui.h
@ -189,7 +189,7 @@ void sendImprovInfoResponse() {
|
|||||||
out[11] = 4; //Firmware len ("WLED")
|
out[11] = 4; //Firmware len ("WLED")
|
||||||
out[12] = 'W'; out[13] = 'L'; out[14] = 'E'; out[15] = 'D';
|
out[12] = 'W'; out[13] = 'L'; out[14] = 'E'; out[15] = 'D';
|
||||||
uint8_t lengthSum = 17;
|
uint8_t lengthSum = 17;
|
||||||
uint8_t vlen = sprintf_P(out+lengthSum,PSTR("0.14.0-b0/%i"),VERSION);
|
uint8_t vlen = sprintf_P(out+lengthSum,PSTR("0.14.0-b1/%i"),VERSION);
|
||||||
out[16] = vlen; lengthSum += vlen;
|
out[16] = vlen; lengthSum += vlen;
|
||||||
uint8_t hlen = 7;
|
uint8_t hlen = 7;
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
|
@ -143,7 +143,7 @@
|
|||||||
#define IR40_AUTO 0xFF50AF // AUTO
|
#define IR40_AUTO 0xFF50AF // AUTO
|
||||||
#define IR40_SLOW 0xFFD02F // SLOW
|
#define IR40_SLOW 0xFFD02F // SLOW
|
||||||
|
|
||||||
// 44-key defs, to be done later
|
// 44-key defs
|
||||||
#define IR44_BPLUS 0xFF3AC5 //
|
#define IR44_BPLUS 0xFF3AC5 //
|
||||||
#define IR44_BMINUS 0xFFBA45 //
|
#define IR44_BMINUS 0xFFBA45 //
|
||||||
#define IR44_OFF 0xFF827D //
|
#define IR44_OFF 0xFF827D //
|
||||||
|
@ -105,7 +105,7 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
|||||||
of = offsetAbs;
|
of = offsetAbs;
|
||||||
}
|
}
|
||||||
if (stop > start && of > len -1) of = len -1;
|
if (stop > start && of > len -1) of = len -1;
|
||||||
strip.setSegment(id, start, stop, grp, spc, of, startY, stopY);
|
seg.set(start, stop, grp, spc, of, startY, stopY);
|
||||||
|
|
||||||
byte segbri = seg.opacity;
|
byte segbri = seg.opacity;
|
||||||
if (getVal(elem["bri"], &segbri)) {
|
if (getVal(elem["bri"], &segbri)) {
|
||||||
@ -170,13 +170,20 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef WLED_DISABLE_2D
|
||||||
|
bool reverse = seg.reverse;
|
||||||
|
bool mirror = seg.mirror;
|
||||||
|
#endif
|
||||||
seg.selected = elem["sel"] | seg.selected;
|
seg.selected = elem["sel"] | seg.selected;
|
||||||
seg.reverse = elem["rev"] | seg.reverse;
|
seg.reverse = elem["rev"] | seg.reverse;
|
||||||
seg.mirror = elem["mi"] | seg.mirror;
|
seg.mirror = elem["mi"] | seg.mirror;
|
||||||
#ifndef WLED_DISABLE_2D
|
#ifndef WLED_DISABLE_2D
|
||||||
|
bool reverse_y = seg.reverse_y;
|
||||||
|
bool mirror_y = seg.mirror_y;
|
||||||
seg.reverse_y = elem["rY"] | seg.reverse_y;
|
seg.reverse_y = elem["rY"] | seg.reverse_y;
|
||||||
seg.mirror_y = elem["mY"] | seg.mirror_y;
|
seg.mirror_y = elem["mY"] | seg.mirror_y;
|
||||||
seg.transpose = elem[F("tp")] | seg.transpose;
|
seg.transpose = elem[F("tp")] | seg.transpose;
|
||||||
|
if (seg.is2D() && seg.map1D2D == M12_pArc && (reverse != seg.reverse || reverse_y != seg.reverse_y || mirror != seg.mirror || mirror_y != seg.mirror_y)) seg.fill(BLACK); // clear entire segment (in case of Arc 1D to 2D expansion)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
byte fx = seg.mode;
|
byte fx = seg.mode;
|
||||||
@ -221,11 +228,11 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
|||||||
for (size_t i = 0; i < iarr.size(); i++) {
|
for (size_t i = 0; i < iarr.size(); i++) {
|
||||||
if(iarr[i].is<JsonInteger>()) {
|
if(iarr[i].is<JsonInteger>()) {
|
||||||
if (!set) {
|
if (!set) {
|
||||||
start = iarr[i];
|
start = abs(iarr[i].as<int>());
|
||||||
set = 1;
|
set++;
|
||||||
} else {
|
} else {
|
||||||
stop = iarr[i];
|
stop = abs(iarr[i].as<int>());
|
||||||
set = 2;
|
set++;
|
||||||
}
|
}
|
||||||
} else { //color
|
} else { //color
|
||||||
uint8_t rgbw[] = {0,0,0,0};
|
uint8_t rgbw[] = {0,0,0,0};
|
||||||
@ -241,16 +248,13 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (set < 2) stop = start + 1;
|
if (set < 2 || stop <= start) stop = start + 1;
|
||||||
uint32_t c = gamma32(RGBW32(rgbw[0], rgbw[1], rgbw[2], rgbw[3]));
|
uint32_t c = gamma32(RGBW32(rgbw[0], rgbw[1], rgbw[2], rgbw[3]));
|
||||||
for (int i = start; i < stop; i++) {
|
while (start < stop) seg.setPixelColor(start++, c);
|
||||||
seg.setPixelColor(i, c);
|
|
||||||
}
|
|
||||||
if (!set) start++;
|
|
||||||
set = 0;
|
set = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
strip.trigger();
|
strip.trigger(); // force segment update
|
||||||
}
|
}
|
||||||
// send UDP/WS if segment options changed (except selection; will also deselect current preset)
|
// send UDP/WS if segment options changed (except selection; will also deselect current preset)
|
||||||
if (seg.differs(prev) & 0x7F) stateChanged = true;
|
if (seg.differs(prev) & 0x7F) stateChanged = true;
|
||||||
@ -477,11 +481,13 @@ void serializeSegment(JsonObject& root, Segment& seg, byte id, bool forPreset, b
|
|||||||
root["sel"] = seg.isSelected();
|
root["sel"] = seg.isSelected();
|
||||||
root["rev"] = seg.reverse;
|
root["rev"] = seg.reverse;
|
||||||
root["mi"] = seg.mirror;
|
root["mi"] = seg.mirror;
|
||||||
|
#ifndef WLED_DISABLE_2D
|
||||||
if (strip.isMatrix) {
|
if (strip.isMatrix) {
|
||||||
root["rY"] = seg.reverse_y;
|
root["rY"] = seg.reverse_y;
|
||||||
root["mY"] = seg.mirror_y;
|
root["mY"] = seg.mirror_y;
|
||||||
root[F("tp")] = seg.transpose;
|
root[F("tp")] = seg.transpose;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
root["o1"] = seg.check1;
|
root["o1"] = seg.check1;
|
||||||
root["o2"] = seg.check2;
|
root["o2"] = seg.check2;
|
||||||
root["o3"] = seg.check3;
|
root["o3"] = seg.check3;
|
||||||
|
@ -50,16 +50,17 @@ enum struct PinOwner : uint8_t {
|
|||||||
// #define USERMOD_ID_VL53L0X // 0x0C // Usermod "usermod_vl53l0x_gestures.h" -- Uses "standard" HW_I2C pins
|
// #define USERMOD_ID_VL53L0X // 0x0C // Usermod "usermod_vl53l0x_gestures.h" -- Uses "standard" HW_I2C pins
|
||||||
UM_MultiRelay = USERMOD_ID_MULTI_RELAY, // 0x0D // Usermod "usermod_multi_relay.h"
|
UM_MultiRelay = USERMOD_ID_MULTI_RELAY, // 0x0D // Usermod "usermod_multi_relay.h"
|
||||||
UM_AnimatedStaircase = USERMOD_ID_ANIMATED_STAIRCASE, // 0x0E // Usermod "Animated_Staircase.h"
|
UM_AnimatedStaircase = USERMOD_ID_ANIMATED_STAIRCASE, // 0x0E // Usermod "Animated_Staircase.h"
|
||||||
|
UM_Battery = USERMOD_ID_BATTERY, //
|
||||||
// #define USERMOD_ID_RTC // 0x0F // Usermod "usermod_rtc.h" -- Uses "standard" HW_I2C pins
|
// #define USERMOD_ID_RTC // 0x0F // Usermod "usermod_rtc.h" -- Uses "standard" HW_I2C pins
|
||||||
// #define USERMOD_ID_ELEKSTUBE_IPS // 0x10 // Usermod "usermod_elekstube_ips.h" -- Uses quite a few pins ... see Hardware.h and User_Setup.h
|
// #define USERMOD_ID_ELEKSTUBE_IPS // 0x10 // Usermod "usermod_elekstube_ips.h" -- Uses quite a few pins ... see Hardware.h and User_Setup.h
|
||||||
// #define USERMOD_ID_SN_PHOTORESISTOR // 0x11 // Usermod "usermod_sn_photoresistor.h" -- Uses hard-coded pin (PHOTORESISTOR_PIN == A0), but could be easily updated to use pinManager
|
// #define USERMOD_ID_SN_PHOTORESISTOR // 0x11 // Usermod "usermod_sn_photoresistor.h" -- Uses hard-coded pin (PHOTORESISTOR_PIN == A0), but could be easily updated to use pinManager
|
||||||
|
UM_BH1750 = USERMOD_ID_BH1750, // 0x14 // Usermod "usermod_bme280.h -- Uses "standard" HW_I2C pins
|
||||||
UM_RGBRotaryEncoder = USERMOD_RGB_ROTARY_ENCODER, // 0x16 // Usermod "rgb-rotary-encoder.h"
|
UM_RGBRotaryEncoder = USERMOD_RGB_ROTARY_ENCODER, // 0x16 // Usermod "rgb-rotary-encoder.h"
|
||||||
UM_QuinLEDAnPenta = USERMOD_ID_QUINLED_AN_PENTA, // 0x17 // Usermod "quinled-an-penta.h"
|
UM_QuinLEDAnPenta = USERMOD_ID_QUINLED_AN_PENTA, // 0x17 // Usermod "quinled-an-penta.h"
|
||||||
UM_BME280 = USERMOD_ID_BME280, // 0x18 // Usermod "usermod_bme280.h -- Uses "standard" HW_I2C pins
|
UM_BME280 = USERMOD_ID_BME280, // 0x1E // Usermod "usermod_bme280.h -- Uses "standard" HW_I2C pins
|
||||||
UM_BH1750 = USERMOD_ID_BH1750, // 0x19 // Usermod "usermod_bme280.h -- Uses "standard" HW_I2C pins
|
UM_Audioreactive = USERMOD_ID_AUDIOREACTIVE, // 0x20 // Usermod "audio_reactive.h"
|
||||||
UM_Audioreactive = USERMOD_ID_AUDIOREACTIVE, // 0x1E // Usermod "audio_reactive.h"
|
UM_SdCard = USERMOD_ID_SD_CARD, // 0x25 // Usermod "usermod_sd_card.h"
|
||||||
UM_SdCard = USERMOD_ID_SD_CARD, // 0x24 // Usermod "usermod_sd_card.h"
|
UM_PWM_OUTPUTS = USERMOD_ID_PWM_OUTPUTS // 0x26 // Usermod "usermod_pwm_outputs.h"
|
||||||
UM_PWM_OUTPUTS = USERMOD_ID_PWM_OUTPUTS // 0x21 // Usermod "usermod_pwm_outputs.h"
|
|
||||||
};
|
};
|
||||||
static_assert(0u == static_cast<uint8_t>(PinOwner::None), "PinOwner::None must be zero, so default array initialization works as expected");
|
static_assert(0u == static_cast<uint8_t>(PinOwner::None), "PinOwner::None must be zero, so default array initialization works as expected");
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
strip.useLedsArray = request->hasArg(F("LD"));
|
strip.useLedsArray = request->hasArg(F("LD"));
|
||||||
|
|
||||||
bool busesChanged = false;
|
bool busesChanged = false;
|
||||||
for (uint8_t s = 0; s < WLED_MAX_BUSSES; s++) {
|
for (uint8_t s = 0; s < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; s++) {
|
||||||
char lp[4] = "L0"; lp[2] = 48+s; lp[3] = 0; //ascii 0-9 //strip data pin
|
char lp[4] = "L0"; lp[2] = 48+s; lp[3] = 0; //ascii 0-9 //strip data pin
|
||||||
char lc[4] = "LC"; lc[2] = 48+s; lc[3] = 0; //strip length
|
char lc[4] = "LC"; lc[2] = 48+s; lc[3] = 0; //strip length
|
||||||
char co[4] = "CO"; co[2] = 48+s; co[3] = 0; //strip color order
|
char co[4] = "CO"; co[2] = 48+s; co[3] = 0; //strip color order
|
||||||
@ -645,22 +645,37 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
if (subPage == 10)
|
if (subPage == 10)
|
||||||
{
|
{
|
||||||
strip.isMatrix = request->arg(F("SOMP")).toInt();
|
strip.isMatrix = request->arg(F("SOMP")).toInt();
|
||||||
strip.panelH = MAX(1,MIN(128,request->arg(F("PH")).toInt()));
|
// strip.panelH = MAX(1,MIN(128,request->arg(F("PH")).toInt()));
|
||||||
strip.panelW = MAX(1,MIN(128,request->arg(F("PW")).toInt()));
|
// strip.panelW = MAX(1,MIN(128,request->arg(F("PW")).toInt()));
|
||||||
strip.hPanels = MAX(1,MIN(8,request->arg(F("MPH")).toInt()));
|
strip.panel.clear(); // release memory if allocated
|
||||||
strip.vPanels = MAX(1,MIN(8,request->arg(F("MPV")).toInt()));
|
if (strip.isMatrix) {
|
||||||
|
strip.panels = MAX(1,MIN(WLED_MAX_PANELS,request->arg(F("MPC")).toInt()));
|
||||||
strip.matrix.bottomStart = request->arg(F("PB")).toInt();
|
strip.matrix.bottomStart = request->arg(F("PB")).toInt();
|
||||||
strip.matrix.rightStart = request->arg(F("PR")).toInt();
|
strip.matrix.rightStart = request->arg(F("PR")).toInt();
|
||||||
strip.matrix.vertical = request->arg(F("PV")).toInt();
|
strip.matrix.vertical = request->arg(F("PV")).toInt();
|
||||||
strip.matrix.serpentine = request->hasArg(F("PS"));
|
strip.matrix.serpentine = request->hasArg(F("PS"));
|
||||||
for (uint8_t i=0; i<WLED_MAX_PANELS; i++) {
|
strip.panel.reserve(strip.panels); // pre-allocate memory
|
||||||
char pO[8]; sprintf_P(pO, PSTR("P%d"), i);
|
for (uint8_t i=0; i<strip.panels; i++) {
|
||||||
uint8_t l = strlen(pO); pO[l+1] = 0;
|
WS2812FX::Panel p;
|
||||||
|
char pO[8] = { '\0' };
|
||||||
|
snprintf_P(pO, 7, PSTR("P%d"), i); // MAX_PANELS is 64 so pO will always only be 4 characters or less
|
||||||
|
pO[7] = '\0';
|
||||||
|
uint8_t l = strlen(pO);
|
||||||
|
// create P0B, P1B, ..., P63B, etc for other PxxX
|
||||||
pO[l] = 'B'; if (!request->hasArg(pO)) break;
|
pO[l] = 'B'; if (!request->hasArg(pO)) break;
|
||||||
pO[l] = 'B'; strip.panel[i].bottomStart = request->arg(pO).toInt();
|
pO[l] = 'B'; p.bottomStart = request->arg(pO).toInt();
|
||||||
pO[l] = 'R'; strip.panel[i].rightStart = request->arg(pO).toInt();
|
pO[l] = 'R'; p.rightStart = request->arg(pO).toInt();
|
||||||
pO[l] = 'V'; strip.panel[i].vertical = request->arg(pO).toInt();
|
pO[l] = 'V'; p.vertical = request->arg(pO).toInt();
|
||||||
pO[l] = 'S'; strip.panel[i].serpentine = request->hasArg(pO);
|
pO[l] = 'S'; p.serpentine = request->hasArg(pO);
|
||||||
|
pO[l] = 'X'; p.xOffset = request->arg(pO).toInt();
|
||||||
|
pO[l] = 'Y'; p.yOffset = request->arg(pO).toInt();
|
||||||
|
pO[l] = 'W'; p.width = request->arg(pO).toInt();
|
||||||
|
pO[l] = 'H'; p.height = request->arg(pO).toInt();
|
||||||
|
strip.panel.push_back(p);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Segment::maxWidth = strip.getLengthTotal();
|
||||||
|
Segment::maxHeight = 1;
|
||||||
}
|
}
|
||||||
strip.setUpMatrix(); // will check limits
|
strip.setUpMatrix(); // will check limits
|
||||||
}
|
}
|
||||||
@ -746,7 +761,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
|||||||
if (pos > 0) {
|
if (pos > 0) {
|
||||||
spcI = getNumVal(&req, pos);
|
spcI = getNumVal(&req, pos);
|
||||||
}
|
}
|
||||||
strip.setSegment(selectedSeg, startI, stopI, grpI, spcI, UINT16_MAX, startY, stopY);
|
selseg.set(startI, stopI, grpI, spcI, UINT16_MAX, startY, stopY);
|
||||||
|
|
||||||
pos = req.indexOf(F("RV=")); //Segment reverse
|
pos = req.indexOf(F("RV=")); //Segment reverse
|
||||||
if (pos > 0) selseg.reverse = req.charAt(pos+3) != '0';
|
if (pos > 0) selseg.reverse = req.charAt(pos+3) != '0';
|
||||||
|
@ -363,7 +363,7 @@ void handleNotifications()
|
|||||||
uint16_t stopY = 1, stop = (udpIn[3+ofs] << 8 | udpIn[4+ofs]);
|
uint16_t stopY = 1, stop = (udpIn[3+ofs] << 8 | udpIn[4+ofs]);
|
||||||
uint16_t offset = (udpIn[7+ofs] << 8 | udpIn[8+ofs]);
|
uint16_t offset = (udpIn[7+ofs] << 8 | udpIn[8+ofs]);
|
||||||
if (!receiveSegmentOptions) {
|
if (!receiveSegmentOptions) {
|
||||||
strip.setSegment(id, start, stop, selseg.grouping, selseg.spacing, offset, startY, stopY);
|
selseg.set(start, stop, selseg.grouping, selseg.spacing, offset, startY, stopY);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
//for (size_t j = 1; j<4; j++) selseg.setOption(j, (udpIn[9 +ofs] >> j) & 0x01); //only take into account mirrored, on, reversed; ignore selected
|
//for (size_t j = 1; j<4; j++) selseg.setOption(j, (udpIn[9 +ofs] >> j) & 0x01); //only take into account mirrored, on, reversed; ignore selected
|
||||||
@ -396,11 +396,10 @@ void handleNotifications()
|
|||||||
startY = (udpIn[32+ofs] << 8 | udpIn[33+ofs]);
|
startY = (udpIn[32+ofs] << 8 | udpIn[33+ofs]);
|
||||||
stopY = (udpIn[34+ofs] << 8 | udpIn[35+ofs]);
|
stopY = (udpIn[34+ofs] << 8 | udpIn[35+ofs]);
|
||||||
}
|
}
|
||||||
//setSegment() also properly resets segments
|
|
||||||
if (receiveSegmentBounds) {
|
if (receiveSegmentBounds) {
|
||||||
strip.setSegment(id, start, stop, udpIn[5+ofs], udpIn[6+ofs], offset, startY, stopY);
|
selseg.set(start, stop, udpIn[5+ofs], udpIn[6+ofs], offset, startY, stopY);
|
||||||
} else {
|
} else {
|
||||||
strip.setSegment(id, selseg.start, selseg.stop, udpIn[5+ofs], udpIn[6+ofs], selseg.offset, selseg.startY, selseg.stopY);
|
selseg.set(selseg.start, selseg.stop, udpIn[5+ofs], udpIn[6+ofs], selseg.offset, selseg.startY, selseg.stopY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stateChanged = true;
|
stateChanged = true;
|
||||||
|
@ -11,8 +11,8 @@
|
|||||||
*/
|
*/
|
||||||
//#include "../usermods/EXAMPLE_v2/usermod_v2_example.h"
|
//#include "../usermods/EXAMPLE_v2/usermod_v2_example.h"
|
||||||
|
|
||||||
#ifdef USERMOD_BATTERY_STATUS_BASIC
|
#ifdef USERMOD_BATTERY
|
||||||
#include "../usermods/battery_status_basic/usermod_v2_battery_status_basic.h"
|
#include "../usermods/Battery/usermod_v2_Battery.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USERMOD_DALLASTEMPERATURE
|
#ifdef USERMOD_DALLASTEMPERATURE
|
||||||
@ -193,8 +193,8 @@ void registerUsermods()
|
|||||||
* \/ \/ \/
|
* \/ \/ \/
|
||||||
*/
|
*/
|
||||||
//usermods.add(new MyExampleUsermod());
|
//usermods.add(new MyExampleUsermod());
|
||||||
#ifdef USERMOD_BATTERY_STATUS_BASIC
|
#ifdef USERMOD_BATTERY
|
||||||
usermods.add(new UsermodBatteryBasic());
|
usermods.add(new UsermodBattery());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USERMOD_DALLASTEMPERATURE
|
#ifdef USERMOD_DALLASTEMPERATURE
|
||||||
|
@ -157,7 +157,7 @@ void WLED::loop()
|
|||||||
bool aligned = strip.checkSegmentAlignment(); //see if old segments match old bus(ses)
|
bool aligned = strip.checkSegmentAlignment(); //see if old segments match old bus(ses)
|
||||||
busses.removeAll();
|
busses.removeAll();
|
||||||
uint32_t mem = 0;
|
uint32_t mem = 0;
|
||||||
for (uint8_t i = 0; i < WLED_MAX_BUSSES; i++) {
|
for (uint8_t i = 0; i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) {
|
||||||
if (busConfigs[i] == nullptr) break;
|
if (busConfigs[i] == nullptr) break;
|
||||||
mem += BusManager::memUsage(*busConfigs[i]);
|
mem += BusManager::memUsage(*busConfigs[i]);
|
||||||
if (mem <= MAX_LED_MEMORY) {
|
if (mem <= MAX_LED_MEMORY) {
|
||||||
@ -268,7 +268,10 @@ void WLED::setup()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
Serial.setTimeout(50);
|
#if !ARDUINO_USB_CDC_ON_BOOT
|
||||||
|
Serial.setTimeout(50); // this causes troubles on new MCUs that have a "virtual" USB Serial (HWCDC)
|
||||||
|
#else
|
||||||
|
#endif
|
||||||
#if defined(WLED_DEBUG) && defined(ARDUINO_ARCH_ESP32) && (defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || ARDUINO_USB_CDC_ON_BOOT)
|
#if defined(WLED_DEBUG) && defined(ARDUINO_ARCH_ESP32) && (defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || ARDUINO_USB_CDC_ON_BOOT)
|
||||||
delay(2500); // allow CDC USB serial to initialise
|
delay(2500); // allow CDC USB serial to initialise
|
||||||
#endif
|
#endif
|
||||||
@ -566,7 +569,7 @@ bool WLED::initEthernet()
|
|||||||
} else {
|
} else {
|
||||||
DEBUG_PRINT(F("initE: Failing due to invalid eth_clk_mode ("));
|
DEBUG_PRINT(F("initE: Failing due to invalid eth_clk_mode ("));
|
||||||
DEBUG_PRINT(es.eth_clk_mode);
|
DEBUG_PRINT(es.eth_clk_mode);
|
||||||
DEBUG_PRINTLN(F(")"));
|
DEBUG_PRINTLN(")");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,12 +3,12 @@
|
|||||||
/*
|
/*
|
||||||
Main sketch, global variable declarations
|
Main sketch, global variable declarations
|
||||||
@title WLED project sketch
|
@title WLED project sketch
|
||||||
@version 0.14.0-b0
|
@version 0.14.0-b1
|
||||||
@author Christian Schwinne
|
@author Christian Schwinne
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// version code in format yymmddb (b = daily build)
|
// version code in format yymmddb (b = daily build)
|
||||||
#define VERSION 2212180
|
#define VERSION 2301140
|
||||||
|
|
||||||
//uncomment this if you have a "my_config.h" file you'd like to use
|
//uncomment this if you have a "my_config.h" file you'd like to use
|
||||||
//#define WLED_USE_MY_CONFIG
|
//#define WLED_USE_MY_CONFIG
|
||||||
@ -71,6 +71,7 @@
|
|||||||
#include <user_interface.h>
|
#include <user_interface.h>
|
||||||
}
|
}
|
||||||
#else // ESP32
|
#else // ESP32
|
||||||
|
#include <HardwareSerial.h> // ensure we have the correct "Serial" on new MCUs (depends on ARDUINO_USB_MODE and ARDUINO_USB_CDC_ON_BOOT)
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <ETH.h>
|
#include <ETH.h>
|
||||||
#include "esp_wifi.h"
|
#include "esp_wifi.h"
|
||||||
@ -669,7 +670,7 @@ WLED_GLOBAL bool e131NewData _INIT(false);
|
|||||||
// led fx library object
|
// led fx library object
|
||||||
WLED_GLOBAL BusManager busses _INIT(BusManager());
|
WLED_GLOBAL BusManager busses _INIT(BusManager());
|
||||||
WLED_GLOBAL WS2812FX strip _INIT(WS2812FX());
|
WLED_GLOBAL WS2812FX strip _INIT(WS2812FX());
|
||||||
WLED_GLOBAL BusConfig* busConfigs[WLED_MAX_BUSSES] _INIT({nullptr}); //temporary, to remember values from network callback until after
|
WLED_GLOBAL BusConfig* busConfigs[WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES] _INIT({nullptr}); //temporary, to remember values from network callback until after
|
||||||
WLED_GLOBAL bool doInitBusses _INIT(false);
|
WLED_GLOBAL bool doInitBusses _INIT(false);
|
||||||
WLED_GLOBAL int8_t loadLedmap _INIT(-1);
|
WLED_GLOBAL int8_t loadLedmap _INIT(-1);
|
||||||
WLED_GLOBAL uint16_t ledMaps _INIT(0); // bitfield representation of available ledmaps
|
WLED_GLOBAL uint16_t ledMaps _INIT(0); // bitfield representation of available ledmaps
|
||||||
|
@ -368,6 +368,7 @@ void getSettingsJS(byte subPage, char* dest)
|
|||||||
// set limits
|
// set limits
|
||||||
oappend(SET_F("bLimits("));
|
oappend(SET_F("bLimits("));
|
||||||
oappend(itoa(WLED_MAX_BUSSES,nS,10)); oappend(",");
|
oappend(itoa(WLED_MAX_BUSSES,nS,10)); oappend(",");
|
||||||
|
oappend(itoa(WLED_MIN_VIRTUAL_BUSSES,nS,10)); oappend(",");
|
||||||
oappend(itoa(MAX_LEDS_PER_BUS,nS,10)); oappend(",");
|
oappend(itoa(MAX_LEDS_PER_BUS,nS,10)); oappend(",");
|
||||||
oappend(itoa(MAX_LED_MEMORY,nS,10)); oappend(",");
|
oappend(itoa(MAX_LED_MEMORY,nS,10)); oappend(",");
|
||||||
oappend(itoa(MAX_LEDS,nS,10));
|
oappend(itoa(MAX_LEDS,nS,10));
|
||||||
@ -726,28 +727,37 @@ void getSettingsJS(byte subPage, char* dest)
|
|||||||
{
|
{
|
||||||
sappend('v',SET_F("SOMP"),strip.isMatrix);
|
sappend('v',SET_F("SOMP"),strip.isMatrix);
|
||||||
#ifndef WLED_DISABLE_2D
|
#ifndef WLED_DISABLE_2D
|
||||||
|
oappend(SET_F("maxPanels=")); oappendi(WLED_MAX_PANELS); oappend(SET_F(";"));
|
||||||
oappend(SET_F("resetPanels();"));
|
oappend(SET_F("resetPanels();"));
|
||||||
if (strip.isMatrix) {
|
if (strip.isMatrix) {
|
||||||
sappend('v',SET_F("PH"),strip.panelH);
|
if(strip.panels>0){
|
||||||
sappend('v',SET_F("PW"),strip.panelW);
|
sappend('v',SET_F("PW"),strip.panel[0].width); //Set generator Width and Height to first panel size for convenience
|
||||||
sappend('v',SET_F("MPH"),strip.hPanels);
|
sappend('v',SET_F("PH"),strip.panel[0].height);
|
||||||
sappend('v',SET_F("MPV"),strip.vPanels);
|
}
|
||||||
|
sappend('v',SET_F("MPC"),strip.panels);
|
||||||
sappend('v',SET_F("PB"),strip.matrix.bottomStart);
|
sappend('v',SET_F("PB"),strip.matrix.bottomStart);
|
||||||
sappend('v',SET_F("PR"),strip.matrix.rightStart);
|
sappend('v',SET_F("PR"),strip.matrix.rightStart);
|
||||||
sappend('v',SET_F("PV"),strip.matrix.vertical);
|
sappend('v',SET_F("PV"),strip.matrix.vertical);
|
||||||
sappend('c',SET_F("PS"),strip.matrix.serpentine);
|
sappend('c',SET_F("PS"),strip.matrix.serpentine);
|
||||||
// panels
|
// panels
|
||||||
for (uint8_t i=0; i<strip.hPanels*strip.vPanels; i++) {
|
for (uint8_t i=0; i<strip.panels; i++) {
|
||||||
char n[5];
|
char n[5];
|
||||||
oappend(SET_F("addPanel("));
|
oappend(SET_F("addPanel("));
|
||||||
oappend(itoa(i,n,10));
|
oappend(itoa(i,n,10));
|
||||||
oappend(SET_F(");"));
|
oappend(SET_F(");"));
|
||||||
char pO[8]; sprintf_P(pO, PSTR("P%d"), i);
|
char pO[8] = { '\0' };
|
||||||
uint8_t l = strlen(pO); pO[l+1] = 0;
|
snprintf_P(pO, 7, PSTR("P%d"), i); // MAX_PANELS is 64 so pO will always only be 4 characters or less
|
||||||
|
pO[7] = '\0';
|
||||||
|
uint8_t l = strlen(pO);
|
||||||
|
// create P0B, P1B, ..., P63B, etc for other PxxX
|
||||||
pO[l] = 'B'; sappend('v',pO,strip.panel[i].bottomStart);
|
pO[l] = 'B'; sappend('v',pO,strip.panel[i].bottomStart);
|
||||||
pO[l] = 'R'; sappend('v',pO,strip.panel[i].rightStart);
|
pO[l] = 'R'; sappend('v',pO,strip.panel[i].rightStart);
|
||||||
pO[l] = 'V'; sappend('v',pO,strip.panel[i].vertical);
|
pO[l] = 'V'; sappend('v',pO,strip.panel[i].vertical);
|
||||||
pO[l] = 'S'; sappend('c',pO,strip.panel[i].serpentine);
|
pO[l] = 'S'; sappend('c',pO,strip.panel[i].serpentine);
|
||||||
|
pO[l] = 'X'; sappend('v',pO,strip.panel[i].xOffset);
|
||||||
|
pO[l] = 'Y'; sappend('v',pO,strip.panel[i].yOffset);
|
||||||
|
pO[l] = 'W'; sappend('v',pO,strip.panel[i].width);
|
||||||
|
pO[l] = 'H'; sappend('v',pO,strip.panel[i].height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|