Compare commits
84 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
32e724e744 | ||
|
5fb891c495 | ||
|
d56cefdc7a | ||
|
80c67d37c0 | ||
|
1e29d9463e | ||
|
75f6a53269 | ||
|
76a7f25083 | ||
|
16617660c3 | ||
|
a83d9a075f | ||
|
eca3fb1e19 | ||
|
44726c7411 | ||
|
c340a1d47f | ||
|
7238ef4f55 | ||
|
e67a210e95 | ||
|
51dfa9a247 | ||
|
7c121b8ba6 | ||
|
9db8d44654 | ||
|
1543862f3b | ||
|
5b7b34a9f0 | ||
|
fb6271eecf | ||
|
031526b619 | ||
|
4f5816f42e | ||
|
555d0d3378 | ||
|
e260b9473a | ||
|
ccc56d446f | ||
|
284366e6bb | ||
|
e5f6f8dfa7 | ||
|
96700fe3d1 | ||
|
34bed44a9b | ||
|
d431aa4b59 | ||
|
9867227ccd | ||
|
0decf94c9c | ||
|
0ae78efd43 | ||
|
3eabefd3d6 | ||
|
7ff6a6e0e7 | ||
|
94dc611024 | ||
|
0b28107432 | ||
|
fe717dad7f | ||
|
535bf4c848 | ||
|
1fc60b0682 | ||
|
302f1ee8e3 | ||
|
42aec56b8e | ||
|
199c00c59b | ||
|
107bb14555 | ||
|
5820792013 | ||
|
0e20248494 | ||
|
0d66bc49c2 | ||
|
aca01044f4 | ||
|
c7d399c122 | ||
|
b6f43966ea | ||
|
36290c20aa | ||
|
c33c7eb68e | ||
|
5da33afecd | ||
|
225fd0d05b | ||
|
c43b4f9cf0 | ||
|
3581f4c87e | ||
|
7a4e0cc850 | ||
|
ba49da75de | ||
|
d95158003c | ||
|
418abc2b0a | ||
|
277f0346f2 | ||
|
6148cbb122 | ||
|
7f6486c77d | ||
|
86300a8e3c | ||
|
b56490650c | ||
|
8ccfb606c0 | ||
|
4194e66d81 | ||
|
c9b9d86892 | ||
|
f2d00e6e42 | ||
|
acfc166a11 | ||
|
9709ca331e | ||
|
b4a9641c31 | ||
|
37dc17ae15 | ||
|
cd6b3d7dee | ||
|
aec0bc5029 | ||
|
e010e67717 | ||
|
44197d91c6 | ||
|
94aeb19245 | ||
|
0d287283d4 | ||
|
ea964124d6 | ||
|
c361c34b16 | ||
|
68860ae866 | ||
|
61637f12c7 | ||
|
b4f08fa8d5 |
10
CHANGELOG.md
10
CHANGELOG.md
@ -1,5 +1,15 @@
|
||||
## WLED changelog
|
||||
|
||||
#### Build 2311160
|
||||
- Version bump: 0.14.1-b1
|
||||
- Bugfixes (#3526, #3502, #3496, #3484, #3487, #3445, #3466, #3296, #3382, #3312)
|
||||
- New feature: Sort presets by ID
|
||||
- New usermod: LDR sensor (#3490 by @JeffWDH)
|
||||
- Effect: Twinklefox & Tinklecat metadata fix
|
||||
- Effect: separate #HH and #MM for Scrolling Text (#3480)
|
||||
- SSDR usermod enhancements (#3368)
|
||||
- PWM fan usermod enhancements (#3414)
|
||||
|
||||
#### Build 2310010, build 2310130
|
||||
- Release of WLED version 0.14.0 "Hoshi"
|
||||
- Bugfixes for #3400, #3403, #3405
|
||||
|
2
package-lock.json
generated
2
package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wled",
|
||||
"version": "0.14.0",
|
||||
"version": "0.14.1-b1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wled",
|
||||
"version": "0.14.0",
|
||||
"version": "0.14.1-b1",
|
||||
"description": "Tools for WLED project",
|
||||
"main": "tools/cdata.js",
|
||||
"directories": {
|
||||
|
@ -217,7 +217,7 @@ build_flags =
|
||||
; restrict to minimal mime-types
|
||||
-DMIMETYPE_MINIMAL
|
||||
; other special-purpose framework flags (see https://docs.platformio.org/en/latest/platforms/espressif8266.html)
|
||||
; -D PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48 ;; in case of linker errors like "section `.text1' will not fit in region `iram1_0_seg'"
|
||||
-D PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48 ;; in case of linker errors like "section `.text1' will not fit in region `iram1_0_seg'"
|
||||
; -D PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48_SECHEAP_SHARED ;; (experimental) adds some extra heap, but may cause slowdown
|
||||
|
||||
lib_deps =
|
||||
|
26
usermods/LDR_Dusk_Dawn_v2/README.md
Normal file
26
usermods/LDR_Dusk_Dawn_v2/README.md
Normal file
@ -0,0 +1,26 @@
|
||||
# LDR_Dusk_Dawn_v2
|
||||
This usermod will obtain readings from a Light Dependent Resistor (LDR) and will turn on/off specific presets based on those readings. This is useful for exterior lighting situations where you want the lights to only be on when it is dark out.
|
||||
|
||||
# Installation
|
||||
Add "-D USERMOD_LDR_DUSK_DAWN" to your platformio.ini [common] build_flags and build.
|
||||
|
||||
Example:
|
||||
```
|
||||
[common]
|
||||
build_flags =
|
||||
-D USERMOD_LDR_DUSK_DAWN # Enable LDR Dusk Dawn Usermod
|
||||
```
|
||||
|
||||
# Usermod Settings
|
||||
Setting | Description | Default
|
||||
--- | --- | ---
|
||||
Enabled | Enable/Disable the LDR functionality. | Disabled
|
||||
LDR Pin | The analog capable pin your LDR is connected to. | 34
|
||||
Threshold Minutes | The number of minutes of consistent readings above/below the on/off threshold before the LED state will change. | 5
|
||||
Threshold | The analog read value threshold from the LDR. Readings lower than this number will count towards changing the LED state to off. You can see the current LDR reading by going into the info section when LDR functionality is enabled. | 1000
|
||||
On Preset | The WLED preset to be used for the LED on state. | 1
|
||||
Off Preset | The WLED preset to be used for the LED off state. | 2
|
||||
|
||||
## Author
|
||||
[@jeffwdh](https://github.com/jeffwdh)
|
||||
jeffwdh@tarball.ca
|
126
usermods/LDR_Dusk_Dawn_v2/usermod_LDR_Dusk_Dawn_v2.h
Normal file
126
usermods/LDR_Dusk_Dawn_v2/usermod_LDR_Dusk_Dawn_v2.h
Normal file
@ -0,0 +1,126 @@
|
||||
#pragma once
|
||||
#include "wled.h"
|
||||
|
||||
class LDR_Dusk_Dawn_v2 : public Usermod {
|
||||
private:
|
||||
// Defaults
|
||||
bool ldrEnabled = false;
|
||||
int ldrPin = 34; //A2 on Adafruit Huzzah32
|
||||
int ldrThresholdMinutes = 5; // How many minutes of readings above/below threshold until it switches LED state
|
||||
int ldrThreshold = 1000; // Readings higher than this number will turn off LED.
|
||||
int ldrOnPreset = 1; // Default "On" Preset
|
||||
int ldrOffPreset = 2; // Default "Off" Preset
|
||||
|
||||
// Variables
|
||||
bool ldrEnabledPreviously = false; // Was LDR enabled for the previous check? First check is always no.
|
||||
int ldrOffCount; // Number of readings above the threshold
|
||||
int ldrOnCount; // Number of readings below the threshold
|
||||
int ldrReading; // Last LDR reading
|
||||
int ldrLEDState; // Current LED on/off state
|
||||
unsigned long lastMillis = 0;
|
||||
static const char _name[];
|
||||
|
||||
public:
|
||||
void setup() {
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Only update every 10 seconds
|
||||
if (millis() - lastMillis > 10000) {
|
||||
if (ldrEnabled == true) {
|
||||
// Default state is off
|
||||
if (ldrEnabledPreviously == false) {
|
||||
applyPreset(ldrOffPreset);
|
||||
ldrEnabledPreviously = true;
|
||||
ldrLEDState = 0;
|
||||
}
|
||||
|
||||
// Get LDR reading and increment counter by number of seconds since last read
|
||||
ldrReading = analogRead(ldrPin);
|
||||
if (ldrReading <= ldrThreshold) {
|
||||
ldrOnCount = ldrOnCount + 10;
|
||||
ldrOffCount = 0;
|
||||
} else {
|
||||
ldrOffCount = ldrOffCount + 10;
|
||||
ldrOnCount = 0;
|
||||
}
|
||||
|
||||
if (ldrOnCount >= (ldrThresholdMinutes * 60)) {
|
||||
ldrOnCount = 0;
|
||||
// If LEDs were previously off, turn on
|
||||
if (ldrLEDState == 0) {
|
||||
applyPreset(ldrOnPreset);
|
||||
ldrLEDState = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (ldrOffCount >= (ldrThresholdMinutes * 60)) {
|
||||
ldrOffCount = 0;
|
||||
// If LEDs were previously on, turn off
|
||||
if (ldrLEDState == 1) {
|
||||
applyPreset(ldrOffPreset);
|
||||
ldrLEDState = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// LDR is disabled, reset variables to default
|
||||
ldrReading = 0;
|
||||
ldrOnCount = 0;
|
||||
ldrOffCount = 0;
|
||||
ldrLEDState = 0;
|
||||
ldrEnabledPreviously = false;
|
||||
}
|
||||
lastMillis = millis();
|
||||
}
|
||||
}
|
||||
|
||||
void addToConfig(JsonObject& root) {
|
||||
JsonObject top = root.createNestedObject(FPSTR(_name));
|
||||
top["Enabled"] = ldrEnabled;
|
||||
top["LDR Pin"] = ldrPin;
|
||||
top["Threshold Minutes"] = ldrThresholdMinutes;
|
||||
top["Threshold"] = ldrThreshold;
|
||||
top["On Preset"] = ldrOnPreset;
|
||||
top["Off Preset"] = ldrOffPreset;
|
||||
}
|
||||
|
||||
bool readFromConfig(JsonObject& root) {
|
||||
JsonObject top = root[FPSTR(_name)];
|
||||
bool configComplete = !top.isNull();
|
||||
configComplete &= getJsonValue(top["Enabled"], ldrEnabled);
|
||||
configComplete &= getJsonValue(top["LDR Pin"], ldrPin);
|
||||
configComplete &= getJsonValue(top["Threshold Minutes"], ldrThresholdMinutes);
|
||||
configComplete &= getJsonValue(top["Threshold"], ldrThreshold);
|
||||
configComplete &= getJsonValue(top["On Preset"], ldrOnPreset);
|
||||
configComplete &= getJsonValue(top["Off Preset"], ldrOffPreset);
|
||||
return configComplete;
|
||||
}
|
||||
|
||||
void addToJsonInfo(JsonObject& root) {
|
||||
// If "u" object does not exist yet we need to create it
|
||||
JsonObject user = root["u"];
|
||||
if (user.isNull()) user = root.createNestedObject("u");
|
||||
|
||||
JsonArray LDR_Enabled = user.createNestedArray("LDR dusk/dawn enabled");
|
||||
LDR_Enabled.add(ldrEnabled);
|
||||
|
||||
JsonArray LDR_Reading = user.createNestedArray("LDR reading");
|
||||
LDR_Reading.add(ldrReading);
|
||||
|
||||
JsonArray LDR_State = user.createNestedArray("LDR turned LEDs on");
|
||||
LDR_State.add(bool(ldrLEDState));
|
||||
|
||||
// Optional debug information:
|
||||
//JsonArray LDR_On_Count = user.createNestedArray("LDR on count");
|
||||
//LDR_On_Count.add(ldrOnCount);
|
||||
|
||||
//JsonArray LDR_Off_Count = user.createNestedArray("LDR off count");
|
||||
//LDR_Off_Count.add(ldrOffCount);
|
||||
}
|
||||
|
||||
uint16_t getId() {
|
||||
return USERMOD_ID_LDR_DUSK_DAWN;
|
||||
}
|
||||
};
|
||||
|
||||
const char LDR_Dusk_Dawn_v2::_name[] PROGMEM = "LDR_Dusk_Dawn_v2";
|
@ -52,9 +52,15 @@ class PWMFanUsermod : public Usermod {
|
||||
uint8_t tachoUpdateSec = 30;
|
||||
float targetTemperature = 35.0;
|
||||
uint8_t minPWMValuePct = 0;
|
||||
uint8_t maxPWMValuePct = 100;
|
||||
uint8_t numberOfInterrupsInOneSingleRotation = 2; // Number of interrupts ESP32 sees on tacho signal on a single fan rotation. All the fans I've seen trigger two interrups.
|
||||
uint8_t pwmValuePct = 0;
|
||||
|
||||
// constant values
|
||||
static const uint8_t _pwmMaxValue = 255;
|
||||
static const uint8_t _pwmMaxStepCount = 7;
|
||||
float _pwmTempStepSize = 0.5f;
|
||||
|
||||
// strings to reduce flash memory usage (used more than twice)
|
||||
static const char _name[];
|
||||
static const char _enabled[];
|
||||
@ -63,6 +69,7 @@ class PWMFanUsermod : public Usermod {
|
||||
static const char _temperature[];
|
||||
static const char _tachoUpdateSec[];
|
||||
static const char _minPWMValuePct[];
|
||||
static const char _maxPWMValuePct[];
|
||||
static const char _IRQperRotation[];
|
||||
static const char _speed[];
|
||||
static const char _lock[];
|
||||
@ -156,31 +163,25 @@ class PWMFanUsermod : public Usermod {
|
||||
|
||||
void setFanPWMbasedOnTemperature(void) {
|
||||
float temp = getActualTemperature();
|
||||
float difftemp = temp - targetTemperature;
|
||||
// Default to run fan at full speed.
|
||||
int newPWMvalue = 255;
|
||||
int pwmStep = ((100 - minPWMValuePct) * newPWMvalue) / (7*100);
|
||||
int pwmMinimumValue = (minPWMValuePct * newPWMvalue) / 100;
|
||||
// dividing minPercent and maxPercent into equal pwmvalue sizes
|
||||
int pwmStepSize = ((maxPWMValuePct - minPWMValuePct) * _pwmMaxValue) / (_pwmMaxStepCount*100);
|
||||
int pwmStep = calculatePwmStep(temp - targetTemperature);
|
||||
// minimum based on full speed - not entered MaxPercent
|
||||
int pwmMinimumValue = (minPWMValuePct * _pwmMaxValue) / 100;
|
||||
updateFanSpeed(pwmMinimumValue + pwmStep*pwmStepSize);
|
||||
}
|
||||
|
||||
if ((temp == NAN) || (temp <= -100.0)) {
|
||||
uint8_t calculatePwmStep(float diffTemp){
|
||||
if ((diffTemp == NAN) || (diffTemp <= -100.0)) {
|
||||
DEBUG_PRINTLN(F("WARNING: no temperature value available. Cannot do temperature control. Will set PWM fan to 255."));
|
||||
} else if (difftemp <= 0.0) {
|
||||
// Temperature is below target temperature. Run fan at minimum speed.
|
||||
newPWMvalue = pwmMinimumValue;
|
||||
} else if (difftemp <= 0.5) {
|
||||
newPWMvalue = pwmMinimumValue + pwmStep;
|
||||
} else if (difftemp <= 1.0) {
|
||||
newPWMvalue = pwmMinimumValue + 2*pwmStep;
|
||||
} else if (difftemp <= 1.5) {
|
||||
newPWMvalue = pwmMinimumValue + 3*pwmStep;
|
||||
} else if (difftemp <= 2.0) {
|
||||
newPWMvalue = pwmMinimumValue + 4*pwmStep;
|
||||
} else if (difftemp <= 2.5) {
|
||||
newPWMvalue = pwmMinimumValue + 5*pwmStep;
|
||||
} else if (difftemp <= 3.0) {
|
||||
newPWMvalue = pwmMinimumValue + 6*pwmStep;
|
||||
return _pwmMaxStepCount;
|
||||
}
|
||||
updateFanSpeed(newPWMvalue);
|
||||
if(diffTemp <=0){
|
||||
return 0;
|
||||
}
|
||||
int calculatedStep = (diffTemp / _pwmTempStepSize)+1;
|
||||
// anything greater than max stepcount gets max
|
||||
return (uint8_t)min((int)_pwmMaxStepCount,calculatedStep);
|
||||
}
|
||||
|
||||
public:
|
||||
@ -312,6 +313,7 @@ class PWMFanUsermod : public Usermod {
|
||||
top[FPSTR(_tachoUpdateSec)] = tachoUpdateSec;
|
||||
top[FPSTR(_temperature)] = targetTemperature;
|
||||
top[FPSTR(_minPWMValuePct)] = minPWMValuePct;
|
||||
top[FPSTR(_maxPWMValuePct)] = maxPWMValuePct;
|
||||
top[FPSTR(_IRQperRotation)] = numberOfInterrupsInOneSingleRotation;
|
||||
DEBUG_PRINTLN(F("Autosave config saved."));
|
||||
}
|
||||
@ -345,6 +347,8 @@ class PWMFanUsermod : public Usermod {
|
||||
targetTemperature = top[FPSTR(_temperature)] | targetTemperature;
|
||||
minPWMValuePct = top[FPSTR(_minPWMValuePct)] | minPWMValuePct;
|
||||
minPWMValuePct = (uint8_t) min(100,max(0,(int)minPWMValuePct)); // bounds checking
|
||||
maxPWMValuePct = top[FPSTR(_maxPWMValuePct)] | maxPWMValuePct;
|
||||
maxPWMValuePct = (uint8_t) min(100,max((int)minPWMValuePct,(int)maxPWMValuePct)); // bounds checking
|
||||
numberOfInterrupsInOneSingleRotation = top[FPSTR(_IRQperRotation)] | numberOfInterrupsInOneSingleRotation;
|
||||
numberOfInterrupsInOneSingleRotation = (uint8_t) max(1,(int)numberOfInterrupsInOneSingleRotation); // bounds checking
|
||||
|
||||
@ -389,6 +393,7 @@ const char PWMFanUsermod::_pwmPin[] PROGMEM = "PWM-pin";
|
||||
const char PWMFanUsermod::_temperature[] PROGMEM = "target-temp-C";
|
||||
const char PWMFanUsermod::_tachoUpdateSec[] PROGMEM = "tacho-update-s";
|
||||
const char PWMFanUsermod::_minPWMValuePct[] PROGMEM = "min-PWM-percent";
|
||||
const char PWMFanUsermod::_maxPWMValuePct[] PROGMEM = "max-PWM-percent";
|
||||
const char PWMFanUsermod::_IRQperRotation[] PROGMEM = "IRQs-per-rotation";
|
||||
const char PWMFanUsermod::_speed[] PROGMEM = "speed";
|
||||
const char PWMFanUsermod::_lock[] PROGMEM = "lock";
|
||||
|
@ -24,6 +24,9 @@ Enables the inverted mode in which the background should be enabled and the digi
|
||||
### Colon-blinking
|
||||
Enables the blinking colon(s) if they are defined
|
||||
|
||||
### Leading-Zero
|
||||
Shows the leading zero of the hour if it exists (i.e. shows `07` instead of `7`)
|
||||
|
||||
### enable-auto-brightness
|
||||
Enables the auto brightness feature. Can be used only when the usermod SN_Photoresistor is installed.
|
||||
|
||||
|
@ -17,6 +17,7 @@ private:
|
||||
bool umSSDRDisplayTime = false;
|
||||
bool umSSDRInverted = false;
|
||||
bool umSSDRColonblink = true;
|
||||
bool umSSDRLeadingZero = false;
|
||||
bool umSSDREnableLDR = false;
|
||||
String umSSDRHours = "";
|
||||
String umSSDRMinutes = "";
|
||||
@ -79,6 +80,7 @@ private:
|
||||
static const char _str_timeEnabled[];
|
||||
static const char _str_inverted[];
|
||||
static const char _str_colonblink[];
|
||||
static const char _str_leadingZero[];
|
||||
static const char _str_displayMask[];
|
||||
static const char _str_hours[];
|
||||
static const char _str_minutes[];
|
||||
@ -105,15 +107,15 @@ private:
|
||||
switch (umSSDRDisplayMask[index]) {
|
||||
case 'h':
|
||||
timeVar = hourFormat12(localTime);
|
||||
_showElements(&umSSDRHours, timeVar, 0, 1);
|
||||
_showElements(&umSSDRHours, timeVar, 0, !umSSDRLeadingZero);
|
||||
break;
|
||||
case 'H':
|
||||
timeVar = hour(localTime);
|
||||
_showElements(&umSSDRHours, timeVar, 0, 1);
|
||||
_showElements(&umSSDRHours, timeVar, 0, !umSSDRLeadingZero);
|
||||
break;
|
||||
case 'k':
|
||||
timeVar = hour(localTime) + 1;
|
||||
_showElements(&umSSDRHours, timeVar, 0, 0);
|
||||
_showElements(&umSSDRHours, timeVar, 0, !umSSDRLeadingZero);
|
||||
break;
|
||||
case 'm':
|
||||
timeVar = minute(localTime);
|
||||
@ -309,6 +311,9 @@ private:
|
||||
if (_cmpIntSetting_P(topic, payload, _str_colonblink, &umSSDRColonblink)) {
|
||||
return true;
|
||||
}
|
||||
if (_cmpIntSetting_P(topic, payload, _str_leadingZero, &umSSDRLeadingZero)) {
|
||||
return true;
|
||||
}
|
||||
if (strcmp_P(topic, _str_displayMask) == 0) {
|
||||
umSSDRDisplayMask = String(payload);
|
||||
_publishMQTTstr_P(_str_displayMask, umSSDRDisplayMask);
|
||||
@ -323,6 +328,7 @@ private:
|
||||
_publishMQTTint_P(_str_ldrEnabled, umSSDREnableLDR);
|
||||
_publishMQTTint_P(_str_inverted, umSSDRInverted);
|
||||
_publishMQTTint_P(_str_colonblink, umSSDRColonblink);
|
||||
_publishMQTTint_P(_str_leadingZero, umSSDRLeadingZero);
|
||||
|
||||
_publishMQTTstr_P(_str_hours, umSSDRHours);
|
||||
_publishMQTTstr_P(_str_minutes, umSSDRMinutes);
|
||||
@ -347,6 +353,7 @@ private:
|
||||
ssdrObj[FPSTR(_str_ldrEnabled)] = umSSDREnableLDR;
|
||||
ssdrObj[FPSTR(_str_inverted)] = umSSDRInverted;
|
||||
ssdrObj[FPSTR(_str_colonblink)] = umSSDRColonblink;
|
||||
ssdrObj[FPSTR(_str_leadingZero)] = umSSDRLeadingZero;
|
||||
ssdrObj[FPSTR(_str_displayMask)] = umSSDRDisplayMask;
|
||||
ssdrObj[FPSTR(_str_hours)] = umSSDRHours;
|
||||
ssdrObj[FPSTR(_str_minutes)] = umSSDRMinutes;
|
||||
@ -425,6 +432,8 @@ public:
|
||||
invert.add(umSSDRInverted);
|
||||
JsonArray blink = user.createNestedArray("Blinking colon");
|
||||
blink.add(umSSDRColonblink);
|
||||
JsonArray zero = user.createNestedArray("Show the hour leading zero");
|
||||
zero.add(umSSDRLeadingZero);
|
||||
JsonArray ldrEnable = user.createNestedArray("Auto Brightness enabled");
|
||||
ldrEnable.add(umSSDREnableLDR);
|
||||
|
||||
@ -454,6 +463,7 @@ public:
|
||||
umSSDREnableLDR = ssdrObj[FPSTR(_str_ldrEnabled)] | umSSDREnableLDR;
|
||||
umSSDRInverted = ssdrObj[FPSTR(_str_inverted)] | umSSDRInverted;
|
||||
umSSDRColonblink = ssdrObj[FPSTR(_str_colonblink)] | umSSDRColonblink;
|
||||
umSSDRLeadingZero = ssdrObj[FPSTR(_str_leadingZero)] | umSSDRLeadingZero;
|
||||
umSSDRDisplayMask = ssdrObj[FPSTR(_str_displayMask)] | umSSDRDisplayMask;
|
||||
}
|
||||
}
|
||||
@ -516,6 +526,7 @@ public:
|
||||
umSSDREnableLDR = (top[FPSTR(_str_ldrEnabled)] | umSSDREnableLDR);
|
||||
umSSDRInverted = (top[FPSTR(_str_inverted)] | umSSDRInverted);
|
||||
umSSDRColonblink = (top[FPSTR(_str_colonblink)] | umSSDRColonblink);
|
||||
umSSDRLeadingZero = (top[FPSTR(_str_leadingZero)] | umSSDRLeadingZero);
|
||||
|
||||
umSSDRDisplayMask = top[FPSTR(_str_displayMask)] | umSSDRDisplayMask;
|
||||
umSSDRHours = top[FPSTR(_str_hours)] | umSSDRHours;
|
||||
@ -546,6 +557,7 @@ const char UsermodSSDR::_str_name[] PROGMEM = "UsermodSSDR";
|
||||
const char UsermodSSDR::_str_timeEnabled[] PROGMEM = "enabled";
|
||||
const char UsermodSSDR::_str_inverted[] PROGMEM = "inverted";
|
||||
const char UsermodSSDR::_str_colonblink[] PROGMEM = "Colon-blinking";
|
||||
const char UsermodSSDR::_str_leadingZero[] PROGMEM = "Leading-Zero";
|
||||
const char UsermodSSDR::_str_displayMask[] PROGMEM = "Display-Mask";
|
||||
const char UsermodSSDR::_str_hours[] PROGMEM = "LED-Numbers-Hours";
|
||||
const char UsermodSSDR::_str_minutes[] PROGMEM = "LED-Numbers-Minutes";
|
||||
|
@ -177,11 +177,11 @@ uint16_t color_wipe(bool rev, bool useRandomColors) {
|
||||
SEGENV.step = 3;
|
||||
}
|
||||
if (SEGENV.step == 1) { //if flag set, change to new random color
|
||||
SEGENV.aux1 = SEGMENT.get_random_wheel_index(SEGENV.aux0);
|
||||
SEGENV.aux1 = get_random_wheel_index(SEGENV.aux0);
|
||||
SEGENV.step = 2;
|
||||
}
|
||||
if (SEGENV.step == 3) {
|
||||
SEGENV.aux0 = SEGMENT.get_random_wheel_index(SEGENV.aux1);
|
||||
SEGENV.aux0 = get_random_wheel_index(SEGENV.aux1);
|
||||
SEGENV.step = 0;
|
||||
}
|
||||
}
|
||||
@ -271,7 +271,7 @@ uint16_t mode_random_color(void) {
|
||||
if (it != SEGENV.step) //new color
|
||||
{
|
||||
SEGENV.aux1 = SEGENV.aux0;
|
||||
SEGENV.aux0 = SEGMENT.get_random_wheel_index(SEGENV.aux0); //aux0 will store our random color wheel index
|
||||
SEGENV.aux0 = get_random_wheel_index(SEGENV.aux0); //aux0 will store our random color wheel index
|
||||
SEGENV.step = it;
|
||||
}
|
||||
|
||||
@ -604,22 +604,36 @@ static const char _data_FX_MODE_TWINKLE[] PROGMEM = "Twinkle@!,!;!,!;!;;m12=0";
|
||||
* Dissolve function
|
||||
*/
|
||||
uint16_t dissolve(uint32_t color) {
|
||||
uint16_t dataSize = (SEGLEN+7) >> 3; //1 bit per LED
|
||||
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
memset(SEGMENT.data, 0xFF, dataSize); // start by fading pixels up
|
||||
SEGENV.aux0 = 1;
|
||||
}
|
||||
|
||||
for (int j = 0; j <= SEGLEN / 15; j++) {
|
||||
if (random8() <= SEGMENT.intensity) {
|
||||
for (size_t times = 0; times < 10; times++) //attempt to spawn a new pixel 10 times
|
||||
{
|
||||
uint16_t i = random16(SEGLEN);
|
||||
for (size_t times = 0; times < 10; times++) { //attempt to spawn a new pixel 10 times
|
||||
unsigned i = random16(SEGLEN);
|
||||
unsigned index = i >> 3;
|
||||
unsigned bitNum = i & 0x07;
|
||||
bool fadeUp = bitRead(SEGENV.data[index], bitNum);
|
||||
if (SEGENV.aux0) { //dissolve to primary/palette
|
||||
if (SEGMENT.getPixelColor(i) == SEGCOLOR(1) /*|| wa*/) {
|
||||
if (fadeUp) {
|
||||
if (color == SEGCOLOR(0)) {
|
||||
SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
|
||||
} else {
|
||||
SEGMENT.setPixelColor(i, color);
|
||||
}
|
||||
bitWrite(SEGENV.data[index], bitNum, false);
|
||||
break; //only spawn 1 new pixel per frame per 50 LEDs
|
||||
}
|
||||
} else { //dissolve to secondary
|
||||
if (SEGMENT.getPixelColor(i) != SEGCOLOR(1)) { SEGMENT.setPixelColor(i, SEGCOLOR(1)); break; }
|
||||
if (!fadeUp) {
|
||||
SEGMENT.setPixelColor(i, SEGCOLOR(1)); break;
|
||||
bitWrite(SEGENV.data[index], bitNum, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -628,6 +642,7 @@ uint16_t dissolve(uint32_t color) {
|
||||
if (SEGENV.step > (255 - SEGMENT.speed) + 15U) {
|
||||
SEGENV.aux0 = !SEGENV.aux0;
|
||||
SEGENV.step = 0;
|
||||
memset(SEGMENT.data, (SEGENV.aux0 ? 0xFF : 0), dataSize); // switch fading
|
||||
} else {
|
||||
SEGENV.step++;
|
||||
}
|
||||
@ -816,7 +831,7 @@ uint16_t chase(uint32_t color1, uint32_t color2, uint32_t color3, bool do_palett
|
||||
if (a < SEGENV.step) //we hit the start again, choose new color for Chase random
|
||||
{
|
||||
SEGENV.aux1 = SEGENV.aux0; //store previous random color
|
||||
SEGENV.aux0 = SEGMENT.get_random_wheel_index(SEGENV.aux0);
|
||||
SEGENV.aux0 = get_random_wheel_index(SEGENV.aux0);
|
||||
}
|
||||
color1 = SEGMENT.color_wheel(SEGENV.aux0);
|
||||
}
|
||||
@ -1056,7 +1071,7 @@ uint16_t mode_chase_flash_random(void) {
|
||||
SEGENV.aux1 = (SEGENV.aux1 + 1) % SEGLEN;
|
||||
|
||||
if (SEGENV.aux1 == 0) {
|
||||
SEGENV.aux0 = SEGMENT.get_random_wheel_index(SEGENV.aux0);
|
||||
SEGENV.aux0 = get_random_wheel_index(SEGENV.aux0);
|
||||
}
|
||||
}
|
||||
return delay;
|
||||
@ -2590,14 +2605,14 @@ uint16_t mode_twinklefox()
|
||||
{
|
||||
return twinklefox_base(false);
|
||||
}
|
||||
static const char _data_FX_MODE_TWINKLEFOX[] PROGMEM = "Twinklefox@!,Twinkle rate,,,,Cool;;!";
|
||||
static const char _data_FX_MODE_TWINKLEFOX[] PROGMEM = "Twinklefox@!,Twinkle rate,,,,Cool;!,!;!";
|
||||
|
||||
|
||||
uint16_t mode_twinklecat()
|
||||
{
|
||||
return twinklefox_base(true);
|
||||
}
|
||||
static const char _data_FX_MODE_TWINKLECAT[] PROGMEM = "Twinklecat@!,Twinkle rate,,,,Cool;;!";
|
||||
static const char _data_FX_MODE_TWINKLECAT[] PROGMEM = "Twinklecat@!,Twinkle rate,,,,Cool;!,!;!";
|
||||
|
||||
|
||||
//inspired by https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/#LEDStripEffectBlinkingHalloweenEyes
|
||||
@ -5946,6 +5961,8 @@ uint16_t mode_2Dscrollingtext(void) {
|
||||
else if (!strncmp_P(text,PSTR("#MMDD"),5)) sprintf_P(text, zero?PSTR("%02d/%02d") :PSTR("%d/%d"), month(localTime), day(localTime));
|
||||
else if (!strncmp_P(text,PSTR("#TIME"),5)) sprintf_P(text, zero?PSTR("%02d:%02d%s") :PSTR("%2d:%02d%s"), AmPmHour, minute(localTime), sec);
|
||||
else if (!strncmp_P(text,PSTR("#HHMM"),5)) sprintf_P(text, zero?PSTR("%02d:%02d") :PSTR("%d:%02d"), AmPmHour, minute(localTime));
|
||||
else if (!strncmp_P(text,PSTR("#HH"),3)) sprintf_P(text, zero?PSTR("%02d") :PSTR("%d"), AmPmHour);
|
||||
else if (!strncmp_P(text,PSTR("#MM"),3)) sprintf_P(text, zero?PSTR("%02d") :PSTR("%d"), minute(localTime));
|
||||
}
|
||||
|
||||
const int numberOfLetters = strlen(text);
|
||||
|
53
wled00/FX.h
53
wled00/FX.h
@ -109,20 +109,15 @@
|
||||
#define PINK (uint32_t)0xFF1493
|
||||
#define ULTRAWHITE (uint32_t)0xFFFFFFFF
|
||||
#define DARKSLATEGRAY (uint32_t)0x2F4F4F
|
||||
#define DARKSLATEGREY (uint32_t)0x2F4F4F
|
||||
#define DARKSLATEGREY DARKSLATEGRAY
|
||||
|
||||
// options
|
||||
// bit 7: segment is in transition mode
|
||||
// bits 4-6: TBD
|
||||
// bit 3: mirror effect within segment
|
||||
// bit 2: segment is on
|
||||
// bit 1: reverse segment
|
||||
// bit 0: segment is selected
|
||||
// segment options
|
||||
#define NO_OPTIONS (uint16_t)0x0000
|
||||
#define TRANSPOSED (uint16_t)0x0400 // rotated 90deg & reversed
|
||||
#define REVERSE_Y_2D (uint16_t)0x0200
|
||||
#define MIRROR_Y_2D (uint16_t)0x0100
|
||||
#define TRANSITIONAL (uint16_t)0x0080
|
||||
#define TRANSPOSED (uint16_t)0x0100 // rotated 90deg & reversed
|
||||
#define MIRROR_Y_2D (uint16_t)0x0080
|
||||
#define REVERSE_Y_2D (uint16_t)0x0040
|
||||
#define RESET_REQ (uint16_t)0x0020
|
||||
#define FROZEN (uint16_t)0x0010
|
||||
#define MIRROR (uint16_t)0x0008
|
||||
#define SEGMENT_ON (uint16_t)0x0004
|
||||
#define REVERSE (uint16_t)0x0002
|
||||
@ -348,12 +343,11 @@ typedef struct Segment {
|
||||
bool mirror : 1; // 3 : mirrored
|
||||
bool freeze : 1; // 4 : paused/frozen
|
||||
bool reset : 1; // 5 : indicates that Segment runtime requires reset
|
||||
bool transitional: 1; // 6 : transitional (there is transition occuring)
|
||||
bool reverse_y : 1; // 7 : reversed Y (2D)
|
||||
bool mirror_y : 1; // 8 : mirrored Y (2D)
|
||||
bool transpose : 1; // 9 : transposed (2D, swapped X & Y)
|
||||
uint8_t map1D2D : 3; // 10-12 : mapping for 1D effect on 2D (0-use as strip, 1-expand vertically, 2-circular/arc, 3-rectangular/corner, ...)
|
||||
uint8_t soundSim : 1; // 13 : 0-1 sound simulation types ("soft" & "hard" or "on"/"off")
|
||||
bool reverse_y : 1; // 6 : reversed Y (2D)
|
||||
bool mirror_y : 1; // 7 : mirrored Y (2D)
|
||||
bool transpose : 1; // 8 : transposed (2D, swapped X & Y)
|
||||
uint8_t map1D2D : 3; // 9-11 : mapping for 1D effect on 2D (0-use as strip, 1-expand vertically, 2-circular/arc, 3-rectangular/corner, ...)
|
||||
uint8_t soundSim : 2; // 12-13 : 0-3 sound simulation types ("soft" & "hard" or "on"/"off")
|
||||
uint8_t set : 2; // 14-15 : 0-3 UI segment sets/groups
|
||||
};
|
||||
};
|
||||
@ -484,7 +478,6 @@ typedef struct Segment {
|
||||
_dataLen(0),
|
||||
_t(nullptr)
|
||||
{
|
||||
//refreshLightCapabilities();
|
||||
#ifdef WLED_DEBUG
|
||||
//Serial.printf("-- Creating segment: %p\n", this);
|
||||
#endif
|
||||
@ -519,6 +512,7 @@ typedef struct Segment {
|
||||
|
||||
inline bool getOption(uint8_t n) const { return ((options >> n) & 0x01); }
|
||||
inline bool isSelected(void) const { return selected; }
|
||||
inline bool isInTransition(void) const { return _t != nullptr; }
|
||||
inline bool isActive(void) const { return stop > start; }
|
||||
inline bool is2D(void) const { return (width()>1 && height()>1); }
|
||||
inline bool hasRGB(void) const { return _isRGB; }
|
||||
@ -569,15 +563,16 @@ typedef struct Segment {
|
||||
void restoreSegenv(tmpsegd_t &tmpSegD);
|
||||
#endif
|
||||
uint16_t progress(void); //transition progression between 0-65535
|
||||
uint8_t currentBri(uint8_t briNew, bool useCct = false);
|
||||
uint8_t currentMode(uint8_t modeNew);
|
||||
uint32_t currentColor(uint8_t slot, uint32_t colorNew);
|
||||
uint8_t currentBri(bool useCct = false);
|
||||
uint8_t currentMode(void);
|
||||
uint32_t currentColor(uint8_t slot);
|
||||
CRGBPalette16 &loadPalette(CRGBPalette16 &tgt, uint8_t pal);
|
||||
CRGBPalette16 ¤tPalette(CRGBPalette16 &tgt, uint8_t paletteID);
|
||||
|
||||
// 1D strip
|
||||
uint16_t virtualLength(void) const;
|
||||
void setPixelColor(int n, uint32_t c); // set relative pixel within segment with color
|
||||
void setPixelColor(unsigned n, uint32_t c) { setPixelColor(int(n), c); }
|
||||
void setPixelColor(int n, byte r, byte g, byte b, byte w = 0) { setPixelColor(n, RGBW32(r,g,b,w)); } // automatically inline
|
||||
void setPixelColor(int n, CRGB c) { setPixelColor(n, RGBW32(c.r,c.g,c.b,0)); } // automatically inline
|
||||
void setPixelColor(float i, uint32_t c, bool aa = true);
|
||||
@ -595,7 +590,6 @@ typedef struct Segment {
|
||||
void addPixelColor(int n, byte r, byte g, byte b, byte w = 0, bool fast = false) { addPixelColor(n, RGBW32(r,g,b,w), fast); } // automatically inline
|
||||
void addPixelColor(int n, CRGB c, bool fast = false) { addPixelColor(n, RGBW32(c.r,c.g,c.b,0), fast); } // automatically inline
|
||||
void fadePixelColor(uint16_t n, uint8_t fade);
|
||||
uint8_t get_random_wheel_index(uint8_t pos);
|
||||
uint32_t color_from_palette(uint16_t, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri = 255);
|
||||
uint32_t color_wheel(uint8_t pos);
|
||||
|
||||
@ -606,6 +600,7 @@ typedef struct Segment {
|
||||
#ifndef WLED_DISABLE_2D
|
||||
uint16_t XY(uint16_t x, uint16_t y); // support function to get relative index within segment
|
||||
void setPixelColorXY(int x, int y, uint32_t c); // set relative pixel within segment with color
|
||||
void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColorXY(int(x), int(y), c); }
|
||||
void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColorXY(x, y, RGBW32(r,g,b,w)); } // automatically inline
|
||||
void setPixelColorXY(int x, int y, CRGB c) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); } // automatically inline
|
||||
void setPixelColorXY(float x, float y, uint32_t c, bool aa = true);
|
||||
@ -881,16 +876,14 @@ class WS2812FX { // 96 bytes
|
||||
std::vector<Panel> panel;
|
||||
#endif
|
||||
|
||||
void
|
||||
setUpMatrix(),
|
||||
setPixelColorXY(int x, int y, uint32_t c);
|
||||
void setUpMatrix();
|
||||
|
||||
// outsmart the compiler :) by correctly overloading
|
||||
inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColorXY(x, y, RGBW32(r,g,b,w)); } // automatically inline
|
||||
inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); }
|
||||
inline void setPixelColorXY(int x, int y, uint32_t c) { setPixelColor(y * Segment::maxWidth + x, c); }
|
||||
inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColorXY(x, y, RGBW32(r,g,b,w)); }
|
||||
inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); }
|
||||
|
||||
uint32_t
|
||||
getPixelColorXY(uint16_t, uint16_t);
|
||||
inline uint32_t getPixelColorXY(uint16_t x, uint16_t y) { return getPixelColor(isMatrix ? y * Segment::maxWidth + x : x);}
|
||||
|
||||
// end 2D support
|
||||
|
||||
|
@ -134,7 +134,7 @@ void WS2812FX::setUpMatrix() {
|
||||
|
||||
#ifdef WLED_DEBUG
|
||||
DEBUG_PRINT(F("Matrix ledmap:"));
|
||||
for (uint16_t i=0; i<customMappingSize; i++) {
|
||||
for (unsigned i=0; i<customMappingSize; i++) {
|
||||
if (!(i%Segment::maxWidth)) DEBUG_PRINTLN();
|
||||
DEBUG_PRINTF("%4d,", customMappingTable[i]);
|
||||
}
|
||||
@ -155,31 +155,6 @@ void WS2812FX::setUpMatrix() {
|
||||
#endif
|
||||
}
|
||||
|
||||
// absolute matrix version of setPixelColor()
|
||||
void /*IRAM_ATTR*/ WS2812FX::setPixelColorXY(int x, int y, uint32_t col)
|
||||
{
|
||||
#ifndef WLED_DISABLE_2D
|
||||
if (!isMatrix) return; // not a matrix set-up
|
||||
uint16_t index = y * Segment::maxWidth + x;
|
||||
#else
|
||||
uint16_t index = x;
|
||||
#endif
|
||||
if (index < customMappingSize) index = customMappingTable[index];
|
||||
if (index >= _length) return;
|
||||
busses.setPixelColor(index, col);
|
||||
}
|
||||
|
||||
// returns RGBW values of pixel
|
||||
uint32_t WS2812FX::getPixelColorXY(uint16_t x, uint16_t y) {
|
||||
#ifndef WLED_DISABLE_2D
|
||||
uint16_t index = (y * Segment::maxWidth + x);
|
||||
#else
|
||||
uint16_t index = x;
|
||||
#endif
|
||||
if (index < customMappingSize) index = customMappingTable[index];
|
||||
if (index >= _length) return 0;
|
||||
return busses.getPixelColor(index);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// Segment:: routines
|
||||
@ -188,18 +163,19 @@ uint32_t WS2812FX::getPixelColorXY(uint16_t x, uint16_t y) {
|
||||
#ifndef WLED_DISABLE_2D
|
||||
|
||||
// XY(x,y) - gets pixel index within current segment (often used to reference leds[] array element)
|
||||
uint16_t /*IRAM_ATTR*/ Segment::XY(uint16_t x, uint16_t y) {
|
||||
uint16_t IRAM_ATTR Segment::XY(uint16_t x, uint16_t y)
|
||||
{
|
||||
uint16_t width = virtualWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
|
||||
uint16_t height = virtualHeight(); // segment height in logical pixels (is always >= 1)
|
||||
return isActive() ? (x%width) + (y%height) * width : 0;
|
||||
}
|
||||
|
||||
void /*IRAM_ATTR*/ Segment::setPixelColorXY(int x, int y, uint32_t col)
|
||||
void IRAM_ATTR Segment::setPixelColorXY(int x, int y, uint32_t col)
|
||||
{
|
||||
if (!isActive()) return; // not active
|
||||
if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit
|
||||
|
||||
uint8_t _bri_t = currentBri(on ? opacity : 0);
|
||||
uint8_t _bri_t = currentBri();
|
||||
if (_bri_t < 255) {
|
||||
byte r = scale8(R(col), _bri_t);
|
||||
byte g = scale8(G(col), _bri_t);
|
||||
@ -310,32 +286,17 @@ void Segment::blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t
|
||||
void Segment::addPixelColorXY(int x, int y, uint32_t color, bool fast) {
|
||||
if (!isActive()) return; // not active
|
||||
if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit
|
||||
uint32_t col = getPixelColorXY(x,y);
|
||||
uint8_t r = R(col);
|
||||
uint8_t g = G(col);
|
||||
uint8_t b = B(col);
|
||||
uint8_t w = W(col);
|
||||
if (fast) {
|
||||
r = qadd8(r, R(color));
|
||||
g = qadd8(g, G(color));
|
||||
b = qadd8(b, B(color));
|
||||
w = qadd8(w, W(color));
|
||||
col = RGBW32(r,g,b,w);
|
||||
} else {
|
||||
col = color_add(col, color);
|
||||
}
|
||||
setPixelColorXY(x, y, col);
|
||||
setPixelColorXY(x, y, color_add(getPixelColorXY(x,y), color, fast));
|
||||
}
|
||||
|
||||
void Segment::fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) {
|
||||
if (!isActive()) return; // not active
|
||||
CRGB pix = CRGB(getPixelColorXY(x,y)).nscale8_video(fade);
|
||||
setPixelColorXY(x, y, pix);
|
||||
setPixelColorXY(x, y, color_fade(getPixelColorXY(x,y), fade, true));
|
||||
}
|
||||
|
||||
// blurRow: perform a blur on a row of a rectangular matrix
|
||||
void Segment::blurRow(uint16_t row, fract8 blur_amount) {
|
||||
if (!isActive()) return; // not active
|
||||
if (!isActive() || blur_amount == 0) return; // not active
|
||||
const uint_fast16_t cols = virtualWidth();
|
||||
const uint_fast16_t rows = virtualHeight();
|
||||
|
||||
@ -344,7 +305,7 @@ void Segment::blurRow(uint16_t row, fract8 blur_amount) {
|
||||
uint8_t keep = 255 - blur_amount;
|
||||
uint8_t seep = blur_amount >> 1;
|
||||
CRGB carryover = CRGB::Black;
|
||||
for (uint_fast16_t x = 0; x < cols; x++) {
|
||||
for (unsigned x = 0; x < cols; x++) {
|
||||
CRGB cur = getPixelColorXY(x, row);
|
||||
CRGB before = cur; // remember color before blur
|
||||
CRGB part = cur;
|
||||
@ -363,7 +324,7 @@ void Segment::blurRow(uint16_t row, fract8 blur_amount) {
|
||||
|
||||
// blurCol: perform a blur on a column of a rectangular matrix
|
||||
void Segment::blurCol(uint16_t col, fract8 blur_amount) {
|
||||
if (!isActive()) return; // not active
|
||||
if (!isActive() || blur_amount == 0) return; // not active
|
||||
const uint_fast16_t cols = virtualWidth();
|
||||
const uint_fast16_t rows = virtualHeight();
|
||||
|
||||
@ -372,7 +333,7 @@ void Segment::blurCol(uint16_t col, fract8 blur_amount) {
|
||||
uint8_t keep = 255 - blur_amount;
|
||||
uint8_t seep = blur_amount >> 1;
|
||||
CRGB carryover = CRGB::Black;
|
||||
for (uint_fast16_t y = 0; y < rows; y++) {
|
||||
for (unsigned y = 0; y < rows; y++) {
|
||||
CRGB cur = getPixelColorXY(col, y);
|
||||
CRGB part = cur;
|
||||
CRGB before = cur; // remember color before blur
|
||||
@ -391,7 +352,7 @@ void Segment::blurCol(uint16_t col, fract8 blur_amount) {
|
||||
|
||||
// 1D Box blur (with added weight - blur_amount: [0=no blur, 255=max blur])
|
||||
void Segment::box_blur(uint16_t i, bool vertical, fract8 blur_amount) {
|
||||
if (!isActive()) return; // not active
|
||||
if (!isActive() || blur_amount == 0) return; // not active
|
||||
const uint16_t cols = virtualWidth();
|
||||
const uint16_t rows = virtualHeight();
|
||||
const uint16_t dim1 = vertical ? rows : cols;
|
||||
@ -401,7 +362,7 @@ void Segment::box_blur(uint16_t i, bool vertical, fract8 blur_amount) {
|
||||
const float keep = 3.f - 2.f*seep;
|
||||
// 1D box blur
|
||||
CRGB tmp[dim1];
|
||||
for (uint16_t j = 0; j < dim1; j++) {
|
||||
for (int j = 0; j < dim1; j++) {
|
||||
uint16_t x = vertical ? i : j;
|
||||
uint16_t y = vertical ? j : i;
|
||||
int16_t xp = vertical ? x : x-1; // "signed" to prevent underflow
|
||||
@ -417,7 +378,7 @@ void Segment::box_blur(uint16_t i, bool vertical, fract8 blur_amount) {
|
||||
b = (curr.b*keep + (prev.b + next.b)*seep) / 3;
|
||||
tmp[j] = CRGB(r,g,b);
|
||||
}
|
||||
for (uint16_t j = 0; j < dim1; j++) {
|
||||
for (int j = 0; j < dim1; j++) {
|
||||
uint16_t x = vertical ? i : j;
|
||||
uint16_t y = vertical ? j : i;
|
||||
setPixelColorXY(x, y, tmp[j]);
|
||||
@ -440,7 +401,7 @@ void Segment::box_blur(uint16_t i, bool vertical, fract8 blur_amount) {
|
||||
|
||||
void Segment::blur1d(fract8 blur_amount) {
|
||||
const uint16_t rows = virtualHeight();
|
||||
for (uint16_t y = 0; y < rows; y++) blurRow(y, blur_amount);
|
||||
for (unsigned y = 0; y < rows; y++) blurRow(y, blur_amount);
|
||||
}
|
||||
|
||||
void Segment::moveX(int8_t delta, bool wrap) {
|
||||
@ -498,7 +459,7 @@ void Segment::move(uint8_t dir, uint8_t delta, bool wrap) {
|
||||
}
|
||||
|
||||
void Segment::draw_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) {
|
||||
if (!isActive()) return; // not active
|
||||
if (!isActive() || radius == 0) return; // not active
|
||||
// Bresenham’s Algorithm
|
||||
int d = 3 - (2*radius);
|
||||
int y = radius, x = 0;
|
||||
@ -523,7 +484,7 @@ void Segment::draw_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) {
|
||||
|
||||
// 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) {
|
||||
if (!isActive()) return; // not active
|
||||
if (!isActive() || radius == 0) return; // not active
|
||||
const uint16_t cols = virtualWidth();
|
||||
const uint16_t rows = virtualHeight();
|
||||
for (int16_t y = -radius; y <= radius; y++) {
|
||||
@ -540,7 +501,7 @@ void Segment::nscale8(uint8_t scale) {
|
||||
if (!isActive()) return; // not active
|
||||
const uint16_t cols = virtualWidth();
|
||||
const uint16_t rows = virtualHeight();
|
||||
for(uint16_t y = 0; y < rows; y++) for (uint16_t x = 0; x < cols; x++) {
|
||||
for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) {
|
||||
setPixelColorXY(x, y, CRGB(getPixelColorXY(x, y)).nscale8(scale));
|
||||
}
|
||||
}
|
||||
|
@ -89,25 +89,19 @@ bool Segment::_modeBlend = false;
|
||||
Segment::Segment(const Segment &orig) {
|
||||
//DEBUG_PRINTF("-- Copy segment constructor: %p -> %p\n", &orig, this);
|
||||
memcpy((void*)this, (void*)&orig, sizeof(Segment));
|
||||
transitional = false; // copied segment cannot be in transition
|
||||
name = nullptr;
|
||||
data = nullptr;
|
||||
_dataLen = 0;
|
||||
_t = nullptr;
|
||||
if (orig.name) { name = new char[strlen(orig.name)+1]; if (name) strcpy(name, orig.name); }
|
||||
if (orig.data) { if (allocateData(orig._dataLen)) memcpy(data, orig.data, orig._dataLen); }
|
||||
//if (orig._t) { _t = new Transition(orig._t->_dur); }
|
||||
_t = nullptr; // copied segment cannot be in transition
|
||||
if (orig.name) { name = new char[strlen(orig.name)+1]; if (name) strcpy(name, orig.name); } else { name = nullptr; }
|
||||
if (orig.data) { if (allocateData(orig._dataLen)) memcpy(data, orig.data, orig._dataLen); } else { data = nullptr; _dataLen = 0; }
|
||||
}
|
||||
|
||||
// move constructor
|
||||
Segment::Segment(Segment &&orig) noexcept {
|
||||
//DEBUG_PRINTF("-- Move segment constructor: %p -> %p\n", &orig, this);
|
||||
memcpy((void*)this, (void*)&orig, sizeof(Segment));
|
||||
orig.transitional = false; // old segment cannot be in transition any more
|
||||
orig.name = nullptr;
|
||||
orig.data = nullptr;
|
||||
orig._dataLen = 0;
|
||||
orig._t = nullptr;
|
||||
orig._t = nullptr; // old segment cannot be in transition any more
|
||||
}
|
||||
|
||||
// copy assignment
|
||||
@ -115,27 +109,23 @@ Segment& Segment::operator= (const Segment &orig) {
|
||||
//DEBUG_PRINTF("-- Copying segment: %p -> %p\n", &orig, this);
|
||||
if (this != &orig) {
|
||||
// clean destination
|
||||
transitional = false; // copied segment cannot be in transition
|
||||
if (name) delete[] name;
|
||||
if (name) { delete[] name; name = nullptr; }
|
||||
if (orig.name) { name = new char[strlen(orig.name)+1]; if (name) strcpy(name, orig.name); }
|
||||
if (_t) {
|
||||
#ifndef WLED_DISABLE_MODE_BLEND
|
||||
if (_t->_segT._dataT) free(_t->_segT._dataT);
|
||||
#endif
|
||||
delete _t;
|
||||
_t = nullptr; // copied segment cannot be in transition
|
||||
}
|
||||
deallocateData();
|
||||
// copy source
|
||||
memcpy((void*)this, (void*)&orig, sizeof(Segment));
|
||||
transitional = false;
|
||||
// erase pointers to allocated data
|
||||
name = nullptr;
|
||||
data = nullptr;
|
||||
_dataLen = 0;
|
||||
_t = nullptr;
|
||||
// copy source data
|
||||
if (orig.name) { name = new char[strlen(orig.name)+1]; if (name) strcpy(name, orig.name); }
|
||||
if (orig.data) { if (allocateData(orig._dataLen)) memcpy(data, orig.data, orig._dataLen); }
|
||||
//if (orig._t) { _t = new Transition(orig._t->_dur, orig._t->_briT, orig._t->_cctT, orig._t->_colorT); }
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@ -144,9 +134,7 @@ Segment& Segment::operator= (const Segment &orig) {
|
||||
Segment& Segment::operator= (Segment &&orig) noexcept {
|
||||
//DEBUG_PRINTF("-- Moving segment: %p -> %p\n", &orig, this);
|
||||
if (this != &orig) {
|
||||
transitional = false; // just temporary
|
||||
if (name) { delete[] name; name = nullptr; } // free old name
|
||||
deallocateData(); // free old runtime data
|
||||
if (_t) {
|
||||
#ifndef WLED_DISABLE_MODE_BLEND
|
||||
if (_t->_segT._dataT) free(_t->_segT._dataT);
|
||||
@ -154,12 +142,12 @@ Segment& Segment::operator= (Segment &&orig) noexcept {
|
||||
delete _t;
|
||||
_t = nullptr;
|
||||
}
|
||||
deallocateData(); // free old runtime data
|
||||
memcpy((void*)this, (void*)&orig, sizeof(Segment));
|
||||
orig.transitional = false; // old segment cannot be in transition
|
||||
orig.name = nullptr;
|
||||
orig.data = nullptr;
|
||||
orig._dataLen = 0;
|
||||
orig._t = nullptr;
|
||||
orig._t = nullptr; // old segment cannot be in transition
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@ -237,7 +225,7 @@ CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) {
|
||||
switch (pal) {
|
||||
case 0: //default palette. Exceptions for specific effects above
|
||||
targetPalette = PartyColors_p; break;
|
||||
case 1: {//periodically replace palette with a random one. Transition palette change in 500ms
|
||||
case 1: {//periodically replace palette with a random one
|
||||
unsigned long timeSinceLastChange = millis() - _lastPaletteChange;
|
||||
if (timeSinceLastChange > randomPaletteChangeTime * 1000U) {
|
||||
_randomPalette = _newRandomPalette;
|
||||
@ -301,47 +289,45 @@ CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) {
|
||||
}
|
||||
|
||||
void Segment::startTransition(uint16_t dur) {
|
||||
if (!dur) {
|
||||
if (_t) _t->_dur = dur; // this will stop transition in next handleTransisiton()
|
||||
else transitional = false;
|
||||
if (dur == 0) {
|
||||
if (isInTransition()) _t->_dur = dur; // this will stop transition in next handleTransisiton()
|
||||
return;
|
||||
}
|
||||
if (transitional && _t) return; // already in transition no need to store anything
|
||||
if (isInTransition()) return; // already in transition no need to store anything
|
||||
|
||||
// starting a transition has to occur before change so we get current values 1st
|
||||
_t = new Transition(dur); // no previous transition running
|
||||
if (!_t) return; // failed to allocate data
|
||||
|
||||
//DEBUG_PRINTF("-- Started transition: %p\n", this);
|
||||
CRGBPalette16 _palT = CRGBPalette16(DEFAULT_COLOR); loadPalette(_palT, palette);
|
||||
_t->_palT = _palT;
|
||||
loadPalette(_t->_palT, palette);
|
||||
_t->_briT = on ? opacity : 0;
|
||||
_t->_cctT = cct;
|
||||
#ifndef WLED_DISABLE_MODE_BLEND
|
||||
swapSegenv(_t->_segT);
|
||||
_t->_modeT = mode;
|
||||
_t->_segT._optionsT |= 0b0000000001000000; // mark old segment transitional
|
||||
_t->_segT._dataLenT = 0;
|
||||
_t->_segT._dataT = nullptr;
|
||||
if (_dataLen > 0 && data) {
|
||||
_t->_segT._dataT = (byte *)malloc(_dataLen);
|
||||
if (_t->_segT._dataT) {
|
||||
//DEBUG_PRINTF("-- Allocated duplicate data (%d): %p\n", _dataLen, _t->_segT._dataT);
|
||||
memcpy(_t->_segT._dataT, data, _dataLen);
|
||||
_t->_segT._dataLenT = _dataLen;
|
||||
if (modeBlending) {
|
||||
swapSegenv(_t->_segT);
|
||||
_t->_modeT = mode;
|
||||
_t->_segT._dataLenT = 0;
|
||||
_t->_segT._dataT = nullptr;
|
||||
if (_dataLen > 0 && data) {
|
||||
_t->_segT._dataT = (byte *)malloc(_dataLen);
|
||||
if (_t->_segT._dataT) {
|
||||
//DEBUG_PRINTF("-- Allocated duplicate data (%d): %p\n", _dataLen, _t->_segT._dataT);
|
||||
memcpy(_t->_segT._dataT, data, _dataLen);
|
||||
_t->_segT._dataLenT = _dataLen;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (size_t i=0; i<NUM_COLORS; i++) _t->_segT._colorT[i] = colors[i];
|
||||
}
|
||||
#else
|
||||
for (size_t i=0; i<NUM_COLORS; i++) _t->_colorT[i] = colors[i];
|
||||
#endif
|
||||
transitional = true; // setOption(SEG_OPTION_TRANSITIONAL, true);
|
||||
}
|
||||
|
||||
void Segment::stopTransition() {
|
||||
if (!transitional) return;
|
||||
transitional = false; // finish transitioning segment
|
||||
//DEBUG_PRINTF("-- Stopping transition: %p\n", this);
|
||||
if (_t) {
|
||||
if (isInTransition()) {
|
||||
#ifndef WLED_DISABLE_MODE_BLEND
|
||||
if (_t->_segT._dataT && _t->_segT._dataLenT > 0) {
|
||||
//DEBUG_PRINTF("-- Released duplicate data (%d): %p\n", _t->_segT._dataLenT, _t->_segT._dataT);
|
||||
@ -356,14 +342,13 @@ void Segment::stopTransition() {
|
||||
}
|
||||
|
||||
void Segment::handleTransition() {
|
||||
if (!transitional) return;
|
||||
uint16_t _progress = progress();
|
||||
if (_progress == 0xFFFFU) stopTransition();
|
||||
}
|
||||
|
||||
// transition progression between 0-65535
|
||||
uint16_t Segment::progress() {
|
||||
if (transitional && _t) {
|
||||
if (isInTransition()) {
|
||||
unsigned long timeNow = millis();
|
||||
if (_t->_dur > 0 && timeNow - _t->_start < _t->_dur) return (timeNow - _t->_start) * 0xFFFFU / _t->_dur;
|
||||
}
|
||||
@ -420,8 +405,8 @@ void Segment::restoreSegenv(tmpsegd_t &tmpSeg) {
|
||||
_t->_segT._stepT = step;
|
||||
_t->_segT._callT = call;
|
||||
//if (_t->_segT._dataT != data) DEBUG_PRINTF("--- data re-allocated: (%p) %p -> %p\n", this, _t->_segT._dataT, data);
|
||||
_t->_segT._dataT = data; // sometimes memory gets re-allocated (!! INVESTIGATE WHY !!)
|
||||
_t->_segT._dataLenT = _dataLen; // sometimes memory gets re-allocated (!! INVESTIGATE WHY !!)
|
||||
_t->_segT._dataT = data;
|
||||
_t->_segT._dataLenT = _dataLen;
|
||||
}
|
||||
options = tmpSeg._optionsT;
|
||||
for (size_t i=0; i<NUM_COLORS; i++) colors[i] = tmpSeg._colorT[i];
|
||||
@ -443,39 +428,40 @@ void Segment::restoreSegenv(tmpsegd_t &tmpSeg) {
|
||||
}
|
||||
#endif
|
||||
|
||||
uint8_t Segment::currentBri(uint8_t briNew, bool useCct) {
|
||||
uint8_t Segment::currentBri(bool useCct) {
|
||||
uint32_t prog = progress();
|
||||
if (prog < 0xFFFFU) {
|
||||
if (useCct) return ((briNew * prog) + _t->_cctT * (0xFFFFU - prog)) >> 16;
|
||||
else return ((briNew * prog) + _t->_briT * (0xFFFFU - prog)) >> 16;
|
||||
uint32_t curBri = (useCct ? cct : (on ? opacity : 0)) * prog;
|
||||
curBri += (useCct ? _t->_cctT : (on ? _t->_briT : 0)) * (0xFFFFU - prog);
|
||||
return curBri / 0xFFFFU;
|
||||
}
|
||||
return briNew;
|
||||
return (useCct ? cct : (on ? opacity : 0));
|
||||
}
|
||||
|
||||
uint8_t Segment::currentMode(uint8_t newMode) {
|
||||
uint8_t Segment::currentMode() {
|
||||
#ifndef WLED_DISABLE_MODE_BLEND
|
||||
uint16_t prog = progress(); // implicit check for transitional & _t in progress()
|
||||
if (prog < 0xFFFFU) return _t->_modeT;
|
||||
uint16_t prog = progress();
|
||||
if (modeBlending && prog < 0xFFFFU) return _t->_modeT;
|
||||
#endif
|
||||
return newMode;
|
||||
return mode;
|
||||
}
|
||||
|
||||
uint32_t Segment::currentColor(uint8_t slot, uint32_t colorNew) {
|
||||
uint32_t Segment::currentColor(uint8_t slot) {
|
||||
#ifndef WLED_DISABLE_MODE_BLEND
|
||||
return transitional && _t ? color_blend(_t->_segT._colorT[slot], colorNew, progress(), true) : colorNew;
|
||||
return isInTransition() ? color_blend(_t->_segT._colorT[slot], colors[slot], progress(), true) : colors[slot];
|
||||
#else
|
||||
return transitional && _t ? color_blend(_t->_colorT[slot], colorNew, progress(), true) : colorNew;
|
||||
return isInTransition() ? color_blend(_t->_colorT[slot], colors[slot], progress(), true) : colors[slot];
|
||||
#endif
|
||||
}
|
||||
|
||||
CRGBPalette16 &Segment::currentPalette(CRGBPalette16 &targetPalette, uint8_t pal) {
|
||||
loadPalette(targetPalette, pal);
|
||||
if (progress() < 0xFFFFU) {
|
||||
uint16_t prog = progress();
|
||||
if (strip.paletteFade && prog < 0xFFFFU) {
|
||||
// blend palettes
|
||||
// there are about 255 blend passes of 48 "blends" to completely blend two palettes (in _dur time)
|
||||
// minimum blend time is 100ms maximum is 65535ms
|
||||
unsigned long timeMS = millis() - _t->_start;
|
||||
uint16_t noOfBlends = (255U * timeMS / _t->_dur) - _t->_prevPaletteBlends;
|
||||
uint16_t noOfBlends = ((255U * prog) / 0xFFFFU) - _t->_prevPaletteBlends;
|
||||
for (int i=0; i<noOfBlends; i++, _t->_prevPaletteBlends++) nblendPaletteTowardPalette(_t->_palT, targetPalette, 48);
|
||||
targetPalette = _t->_palT; // copy transitioning/temporary palette
|
||||
}
|
||||
@ -500,6 +486,8 @@ void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t
|
||||
&& (!grp || (grouping == grp && spacing == spc))
|
||||
&& (ofs == UINT16_MAX || ofs == offset)) return;
|
||||
|
||||
stateChanged = true; // send UDP/WS broadcast
|
||||
|
||||
if (stop) fill(BLACK); // turn old segment range off (clears pixels if changing spacing)
|
||||
if (grp) { // prevent assignment of 0
|
||||
grouping = grp;
|
||||
@ -510,6 +498,10 @@ void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t
|
||||
}
|
||||
if (ofs < UINT16_MAX) offset = ofs;
|
||||
|
||||
DEBUG_PRINT(F("setUp segment: ")); DEBUG_PRINT(i1);
|
||||
DEBUG_PRINT(','); DEBUG_PRINT(i2);
|
||||
DEBUG_PRINT(F(" -> ")); DEBUG_PRINT(i1Y);
|
||||
DEBUG_PRINT(','); DEBUG_PRINTLN(i2Y);
|
||||
markForReset();
|
||||
if (boundsUnchanged) return;
|
||||
|
||||
@ -564,7 +556,6 @@ void Segment::setCCT(uint16_t k) {
|
||||
void Segment::setOpacity(uint8_t o) {
|
||||
if (opacity == o) return;
|
||||
if (fadeTransition) startTransition(strip.getTransition()); // start transition prior to change
|
||||
DEBUG_PRINT(F("-- Setting opacity: ")); DEBUG_PRINTLN(o);
|
||||
opacity = o;
|
||||
stateChanged = true; // send UDP/WS broadcast
|
||||
}
|
||||
@ -574,14 +565,16 @@ void Segment::setOption(uint8_t n, bool val) {
|
||||
if (fadeTransition && n == SEG_OPTION_ON && val != prevOn) startTransition(strip.getTransition()); // start transition prior to change
|
||||
if (val) options |= 0x01 << n;
|
||||
else options &= ~(0x01 << n);
|
||||
if (!(n == SEG_OPTION_SELECTED || n == SEG_OPTION_RESET || n == SEG_OPTION_TRANSITIONAL)) stateChanged = true; // send UDP/WS broadcast
|
||||
if (!(n == SEG_OPTION_SELECTED || n == SEG_OPTION_RESET)) stateChanged = true; // send UDP/WS broadcast
|
||||
}
|
||||
|
||||
void Segment::setMode(uint8_t fx, bool loadDefaults) {
|
||||
// if we have a valid mode & is not reserved
|
||||
if (fx < strip.getModeCount() && strncmp_P("RSVD", strip.getModeData(fx), 4)) {
|
||||
if (fx != mode) {
|
||||
if (fadeTransition) startTransition(strip.getTransition()); // set effect transitions
|
||||
#ifndef WLED_DISABLE_MODE_BLEND
|
||||
if (modeBlending) startTransition(strip.getTransition()); // set effect transitions
|
||||
#endif
|
||||
mode = fx;
|
||||
// load default values from effect string
|
||||
if (loadDefaults) {
|
||||
@ -743,7 +736,7 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col)
|
||||
#endif
|
||||
|
||||
uint16_t len = length();
|
||||
uint8_t _bri_t = currentBri(on ? opacity : 0);
|
||||
uint8_t _bri_t = currentBri();
|
||||
if (_bri_t < 255) {
|
||||
byte r = scale8(R(col), _bri_t);
|
||||
byte g = scale8(G(col), _bri_t);
|
||||
@ -877,10 +870,11 @@ uint8_t Segment::differs(Segment& b) const {
|
||||
if (startY != b.startY) d |= SEG_DIFFERS_BOUNDS;
|
||||
if (stopY != b.stopY) d |= SEG_DIFFERS_BOUNDS;
|
||||
|
||||
//bit pattern: (msb first) set:2, sound:1, mapping:3, transposed, mirrorY, reverseY, [transitional, reset,] paused, mirrored, on, reverse, [selected]
|
||||
if ((options & 0b1111111110011110U) != (b.options & 0b1111111110011110U)) d |= SEG_DIFFERS_OPT;
|
||||
//bit pattern: (msb first)
|
||||
// set:2, sound:2, mapping:3, transposed, mirrorY, reverseY, [reset,] paused, mirrored, on, reverse, [selected]
|
||||
if ((options & 0b1111111111011110U) != (b.options & 0b1111111111011110U)) d |= SEG_DIFFERS_OPT;
|
||||
if ((options & 0x0001U) != (b.options & 0x0001U)) d |= SEG_DIFFERS_SEL;
|
||||
for (uint8_t i = 0; i < NUM_COLORS; i++) if (colors[i] != b.colors[i]) d |= SEG_DIFFERS_COL;
|
||||
for (unsigned i = 0; i < NUM_COLORS; i++) if (colors[i] != b.colors[i]) d |= SEG_DIFFERS_COL;
|
||||
|
||||
return d;
|
||||
}
|
||||
@ -912,7 +906,7 @@ void Segment::refreshLightCapabilities() {
|
||||
segStopIdx = stop;
|
||||
}
|
||||
|
||||
for (uint8_t b = 0; b < busses.getNumBusses(); b++) {
|
||||
for (unsigned b = 0; b < busses.getNumBusses(); b++) {
|
||||
Bus *bus = busses.getBus(b);
|
||||
if (bus == nullptr || bus->getLength()==0) break;
|
||||
if (!bus->isOk()) continue;
|
||||
@ -942,7 +936,7 @@ void Segment::fill(uint32_t c) {
|
||||
if (!isActive()) return; // not active
|
||||
const uint16_t cols = is2D() ? virtualWidth() : virtualLength();
|
||||
const uint16_t rows = virtualHeight(); // will be 1 for 1D
|
||||
for(uint16_t y = 0; y < rows; y++) for (uint16_t x = 0; x < cols; x++) {
|
||||
for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) {
|
||||
if (is2D()) setPixelColorXY(x, y, c);
|
||||
else setPixelColor(x, c);
|
||||
}
|
||||
@ -956,27 +950,12 @@ void Segment::blendPixelColor(int n, uint32_t color, uint8_t blend) {
|
||||
// Adds the specified color with the existing pixel color perserving color balance.
|
||||
void Segment::addPixelColor(int n, uint32_t color, bool fast) {
|
||||
if (!isActive()) return; // not active
|
||||
uint32_t col = getPixelColor(n);
|
||||
uint8_t r = R(col);
|
||||
uint8_t g = G(col);
|
||||
uint8_t b = B(col);
|
||||
uint8_t w = W(col);
|
||||
if (fast) {
|
||||
r = qadd8(r, R(color));
|
||||
g = qadd8(g, G(color));
|
||||
b = qadd8(b, B(color));
|
||||
w = qadd8(w, W(color));
|
||||
col = RGBW32(r,g,b,w);
|
||||
} else {
|
||||
col = color_add(col, color);
|
||||
}
|
||||
setPixelColor(n, col);
|
||||
setPixelColor(n, color_add(getPixelColor(n), color, fast));
|
||||
}
|
||||
|
||||
void Segment::fadePixelColor(uint16_t n, uint8_t fade) {
|
||||
if (!isActive()) return; // not active
|
||||
CRGB pix = CRGB(getPixelColor(n)).nscale8_video(fade);
|
||||
setPixelColor(n, pix);
|
||||
setPixelColor(n, color_fade(getPixelColor(n), fade, true));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -996,7 +975,7 @@ void Segment::fade_out(uint8_t rate) {
|
||||
int g2 = G(color);
|
||||
int b2 = B(color);
|
||||
|
||||
for (uint16_t y = 0; y < rows; y++) for (uint16_t x = 0; x < cols; x++) {
|
||||
for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) {
|
||||
color = is2D() ? getPixelColorXY(x, y) : getPixelColor(x);
|
||||
int w1 = W(color);
|
||||
int r1 = R(color);
|
||||
@ -1025,9 +1004,9 @@ void Segment::fadeToBlackBy(uint8_t fadeBy) {
|
||||
const uint16_t cols = is2D() ? virtualWidth() : virtualLength();
|
||||
const uint16_t rows = virtualHeight(); // will be 1 for 1D
|
||||
|
||||
for (uint16_t y = 0; y < rows; y++) for (uint16_t x = 0; x < cols; x++) {
|
||||
if (is2D()) setPixelColorXY(x, y, CRGB(getPixelColorXY(x,y)).nscale8(255-fadeBy));
|
||||
else setPixelColor(x, CRGB(getPixelColor(x)).nscale8(255-fadeBy));
|
||||
for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) {
|
||||
if (is2D()) setPixelColorXY(x, y, color_fade(getPixelColorXY(x,y), 255-fadeBy));
|
||||
else setPixelColor(x, color_fade(getPixelColor(x), 255-fadeBy));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1040,34 +1019,26 @@ void Segment::blur(uint8_t blur_amount)
|
||||
#ifndef WLED_DISABLE_2D
|
||||
if (is2D()) {
|
||||
// compatibility with 2D
|
||||
const uint_fast16_t cols = virtualWidth();
|
||||
const uint_fast16_t rows = virtualHeight();
|
||||
for (uint_fast16_t i = 0; i < rows; i++) blurRow(i, blur_amount); // blur all rows
|
||||
for (uint_fast16_t k = 0; k < cols; k++) blurCol(k, blur_amount); // blur all columns
|
||||
const unsigned cols = virtualWidth();
|
||||
const unsigned rows = virtualHeight();
|
||||
for (unsigned i = 0; i < rows; i++) blurRow(i, blur_amount); // blur all rows
|
||||
for (unsigned k = 0; k < cols; k++) blurCol(k, blur_amount); // blur all columns
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
uint8_t keep = 255 - blur_amount;
|
||||
uint8_t seep = blur_amount >> 1;
|
||||
CRGB carryover = CRGB::Black;
|
||||
uint_fast16_t vlength = virtualLength();
|
||||
for(uint_fast16_t i = 0; i < vlength; i++)
|
||||
{
|
||||
CRGB cur = CRGB(getPixelColor(i));
|
||||
CRGB part = cur;
|
||||
CRGB before = cur; // remember color before blur
|
||||
part.nscale8(seep);
|
||||
cur.nscale8(keep);
|
||||
cur += carryover;
|
||||
if(i > 0) {
|
||||
uint32_t carryover = BLACK;
|
||||
unsigned vlength = virtualLength();
|
||||
for (unsigned i = 0; i < vlength; i++) {
|
||||
uint32_t cur = getPixelColor(i);
|
||||
uint32_t part = color_fade(cur, seep);
|
||||
cur = color_add(color_fade(cur, keep), carryover, true);
|
||||
if (i > 0) {
|
||||
uint32_t c = getPixelColor(i-1);
|
||||
uint8_t r = R(c);
|
||||
uint8_t g = G(c);
|
||||
uint8_t b = B(c);
|
||||
setPixelColor((uint16_t)(i-1), qadd8(r, part.red), qadd8(g, part.green), qadd8(b, part.blue));
|
||||
setPixelColor(i-1, color_add(c, part, true));
|
||||
}
|
||||
if (before != cur) // optimization: only set pixel if color has changed
|
||||
setPixelColor((uint16_t)i,cur.red, cur.green, cur.blue);
|
||||
setPixelColor(i, cur);
|
||||
carryover = part;
|
||||
}
|
||||
}
|
||||
@ -1080,7 +1051,7 @@ void Segment::blur(uint8_t blur_amount)
|
||||
uint32_t Segment::color_wheel(uint8_t pos) {
|
||||
if (palette) return color_from_palette(pos, false, true, 0);
|
||||
pos = 255 - pos;
|
||||
if(pos < 85) {
|
||||
if (pos < 85) {
|
||||
return ((uint32_t)(255 - pos * 3) << 16) | ((uint32_t)(0) << 8) | (pos * 3);
|
||||
} else if(pos < 170) {
|
||||
pos -= 85;
|
||||
@ -1091,21 +1062,6 @@ uint32_t Segment::color_wheel(uint8_t pos) {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a new, random wheel index with a minimum distance of 42 from pos.
|
||||
*/
|
||||
uint8_t Segment::get_random_wheel_index(uint8_t pos) {
|
||||
uint8_t r = 0, x = 0, y = 0, d = 0;
|
||||
|
||||
while(d < 42) {
|
||||
r = random8();
|
||||
x = abs(pos - r);
|
||||
y = 255 - x;
|
||||
d = MIN(x, y);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
@ -1119,20 +1075,20 @@ uint32_t Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_
|
||||
{
|
||||
// default palette or no RGB support on segment
|
||||
if ((palette == 0 && mcol < NUM_COLORS) || !_isRGB) {
|
||||
uint32_t color = currentColor(mcol, colors[mcol]);
|
||||
uint32_t color = currentColor(mcol);
|
||||
color = gamma32(color);
|
||||
if (pbri == 255) return color;
|
||||
return RGBW32(scale8_video(R(color),pbri), scale8_video(G(color),pbri), scale8_video(B(color),pbri), scale8_video(W(color),pbri));
|
||||
return color_fade(color, pbri, true);
|
||||
}
|
||||
|
||||
uint8_t paletteIndex = i;
|
||||
if (mapping && virtualLength() > 1) paletteIndex = (i*255)/(virtualLength() -1);
|
||||
if (!wrap) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end"
|
||||
CRGB fastled_col;
|
||||
if (!wrap && strip.paletteBlend != 3) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end"
|
||||
CRGBPalette16 curPal;
|
||||
if (transitional && _t) curPal = _t->_palT;
|
||||
else loadPalette(curPal, palette);
|
||||
fastled_col = ColorFromPalette(curPal, paletteIndex, pbri, (strip.paletteBlend == 3)? NOBLEND:LINEARBLEND); // NOTE: paletteBlend should be global
|
||||
curPal = currentPalette(curPal, palette);
|
||||
//if (isInTransition()) curPal = _t->_palT;
|
||||
//else loadPalette(curPal, palette);
|
||||
CRGB fastled_col = ColorFromPalette(curPal, paletteIndex, pbri, (strip.paletteBlend == 3)? NOBLEND:LINEARBLEND); // NOTE: paletteBlend should be global
|
||||
|
||||
return RGBW32(fastled_col.r, fastled_col.g, fastled_col.b, 0);
|
||||
}
|
||||
@ -1166,7 +1122,7 @@ void WS2812FX::finalizeInit(void)
|
||||
const uint8_t defNumBusses = ((sizeof defDataPins) / (sizeof defDataPins[0]));
|
||||
const uint8_t defNumCounts = ((sizeof defCounts) / (sizeof defCounts[0]));
|
||||
uint16_t prevLen = 0;
|
||||
for (uint8_t i = 0; i < defNumBusses && i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) {
|
||||
for (int i = 0; i < defNumBusses && i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) {
|
||||
uint8_t defPin[] = {defDataPins[i]};
|
||||
uint16_t start = prevLen;
|
||||
uint16_t count = defCounts[(i < defNumCounts) ? i : defNumCounts -1];
|
||||
@ -1177,7 +1133,7 @@ void WS2812FX::finalizeInit(void)
|
||||
}
|
||||
|
||||
_length = 0;
|
||||
for (uint8_t i=0; i<busses.getNumBusses(); i++) {
|
||||
for (int i=0; i<busses.getNumBusses(); i++) {
|
||||
Bus *bus = busses.getBus(i);
|
||||
if (bus == nullptr) continue;
|
||||
if (bus->getStart() + bus->getLength() > MAX_LEDS) break;
|
||||
@ -1234,24 +1190,24 @@ void WS2812FX::service() {
|
||||
|
||||
if (!seg.freeze) { //only run effect function if not frozen
|
||||
_virtualSegmentLength = seg.virtualLength();
|
||||
_colors_t[0] = seg.currentColor(0, seg.colors[0]);
|
||||
_colors_t[1] = seg.currentColor(1, seg.colors[1]);
|
||||
_colors_t[2] = seg.currentColor(2, seg.colors[2]);
|
||||
seg.currentPalette(_currentPalette, seg.palette);
|
||||
_colors_t[0] = seg.currentColor(0);
|
||||
_colors_t[1] = seg.currentColor(1);
|
||||
_colors_t[2] = seg.currentColor(2);
|
||||
seg.currentPalette(_currentPalette, seg.palette); // we need to pass reference
|
||||
|
||||
if (!cctFromRgb || correctWB) busses.setSegmentCCT(seg.currentBri(seg.cct, true), correctWB);
|
||||
for (uint8_t c = 0; c < NUM_COLORS; c++) _colors_t[c] = gamma32(_colors_t[c]);
|
||||
if (!cctFromRgb || correctWB) busses.setSegmentCCT(seg.currentBri(true), correctWB);
|
||||
for (int c = 0; c < NUM_COLORS; c++) _colors_t[c] = gamma32(_colors_t[c]);
|
||||
|
||||
// Effect blending
|
||||
// When two effects are being blended, each may have different segment data, this
|
||||
// data needs to be saved first and then restored before running previous/transitional mode.
|
||||
// data needs to be saved first and then restored before running previous mode.
|
||||
// The blending will largely depend on the effect behaviour since actual output (LEDs) may be
|
||||
// overwritten by later effect. To enable seamless blending for every effect, additional LED buffer
|
||||
// would need to be allocated for each effect and then blended together for each pixel.
|
||||
[[maybe_unused]] uint8_t tmpMode = seg.currentMode(seg.mode); // this will return old mode while in transition
|
||||
[[maybe_unused]] uint8_t tmpMode = seg.currentMode(); // this will return old mode while in transition
|
||||
delay = (*_mode[seg.mode])(); // run new/current mode
|
||||
#ifndef WLED_DISABLE_MODE_BLEND
|
||||
if (seg.mode != tmpMode) {
|
||||
if (modeBlending && seg.mode != tmpMode) {
|
||||
Segment::tmpsegd_t _tmpSegData;
|
||||
Segment::modeBlend(true); // set semaphore
|
||||
seg.swapSegenv(_tmpSegData); // temporarily store new mode state (and swap it with transitional state)
|
||||
@ -1262,7 +1218,7 @@ void WS2812FX::service() {
|
||||
}
|
||||
#endif
|
||||
if (seg.mode != FX_MODE_HALLOWEEN_EYES) seg.call++;
|
||||
if (seg.transitional && delay > FRAMETIME) delay = FRAMETIME; // force faster updates during transition
|
||||
if (seg.isInTransition() && delay > FRAMETIME) delay = FRAMETIME; // force faster updates during transition
|
||||
}
|
||||
|
||||
seg.next_time = nowUp + delay;
|
||||
@ -1399,12 +1355,12 @@ void WS2812FX::show(void) {
|
||||
// or async show has a separate buffer (ESP32 RMT and I2S are ok)
|
||||
if (newBri < _brightness) busses.setBrightness(_brightness);
|
||||
|
||||
unsigned long now = millis();
|
||||
size_t diff = now - _lastShow;
|
||||
unsigned long showNow = millis();
|
||||
size_t diff = showNow - _lastShow;
|
||||
size_t fpsCurr = 200;
|
||||
if (diff > 0) fpsCurr = 1000 / diff;
|
||||
_cumulativeFps = (3 * _cumulativeFps + fpsCurr +2) >> 2; // "+2" for proper rounding (2/4 = 0.5)
|
||||
_lastShow = now;
|
||||
_lastShow = showNow;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1597,10 +1553,12 @@ void WS2812FX::setSegment(uint8_t segId, uint16_t i1, uint16_t i2, uint8_t group
|
||||
_qStart = i1; _qStop = i2; _qStartY = startY; _qStopY = stopY;
|
||||
_qGrouping = grouping; _qSpacing = spacing; _qOffset = offset;
|
||||
_queuedChangesSegId = segId;
|
||||
DEBUG_PRINT(F("Segment queued: ")); DEBUG_PRINTLN(segId);
|
||||
return; // queued changes are applied immediately after effect function returns
|
||||
}
|
||||
|
||||
_segments[segId].setUp(i1, i2, grouping, spacing, offset, startY, stopY);
|
||||
if (segId > 0 && segId == getSegmentsNum()-1 && i2 <= i1) _segments.pop_back(); // if last segment was deleted remove it from vector
|
||||
}
|
||||
|
||||
void WS2812FX::setUpSegmentFromQueuedChanges() {
|
||||
@ -1729,7 +1687,7 @@ void WS2812FX::fixInvalidSegments() {
|
||||
bool WS2812FX::checkSegmentAlignment() {
|
||||
bool aligned = false;
|
||||
for (segment &seg : _segments) {
|
||||
for (uint8_t b = 0; b<busses.getNumBusses(); b++) {
|
||||
for (unsigned b = 0; b<busses.getNumBusses(); b++) {
|
||||
Bus *bus = busses.getBus(b);
|
||||
if (seg.start == bus->getStart() && seg.stop == bus->getStart() + bus->getLength()) aligned = true;
|
||||
}
|
||||
@ -1752,13 +1710,8 @@ uint8_t WS2812FX::setPixelSegment(uint8_t n) {
|
||||
}
|
||||
|
||||
void WS2812FX::setRange(uint16_t i, uint16_t i2, uint32_t col) {
|
||||
if (i2 >= i)
|
||||
{
|
||||
for (uint16_t x = i; x <= i2; x++) setPixelColor(x, col);
|
||||
} else
|
||||
{
|
||||
for (uint16_t x = i2; x <= i; x++) setPixelColor(x, col);
|
||||
}
|
||||
if (i2 < i) std::swap(i,i2);
|
||||
for (unsigned x = i; x <= i2; x++) setPixelColor(x, col);
|
||||
}
|
||||
|
||||
void WS2812FX::setTransitionMode(bool t) {
|
||||
@ -1793,7 +1746,7 @@ void WS2812FX::loadCustomPalettes() {
|
||||
|
||||
if (readObjectFromFile(fileName, nullptr, &pDoc)) {
|
||||
JsonArray pal = pDoc[F("palette")];
|
||||
if (!pal.isNull() && pal.size()>4) { // not an empty palette (at least 2 entries)
|
||||
if (!pal.isNull() && pal.size()>3) { // 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);
|
||||
@ -1802,7 +1755,7 @@ void WS2812FX::loadCustomPalettes() {
|
||||
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
|
||||
for (size_t c=0; c<3; c++) tcp[j+1+c] = gamma8(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 {
|
||||
@ -1810,13 +1763,15 @@ void WS2812FX::loadCustomPalettes() {
|
||||
palSize -= palSize % 4; // make sure size is multiple of 4
|
||||
for (size_t i=0; i<palSize && pal[i].as<int>()<256; i+=4) {
|
||||
tcp[ i ] = (uint8_t) pal[ i ].as<int>(); // index
|
||||
tcp[i+1] = (uint8_t) pal[i+1].as<int>(); // R
|
||||
tcp[i+2] = (uint8_t) pal[i+2].as<int>(); // G
|
||||
tcp[i+3] = (uint8_t) pal[i+3].as<int>(); // B
|
||||
tcp[i+1] = gamma8((uint8_t) pal[i+1].as<int>()); // R
|
||||
tcp[i+2] = gamma8((uint8_t) pal[i+2].as<int>()); // G
|
||||
tcp[i+3] = gamma8((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]));
|
||||
}
|
||||
}
|
||||
customPalettes.push_back(targetPalette.loadDynamicGradientPalette(tcp));
|
||||
} else {
|
||||
DEBUG_PRINTLN(F("Wrong palette format."));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -1832,7 +1787,7 @@ bool WS2812FX::deserializeMap(uint8_t n) {
|
||||
char fileName[32];
|
||||
strcpy_P(fileName, PSTR("/ledmap"));
|
||||
if (n) sprintf(fileName +7, "%d", n);
|
||||
strcat(fileName, ".json");
|
||||
strcat_P(fileName, PSTR(".json"));
|
||||
bool isFile = WLED_FS.exists(fileName);
|
||||
|
||||
if (!isFile) {
|
||||
@ -1866,7 +1821,7 @@ bool WS2812FX::deserializeMap(uint8_t n) {
|
||||
if (!map.isNull() && map.size()) { // not an empty map
|
||||
customMappingSize = map.size();
|
||||
customMappingTable = new uint16_t[customMappingSize];
|
||||
for (uint16_t i=0; i<customMappingSize; i++) {
|
||||
for (unsigned i=0; i<customMappingSize; i++) {
|
||||
customMappingTable[i] = (uint16_t) (map[i]<0 ? 0xFFFFU : map[i]);
|
||||
}
|
||||
}
|
||||
|
@ -216,7 +216,9 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
if (((buttonType[s] == BTN_TYPE_ANALOG) || (buttonType[s] == BTN_TYPE_ANALOG_INVERTED)) && (digitalPinToAnalogChannel(btnPin[s]) < 0))
|
||||
{
|
||||
// not an ADC analog pin
|
||||
DEBUG_PRINTF("PIN ALLOC error: GPIO%d for analog button #%d is not an analog pin!\n", btnPin[s], s);
|
||||
DEBUG_PRINT(F("PIN ALLOC error: GPIO")); DEBUG_PRINT(btnPin[s]);
|
||||
DEBUG_PRINT(F("for analog button #")); DEBUG_PRINT(s);
|
||||
DEBUG_PRINTLN(F(" is not an analog pin!"));
|
||||
btnPin[s] = -1;
|
||||
pinManager.deallocatePin(pin,PinOwner::Button);
|
||||
}
|
||||
@ -357,6 +359,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
|
||||
JsonObject light_tr = light["tr"];
|
||||
CJSON(fadeTransition, light_tr["mode"]);
|
||||
CJSON(modeBlending, light_tr["fx"]);
|
||||
int tdd = light_tr["dur"] | -1;
|
||||
if (tdd >= 0) transitionDelay = transitionDelayDefault = tdd * 100;
|
||||
CJSON(strip.paletteFade, light_tr["pal"]);
|
||||
@ -827,6 +830,7 @@ void serializeConfig() {
|
||||
|
||||
JsonObject light_tr = light.createNestedObject("tr");
|
||||
light_tr["mode"] = fadeTransition;
|
||||
light_tr["fx"] = modeBlending;
|
||||
light_tr["dur"] = transitionDelayDefault / 100;
|
||||
light_tr["pal"] = strip.paletteFade;
|
||||
light_tr[F("rpc")] = randomPaletteChangeTime;
|
||||
@ -888,6 +892,7 @@ void serializeConfig() {
|
||||
if_live[F("no-gc")] = arlsDisableGammaCorrection;
|
||||
if_live[F("offset")] = arlsOffset;
|
||||
|
||||
#ifndef WLED_DISABLE_ALEXA
|
||||
JsonObject if_va = interfaces.createNestedObject("va");
|
||||
if_va[F("alexa")] = alexaEnabled;
|
||||
|
||||
@ -896,6 +901,7 @@ void serializeConfig() {
|
||||
if_va_macros.add(macroAlexaOff);
|
||||
|
||||
if_va["p"] = alexaNumPresets;
|
||||
#endif
|
||||
|
||||
#ifdef WLED_ENABLE_MQTT
|
||||
JsonObject if_mqtt = interfaces.createNestedObject("mqtt");
|
||||
@ -1033,7 +1039,7 @@ bool deserializeConfigSec() {
|
||||
JsonObject ap = doc["ap"];
|
||||
getStringFromJson(apPass, ap["psk"] , 65);
|
||||
|
||||
JsonObject interfaces = doc["if"];
|
||||
[[maybe_unused]] JsonObject interfaces = doc["if"];
|
||||
|
||||
#ifdef WLED_ENABLE_MQTT
|
||||
JsonObject if_mqtt = interfaces["mqtt"];
|
||||
@ -1072,7 +1078,7 @@ void serializeConfigSec() {
|
||||
JsonObject ap = doc.createNestedObject("ap");
|
||||
ap["psk"] = apPass;
|
||||
|
||||
JsonObject interfaces = doc.createNestedObject("if");
|
||||
[[maybe_unused]] JsonObject interfaces = doc.createNestedObject("if");
|
||||
#ifdef WLED_ENABLE_MQTT
|
||||
JsonObject if_mqtt = interfaces.createNestedObject("mqtt");
|
||||
if_mqtt["psk"] = mqttPass;
|
||||
|
@ -35,23 +35,59 @@ uint32_t color_blend(uint32_t color1, uint32_t color2, uint16_t blend, bool b16)
|
||||
* color add function that preserves ratio
|
||||
* idea: https://github.com/Aircoookie/WLED/pull/2465 by https://github.com/Proto-molecule
|
||||
*/
|
||||
uint32_t color_add(uint32_t c1, uint32_t c2)
|
||||
uint32_t color_add(uint32_t c1, uint32_t c2, bool fast)
|
||||
{
|
||||
uint32_t r = R(c1) + R(c2);
|
||||
uint32_t g = G(c1) + G(c2);
|
||||
uint32_t b = B(c1) + B(c2);
|
||||
uint32_t w = W(c1) + W(c2);
|
||||
uint16_t max = r;
|
||||
if (g > max) max = g;
|
||||
if (b > max) max = b;
|
||||
if (w > max) max = w;
|
||||
if (max < 256) return RGBW32(r, g, b, w);
|
||||
else return RGBW32(r * 255 / max, g * 255 / max, b * 255 / max, w * 255 / max);
|
||||
if (fast) {
|
||||
uint8_t r = R(c1);
|
||||
uint8_t g = G(c1);
|
||||
uint8_t b = B(c1);
|
||||
uint8_t w = W(c1);
|
||||
r = qadd8(r, R(c2));
|
||||
g = qadd8(g, G(c2));
|
||||
b = qadd8(b, B(c2));
|
||||
w = qadd8(w, W(c2));
|
||||
return RGBW32(r,g,b,w);
|
||||
} else {
|
||||
uint32_t r = R(c1) + R(c2);
|
||||
uint32_t g = G(c1) + G(c2);
|
||||
uint32_t b = B(c1) + B(c2);
|
||||
uint32_t w = W(c1) + W(c2);
|
||||
uint16_t max = r;
|
||||
if (g > max) max = g;
|
||||
if (b > max) max = b;
|
||||
if (w > max) max = w;
|
||||
if (max < 256) return RGBW32(r, g, b, w);
|
||||
else return RGBW32(r * 255 / max, g * 255 / max, b * 255 / max, w * 255 / max);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* fades color toward black
|
||||
* if using "video" method the resulting color will never become black unless it is already black
|
||||
*/
|
||||
uint32_t color_fade(uint32_t c1, uint8_t amount, bool video)
|
||||
{
|
||||
uint8_t r = R(c1);
|
||||
uint8_t g = G(c1);
|
||||
uint8_t b = B(c1);
|
||||
uint8_t w = W(c1);
|
||||
if (video) {
|
||||
r = scale8_video(r, amount);
|
||||
g = scale8_video(g, amount);
|
||||
b = scale8_video(b, amount);
|
||||
w = scale8_video(w, amount);
|
||||
} else {
|
||||
r = scale8(r, amount);
|
||||
g = scale8(g, amount);
|
||||
b = scale8(b, amount);
|
||||
w = scale8(w, amount);
|
||||
}
|
||||
return RGBW32(r, g, b, w);
|
||||
}
|
||||
|
||||
void setRandomColor(byte* rgb)
|
||||
{
|
||||
lastRandomIndex = strip.getMainSegment().get_random_wheel_index(lastRandomIndex);
|
||||
lastRandomIndex = get_random_wheel_index(lastRandomIndex);
|
||||
colorHStoRGB(lastRandomIndex*256,255,rgb);
|
||||
}
|
||||
|
||||
|
@ -150,6 +150,7 @@
|
||||
#define USERMOD_ID_KLIPPER 40 //Usermod Klipper percentage
|
||||
#define USERMOD_ID_WIREGUARD 41 //Usermod "wireguard.h"
|
||||
#define USERMOD_ID_INTERNAL_TEMPERATURE 42 //Usermod "usermod_internal_temperature.h"
|
||||
#define USERMOD_ID_LDR_DUSK_DAWN 43 //Usermod "usermod_LDR_Dusk_Dawn_v2.h"
|
||||
|
||||
//Access point behavior
|
||||
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot
|
||||
@ -166,7 +167,7 @@
|
||||
#define CALL_MODE_NO_NOTIFY 5
|
||||
#define CALL_MODE_FX_CHANGED 6 //no longer used
|
||||
#define CALL_MODE_HUE 7
|
||||
#define CALL_MODE_PRESET_CYCLE 8
|
||||
#define CALL_MODE_PRESET_CYCLE 8 //no longer used
|
||||
#define CALL_MODE_BLYNK 9 //no longer used
|
||||
#define CALL_MODE_ALEXA 10
|
||||
#define CALL_MODE_WS_SEND 11 //special call mode, not for notifier, updates websocket only
|
||||
@ -313,10 +314,9 @@
|
||||
#define SEG_OPTION_MIRROR 3 //Indicates that the effect will be mirrored within the segment
|
||||
#define SEG_OPTION_FREEZE 4 //Segment contents will not be refreshed
|
||||
#define SEG_OPTION_RESET 5 //Segment runtime requires reset
|
||||
#define SEG_OPTION_TRANSITIONAL 6
|
||||
#define SEG_OPTION_REVERSED_Y 7
|
||||
#define SEG_OPTION_MIRROR_Y 8
|
||||
#define SEG_OPTION_TRANSPOSED 9
|
||||
#define SEG_OPTION_REVERSED_Y 6
|
||||
#define SEG_OPTION_MIRROR_Y 7
|
||||
#define SEG_OPTION_TRANSPOSED 8
|
||||
|
||||
//Segment differs return byte
|
||||
#define SEG_DIFFERS_BRI 0x01 // opacity
|
||||
@ -345,6 +345,7 @@
|
||||
#define ERR_FS_QUOTA 11 // The FS is full or the maximum file size is reached
|
||||
#define ERR_FS_PLOAD 12 // It was attempted to load a preset that does not exist
|
||||
#define ERR_FS_IRLOAD 13 // It was attempted to load an IR JSON cmd, but the "ir.json" file does not exist
|
||||
#define ERR_FS_RMLOAD 14 // It was attempted to load an remote JSON cmd, but the "remote.json" file does not exist
|
||||
#define ERR_FS_GENERAL 19 // A general unspecified filesystem error occured
|
||||
#define ERR_OVERTEMP 30 // An attached temperature sensor has measured above threshold temperature (not implemented)
|
||||
#define ERR_OVERCURRENT 31 // An attached current sensor has measured a current above the threshold (not implemented)
|
||||
@ -374,7 +375,8 @@
|
||||
#define SUBPAGE_JS 254
|
||||
#define SUBPAGE_WELCOME 255
|
||||
|
||||
#define NTP_PACKET_SIZE 48
|
||||
#define NTP_PACKET_SIZE 48 // size of NTP recive buffer
|
||||
#define NTP_MIN_PACKET_SIZE 48 // min expected size - NTP v4 allows for "extended information" appended to the standard fields
|
||||
|
||||
//maximum number of rendered LEDs - this does not have to match max. physical LEDs, e.g. if there are virtual busses
|
||||
#ifndef MAX_LEDS
|
||||
|
@ -198,10 +198,11 @@
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div style="padding-bottom: 10px;">
|
||||
<button class="btn btn-xs" type="button" onclick="window.location.href=getURL('/cpal.htm')"><i class="icons btn-icon"></i></button>
|
||||
<button class="btn btn-xs" type="button" onclick="palettesData=null;localStorage.removeItem('wledPalx');requestJson({rmcpal:true});setTimeout(loadPalettes,250,loadPalettesData);"><i class="icons btn-icon"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
<div style="padding-block: 10px;">
|
||||
<button class="btn btn-xs" type="button" onclick="togglePixelMagicTool()"><i class="icons btn-icon"></i></button>
|
||||
<button class="btn btn-xs" type="button" onclick="window.location.href=getURL('/cpal.htm')"><i class="icons btn-icon"></i></button>
|
||||
<button class="btn btn-xs" type="button" onclick="palettesData=null;localStorage.removeItem('wledPalx');requestJson({rmcpal:true});setTimeout(loadPalettes,250,loadPalettesData);"><i class="icons btn-icon"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -392,6 +393,7 @@
|
||||
<button class="btn" onclick="setLor(2)">Override until reboot</button><br>
|
||||
<span class="h">For best performance, it is recommended to turn off the streaming source when not in use.</span>
|
||||
</div>
|
||||
|
||||
<i id="roverstar" class="icons huge" onclick="setLor(0)"></i><br>
|
||||
<script src="index.js"></script>
|
||||
</body>
|
||||
|
@ -27,16 +27,15 @@ var cfg = {
|
||||
theme:{base:"dark", bg:{url:""}, alpha:{bg:0.6,tab:0.8}, color:{bg:""}},
|
||||
comp :{colors:{picker: true, rgb: false, quick: true, hex: false},
|
||||
labels:true, pcmbot:false, pid:true, seglen:false, segpwr:false, segexp:false,
|
||||
css:true, hdays:false, fxdef:true}
|
||||
css:true, hdays:false, fxdef:true, idsort: false}
|
||||
};
|
||||
var hol = [
|
||||
[0,11,24,4,"https://aircoookie.github.io/xmas.png"], // christmas
|
||||
[0,2,17,1,"https://images.alphacoders.com/491/491123.jpg"], // st. Patrick's day
|
||||
[2025,3,20,2,"https://aircoookie.github.io/easter.png"],
|
||||
[2023,3,9,2,"https://aircoookie.github.io/easter.png"],
|
||||
[2024,2,31,2,"https://aircoookie.github.io/easter.png"],
|
||||
[0,6,4,1,"https://initiate.alphacoders.com/download/wallpaper/516792/images/jpg/510921363292536"], // 4th of July
|
||||
[0,0,1,1,"https://initiate.alphacoders.com/download/wallpaper/1198800/images/jpg/2522807481585600"] // new year
|
||||
[0,6,4,1,"https://images.alphacoders.com/516/516792.jpg"], // 4th of July
|
||||
[0,0,1,1,"https://images.alphacoders.com/119/1198800.jpg"] // new year
|
||||
];
|
||||
|
||||
function handleVisibilityChange() {if (!d.hidden && new Date () - lastUpdate > 3000) requestJson();}
|
||||
@ -1209,7 +1208,7 @@ function updateUI()
|
||||
if (hasRGB) {
|
||||
updateTrail(gId('sliderR'));
|
||||
updateTrail(gId('sliderG'));
|
||||
updateTrail(gId('sliderB'));
|
||||
updateTrail(gId('sliderB'));
|
||||
}
|
||||
if (hasWhite) updateTrail(gId('sliderW'));
|
||||
|
||||
@ -1302,7 +1301,7 @@ function displayRover(i,s)
|
||||
|
||||
function cmpP(a, b)
|
||||
{
|
||||
if (!a[1].n) return (a[0] > b[0]);
|
||||
if (cfg.comp.idsort || !a[1].n) return (parseInt(a[0]) > parseInt(b[0]));
|
||||
// sort playlists first, followed by presets with characters and last presets with special 1st character
|
||||
const c = a[1].n.charCodeAt(0);
|
||||
const d = b[1].n.charCodeAt(0);
|
||||
@ -1514,12 +1513,15 @@ function setEffectParameters(idx)
|
||||
}
|
||||
|
||||
// set the bottom position of selected effect (sticky) as the top of sliders div
|
||||
setInterval(()=>{
|
||||
function setSelectedEffectPosition() {
|
||||
let top = parseInt(getComputedStyle(gId("sliders")).height);
|
||||
top += 5;
|
||||
let sel = d.querySelector('#fxlist .selected');
|
||||
if (sel) sel.style.bottom = top + "px"; // we will need to remove this when unselected (in setFX())
|
||||
},750);
|
||||
}
|
||||
|
||||
setSelectedEffectPosition();
|
||||
setInterval(setSelectedEffectPosition,750);
|
||||
// set html color items on/off
|
||||
var cslLabel = '';
|
||||
var sep = '';
|
||||
@ -1700,7 +1702,7 @@ function toggleLiveview()
|
||||
let wsOn = ws && ws.readyState === WebSocket.OPEN;
|
||||
|
||||
var lvID = "liveview";
|
||||
if (isM && wsOn) {
|
||||
if (isM && wsOn) {
|
||||
lvID += "2D";
|
||||
if (isLv) gId('klv2D').innerHTML = `<iframe id="${lvID}" src="about:blank"></iframe>`;
|
||||
gId('mlv2D').style.transform = (isLv) ? "translateY(0px)":"translateY(100%)";
|
||||
@ -1796,6 +1798,7 @@ function makePlSel(el, incPl=false)
|
||||
var arr = Object.entries(pJson);
|
||||
for (var a of arr) {
|
||||
var n = a[1].n ? a[1].n : "Preset " + a[0];
|
||||
if (cfg.comp.idsort) n = a[0] + ' ' + n;
|
||||
if (!incPl && a[1].playlist && a[1].playlist.ps) continue; // remove playlists, sub-playlists not yet supported
|
||||
plSelContent += `<option value="${a[0]}" ${a[0]==el?"selected":""}>${n}</option>`
|
||||
}
|
||||
@ -1887,7 +1890,7 @@ function makeP(i,pl)
|
||||
end: 0
|
||||
};
|
||||
var rep = plJson[i].repeat ? plJson[i].repeat : 0;
|
||||
content =
|
||||
content =
|
||||
`<div id="ple${i}" style="margin-top:10px;"></div><label class="check revchkl">Shuffle
|
||||
<input type="checkbox" id="pl${i}rtgl" onchange="plR(${i})" ${plJson[i].r||rep<0?"checked":""}>
|
||||
<span class="checkmark"></span>
|
||||
|
@ -7,13 +7,10 @@
|
||||
|
||||
<title>Pixel Magic Tool</title>
|
||||
|
||||
<!-- <link
|
||||
rel="shortcut icon"
|
||||
href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAK9JREFUeNqUUssNwyAMJZWVUw4dhRHakZA6RqWMFEbwKDnk1FNBekEWxOBYQggL/D68yXXq+M7PtHkcefn89vrOw/UrP96w/NUFGiDLRz71GyY0QJa1Yn+nFa0ShqUNYCAF0QvoceOB4naEZif6UTNRapYaTyauRi4DEspr4Hbs5YKsbmtMyeJ0LxeESV4gB+hlSy4oO2txWysyus0a0+lO6vBjxcTMlG4mt2H6F2AAhU5NWu4dorQAAAAASUVORK5CYII=
|
||||
" /> -->
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--s-thumb: #0006;
|
||||
--s-background: #0003;
|
||||
--overlay: rgba(0, 0, 0, 0.5);
|
||||
--background: #111;
|
||||
--text: #bbb;
|
||||
@ -34,6 +31,24 @@
|
||||
--warning-light: #f48c06;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: var(--s-thumb);
|
||||
opacity: 0.2;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--s-background);
|
||||
}
|
||||
|
||||
::selection {
|
||||
background: var(--blue-light);
|
||||
}
|
||||
@ -65,7 +80,7 @@
|
||||
display: block;
|
||||
font-weight: 400;
|
||||
margin: 2px 0 5px;
|
||||
color: var(--text);
|
||||
color: var(--gray-light);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
@ -83,10 +98,19 @@
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
:is(a:hover, a:focus, a:active) {
|
||||
a:is(:hover, :focus, :active) {
|
||||
color: var(--blue-medium);
|
||||
}
|
||||
|
||||
#wledEdit {
|
||||
padding: 4px 8px;
|
||||
background: var(--blue-light);
|
||||
margin-left: 6px;
|
||||
display: inline-block;
|
||||
border-radius: 4px;
|
||||
color: var(--gray-light);
|
||||
}
|
||||
|
||||
.m-zero {
|
||||
margin: 0 !important;
|
||||
}
|
||||
@ -108,8 +132,7 @@
|
||||
}
|
||||
|
||||
.content {
|
||||
width: calc(100% - 40px);
|
||||
max-width: 768px;
|
||||
width: min(768px, calc(100% - 40px));
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
@ -117,26 +140,43 @@
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: space-between;
|
||||
margin: 20px 0 0;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.column {
|
||||
flex-basis: calc(50% - 10px);
|
||||
position: relative;
|
||||
padding: 0 5px;
|
||||
padding-inline: 5px;
|
||||
}
|
||||
|
||||
.column-full {
|
||||
flex-basis: 100%;
|
||||
position: relative;
|
||||
padding: 0 5px;
|
||||
padding-inline: 5px;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
.header .brand {
|
||||
width: 100%;
|
||||
max-width: 200px;
|
||||
height: 100%;
|
||||
display: block;
|
||||
outline: none;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
display: flex;
|
||||
margin-bottom: 5px;
|
||||
font-weight: bold;
|
||||
color: var(--text);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
@ -157,7 +197,7 @@
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
cursor: pointer;
|
||||
padding: 0px 1px;
|
||||
padding-inline: 1px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
@ -172,18 +212,19 @@
|
||||
}
|
||||
|
||||
.input-group .input-description {
|
||||
width: 38px;
|
||||
width: 100%;
|
||||
max-width: 38px;
|
||||
height: 38px;
|
||||
padding: 10px 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: var(--gray-dark);
|
||||
background: var(--gray-light);
|
||||
border-radius: 0px 5px 5px 0;
|
||||
border-radius: 0px 8px 8px 0;
|
||||
border: 1px solid var(--gray-light);
|
||||
border-left: 0;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
line-height: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.input-group .square {
|
||||
@ -191,10 +232,19 @@
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.input-group .square input {
|
||||
text-align: center;
|
||||
background: none;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
color: var(--gray-dark);
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
resize: none;
|
||||
min-height: 200px;
|
||||
border-radius: 8px;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.custom-select {
|
||||
@ -231,7 +281,7 @@
|
||||
text-align: center;
|
||||
padding: 40px 10px;
|
||||
border-radius: 8px;
|
||||
margin: 20px 0 0;
|
||||
margin-top: 20px;
|
||||
transition: all 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
@ -253,14 +303,15 @@
|
||||
width: 100%;
|
||||
border-radius: 10px;
|
||||
outline: none;
|
||||
margin: 16px 0;
|
||||
margin-block: 15px;
|
||||
}
|
||||
|
||||
.range-slider::-webkit-slider-thumb {
|
||||
.range-slider::-webkit-slider-thumb,
|
||||
.range-slider::-moz-range-thumb {
|
||||
appearance: none;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
background-color: var(--gray-dark);
|
||||
background-color: var(--blue-light);
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
border: 0;
|
||||
@ -326,7 +377,7 @@
|
||||
align-items: center;
|
||||
width: auto;
|
||||
padding: 6px 12px;
|
||||
margin: 10px 0 0;
|
||||
margin-top: 10px;
|
||||
border-radius: 8px;
|
||||
transform: translateY(30px);
|
||||
opacity: 0;
|
||||
@ -334,7 +385,7 @@
|
||||
}
|
||||
|
||||
.toast .toast-body {
|
||||
padding: 8px 0;
|
||||
padding-block: 8px;
|
||||
font-weight: 600;
|
||||
color: var(--text);
|
||||
letter-spacing: 0.5px;
|
||||
@ -360,7 +411,7 @@
|
||||
height: 3px;
|
||||
transform: scaleX(0);
|
||||
transform-origin: left;
|
||||
border-radius: inherit;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.toast.success .toast-progress {
|
||||
@ -387,22 +438,6 @@
|
||||
);
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 0 0 20px;
|
||||
}
|
||||
|
||||
.header .brand {
|
||||
width: 100%;
|
||||
max-width: 200px;
|
||||
height: 100%;
|
||||
display: block;
|
||||
outline: none;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.carousel {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
@ -410,18 +445,6 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.carousel img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin-right: 20px;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.carousel img:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.button {
|
||||
width: 100%;
|
||||
border: 0;
|
||||
@ -429,7 +452,7 @@
|
||||
border-radius: 50px;
|
||||
color: var(--text);
|
||||
cursor: pointer;
|
||||
margin: 0 0 10px;
|
||||
margin-bottom: 10px;
|
||||
background: var(--gray-medium);
|
||||
border: 1px solid var(--gray-dark);
|
||||
transition: all 0.5s ease-in-out;
|
||||
@ -477,7 +500,7 @@
|
||||
}
|
||||
|
||||
#recreatedImage {
|
||||
margin: 20px 0;
|
||||
margin-block: 20px;
|
||||
}
|
||||
|
||||
.invalid {
|
||||
@ -487,16 +510,12 @@
|
||||
.error-message {
|
||||
display: block;
|
||||
color: var(--error-dark);
|
||||
padding: 4px 0;
|
||||
padding-block: 4px;
|
||||
font-weight: 600;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.header {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.row {
|
||||
flex-wrap: wrap;
|
||||
flex-direction: column;
|
||||
@ -506,7 +525,7 @@
|
||||
.column,
|
||||
.column-full {
|
||||
flex-basis: 100%;
|
||||
margin: 20px 0 0;
|
||||
margin-top: 20px;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
@ -542,68 +561,7 @@
|
||||
<div class="content">
|
||||
<form id="formGenerate" novalidate>
|
||||
<div class="header">
|
||||
<svg
|
||||
class="brand"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="200px"
|
||||
height="130px"
|
||||
viewBox="0 0 200 130"
|
||||
enable-background="new 0 0 200 130"
|
||||
xml:space="preserve">
|
||||
<image
|
||||
width="200"
|
||||
height="130"
|
||||
x="0"
|
||||
y="0"
|
||||
href="data:image/png;base64,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
|
||||
ZVJlYWR5ccllPAAAAABJRU5ErkJggg==" />
|
||||
</svg>
|
||||
<img src=" data:image/png;base64,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" alt="Pixel Magic Tool" class="brand">
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="column" validate>
|
||||
@ -626,11 +584,11 @@
|
||||
<label for="pattern">Pattern</label>
|
||||
<select name="pattern" id="pattern" required>
|
||||
<option value="">Select a choice</option>
|
||||
<option value="1" title="['ffffff']" selected>
|
||||
Individual
|
||||
</option>
|
||||
<option value="1" title="['ffffff']">Individual</option>
|
||||
<option value="2" title="[0, 'ffffff']">Index</option>
|
||||
<option value="3" title="[0, 5, 'ffffff']">Range</option>
|
||||
<option value="3" title="[0, 5, 'ffffff']" selected>
|
||||
Range
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@ -686,11 +644,13 @@
|
||||
max="255"
|
||||
value="128"
|
||||
class="range-slider" />
|
||||
<input
|
||||
type="text"
|
||||
id="brightnessValue"
|
||||
class="input-description square"
|
||||
value="128" />
|
||||
<div class="input-description square">
|
||||
<input
|
||||
type="text"
|
||||
name="brightnessValue"
|
||||
id="brightnessValue"
|
||||
value="128" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -698,7 +658,11 @@
|
||||
<div class="column" validate>
|
||||
<label for="animation">Animation</label>
|
||||
<label class="switch">
|
||||
<input type="checkbox" name="animation" id="animation" />
|
||||
<input
|
||||
type="checkbox"
|
||||
name="animation"
|
||||
id="animation"
|
||||
data-parent="animation" />
|
||||
<span class="switch-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
@ -708,19 +672,25 @@
|
||||
<input
|
||||
type="checkbox"
|
||||
name="transparentImage"
|
||||
id="transparentImage" />
|
||||
id="transparentImage"
|
||||
data-parent="transparentImage" />
|
||||
<span class="switch-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="column" validate>
|
||||
<label for="resizeImage">Resize Image</label>
|
||||
<label class="switch">
|
||||
<input type="checkbox" name="resizeImage" id="resizeImage" />
|
||||
<input
|
||||
type="checkbox"
|
||||
name="resizeImage"
|
||||
id="resizeImage"
|
||||
data-parent="resizeImage"
|
||||
checked />
|
||||
<span class="switch-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row resizeImage" style="display: none">
|
||||
<div class="row resizeImage">
|
||||
<div class="column" validate>
|
||||
<label for="width">Width</label>
|
||||
<input type="number" name="width" id="width" value="16" />
|
||||
@ -747,7 +717,9 @@
|
||||
min="0"
|
||||
step="0.1"
|
||||
inputmode="numeric" />
|
||||
<div class="input-description">sec</div>
|
||||
<div class="input-description">
|
||||
<span>sec</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column" validate>
|
||||
@ -762,7 +734,9 @@
|
||||
min="0"
|
||||
step="0.1"
|
||||
inputmode="numeric" />
|
||||
<div class="input-description">sec</div>
|
||||
<div class="input-description">
|
||||
<span>sec</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -773,30 +747,27 @@
|
||||
Color that will replace the
|
||||
<strong>transparent pixels</strong> in the image
|
||||
</small>
|
||||
<input type="color" name="color" id="color" value="#eeeeee" />
|
||||
<input type="color" name="color" id="color" value="#00BFFF" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="column-full" validate>
|
||||
<div class="custom-select">
|
||||
<label for="images">Images</label>
|
||||
<select name="images" id="images" required>
|
||||
<option value="">Select a choice</option>
|
||||
<option value="upload">Upload</option>
|
||||
<label for="images">
|
||||
<span>Images upload to WLED</span>
|
||||
<a id="wledEdit" href="http://[wled-ip]/edit" target="_blank">
|
||||
upload
|
||||
</a>
|
||||
</label>
|
||||
<select name="images" id="images">
|
||||
<option value="">Select image</option>
|
||||
</select>
|
||||
</div>
|
||||
<small>
|
||||
Images uploaded to
|
||||
<a id="wledEdit" href="http://[wled-ip]/edit" target="_blank">
|
||||
<strong>WLED</strong>
|
||||
</a>
|
||||
or upload image
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
<div id="dropzone" class="dropzone" validate style="display: none">
|
||||
<div id="dropzone" class="dropzone" validate>
|
||||
<p id="dropzoneLabel">
|
||||
Drag and drop a file here or click to select a file
|
||||
Drag and drop a file here or click to select a local file
|
||||
</p>
|
||||
<input
|
||||
type="file"
|
||||
@ -868,7 +839,7 @@
|
||||
const hostname = element("hostname");
|
||||
hostname.value = host;
|
||||
|
||||
hostname.addEventListener("change", async () => {
|
||||
hostname.addEventListener("blur", async () => {
|
||||
WLED_URL = `${protocol}//${hostname.value}`;
|
||||
|
||||
await segments();
|
||||
@ -893,7 +864,7 @@
|
||||
|
||||
function hostnameLabel() {
|
||||
const link = element("wledEdit");
|
||||
link.href = link.href.replace("[wled-ip]", hostname.value);
|
||||
link.href = WLED_URL + "/edit";
|
||||
}
|
||||
|
||||
async function playlist() {
|
||||
@ -999,6 +970,7 @@
|
||||
|
||||
if (success) {
|
||||
toast(`Preset "${item.n}" save successfully`);
|
||||
window.parent.postMessage("loadPresets", WLED_URL);
|
||||
}
|
||||
} catch (error) {
|
||||
toast(`Error saving preset: ${error}`, "error");
|
||||
@ -1047,12 +1019,9 @@
|
||||
return mimeTypes.includes(mimetype);
|
||||
});
|
||||
|
||||
const options = [
|
||||
{ text: "Select a choice", value: "" },
|
||||
{ text: "Upload", value: "upload" },
|
||||
];
|
||||
const options = [{ text: "Select image", value: "" }];
|
||||
|
||||
if (images) {
|
||||
if (images.length > 0) {
|
||||
options.push(
|
||||
...images.map(({ name }) => ({
|
||||
text: name,
|
||||
@ -1064,6 +1033,11 @@
|
||||
|
||||
options.forEach(({ text, value }) => {
|
||||
const option = new Option(text, value);
|
||||
|
||||
if (index === 0) {
|
||||
option.selected = true;
|
||||
}
|
||||
|
||||
select.appendChild(option);
|
||||
});
|
||||
}
|
||||
@ -1076,7 +1050,6 @@
|
||||
|
||||
async function segments() {
|
||||
const select = element("segments");
|
||||
const pattern = element("pattern");
|
||||
const width = element("width");
|
||||
const height = element("height");
|
||||
|
||||
@ -1114,7 +1087,6 @@
|
||||
option.selected = true;
|
||||
width.value = w;
|
||||
height.value = h;
|
||||
pattern.value = w * h > 512 ? 3 : 1;
|
||||
}
|
||||
|
||||
select.add(option);
|
||||
@ -1278,12 +1250,12 @@
|
||||
const dropzone = element("dropzone");
|
||||
const { value } = e.target.selectedOptions[0];
|
||||
|
||||
if (value === "upload") {
|
||||
if (!value) {
|
||||
const dropzoneLabel = element("dropzoneLabel");
|
||||
const source = element("source");
|
||||
|
||||
dropzoneLabel.textContent =
|
||||
"Drag and drop a file here or click to select a file";
|
||||
"Drag and drop a file here or click to select a local file";
|
||||
source.value = "";
|
||||
|
||||
dropzone.style.display = "block";
|
||||
@ -1293,62 +1265,51 @@
|
||||
});
|
||||
|
||||
element("transparentImage").addEventListener("change", (e) => {
|
||||
const transparentImage = d.getElementsByClassName("transparentImage");
|
||||
const transparentImage = d.getElementsByClassName("transparentImage")[0];
|
||||
const { checked } = e.target;
|
||||
|
||||
Array.from(transparentImage).forEach(function (element) {
|
||||
if (checked) {
|
||||
element.style.display = "flex";
|
||||
} else {
|
||||
element.style.display = "none";
|
||||
}
|
||||
});
|
||||
if (checked) {
|
||||
transparentImage.style.display = "flex";
|
||||
} else {
|
||||
transparentImage.style.display = "none";
|
||||
}
|
||||
});
|
||||
|
||||
element("resizeImage").addEventListener("change", (e) => {
|
||||
const resizeImage = d.getElementsByClassName("resizeImage");
|
||||
const resizeImage = d.getElementsByClassName("resizeImage")[0];
|
||||
const pattern = element("pattern");
|
||||
const { checked } = e.target;
|
||||
|
||||
Array.from(resizeImage).forEach(function (element) {
|
||||
if (checked) {
|
||||
pattern.value = 3;
|
||||
element.style.display = "flex";
|
||||
} else {
|
||||
pattern.value = 1;
|
||||
element.style.display = "none";
|
||||
}
|
||||
});
|
||||
if (checked) {
|
||||
resizeImage.style.display = "flex";
|
||||
} else {
|
||||
resizeImage.style.display = "none";
|
||||
}
|
||||
});
|
||||
|
||||
element("animation").addEventListener("change", (e) => {
|
||||
const animation = d.getElementsByClassName("animation");
|
||||
|
||||
const animation = d.getElementsByClassName("animation")[0];
|
||||
const pattern = element("pattern");
|
||||
const source = element("source");
|
||||
|
||||
const { checked } = e.target;
|
||||
|
||||
Array.from(animation).forEach(function (element) {
|
||||
if (checked) {
|
||||
toast(
|
||||
'If you want all frames in the image, set it to "0"',
|
||||
"warning",
|
||||
5000
|
||||
);
|
||||
if (checked) {
|
||||
toast(
|
||||
'If you want all frames in the image, set it to "0"',
|
||||
"warning",
|
||||
5000
|
||||
);
|
||||
|
||||
source.setAttribute("accept", "image/gif");
|
||||
element.style.display = "flex";
|
||||
pattern.value = 3;
|
||||
} else {
|
||||
source.setAttribute(
|
||||
"accept",
|
||||
"image/jpg,image/jpeg,image/png,image/gif"
|
||||
);
|
||||
element.style.display = "none";
|
||||
pattern.value = 1;
|
||||
}
|
||||
});
|
||||
source.setAttribute("accept", "image/gif");
|
||||
animation.style.display = "flex";
|
||||
} else {
|
||||
source.setAttribute(
|
||||
"accept",
|
||||
"image/jpg,image/jpeg,image/png,image/gif"
|
||||
);
|
||||
animation.style.display = "none";
|
||||
}
|
||||
});
|
||||
|
||||
element("btnGenerate").addEventListener("click", async (event) => {
|
||||
@ -1402,8 +1363,7 @@
|
||||
const response = element("response");
|
||||
const recreatedImage = element("recreatedImage");
|
||||
|
||||
const urlImage =
|
||||
images === "upload" ? URL.createObjectURL(file) : images;
|
||||
const urlImage = !images ? URL.createObjectURL(file) : images;
|
||||
|
||||
const image = await loadImage(urlImage);
|
||||
const { canvas, bri, id, i } = recreate(image);
|
||||
|
@ -80,7 +80,7 @@
|
||||
<button type=submit id="b" onclick="window.location=getURL('/')">Back</button>
|
||||
<button type="submit" onclick="window.location=getURL('/settings/wifi')">WiFi Setup</button>
|
||||
<button type="submit" onclick="window.location=getURL('/settings/leds')">LED Preferences</button>
|
||||
<button id="2dbtn" style="display:none;" type="submit" onclick="window.location=getURL('/settings/2D')">2D Configuration</button>
|
||||
<button id="2dbtn" type="submit" onclick="window.location=getURL('/settings/2D')">2D Configuration</button>
|
||||
<button type="submit" onclick="window.location=getURL('/settings/ui')">User Interface</button>
|
||||
<button id="dmxbtn" style="display:none;" type="submit" onclick="window.location=getURL('/settings/dmx')">DMX Output</button>
|
||||
<button type="submit" onclick="window.location=getURL('/settings/sync')">Sync Interfaces</button>
|
||||
|
@ -26,8 +26,8 @@
|
||||
// success event
|
||||
scE.addEventListener("load", () => {
|
||||
GetV();
|
||||
checkSi();
|
||||
setABL();
|
||||
checkSi();
|
||||
d.Sf.addEventListener("submit", trySubmit);
|
||||
if (d.um_p[0]==-1) d.um_p.shift();
|
||||
pinDropdowns();
|
||||
@ -773,6 +773,7 @@ Length: <input type="number" name="XC${i}" id="xc${i}" class="l" min="1" max="65
|
||||
Brightness factor: <input name="BF" type="number" class="m" min="1" max="255" required> %
|
||||
<h3>Transitions</h3>
|
||||
Crossfade: <input type="checkbox" name="TF"><br>
|
||||
Effect blending: <input type="checkbox" name="EB"><br>
|
||||
Transition Time: <input name="TD" type="number" class="xl" min="0" max="65500"> ms<br>
|
||||
Enable Palette transitions: <input type="checkbox" name="PF"><br>
|
||||
<i>Random Cycle</i> Palette Time: <input name="TP" type="number" class="m" min="1" max="255"> s<br>
|
||||
|
@ -26,7 +26,8 @@
|
||||
"segexp" : "Always expand first segment",
|
||||
"css": "Enable custom CSS",
|
||||
"hdays": "Enable custom Holidays list",
|
||||
"fxdef": "Use effect default parameters"
|
||||
"fxdef": "Use effect default parameters",
|
||||
"idsort": "Sort presets by ID"
|
||||
},
|
||||
"theme":{
|
||||
"alpha": {
|
||||
@ -277,6 +278,8 @@
|
||||
<span class="l"></span>: <input type="checkbox" id="comp_seglen" class="agi cb"><br>
|
||||
<span class="l"></span>: <input type="checkbox" id="comp_segpwr" class="agi cb"><br>
|
||||
<span class="l"></span>: <input type="checkbox" id="comp_segexp" class="agi cb"><br>
|
||||
<span class="l"></span>: <input type="checkbox" id="comp_fxdef" class="agi cb"><br>
|
||||
<span class="l"></span>: <input type="checkbox" id="comp_idsort" class="agi cb"><br>
|
||||
I hate dark mode: <input type="checkbox" id="dm" onchange="UI()"><br>
|
||||
<span id="idonthateyou" style="display:none"><i>Why would you? </i>🥺<br></span>
|
||||
<span class="l"></span>: <input type="number" min=0.0 max=1.0 step=0.01 id="theme_alpha_tab" class="agi"><br>
|
||||
|
@ -63,7 +63,8 @@ class NeoGammaWLEDMethod {
|
||||
#define gamma32(c) NeoGammaWLEDMethod::Correct32(c)
|
||||
#define gamma8(c) NeoGammaWLEDMethod::rawGamma8(c)
|
||||
uint32_t color_blend(uint32_t,uint32_t,uint16_t,bool b16=false);
|
||||
uint32_t color_add(uint32_t,uint32_t);
|
||||
uint32_t color_add(uint32_t,uint32_t, bool fast=false);
|
||||
uint32_t color_fade(uint32_t c1, uint8_t amount, bool video=false);
|
||||
inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); }
|
||||
void colorHStoRGB(uint16_t hue, byte sat, byte* rgb); //hue, sat to rgb
|
||||
void colorKtoRGB(uint16_t kelvin, byte* rgb);
|
||||
@ -353,6 +354,7 @@ void checkSettingsPIN(const char *pin);
|
||||
uint16_t crc16(const unsigned char* data_p, size_t length);
|
||||
um_data_t* simulateSound(uint8_t simulationId);
|
||||
void enumerateLedmaps();
|
||||
uint8_t get_random_wheel_index(uint8_t pos);
|
||||
|
||||
#ifdef WLED_ADD_EEPROM_SUPPORT
|
||||
//wled_eeprom.cpp
|
||||
|
@ -9,7 +9,7 @@
|
||||
// Autogenerated from wled00/data/cpal/cpal.htm, do not edit!!
|
||||
const uint16_t PAGE_cpal_L = 4721;
|
||||
const uint8_t PAGE_cpal[] PROGMEM = {
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0a, 0xbd, 0x3b, 0x7f, 0x73, 0xdb, 0xb6,
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x13, 0xbd, 0x3b, 0x7f, 0x73, 0xdb, 0xb6,
|
||||
0x92, 0xff, 0xe7, 0x53, 0x20, 0x4c, 0x5f, 0x42, 0xd6, 0x14, 0x45, 0xd2, 0xb6, 0x64, 0x4b, 0xa2,
|
||||
0x3b, 0xa9, 0x93, 0x77, 0xce, 0x8d, 0xdd, 0x64, 0x5e, 0x7c, 0x6e, 0x7b, 0x3e, 0xbf, 0x31, 0x4d,
|
||||
0x42, 0x12, 0x1b, 0x8a, 0xe0, 0x03, 0x21, 0xd9, 0xae, 0xac, 0xef, 0x7e, 0xbb, 0x00, 0x48, 0x91,
|
||||
|
1564
wled00/html_other.h
1564
wled00/html_other.h
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
2262
wled00/html_simple.h
2262
wled00/html_simple.h
File diff suppressed because it is too large
Load Diff
4002
wled00/html_ui.h
4002
wled00/html_ui.h
File diff suppressed because it is too large
Load Diff
@ -210,7 +210,7 @@ void sendImprovInfoResponse() {
|
||||
//Use serverDescription if it has been changed from the default "WLED", else mDNS name
|
||||
bool useMdnsName = (strcmp(serverDescription, "WLED") == 0 && strlen(cmDNS) > 0);
|
||||
char vString[20];
|
||||
sprintf_P(vString, PSTR("0.14.0/%i"), VERSION);
|
||||
sprintf_P(vString, PSTR("0.14.1-b1/%i"), VERSION);
|
||||
const char *str[4] = {"WLED", vString, bString, useMdnsName ? cmDNS : serverDescription};
|
||||
|
||||
sendImprovRPCResult(ImprovRPCType::Request_Info, 4, str);
|
||||
|
@ -675,7 +675,7 @@ void decodeIRJson(uint32_t code)
|
||||
} else {
|
||||
// HTTP API command
|
||||
String apireq = "win"; apireq += '&'; // reduce flash string usage
|
||||
if (cmdStr.indexOf("~") || fdo["rpt"]) lastValidCode = code; // repeatable action
|
||||
if (cmdStr.indexOf("~") > 0 || fdo["rpt"]) lastValidCode = code; // repeatable action
|
||||
if (!cmdStr.startsWith(apireq)) cmdStr = apireq + cmdStr; // if no "win&" prefix
|
||||
if (!irApplyToAllSelected && cmdStr.indexOf(F("SS="))<0) {
|
||||
char tmp[10];
|
||||
|
@ -501,7 +501,8 @@ void serializeSegment(JsonObject& root, Segment& seg, byte id, bool forPreset, b
|
||||
root["cct"] = seg.cct;
|
||||
root[F("set")] = seg.set;
|
||||
|
||||
if (segmentBounds && seg.name != nullptr) root["n"] = reinterpret_cast<const char *>(seg.name); //not good practice, but decreases required JSON buffer
|
||||
if (seg.name != nullptr) root["n"] = reinterpret_cast<const char *>(seg.name); //not good practice, but decreases required JSON buffer
|
||||
else if (forPreset) root["n"] = "";
|
||||
|
||||
// to conserve RAM we will serialize the col array manually
|
||||
// this will reduce RAM footprint from ~300 bytes to 84 bytes per segment
|
||||
|
@ -165,6 +165,8 @@ void updateInterfaces(uint8_t callMode)
|
||||
|
||||
sendDataWs();
|
||||
lastInterfaceUpdate = millis();
|
||||
interfaceUpdateCallMode = 0; //disable
|
||||
|
||||
if (callMode == CALL_MODE_WS_SEND) return;
|
||||
|
||||
#ifndef WLED_DISABLE_ALEXA
|
||||
@ -174,7 +176,6 @@ void updateInterfaces(uint8_t callMode)
|
||||
}
|
||||
#endif
|
||||
doPublishMqtt = true;
|
||||
interfaceUpdateCallMode = 0; //disable
|
||||
}
|
||||
|
||||
|
||||
|
@ -199,6 +199,9 @@ void handleNetworkTime()
|
||||
{
|
||||
if (millis() - ntpPacketSentTime > 10000)
|
||||
{
|
||||
#ifdef ARDUINO_ARCH_ESP32 // I had problems using udp.flush() on 8266
|
||||
while (ntpUdp.parsePacket() > 0) ntpUdp.flush(); // flush any existing packets
|
||||
#endif
|
||||
sendNTPPacket();
|
||||
ntpPacketSentTime = millis();
|
||||
}
|
||||
@ -239,16 +242,38 @@ void sendNTPPacket()
|
||||
ntpUdp.endPacket();
|
||||
}
|
||||
|
||||
static bool isValidNtpResponse(byte * ntpPacket) {
|
||||
// Perform a few validity checks on the packet
|
||||
// based on https://github.com/taranais/NTPClient/blob/master/NTPClient.cpp
|
||||
if((ntpPacket[0] & 0b11000000) == 0b11000000) return false; //reject LI=UNSYNC
|
||||
// if((ntpPacket[0] & 0b00111000) >> 3 < 0b100) return false; //reject Version < 4
|
||||
if((ntpPacket[0] & 0b00000111) != 0b100) return false; //reject Mode != Server
|
||||
if((ntpPacket[1] < 1) || (ntpPacket[1] > 15)) return false; //reject invalid Stratum
|
||||
if( ntpPacket[16] == 0 && ntpPacket[17] == 0 &&
|
||||
ntpPacket[18] == 0 && ntpPacket[19] == 0 &&
|
||||
ntpPacket[20] == 0 && ntpPacket[21] == 0 &&
|
||||
ntpPacket[22] == 0 && ntpPacket[23] == 0) //reject ReferenceTimestamp == 0
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool checkNTPResponse()
|
||||
{
|
||||
int cb = ntpUdp.parsePacket();
|
||||
if (!cb) return false;
|
||||
if (cb < NTP_MIN_PACKET_SIZE) {
|
||||
#ifdef ARDUINO_ARCH_ESP32 // I had problems using udp.flush() on 8266
|
||||
if (cb > 0) ntpUdp.flush(); // this avoids memory leaks on esp32
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t ntpPacketReceivedTime = millis();
|
||||
DEBUG_PRINT(F("NTP recv, l="));
|
||||
DEBUG_PRINTLN(cb);
|
||||
byte pbuf[NTP_PACKET_SIZE];
|
||||
ntpUdp.read(pbuf, NTP_PACKET_SIZE); // read the packet into the buffer
|
||||
if (!isValidNtpResponse(pbuf)) return false; // verify we have a valid response to client
|
||||
|
||||
Toki::Time arrived = toki.fromNTP(pbuf + 32);
|
||||
Toki::Time departed = toki.fromNTP(pbuf + 40);
|
||||
|
@ -212,9 +212,9 @@ void savePreset(byte index, const char* pname, JsonObject sObj)
|
||||
playlistSave = false;
|
||||
if (sObj[F("ql")].is<const char*>()) strlcpy(quickLoad, sObj[F("ql")].as<const char*>(), 9); // client limits QL to 2 chars, buffer for 8 bytes to allow unicode
|
||||
|
||||
if (sObj["o"].isNull()) { // no "o" means not a playlist or custom API call, saving of state is async (not immediately)
|
||||
includeBri = sObj["ib"].as<bool>() || index==255; // temporary preset needs brightness
|
||||
segBounds = sObj["sb"].as<bool>() || index==255; // temporary preset needs bounds
|
||||
if (sObj.size()==0 || sObj["o"].isNull()) { // no "o" means not a playlist or custom API call, saving of state is async (not immediately)
|
||||
includeBri = sObj["ib"].as<bool>() || sObj.size()==0 || index==255; // temporary preset needs brightness
|
||||
segBounds = sObj["sb"].as<bool>() || sObj.size()==0 || index==255; // temporary preset needs bounds
|
||||
selectedOnly = sObj[F("sc")].as<bool>();
|
||||
saveLedmap = sObj[F("ledmap")] | -1;
|
||||
} else {
|
||||
|
@ -247,6 +247,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
}
|
||||
|
||||
fadeTransition = request->hasArg(F("TF"));
|
||||
modeBlending = request->hasArg(F("EB"));
|
||||
t = request->arg(F("TD")).toInt();
|
||||
if (t >= 0) transitionDelayDefault = t;
|
||||
strip.paletteFade = request->hasArg(F("PF"));
|
||||
@ -395,7 +396,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
|
||||
//start ntp if not already connected
|
||||
if (ntpEnabled && WLED_CONNECTED && !ntpConnected) ntpConnected = ntpUdp.begin(ntpLocalPort);
|
||||
ntpLastSyncTime = 0; // force new NTP query
|
||||
ntpLastSyncTime = NTP_NEVER; // force new NTP query
|
||||
|
||||
longitude = request->arg(F("LN")).toFloat();
|
||||
latitude = request->arg(F("LT")).toFloat();
|
||||
|
@ -382,8 +382,9 @@ void handleNotifications()
|
||||
}
|
||||
if (version > 11) {
|
||||
// when applying synced options ignore selected as it may be used as indicator of which segments to sync
|
||||
// freeze, reset & transitional should never be synced
|
||||
selseg.options = (selseg.options & 0x0071U) | (udpIn[28+ofs]<<8) | (udpIn[9 +ofs] & 0x8E); // ignore selected, freeze, reset & transitional
|
||||
// freeze, reset should never be synced
|
||||
// LSB to MSB: select, reverse, on, mirror, freeze, reset, reverse_y, mirror_y, transpose, map1d2d (3), ssim (2), set (2)
|
||||
selseg.options = (selseg.options & 0b0000000000110001U) | (udpIn[28+ofs]<<8) | (udpIn[9 +ofs] & 0b11001110U); // ignore selected, freeze, reset
|
||||
if (applyEffects) {
|
||||
selseg.custom1 = udpIn[29+ofs];
|
||||
selseg.custom2 = udpIn[30+ofs];
|
||||
|
@ -197,6 +197,9 @@
|
||||
#include "../usermods/pwm_outputs/usermod_pwm_outputs.h"
|
||||
#endif
|
||||
|
||||
#ifdef USERMOD_LDR_DUSK_DAWN
|
||||
#include "../usermods/LDR_Dusk_Dawn_v2/usermod_LDR_Dusk_Dawn_v2.h"
|
||||
#endif
|
||||
|
||||
void registerUsermods()
|
||||
{
|
||||
@ -373,4 +376,8 @@ void registerUsermods()
|
||||
#ifdef USERMOD_INTERNAL_TEMPERATURE
|
||||
usermods.add(new InternalTemperatureUsermod());
|
||||
#endif
|
||||
|
||||
#ifdef USERMOD_LDR_DUSK_DAWN
|
||||
usermods.add(new LDR_Dusk_Dawn_v2());
|
||||
#endif
|
||||
}
|
||||
|
@ -416,9 +416,9 @@ uint16_t crc16(const unsigned char* data_p, size_t length) {
|
||||
// (only 2 used as stored in 1 bit in segment options, consider switching to a single global simulation type)
|
||||
typedef enum UM_SoundSimulations {
|
||||
UMS_BeatSin = 0,
|
||||
UMS_WeWillRockYou
|
||||
//UMS_10_13,
|
||||
//UMS_14_3
|
||||
UMS_WeWillRockYou,
|
||||
UMS_10_13,
|
||||
UMS_14_3
|
||||
} um_soundSimulations_t;
|
||||
|
||||
um_data_t* simulateSound(uint8_t simulationId)
|
||||
@ -503,7 +503,7 @@ um_data_t* simulateSound(uint8_t simulationId)
|
||||
fftResult[i] = 0;
|
||||
}
|
||||
break;
|
||||
/*case UMS_10_3:
|
||||
case UMS_10_13:
|
||||
for (int i = 0; i<16; i++)
|
||||
fftResult[i] = inoise8(beatsin8(90 / (i+1), 0, 200)*15 + (ms>>10), ms>>3);
|
||||
volumeSmth = fftResult[8];
|
||||
@ -512,7 +512,7 @@ um_data_t* simulateSound(uint8_t simulationId)
|
||||
for (int i = 0; i<16; i++)
|
||||
fftResult[i] = inoise8(beatsin8(120 / (i+1), 10, 30)*10 + (ms>>14), ms>>3);
|
||||
volumeSmth = fftResult[8];
|
||||
break;*/
|
||||
break;
|
||||
}
|
||||
|
||||
samplePeak = random8() > 250;
|
||||
@ -573,3 +573,17 @@ void enumerateLedmaps() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a new, random color wheel index with a minimum distance of 42 from pos.
|
||||
*/
|
||||
uint8_t get_random_wheel_index(uint8_t pos) {
|
||||
uint8_t r = 0, x = 0, y = 0, d = 0;
|
||||
while (d < 42) {
|
||||
r = random8();
|
||||
x = abs(pos - r);
|
||||
y = 255 - x;
|
||||
d = MIN(x, y);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ void WLED::loop()
|
||||
if (lastMqttReconnectAttempt > millis()) {
|
||||
rolloverMillis++;
|
||||
lastMqttReconnectAttempt = 0;
|
||||
ntpLastSyncTime = 0;
|
||||
ntpLastSyncTime = NTP_NEVER; // force new NTP query
|
||||
strip.restartRuntime();
|
||||
}
|
||||
if (millis() - lastMqttReconnectAttempt > 30000 || lastMqttReconnectAttempt == 0) { // lastMqttReconnectAttempt==0 forces immediate broadcast
|
||||
|
@ -3,12 +3,12 @@
|
||||
/*
|
||||
Main sketch, global variable declarations
|
||||
@title WLED project sketch
|
||||
@version 0.14.0-b4
|
||||
@version 0.14.1-a1
|
||||
@author Christian Schwinne
|
||||
*/
|
||||
|
||||
// version code in format yymmddb (b = daily build)
|
||||
#define VERSION 2310130
|
||||
#define VERSION 2311160
|
||||
|
||||
//uncomment this if you have a "my_config.h" file you'd like to use
|
||||
//#define WLED_USE_MY_CONFIG
|
||||
@ -351,6 +351,7 @@ WLED_GLOBAL byte nightlightTargetBri _INIT(0); // brightness after nightlig
|
||||
WLED_GLOBAL byte nightlightDelayMins _INIT(60);
|
||||
WLED_GLOBAL byte nightlightMode _INIT(NL_MODE_FADE); // See const.h for available modes. Was nightlightFade
|
||||
WLED_GLOBAL bool fadeTransition _INIT(true); // enable crossfading color transition
|
||||
WLED_GLOBAL bool modeBlending _INIT(true); // enable effect blending
|
||||
WLED_GLOBAL uint16_t transitionDelay _INIT(750); // default crossfade duration in ms
|
||||
|
||||
WLED_GLOBAL byte briMultiplier _INIT(100); // % of brightness to set (to limit power, if you set it to 50 and set bri to 255, actual brightness will be 127)
|
||||
@ -643,10 +644,11 @@ WLED_GLOBAL String escapedMac;
|
||||
WLED_GLOBAL DNSServer dnsServer;
|
||||
|
||||
// network time
|
||||
#define NTP_NEVER 999000000L
|
||||
WLED_GLOBAL bool ntpConnected _INIT(false);
|
||||
WLED_GLOBAL time_t localTime _INIT(0);
|
||||
WLED_GLOBAL unsigned long ntpLastSyncTime _INIT(999000000L);
|
||||
WLED_GLOBAL unsigned long ntpPacketSentTime _INIT(999000000L);
|
||||
WLED_GLOBAL unsigned long ntpLastSyncTime _INIT(NTP_NEVER);
|
||||
WLED_GLOBAL unsigned long ntpPacketSentTime _INIT(NTP_NEVER);
|
||||
WLED_GLOBAL IPAddress ntpServerIP;
|
||||
WLED_GLOBAL uint16_t ntpLocalPort _INIT(2390);
|
||||
WLED_GLOBAL uint16_t rolloverMillis _INIT(0);
|
||||
|
@ -40,7 +40,7 @@ bool isIp(String str) {
|
||||
|
||||
void handleUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) {
|
||||
if (!correctPIN) {
|
||||
if (final) request->send(500, "text/plain", FPSTR(s_unlock_cfg));
|
||||
if (final) request->send(401, "text/plain", FPSTR(s_unlock_cfg));
|
||||
return;
|
||||
}
|
||||
if (!index) {
|
||||
@ -86,7 +86,7 @@ void createEditHandler(bool enable) {
|
||||
#endif
|
||||
} else {
|
||||
editHandler = &server.on("/edit", HTTP_ANY, [](AsyncWebServerRequest *request){
|
||||
serveMessage(request, 500, "Access Denied", FPSTR(s_unlock_cfg), 254);
|
||||
serveMessage(request, 401, "Access Denied", FPSTR(s_unlock_cfg), 254);
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -201,7 +201,7 @@ void initServer()
|
||||
verboseResponse = deserializeState(root);
|
||||
} else {
|
||||
if (!correctPIN && strlen(settingsPIN)>0) {
|
||||
request->send(403, "application/json", F("{\"error\":1}")); // ERR_DENIED
|
||||
request->send(401, "application/json", F("{\"error\":1}")); // ERR_DENIED
|
||||
releaseJSONBufferLock();
|
||||
return;
|
||||
}
|
||||
@ -211,6 +211,8 @@ void initServer()
|
||||
|
||||
if (verboseResponse) {
|
||||
if (!isConfig) {
|
||||
lastInterfaceUpdate = millis(); // prevent WS update until cooldown
|
||||
interfaceUpdateCallMode = CALL_MODE_WS_SEND; // schedule WS update
|
||||
serveJson(request); return; //if JSON contains "v"
|
||||
} else {
|
||||
doSerializeConfig = true; //serializeConfig(); //Save new settings to FS
|
||||
@ -282,7 +284,7 @@ void initServer()
|
||||
//init ota page
|
||||
server.on("/update", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
if (otaLock) {
|
||||
serveMessage(request, 500, "Access Denied", FPSTR(s_unlock_ota), 254);
|
||||
serveMessage(request, 401, "Access Denied", FPSTR(s_unlock_ota), 254);
|
||||
} else
|
||||
serveSettings(request); // checks for "upd" in URL and handles PIN
|
||||
});
|
||||
@ -292,7 +294,11 @@ void initServer()
|
||||
serveSettings(request, true); // handle PIN page POST request
|
||||
return;
|
||||
}
|
||||
if (Update.hasError() || otaLock) {
|
||||
if (otaLock) {
|
||||
serveMessage(request, 401, "Access Denied", FPSTR(s_unlock_ota), 254);
|
||||
return;
|
||||
}
|
||||
if (Update.hasError()) {
|
||||
serveMessage(request, 500, F("Update failed!"), F("Please check your file and retry!"), 254);
|
||||
} else {
|
||||
serveMessage(request, 200, F("Update successful!"), F("Rebooting..."), 131);
|
||||
@ -533,13 +539,18 @@ void serveSettingsJS(AsyncWebServerRequest* request)
|
||||
}
|
||||
if (subPage > 0 && !correctPIN && strlen(settingsPIN)>0) {
|
||||
strcpy_P(buf, PSTR("alert('PIN incorrect.');"));
|
||||
request->send(403, "application/javascript", buf);
|
||||
request->send(401, "application/javascript", buf);
|
||||
return;
|
||||
}
|
||||
strcat_P(buf,PSTR("function GetV(){var d=document;"));
|
||||
getSettingsJS(subPage, buf+strlen(buf)); // this may overflow by 35bytes!!!
|
||||
strcat_P(buf,PSTR("}"));
|
||||
request->send(200, "application/javascript", buf);
|
||||
|
||||
AsyncWebServerResponse *response;
|
||||
response = request->beginResponse(200, "application/javascript", buf);
|
||||
response->addHeader(F("Cache-Control"),"no-store");
|
||||
response->addHeader(F("Expires"),"0");
|
||||
request->send(response);
|
||||
}
|
||||
|
||||
|
||||
@ -575,7 +586,7 @@ void serveSettings(AsyncWebServerRequest* request, bool post)
|
||||
// if OTA locked or too frequent PIN entry requests fail hard
|
||||
if ((subPage == SUBPAGE_WIFI && wifiLock && otaLock) || (post && !correctPIN && millis()-lastEditTime < PIN_RETRY_COOLDOWN))
|
||||
{
|
||||
serveMessage(request, 500, "Access Denied", FPSTR(s_unlock_ota), 254); return;
|
||||
serveMessage(request, 401, "Access Denied", FPSTR(s_unlock_ota), 254); return;
|
||||
}
|
||||
|
||||
if (post) { //settings/set POST request, saving
|
||||
@ -605,7 +616,7 @@ void serveSettings(AsyncWebServerRequest* request, bool post)
|
||||
if (!s2[0]) strcpy_P(s2, s_redirecting);
|
||||
|
||||
bool redirectAfter9s = (subPage == SUBPAGE_WIFI || ((subPage == SUBPAGE_SEC || subPage == SUBPAGE_UM) && doReboot));
|
||||
serveMessage(request, 200, s, s2, redirectAfter9s ? 129 : (correctPIN ? 1 : 3));
|
||||
serveMessage(request, (correctPIN ? 200 : 401), s, s2, redirectAfter9s ? 129 : (correctPIN ? 1 : 3));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -633,7 +644,7 @@ void serveSettings(AsyncWebServerRequest* request, bool post)
|
||||
serveMessage(request, 200, strlen(settingsPIN) > 0 ? PSTR("Settings locked") : PSTR("No PIN set"), FPSTR(s_redirecting), 1);
|
||||
return;
|
||||
}
|
||||
case SUBPAGE_PINREQ : response = request->beginResponse_P(200, "text/html", PAGE_settings_pin, PAGE_settings_pin_length); break;
|
||||
case SUBPAGE_PINREQ : response = request->beginResponse_P(401, "text/html", PAGE_settings_pin, PAGE_settings_pin_length); break;
|
||||
case SUBPAGE_CSS : response = request->beginResponse_P(200, "text/css", PAGE_settingsCss, PAGE_settingsCss_length); break;
|
||||
case SUBPAGE_JS : serveSettingsJS(request); return;
|
||||
case SUBPAGE_WELCOME : response = request->beginResponse_P(200, "text/html", PAGE_welcome, PAGE_welcome_length); break;
|
||||
|
@ -238,8 +238,8 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
|
||||
if (subPage == SUBPAGE_MENU)
|
||||
{
|
||||
#ifndef WLED_DISABLE_2D // include only if 2D is compiled in
|
||||
oappend(PSTR("gId('2dbtn').style.display='';"));
|
||||
#ifdef WLED_DISABLE_2D // include only if 2D is not compiled in
|
||||
oappend(PSTR("gId('2dbtn').style.display='none';"));
|
||||
#endif
|
||||
#ifdef WLED_ENABLE_DMX // include only if DMX is enabled
|
||||
oappend(PSTR("gId('dmxbtn').style.display='';"));
|
||||
@ -441,6 +441,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
sappend('c',SET_F("GC"),gammaCorrectCol);
|
||||
dtostrf(gammaCorrectVal,3,1,nS); sappends('s',SET_F("GV"),nS);
|
||||
sappend('c',SET_F("TF"),fadeTransition);
|
||||
sappend('c',SET_F("EB"),modeBlending);
|
||||
sappend('v',SET_F("TD"),transitionDelayDefault);
|
||||
sappend('c',SET_F("PF"),strip.paletteFade);
|
||||
sappend('v',SET_F("TP"),randomPaletteChangeTime);
|
||||
@ -478,7 +479,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
|
||||
if (subPage == SUBPAGE_SYNC)
|
||||
{
|
||||
char nS[32];
|
||||
[[maybe_unused]] char nS[32];
|
||||
sappend('v',SET_F("UP"),udpPort);
|
||||
sappend('v',SET_F("U2"),udpPort2);
|
||||
sappend('v',SET_F("GS"),syncGroups);
|
||||
|
Loading…
Reference in New Issue
Block a user