mirror of
https://github.com/wled/WLED.git
synced 2025-07-20 17:26:32 +00:00
Merge branch '0_15' into temporary-AP
This commit is contained in:
commit
2944b2a8f6
@ -297,8 +297,8 @@ class Animated_Staircase : public Usermod {
|
|||||||
offIndex = maxSegmentId = strip.getLastActiveSegmentId() + 1;
|
offIndex = maxSegmentId = strip.getLastActiveSegmentId() + 1;
|
||||||
|
|
||||||
// shorten the strip transition time to be equal or shorter than segment delay
|
// shorten the strip transition time to be equal or shorter than segment delay
|
||||||
transitionDelayTemp = transitionDelay = segment_delay_ms;
|
transitionDelay = segment_delay_ms;
|
||||||
strip.setTransition(segment_delay_ms/100);
|
strip.setTransition(segment_delay_ms);
|
||||||
strip.trigger();
|
strip.trigger();
|
||||||
} else {
|
} else {
|
||||||
if (togglePower && !on && offMode) toggleOnOff(); // toggle power on if off
|
if (togglePower && !on && offMode) toggleOnOff(); // toggle power on if off
|
||||||
|
@ -70,6 +70,7 @@ private:
|
|||||||
|
|
||||||
// Home Assistant
|
// Home Assistant
|
||||||
bool HomeAssistantDiscovery = false; // is HA discovery turned on
|
bool HomeAssistantDiscovery = false; // is HA discovery turned on
|
||||||
|
int16_t idx = -1; // Domoticz virtual switch idx
|
||||||
|
|
||||||
// strings to reduce flash memory usage (used more than twice)
|
// strings to reduce flash memory usage (used more than twice)
|
||||||
static const char _name[];
|
static const char _name[];
|
||||||
@ -83,6 +84,7 @@ private:
|
|||||||
static const char _haDiscovery[];
|
static const char _haDiscovery[];
|
||||||
static const char _notify[];
|
static const char _notify[];
|
||||||
static const char _override[];
|
static const char _override[];
|
||||||
|
static const char _domoticzIDX[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* check if it is daytime
|
* check if it is daytime
|
||||||
@ -196,6 +198,7 @@ const char PIRsensorSwitch::_offOnly[] PROGMEM = "off-only";
|
|||||||
const char PIRsensorSwitch::_haDiscovery[] PROGMEM = "HA-discovery";
|
const char PIRsensorSwitch::_haDiscovery[] PROGMEM = "HA-discovery";
|
||||||
const char PIRsensorSwitch::_notify[] PROGMEM = "notifications";
|
const char PIRsensorSwitch::_notify[] PROGMEM = "notifications";
|
||||||
const char PIRsensorSwitch::_override[] PROGMEM = "override";
|
const char PIRsensorSwitch::_override[] PROGMEM = "override";
|
||||||
|
const char PIRsensorSwitch::_domoticzIDX[] PROGMEM = "domoticz-idx";
|
||||||
|
|
||||||
bool PIRsensorSwitch::isDayTime() {
|
bool PIRsensorSwitch::isDayTime() {
|
||||||
updateLocalTime();
|
updateLocalTime();
|
||||||
@ -271,9 +274,20 @@ void PIRsensorSwitch::publishMqtt(const char* state)
|
|||||||
#ifndef WLED_DISABLE_MQTT
|
#ifndef WLED_DISABLE_MQTT
|
||||||
//Check if MQTT Connected, otherwise it will crash the 8266
|
//Check if MQTT Connected, otherwise it will crash the 8266
|
||||||
if (WLED_MQTT_CONNECTED) {
|
if (WLED_MQTT_CONNECTED) {
|
||||||
char buf[64];
|
char buf[128];
|
||||||
sprintf_P(buf, PSTR("%s/motion"), mqttDeviceTopic); //max length: 33 + 7 = 40
|
sprintf_P(buf, PSTR("%s/motion"), mqttDeviceTopic); //max length: 33 + 7 = 40
|
||||||
mqtt->publish(buf, 0, false, state);
|
mqtt->publish(buf, 0, false, state);
|
||||||
|
// Domoticz formatted message
|
||||||
|
if (idx > 0) {
|
||||||
|
StaticJsonDocument <128> msg;
|
||||||
|
msg[F("idx")] = idx;
|
||||||
|
msg[F("RSSI")] = WiFi.RSSI();
|
||||||
|
msg[F("command")] = F("switchlight");
|
||||||
|
strcpy(buf, state); buf[0] = toupper(buf[0]);
|
||||||
|
msg[F("switchcmd")] = (const char *)buf;
|
||||||
|
serializeJson(msg, buf, 127);
|
||||||
|
mqtt->publish("domoticz/in", 0, false, buf);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -482,6 +496,7 @@ void PIRsensorSwitch::addToConfig(JsonObject &root)
|
|||||||
top[FPSTR(_offOnly)] = m_offOnly;
|
top[FPSTR(_offOnly)] = m_offOnly;
|
||||||
top[FPSTR(_override)] = m_override;
|
top[FPSTR(_override)] = m_override;
|
||||||
top[FPSTR(_haDiscovery)] = HomeAssistantDiscovery;
|
top[FPSTR(_haDiscovery)] = HomeAssistantDiscovery;
|
||||||
|
top[FPSTR(_domoticzIDX)] = idx;
|
||||||
top[FPSTR(_notify)] = (NotifyUpdateMode != CALL_MODE_NO_NOTIFY);
|
top[FPSTR(_notify)] = (NotifyUpdateMode != CALL_MODE_NO_NOTIFY);
|
||||||
DEBUG_PRINTLN(F("PIR config saved."));
|
DEBUG_PRINTLN(F("PIR config saved."));
|
||||||
}
|
}
|
||||||
@ -521,6 +536,7 @@ bool PIRsensorSwitch::readFromConfig(JsonObject &root)
|
|||||||
m_offOnly = top[FPSTR(_offOnly)] | m_offOnly;
|
m_offOnly = top[FPSTR(_offOnly)] | m_offOnly;
|
||||||
m_override = top[FPSTR(_override)] | m_override;
|
m_override = top[FPSTR(_override)] | m_override;
|
||||||
HomeAssistantDiscovery = top[FPSTR(_haDiscovery)] | HomeAssistantDiscovery;
|
HomeAssistantDiscovery = top[FPSTR(_haDiscovery)] | HomeAssistantDiscovery;
|
||||||
|
idx = top[FPSTR(_domoticzIDX)] | idx;
|
||||||
|
|
||||||
NotifyUpdateMode = top[FPSTR(_notify)] ? CALL_MODE_DIRECT_CHANGE : CALL_MODE_NO_NOTIFY;
|
NotifyUpdateMode = top[FPSTR(_notify)] ? CALL_MODE_DIRECT_CHANGE : CALL_MODE_NO_NOTIFY;
|
||||||
|
|
||||||
@ -549,5 +565,5 @@ bool PIRsensorSwitch::readFromConfig(JsonObject &root)
|
|||||||
DEBUG_PRINTLN(F(" config (re)loaded."));
|
DEBUG_PRINTLN(F(" config (re)loaded."));
|
||||||
}
|
}
|
||||||
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
||||||
return !top[FPSTR(_override)].isNull();
|
return !top[FPSTR(_domoticzIDX)].isNull();
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,7 @@ class UsermodTemperature : public Usermod {
|
|||||||
bool enabled = true;
|
bool enabled = true;
|
||||||
|
|
||||||
bool HApublished = false;
|
bool HApublished = false;
|
||||||
|
int16_t idx = -1; // Domoticz virtual sensor idx
|
||||||
|
|
||||||
// strings to reduce flash memory usage (used more than twice)
|
// strings to reduce flash memory usage (used more than twice)
|
||||||
static const char _name[];
|
static const char _name[];
|
||||||
@ -55,6 +56,7 @@ class UsermodTemperature : public Usermod {
|
|||||||
static const char _readInterval[];
|
static const char _readInterval[];
|
||||||
static const char _parasite[];
|
static const char _parasite[];
|
||||||
static const char _parasitePin[];
|
static const char _parasitePin[];
|
||||||
|
static const char _domoticzIDX[];
|
||||||
|
|
||||||
//Dallas sensor quick (& dirty) reading. Credit to - Author: Peter Scargill, August 17th, 2013
|
//Dallas sensor quick (& dirty) reading. Credit to - Author: Peter Scargill, August 17th, 2013
|
||||||
float readDallas();
|
float readDallas();
|
||||||
@ -264,7 +266,7 @@ void UsermodTemperature::loop() {
|
|||||||
|
|
||||||
#ifndef WLED_DISABLE_MQTT
|
#ifndef WLED_DISABLE_MQTT
|
||||||
if (WLED_MQTT_CONNECTED) {
|
if (WLED_MQTT_CONNECTED) {
|
||||||
char subuf[64];
|
char subuf[128];
|
||||||
strcpy(subuf, mqttDeviceTopic);
|
strcpy(subuf, mqttDeviceTopic);
|
||||||
if (temperature > -100.0f) {
|
if (temperature > -100.0f) {
|
||||||
// dont publish super low temperature as the graph will get messed up
|
// dont publish super low temperature as the graph will get messed up
|
||||||
@ -274,6 +276,16 @@ void UsermodTemperature::loop() {
|
|||||||
mqtt->publish(subuf, 0, false, String(getTemperatureC()).c_str());
|
mqtt->publish(subuf, 0, false, String(getTemperatureC()).c_str());
|
||||||
strcat_P(subuf, PSTR("_f"));
|
strcat_P(subuf, PSTR("_f"));
|
||||||
mqtt->publish(subuf, 0, false, String(getTemperatureF()).c_str());
|
mqtt->publish(subuf, 0, false, String(getTemperatureF()).c_str());
|
||||||
|
if (idx > 0) {
|
||||||
|
StaticJsonDocument <128> msg;
|
||||||
|
msg[F("idx")] = idx;
|
||||||
|
msg[F("RSSI")] = WiFi.RSSI();
|
||||||
|
msg[F("nvalue")] = 0;
|
||||||
|
msg[F("svalue")] = String(getTemperatureC());
|
||||||
|
serializeJson(msg, subuf, 127);
|
||||||
|
DEBUG_PRINTLN(subuf);
|
||||||
|
mqtt->publish("domoticz/in", 0, false, subuf);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// publish something else to indicate status?
|
// publish something else to indicate status?
|
||||||
}
|
}
|
||||||
@ -360,6 +372,7 @@ void UsermodTemperature::addToConfig(JsonObject &root) {
|
|||||||
top[FPSTR(_readInterval)] = readingInterval / 1000;
|
top[FPSTR(_readInterval)] = readingInterval / 1000;
|
||||||
top[FPSTR(_parasite)] = parasite;
|
top[FPSTR(_parasite)] = parasite;
|
||||||
top[FPSTR(_parasitePin)] = parasitePin;
|
top[FPSTR(_parasitePin)] = parasitePin;
|
||||||
|
top[FPSTR(_domoticzIDX)] = idx;
|
||||||
DEBUG_PRINTLN(F("Temperature config saved."));
|
DEBUG_PRINTLN(F("Temperature config saved."));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,6 +399,7 @@ bool UsermodTemperature::readFromConfig(JsonObject &root) {
|
|||||||
readingInterval = min(120,max(10,(int)readingInterval)) * 1000; // convert to ms
|
readingInterval = min(120,max(10,(int)readingInterval)) * 1000; // convert to ms
|
||||||
parasite = top[FPSTR(_parasite)] | parasite;
|
parasite = top[FPSTR(_parasite)] | parasite;
|
||||||
parasitePin = top[FPSTR(_parasitePin)] | parasitePin;
|
parasitePin = top[FPSTR(_parasitePin)] | parasitePin;
|
||||||
|
idx = top[FPSTR(_domoticzIDX)] | idx;
|
||||||
|
|
||||||
if (!initDone) {
|
if (!initDone) {
|
||||||
// first run: reading from cfg.json
|
// first run: reading from cfg.json
|
||||||
@ -406,7 +420,7 @@ bool UsermodTemperature::readFromConfig(JsonObject &root) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
||||||
return !top[FPSTR(_parasitePin)].isNull();
|
return !top[FPSTR(_domoticzIDX)].isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UsermodTemperature::appendConfigData() {
|
void UsermodTemperature::appendConfigData() {
|
||||||
@ -430,3 +444,4 @@ const char UsermodTemperature::_enabled[] PROGMEM = "enabled";
|
|||||||
const char UsermodTemperature::_readInterval[] PROGMEM = "read-interval-s";
|
const char UsermodTemperature::_readInterval[] PROGMEM = "read-interval-s";
|
||||||
const char UsermodTemperature::_parasite[] PROGMEM = "parasite-pwr";
|
const char UsermodTemperature::_parasite[] PROGMEM = "parasite-pwr";
|
||||||
const char UsermodTemperature::_parasitePin[] PROGMEM = "parasite-pwr-pin";
|
const char UsermodTemperature::_parasitePin[] PROGMEM = "parasite-pwr-pin";
|
||||||
|
const char UsermodTemperature::_domoticzIDX[] PROGMEM = "domoticz-idx";
|
||||||
|
@ -803,13 +803,6 @@ bool MultiRelay::readFromConfig(JsonObject &root) {
|
|||||||
_relay[i].external = top[parName][FPSTR(_external)] | _relay[i].external;
|
_relay[i].external = top[parName][FPSTR(_external)] | _relay[i].external;
|
||||||
_relay[i].delay = top[parName][FPSTR(_delay_str)] | _relay[i].delay;
|
_relay[i].delay = top[parName][FPSTR(_delay_str)] | _relay[i].delay;
|
||||||
_relay[i].button = top[parName][FPSTR(_button)] | _relay[i].button;
|
_relay[i].button = top[parName][FPSTR(_button)] | _relay[i].button;
|
||||||
// begin backwards compatibility (beta) remove when 0.13 is released
|
|
||||||
parName += '-';
|
|
||||||
_relay[i].pin = top[parName+"pin"] | _relay[i].pin;
|
|
||||||
_relay[i].invert = top[parName+FPSTR(_activeHigh)] | _relay[i].invert;
|
|
||||||
_relay[i].external = top[parName+FPSTR(_external)] | _relay[i].external;
|
|
||||||
_relay[i].delay = top[parName+FPSTR(_delay_str)] | _relay[i].delay;
|
|
||||||
// end compatibility
|
|
||||||
_relay[i].delay = min(600,max(0,abs((int)_relay[i].delay))); // bounds checking max 10min
|
_relay[i].delay = min(600,max(0,abs((int)_relay[i].delay))); // bounds checking max 10min
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
| `pinSourceSelect` | GPIO that is connected to SD's `SS`(source select) / `CS`(chip select) | 16 |
|
| `pinSourceSelect` | GPIO that is connected to SD's `SS`(source select) / `CS`(chip select) | 16 |
|
||||||
| `pinSourceClock` | GPIO that is connected to SD's `SCLK` (source clock) / `CLK`(clock) | 14 |
|
| `pinSourceClock` | GPIO that is connected to SD's `SCLK` (source clock) / `CLK`(clock) | 14 |
|
||||||
| `pinPoci` | GPIO that is connected to SD's `POCI`<sup>☨</sup> (Peripheral-Out-Ctrl-In) / `MISO` (deprecated) | 36 |
|
| `pinPoci` | GPIO that is connected to SD's `POCI`<sup>☨</sup> (Peripheral-Out-Ctrl-In) / `MISO` (deprecated) | 36 |
|
||||||
| `pinPico` | GPIO that is connected to SD's `PICO`<sup>☨</sup> (Peripheral-In-Ctrl-Out) / `MOSI` (deprecated) | 14 |
|
| `pinPico` | GPIO that is connected to SD's `PICO`<sup>☨</sup> (Peripheral-In-Ctrl-Out) / `MOSI` (deprecated) | 15 |
|
||||||
| `sdEnable` | Enable to read data from the SD-card | true |
|
| `sdEnable` | Enable to read data from the SD-card | true |
|
||||||
|
|
||||||
<sup>☨</sup><sub>Following new naming convention of [OSHWA](https://www.oshwa.org/a-resolution-to-redefine-spi-signal-names/)</sub>
|
<sup>☨</sup><sub>Following new naming convention of [OSHWA](https://www.oshwa.org/a-resolution-to-redefine-spi-signal-names/)</sub>
|
||||||
|
@ -91,7 +91,8 @@ class StairwayWipeUsermod : public Usermod {
|
|||||||
void startWipe()
|
void startWipe()
|
||||||
{
|
{
|
||||||
bri = briLast; //turn on
|
bri = briLast; //turn on
|
||||||
transitionDelayTemp = 0; //no transition
|
jsonTransitionOnce = true;
|
||||||
|
strip.setTransition(0); //no transition
|
||||||
effectCurrent = FX_MODE_COLOR_WIPE;
|
effectCurrent = FX_MODE_COLOR_WIPE;
|
||||||
resetTimebase(); //make sure wipe starts from beginning
|
resetTimebase(); //make sure wipe starts from beginning
|
||||||
|
|
||||||
@ -105,10 +106,11 @@ class StairwayWipeUsermod : public Usermod {
|
|||||||
|
|
||||||
void turnOff()
|
void turnOff()
|
||||||
{
|
{
|
||||||
|
jsonTransitionOnce = true;
|
||||||
#ifdef STAIRCASE_WIPE_OFF
|
#ifdef STAIRCASE_WIPE_OFF
|
||||||
transitionDelayTemp = 0; //turn off immediately after wipe completed
|
strip.setTransition(0); //turn off immediately after wipe completed
|
||||||
#else
|
#else
|
||||||
transitionDelayTemp = 4000; //fade out slowly
|
strip.setTransition(4000); //fade out slowly
|
||||||
#endif
|
#endif
|
||||||
bri = 0;
|
bri = 0;
|
||||||
stateUpdated(CALL_MODE_NOTIFICATION);
|
stateUpdated(CALL_MODE_NOTIFICATION);
|
||||||
|
@ -80,7 +80,7 @@ int8_t tristate_square8(uint8_t x, uint8_t pulsewidth, uint8_t attdec) {
|
|||||||
*/
|
*/
|
||||||
uint16_t mode_static(void) {
|
uint16_t mode_static(void) {
|
||||||
SEGMENT.fill(SEGCOLOR(0));
|
SEGMENT.fill(SEGCOLOR(0));
|
||||||
return 350;
|
return strip.isOffRefreshRequired() ? FRAMETIME : 350;
|
||||||
}
|
}
|
||||||
static const char _data_FX_MODE_STATIC[] PROGMEM = "Solid";
|
static const char _data_FX_MODE_STATIC[] PROGMEM = "Solid";
|
||||||
|
|
||||||
@ -1714,7 +1714,7 @@ uint16_t mode_multi_comet(void) {
|
|||||||
}
|
}
|
||||||
comets[i]++;
|
comets[i]++;
|
||||||
} else {
|
} else {
|
||||||
if(!random(SEGLEN)) {
|
if(!random16(SEGLEN)) {
|
||||||
comets[i] = 0;
|
comets[i] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1990,7 +1990,7 @@ uint16_t mode_fire_2012() {
|
|||||||
|
|
||||||
// Step 1. Cool down every cell a little
|
// Step 1. Cool down every cell a little
|
||||||
for (int i = 0; i < SEGLEN; i++) {
|
for (int i = 0; i < SEGLEN; i++) {
|
||||||
uint8_t cool = (it != SEGENV.step) ? random8((((20 + SEGMENT.speed/3) * 16) / SEGLEN)+2) : random(4);
|
uint8_t cool = (it != SEGENV.step) ? random8((((20 + SEGMENT.speed/3) * 16) / SEGLEN)+2) : random8(4);
|
||||||
uint8_t minTemp = (i<ignition) ? (ignition-i)/4 + 16 : 0; // should not become black in ignition area
|
uint8_t minTemp = (i<ignition) ? (ignition-i)/4 + 16 : 0; // should not become black in ignition area
|
||||||
uint8_t temp = qsub8(heat[i], cool);
|
uint8_t temp = qsub8(heat[i], cool);
|
||||||
heat[i] = temp<minTemp ? minTemp : temp;
|
heat[i] = temp<minTemp ? minTemp : temp;
|
||||||
@ -4075,6 +4075,7 @@ static const char _data_FX_MODE_PHASEDNOISE[] PROGMEM = "Phased Noise@!,!;!,!;!"
|
|||||||
|
|
||||||
|
|
||||||
uint16_t mode_twinkleup(void) { // A very short twinkle routine with fade-in and dual controls. By Andrew Tuline.
|
uint16_t mode_twinkleup(void) { // A very short twinkle routine with fade-in and dual controls. By Andrew Tuline.
|
||||||
|
uint16_t prevSeed = random16_get_seed(); // save seed so we can restore it at the end of the function
|
||||||
random16_set_seed(535); // The randomizer needs to be re-set each time through the loop in order for the same 'random' numbers to be the same each time through.
|
random16_set_seed(535); // The randomizer needs to be re-set each time through the loop in order for the same 'random' numbers to be the same each time through.
|
||||||
|
|
||||||
for (int i = 0; i < SEGLEN; i++) {
|
for (int i = 0; i < SEGLEN; i++) {
|
||||||
@ -4084,6 +4085,7 @@ uint16_t mode_twinkleup(void) { // A very short twinkle routine
|
|||||||
SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(random8()+strip.now/100, false, PALETTE_SOLID_WRAP, 0), pixBri));
|
SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(random8()+strip.now/100, false, PALETTE_SOLID_WRAP, 0), pixBri));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
random16_set_seed(prevSeed); // restore original seed so other effects can use "random" PRNG
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
static const char _data_FX_MODE_TWINKLEUP[] PROGMEM = "Twinkleup@!,Intensity;!,!;!;;m12=0";
|
static const char _data_FX_MODE_TWINKLEUP[] PROGMEM = "Twinkleup@!,Intensity;!,!;!;;m12=0";
|
||||||
@ -4566,15 +4568,15 @@ class AuroraWave {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
void init(uint32_t segment_length, CRGB color) {
|
void init(uint32_t segment_length, CRGB color) {
|
||||||
ttl = random(500, 1501);
|
ttl = random16(500, 1501);
|
||||||
basecolor = color;
|
basecolor = color;
|
||||||
basealpha = random(60, 101) / (float)100;
|
basealpha = random8(60, 101) / (float)100;
|
||||||
age = 0;
|
age = 0;
|
||||||
width = random(segment_length / 20, segment_length / W_WIDTH_FACTOR); //half of width to make math easier
|
width = random16(segment_length / 20, segment_length / W_WIDTH_FACTOR); //half of width to make math easier
|
||||||
if (!width) width = 1;
|
if (!width) width = 1;
|
||||||
center = random(101) / (float)100 * segment_length;
|
center = random8(101) / (float)100 * segment_length;
|
||||||
goingleft = random(0, 2) == 0;
|
goingleft = random8(0, 2) == 0;
|
||||||
speed_factor = (random(10, 31) / (float)100 * W_MAX_SPEED / 255);
|
speed_factor = (random8(10, 31) / (float)100 * W_MAX_SPEED / 255);
|
||||||
alive = true;
|
alive = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4659,7 +4661,7 @@ uint16_t mode_aurora(void) {
|
|||||||
waves = reinterpret_cast<AuroraWave*>(SEGENV.data);
|
waves = reinterpret_cast<AuroraWave*>(SEGENV.data);
|
||||||
|
|
||||||
for (int i = 0; i < SEGENV.aux1; i++) {
|
for (int i = 0; i < SEGENV.aux1; i++) {
|
||||||
waves[i].init(SEGLEN, CRGB(SEGMENT.color_from_palette(random8(), false, false, random(0, 3))));
|
waves[i].init(SEGLEN, CRGB(SEGMENT.color_from_palette(random8(), false, false, random8(0, 3))));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
waves = reinterpret_cast<AuroraWave*>(SEGENV.data);
|
waves = reinterpret_cast<AuroraWave*>(SEGENV.data);
|
||||||
@ -4671,7 +4673,7 @@ uint16_t mode_aurora(void) {
|
|||||||
|
|
||||||
if(!(waves[i].stillAlive())) {
|
if(!(waves[i].stillAlive())) {
|
||||||
//If a wave dies, reinitialize it starts over.
|
//If a wave dies, reinitialize it starts over.
|
||||||
waves[i].init(SEGLEN, CRGB(SEGMENT.color_from_palette(random8(), false, false, random(0, 3))));
|
waves[i].init(SEGLEN, CRGB(SEGMENT.color_from_palette(random8(), false, false, random8(0, 3))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5025,7 +5027,7 @@ uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https:
|
|||||||
if (SEGENV.call == 0 || strip.now - SEGMENT.step > 3000) {
|
if (SEGENV.call == 0 || strip.now - SEGMENT.step > 3000) {
|
||||||
SEGENV.step = strip.now;
|
SEGENV.step = strip.now;
|
||||||
SEGENV.aux0 = 0;
|
SEGENV.aux0 = 0;
|
||||||
random16_set_seed(millis()>>2); //seed the random generator
|
//random16_set_seed(millis()>>2); //seed the random generator
|
||||||
|
|
||||||
//give the leds random state and colors (based on intensity, colors from palette or all posible colors are chosen)
|
//give the leds random state and colors (based on intensity, colors from palette or all posible colors are chosen)
|
||||||
for (int x = 0; x < cols; x++) for (int y = 0; y < rows; y++) {
|
for (int x = 0; x < cols; x++) for (int y = 0; y < rows; y++) {
|
||||||
@ -5274,7 +5276,7 @@ uint16_t mode_2DLissajous(void) { // By: Andrew Tuline
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
} // mode_2DLissajous()
|
} // mode_2DLissajous()
|
||||||
static const char _data_FX_MODE_2DLISSAJOUS[] PROGMEM = "Lissajous@X frequency,Fade rate,,,Speed;!;!;2;;c3=15";
|
static const char _data_FX_MODE_2DLISSAJOUS[] PROGMEM = "Lissajous@X frequency,Fade rate,,,Speed;!;!;2;c3=15";
|
||||||
|
|
||||||
|
|
||||||
///////////////////////
|
///////////////////////
|
||||||
@ -5286,7 +5288,7 @@ uint16_t mode_2Dmatrix(void) { // Matrix2D. By Jeremy Williams.
|
|||||||
const uint16_t cols = SEGMENT.virtualWidth();
|
const uint16_t cols = SEGMENT.virtualWidth();
|
||||||
const uint16_t rows = SEGMENT.virtualHeight();
|
const uint16_t rows = SEGMENT.virtualHeight();
|
||||||
|
|
||||||
uint16_t dataSize = (SEGLEN+7) >> 3; //1 bit per LED for trails
|
uint16_t dataSize = (SEGMENT.length()+7) >> 3; //1 bit per LED for trails
|
||||||
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
||||||
|
|
||||||
if (SEGENV.call == 0) {
|
if (SEGENV.call == 0) {
|
||||||
@ -5755,7 +5757,7 @@ uint16_t mode_2Dcrazybees(void) {
|
|||||||
uint8_t posX, posY, aimX, aimY, hue;
|
uint8_t posX, posY, aimX, aimY, hue;
|
||||||
int8_t deltaX, deltaY, signX, signY, error;
|
int8_t deltaX, deltaY, signX, signY, error;
|
||||||
void aimed(uint16_t w, uint16_t h) {
|
void aimed(uint16_t w, uint16_t h) {
|
||||||
random16_set_seed(millis());
|
//random16_set_seed(millis());
|
||||||
aimX = random8(0, w);
|
aimX = random8(0, w);
|
||||||
aimY = random8(0, h);
|
aimY = random8(0, h);
|
||||||
hue = random8();
|
hue = random8();
|
||||||
@ -5842,7 +5844,7 @@ uint16_t mode_2Dghostrider(void) {
|
|||||||
if (SEGENV.aux0 != cols || SEGENV.aux1 != rows) {
|
if (SEGENV.aux0 != cols || SEGENV.aux1 != rows) {
|
||||||
SEGENV.aux0 = cols;
|
SEGENV.aux0 = cols;
|
||||||
SEGENV.aux1 = rows;
|
SEGENV.aux1 = rows;
|
||||||
random16_set_seed(strip.now);
|
//random16_set_seed(strip.now);
|
||||||
lighter->angleSpeed = random8(0,20) - 10;
|
lighter->angleSpeed = random8(0,20) - 10;
|
||||||
lighter->gAngle = random16();
|
lighter->gAngle = random16();
|
||||||
lighter->Vspeed = 5;
|
lighter->Vspeed = 5;
|
||||||
@ -5883,7 +5885,7 @@ uint16_t mode_2Dghostrider(void) {
|
|||||||
if (lighter->reg[i]) {
|
if (lighter->reg[i]) {
|
||||||
lighter->lightersPosY[i] = lighter->gPosY;
|
lighter->lightersPosY[i] = lighter->gPosY;
|
||||||
lighter->lightersPosX[i] = lighter->gPosX;
|
lighter->lightersPosX[i] = lighter->gPosX;
|
||||||
lighter->Angle[i] = lighter->gAngle + random(-10, 10);
|
lighter->Angle[i] = lighter->gAngle + ((int)random8(20) - 10);
|
||||||
lighter->time[i] = 0;
|
lighter->time[i] = 0;
|
||||||
lighter->reg[i] = false;
|
lighter->reg[i] = false;
|
||||||
} else {
|
} else {
|
||||||
@ -6744,7 +6746,7 @@ uint16_t mode_puddlepeak(void) { // Puddlepeak. By Andrew Tuline.
|
|||||||
|
|
||||||
uint16_t size = 0;
|
uint16_t size = 0;
|
||||||
uint8_t fadeVal = map(SEGMENT.speed,0,255, 224, 254);
|
uint8_t fadeVal = map(SEGMENT.speed,0,255, 224, 254);
|
||||||
uint16_t pos = random(SEGLEN); // Set a random starting position.
|
uint16_t pos = random16(SEGLEN); // Set a random starting position.
|
||||||
|
|
||||||
um_data_t *um_data;
|
um_data_t *um_data;
|
||||||
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
|
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
|
||||||
|
@ -493,9 +493,9 @@ typedef struct Segment {
|
|||||||
|
|
||||||
~Segment() {
|
~Segment() {
|
||||||
#ifdef WLED_DEBUG
|
#ifdef WLED_DEBUG
|
||||||
//Serial.printf("-- Destroying segment: %p\n", this);
|
//Serial.printf("-- Destroying segment: %p", this);
|
||||||
//if (name) Serial.printf(" %s (%p)", name, name);
|
//if (name) Serial.printf(" %s (%p)", name, name);
|
||||||
//if (data) Serial.printf(" %d (%p)", (int)_dataLen, data);
|
//if (data) Serial.printf(" %d->(%p)", (int)_dataLen, data);
|
||||||
//Serial.println();
|
//Serial.println();
|
||||||
#endif
|
#endif
|
||||||
if (name) { delete[] name; name = nullptr; }
|
if (name) { delete[] name; name = nullptr; }
|
||||||
@ -779,6 +779,7 @@ class WS2812FX { // 96 bytes
|
|||||||
inline void appendSegment(const Segment &seg = Segment()) { if (_segments.size() < getMaxSegments()) _segments.push_back(seg); }
|
inline void appendSegment(const Segment &seg = Segment()) { if (_segments.size() < getMaxSegments()) _segments.push_back(seg); }
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
paletteFade,
|
||||||
checkSegmentAlignment(void),
|
checkSegmentAlignment(void),
|
||||||
hasRGBWBus(void),
|
hasRGBWBus(void),
|
||||||
hasCCTBus(void),
|
hasCCTBus(void),
|
||||||
@ -791,7 +792,6 @@ class WS2812FX { // 96 bytes
|
|||||||
inline bool isOffRefreshRequired(void) {return _isOffRefreshRequired;}
|
inline bool isOffRefreshRequired(void) {return _isOffRefreshRequired;}
|
||||||
|
|
||||||
uint8_t
|
uint8_t
|
||||||
paletteFade,
|
|
||||||
paletteBlend,
|
paletteBlend,
|
||||||
milliampsPerLed,
|
milliampsPerLed,
|
||||||
cctBlending,
|
cctBlending,
|
||||||
|
@ -144,10 +144,13 @@ Segment& Segment::operator= (Segment &&orig) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool IRAM_ATTR Segment::allocateData(size_t len) {
|
bool IRAM_ATTR Segment::allocateData(size_t len) {
|
||||||
if (data && _dataLen == len) return true; //already allocated
|
if (data && _dataLen >= len) { // already allocated enough (reduce fragmentation)
|
||||||
|
if (call == 0) memset(data, 0, len); // erase buffer if called during effect initialisation
|
||||||
|
return true;
|
||||||
|
}
|
||||||
//DEBUG_PRINTF("-- Allocating data (%d): %p\n", len, this);
|
//DEBUG_PRINTF("-- Allocating data (%d): %p\n", len, this);
|
||||||
deallocateData();
|
deallocateData();
|
||||||
if (len == 0) return(false); // nothing to do
|
if (len == 0) return false; // nothing to do
|
||||||
if (Segment::getUsedSegmentData() + len > MAX_SEGMENT_DATA) {
|
if (Segment::getUsedSegmentData() + len > MAX_SEGMENT_DATA) {
|
||||||
// not enough memory
|
// not enough memory
|
||||||
DEBUG_PRINT(F("!!! Effect RAM depleted: "));
|
DEBUG_PRINT(F("!!! Effect RAM depleted: "));
|
||||||
@ -290,7 +293,7 @@ void Segment::startTransition(uint16_t dur) {
|
|||||||
_t = new Transition(dur); // no previous transition running
|
_t = new Transition(dur); // no previous transition running
|
||||||
if (!_t) return; // failed to allocate data
|
if (!_t) return; // failed to allocate data
|
||||||
|
|
||||||
//DEBUG_PRINTF("-- Started transition: %p\n", this);
|
//DEBUG_PRINTF("-- Started transition: %p (%p)\n", this, _t);
|
||||||
loadPalette(_t->_palT, palette);
|
loadPalette(_t->_palT, palette);
|
||||||
_t->_briT = on ? opacity : 0;
|
_t->_briT = on ? opacity : 0;
|
||||||
_t->_cctT = cct;
|
_t->_cctT = cct;
|
||||||
@ -317,8 +320,8 @@ void Segment::startTransition(uint16_t dur) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Segment::stopTransition() {
|
void Segment::stopTransition() {
|
||||||
//DEBUG_PRINTF("-- Stopping transition: %p\n", this);
|
|
||||||
if (isInTransition()) {
|
if (isInTransition()) {
|
||||||
|
//DEBUG_PRINTF("-- Stopping transition: %p\n", this);
|
||||||
#ifndef WLED_DISABLE_MODE_BLEND
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
if (_t->_segT._dataT && _t->_segT._dataLenT > 0) {
|
if (_t->_segT._dataT && _t->_segT._dataLenT > 0) {
|
||||||
//DEBUG_PRINTF("-- Released duplicate data (%d) for %p: %p\n", _t->_segT._dataLenT, this, _t->_segT._dataT);
|
//DEBUG_PRINTF("-- Released duplicate data (%d) for %p: %p\n", _t->_segT._dataLenT, this, _t->_segT._dataT);
|
||||||
@ -348,7 +351,7 @@ uint16_t IRAM_ATTR Segment::progress() {
|
|||||||
|
|
||||||
#ifndef WLED_DISABLE_MODE_BLEND
|
#ifndef WLED_DISABLE_MODE_BLEND
|
||||||
void Segment::swapSegenv(tmpsegd_t &tmpSeg) {
|
void Segment::swapSegenv(tmpsegd_t &tmpSeg) {
|
||||||
//DEBUG_PRINTF("-- Saving temp seg: %p (%p)\n", this, tmpSeg);
|
//DEBUG_PRINTF("-- Saving temp seg: %p->(%p) [%d->%p]\n", this, &tmpSeg, _dataLen, data);
|
||||||
tmpSeg._optionsT = options;
|
tmpSeg._optionsT = options;
|
||||||
for (size_t i=0; i<NUM_COLORS; i++) tmpSeg._colorT[i] = colors[i];
|
for (size_t i=0; i<NUM_COLORS; i++) tmpSeg._colorT[i] = colors[i];
|
||||||
tmpSeg._speedT = speed;
|
tmpSeg._speedT = speed;
|
||||||
@ -384,11 +387,10 @@ void Segment::swapSegenv(tmpsegd_t &tmpSeg) {
|
|||||||
data = _t->_segT._dataT;
|
data = _t->_segT._dataT;
|
||||||
_dataLen = _t->_segT._dataLenT;
|
_dataLen = _t->_segT._dataLenT;
|
||||||
}
|
}
|
||||||
//DEBUG_PRINTF("-- temp seg data: %p (%d,%p)\n", this, _dataLen, data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Segment::restoreSegenv(tmpsegd_t &tmpSeg) {
|
void Segment::restoreSegenv(tmpsegd_t &tmpSeg) {
|
||||||
//DEBUG_PRINTF("-- Restoring temp seg: %p (%p)\n", this, tmpSeg);
|
//DEBUG_PRINTF("-- Restoring temp seg: %p->(%p) [%d->%p]\n", &tmpSeg, this, _dataLen, data);
|
||||||
if (_t && &(_t->_segT) != &tmpSeg) {
|
if (_t && &(_t->_segT) != &tmpSeg) {
|
||||||
// update possibly changed variables to keep old effect running correctly
|
// update possibly changed variables to keep old effect running correctly
|
||||||
_t->_segT._aux0T = aux0;
|
_t->_segT._aux0T = aux0;
|
||||||
@ -415,7 +417,6 @@ void Segment::restoreSegenv(tmpsegd_t &tmpSeg) {
|
|||||||
call = tmpSeg._callT;
|
call = tmpSeg._callT;
|
||||||
data = tmpSeg._dataT;
|
data = tmpSeg._dataT;
|
||||||
_dataLen = tmpSeg._dataLenT;
|
_dataLen = tmpSeg._dataLenT;
|
||||||
//DEBUG_PRINTF("-- temp seg data: %p (%d,%p)\n", this, _dataLen, data);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -578,7 +579,7 @@ void Segment::setMode(uint8_t fx, bool loadDefaults) {
|
|||||||
sOpt = extractModeDefaults(fx, "o1"); check1 = (sOpt >= 0) ? (bool)sOpt : false;
|
sOpt = extractModeDefaults(fx, "o1"); check1 = (sOpt >= 0) ? (bool)sOpt : false;
|
||||||
sOpt = extractModeDefaults(fx, "o2"); check2 = (sOpt >= 0) ? (bool)sOpt : false;
|
sOpt = extractModeDefaults(fx, "o2"); check2 = (sOpt >= 0) ? (bool)sOpt : false;
|
||||||
sOpt = extractModeDefaults(fx, "o3"); check3 = (sOpt >= 0) ? (bool)sOpt : false;
|
sOpt = extractModeDefaults(fx, "o3"); check3 = (sOpt >= 0) ? (bool)sOpt : false;
|
||||||
sOpt = extractModeDefaults(fx, "m12"); if (sOpt >= 0) map1D2D = constrain(sOpt, 0, 7);
|
sOpt = extractModeDefaults(fx, "m12"); if (sOpt >= 0) map1D2D = constrain(sOpt, 0, 7); else map1D2D = M12_Pixels; // reset mapping if not defined (2D FX may not work)
|
||||||
sOpt = extractModeDefaults(fx, "si"); if (sOpt >= 0) soundSim = constrain(sOpt, 0, 3);
|
sOpt = extractModeDefaults(fx, "si"); if (sOpt >= 0) soundSim = constrain(sOpt, 0, 3);
|
||||||
sOpt = extractModeDefaults(fx, "rev"); if (sOpt >= 0) reverse = (bool)sOpt;
|
sOpt = extractModeDefaults(fx, "rev"); if (sOpt >= 0) reverse = (bool)sOpt;
|
||||||
sOpt = extractModeDefaults(fx, "mi"); if (sOpt >= 0) mirror = (bool)sOpt; // NOTE: setting this option is a risky business
|
sOpt = extractModeDefaults(fx, "mi"); if (sOpt >= 0) mirror = (bool)sOpt; // NOTE: setting this option is a risky business
|
||||||
@ -1024,15 +1025,16 @@ void Segment::blur(uint8_t blur_amount) {
|
|||||||
*/
|
*/
|
||||||
uint32_t Segment::color_wheel(uint8_t pos) {
|
uint32_t Segment::color_wheel(uint8_t pos) {
|
||||||
if (palette) return color_from_palette(pos, false, true, 0);
|
if (palette) return color_from_palette(pos, false, true, 0);
|
||||||
|
uint8_t w = W(currentColor(0));
|
||||||
pos = 255 - pos;
|
pos = 255 - pos;
|
||||||
if (pos < 85) {
|
if (pos < 85) {
|
||||||
return ((uint32_t)(255 - pos * 3) << 16) | ((uint32_t)(0) << 8) | (pos * 3);
|
return RGBW32((255 - pos * 3), 0, (pos * 3), w);
|
||||||
} else if(pos < 170) {
|
} else if(pos < 170) {
|
||||||
pos -= 85;
|
pos -= 85;
|
||||||
return ((uint32_t)(0) << 16) | ((uint32_t)(pos * 3) << 8) | (255 - pos * 3);
|
return RGBW32(0, (pos * 3), (255 - pos * 3), w);
|
||||||
} else {
|
} else {
|
||||||
pos -= 170;
|
pos -= 170;
|
||||||
return ((uint32_t)(pos * 3) << 16) | ((uint32_t)(255 - pos * 3) << 8) | (0);
|
return RGBW32((pos * 3), (255 - pos * 3), 0, w);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1046,13 +1048,10 @@ uint32_t Segment::color_wheel(uint8_t pos) {
|
|||||||
* @returns Single color from palette
|
* @returns Single color from palette
|
||||||
*/
|
*/
|
||||||
uint32_t Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri) {
|
uint32_t Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri) {
|
||||||
|
uint32_t color = gamma32(currentColor(mcol));
|
||||||
|
|
||||||
// default palette or no RGB support on segment
|
// default palette or no RGB support on segment
|
||||||
if ((palette == 0 && mcol < NUM_COLORS) || !_isRGB) {
|
if ((palette == 0 && mcol < NUM_COLORS) || !_isRGB) return (pbri == 255) ? color : color_fade(color, pbri, true);
|
||||||
uint32_t color = currentColor(mcol);
|
|
||||||
color = gamma32(color);
|
|
||||||
if (pbri == 255) return color;
|
|
||||||
return color_fade(color, pbri, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t paletteIndex = i;
|
uint8_t paletteIndex = i;
|
||||||
if (mapping && virtualLength() > 1) paletteIndex = (i*255)/(virtualLength() -1);
|
if (mapping && virtualLength() > 1) paletteIndex = (i*255)/(virtualLength() -1);
|
||||||
@ -1061,7 +1060,7 @@ uint32_t Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_
|
|||||||
curPal = currentPalette(curPal, palette);
|
curPal = currentPalette(curPal, palette);
|
||||||
CRGB fastled_col = ColorFromPalette(curPal, paletteIndex, pbri, (strip.paletteBlend == 3)? NOBLEND:LINEARBLEND); // NOTE: paletteBlend should be global
|
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);
|
return RGBW32(fastled_col.r, fastled_col.g, fastled_col.b, W(color));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1159,15 +1158,12 @@ void WS2812FX::service() {
|
|||||||
uint16_t delay = FRAMETIME;
|
uint16_t delay = FRAMETIME;
|
||||||
|
|
||||||
if (!seg.freeze) { //only run effect function if not frozen
|
if (!seg.freeze) { //only run effect function if not frozen
|
||||||
_virtualSegmentLength = seg.virtualLength();
|
_virtualSegmentLength = seg.virtualLength(); //SEGLEN
|
||||||
_colors_t[0] = seg.currentColor(0);
|
_colors_t[0] = gamma32(seg.currentColor(0));
|
||||||
_colors_t[1] = seg.currentColor(1);
|
_colors_t[1] = gamma32(seg.currentColor(1));
|
||||||
_colors_t[2] = seg.currentColor(2);
|
_colors_t[2] = gamma32(seg.currentColor(2));
|
||||||
seg.currentPalette(_currentPalette, seg.palette); // we need to pass reference
|
seg.currentPalette(_currentPalette, seg.palette); // we need to pass reference
|
||||||
|
|
||||||
if (!cctFromRgb || correctWB) busses.setSegmentCCT(seg.currentBri(true), correctWB);
|
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
|
// Effect blending
|
||||||
// When two effects are being blended, each may have different segment data, this
|
// 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 mode.
|
// data needs to be saved first and then restored before running previous mode.
|
||||||
@ -1181,6 +1177,7 @@ void WS2812FX::service() {
|
|||||||
Segment::tmpsegd_t _tmpSegData;
|
Segment::tmpsegd_t _tmpSegData;
|
||||||
Segment::modeBlend(true); // set semaphore
|
Segment::modeBlend(true); // set semaphore
|
||||||
seg.swapSegenv(_tmpSegData); // temporarily store new mode state (and swap it with transitional state)
|
seg.swapSegenv(_tmpSegData); // temporarily store new mode state (and swap it with transitional state)
|
||||||
|
_virtualSegmentLength = seg.virtualLength(); // update SEGLEN (mapping may have changed)
|
||||||
uint16_t d2 = (*_mode[tmpMode])(); // run old mode
|
uint16_t d2 = (*_mode[tmpMode])(); // run old mode
|
||||||
seg.restoreSegenv(_tmpSegData); // restore mode state (will also update transitional state)
|
seg.restoreSegenv(_tmpSegData); // restore mode state (will also update transitional state)
|
||||||
delay = MIN(delay,d2); // use shortest delay
|
delay = MIN(delay,d2); // use shortest delay
|
||||||
|
@ -77,7 +77,7 @@ uint8_t IRAM_ATTR ColorOrderMap::getPixelColorOrder(uint16_t pix, uint8_t defaul
|
|||||||
|
|
||||||
uint32_t Bus::autoWhiteCalc(uint32_t c) {
|
uint32_t Bus::autoWhiteCalc(uint32_t c) {
|
||||||
uint8_t aWM = _autoWhiteMode;
|
uint8_t aWM = _autoWhiteMode;
|
||||||
if (_gAWM < 255) aWM = _gAWM;
|
if (_gAWM < AW_GLOBAL_DISABLED) aWM = _gAWM;
|
||||||
if (aWM == RGBW_MODE_MANUAL_ONLY) return c;
|
if (aWM == RGBW_MODE_MANUAL_ONLY) return c;
|
||||||
uint8_t w = W(c);
|
uint8_t w = W(c);
|
||||||
//ignore auto-white calculation if w>0 and mode DUAL (DUAL behaves as BRIGHTER if w==0)
|
//ignore auto-white calculation if w>0 and mode DUAL (DUAL behaves as BRIGHTER if w==0)
|
||||||
|
@ -118,7 +118,7 @@ class Bus {
|
|||||||
, _needsRefresh(refresh)
|
, _needsRefresh(refresh)
|
||||||
, _data(nullptr) // keep data access consistent across all types of buses
|
, _data(nullptr) // keep data access consistent across all types of buses
|
||||||
{
|
{
|
||||||
_autoWhiteMode = Bus::hasWhite(_type) ? aw : RGBW_MODE_MANUAL_ONLY;
|
_autoWhiteMode = Bus::hasWhite(type) ? aw : RGBW_MODE_MANUAL_ONLY;
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual ~Bus() {} //throw the bus under the bus
|
virtual ~Bus() {} //throw the bus under the bus
|
||||||
@ -154,7 +154,7 @@ class Bus {
|
|||||||
}
|
}
|
||||||
virtual bool hasWhite(void) { return Bus::hasWhite(_type); }
|
virtual bool hasWhite(void) { return Bus::hasWhite(_type); }
|
||||||
static bool hasWhite(uint8_t type) {
|
static bool hasWhite(uint8_t type) {
|
||||||
if ((type >= TYPE_WS2812_1CH && type <= TYPE_WS2812_WWA) || type == TYPE_SK6812_RGBW || type == TYPE_TM1814) return true; // digital types with white channel
|
if ((type >= TYPE_WS2812_1CH && type <= TYPE_WS2812_WWA) || type == TYPE_SK6812_RGBW || type == TYPE_TM1814 || type == TYPE_UCS8904) return true; // digital types with white channel
|
||||||
if (type > TYPE_ONOFF && type <= TYPE_ANALOG_5CH && type != TYPE_ANALOG_3CH) return true; // analog types with white channel
|
if (type > TYPE_ONOFF && type <= TYPE_ANALOG_5CH && type != TYPE_ANALOG_3CH) return true; // analog types with white channel
|
||||||
if (type == TYPE_NET_DDP_RGBW) return true; // network types with white channel
|
if (type == TYPE_NET_DDP_RGBW) return true; // network types with white channel
|
||||||
return false;
|
return false;
|
||||||
|
@ -97,8 +97,9 @@ bool isButtonPressed(uint8_t i)
|
|||||||
if (digitalRead(pin) == HIGH) return true;
|
if (digitalRead(pin) == HIGH) return true;
|
||||||
break;
|
break;
|
||||||
case BTN_TYPE_TOUCH:
|
case BTN_TYPE_TOUCH:
|
||||||
|
case BTN_TYPE_TOUCH_SWITCH:
|
||||||
#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||||
if (touchRead(pin) <= touchThreshold) return true;
|
if (digitalPinToTouchChannel(btnPin[i]) >= 0 && touchRead(pin) <= touchThreshold) return true;
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -109,6 +110,7 @@ void handleSwitch(uint8_t b)
|
|||||||
{
|
{
|
||||||
// isButtonPressed() handles inverted/noninverted logic
|
// isButtonPressed() handles inverted/noninverted logic
|
||||||
if (buttonPressedBefore[b] != isButtonPressed(b)) {
|
if (buttonPressedBefore[b] != isButtonPressed(b)) {
|
||||||
|
DEBUG_PRINT(F("Switch: State changed ")); DEBUG_PRINTLN(b);
|
||||||
buttonPressedTime[b] = millis();
|
buttonPressedTime[b] = millis();
|
||||||
buttonPressedBefore[b] = !buttonPressedBefore[b];
|
buttonPressedBefore[b] = !buttonPressedBefore[b];
|
||||||
}
|
}
|
||||||
@ -116,12 +118,15 @@ void handleSwitch(uint8_t b)
|
|||||||
if (buttonLongPressed[b] == buttonPressedBefore[b]) return;
|
if (buttonLongPressed[b] == buttonPressedBefore[b]) return;
|
||||||
|
|
||||||
if (millis() - buttonPressedTime[b] > WLED_DEBOUNCE_THRESHOLD) { //fire edge event only after 50ms without change (debounce)
|
if (millis() - buttonPressedTime[b] > WLED_DEBOUNCE_THRESHOLD) { //fire edge event only after 50ms without change (debounce)
|
||||||
|
DEBUG_PRINT(F("Switch: Activating ")); DEBUG_PRINTLN(b);
|
||||||
if (!buttonPressedBefore[b]) { // on -> off
|
if (!buttonPressedBefore[b]) { // on -> off
|
||||||
|
DEBUG_PRINT(F("Switch: On -> Off ")); DEBUG_PRINTLN(b);
|
||||||
if (macroButton[b]) applyPreset(macroButton[b], CALL_MODE_BUTTON_PRESET);
|
if (macroButton[b]) applyPreset(macroButton[b], CALL_MODE_BUTTON_PRESET);
|
||||||
else { //turn on
|
else { //turn on
|
||||||
if (!bri) {toggleOnOff(); stateUpdated(CALL_MODE_BUTTON);}
|
if (!bri) {toggleOnOff(); stateUpdated(CALL_MODE_BUTTON);}
|
||||||
}
|
}
|
||||||
} else { // off -> on
|
} else { // off -> on
|
||||||
|
DEBUG_PRINT(F("Switch: Off -> On ")); DEBUG_PRINTLN(b);
|
||||||
if (macroLongPress[b]) applyPreset(macroLongPress[b], CALL_MODE_BUTTON_PRESET);
|
if (macroLongPress[b]) applyPreset(macroLongPress[b], CALL_MODE_BUTTON_PRESET);
|
||||||
else { //turn off
|
else { //turn off
|
||||||
if (bri) {toggleOnOff(); stateUpdated(CALL_MODE_BUTTON);}
|
if (bri) {toggleOnOff(); stateUpdated(CALL_MODE_BUTTON);}
|
||||||
@ -153,6 +158,8 @@ void handleAnalog(uint8_t b)
|
|||||||
static float filteredReading[WLED_MAX_BUTTONS] = {0.0f};
|
static float filteredReading[WLED_MAX_BUTTONS] = {0.0f};
|
||||||
uint16_t rawReading; // raw value from analogRead, scaled to 12bit
|
uint16_t rawReading; // raw value from analogRead, scaled to 12bit
|
||||||
|
|
||||||
|
DEBUG_PRINT(F("Analog: Reading button ")); DEBUG_PRINTLN(b);
|
||||||
|
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
rawReading = analogRead(A0) << 2; // convert 10bit read to 12bit
|
rawReading = analogRead(A0) << 2; // convert 10bit read to 12bit
|
||||||
#else
|
#else
|
||||||
@ -161,6 +168,8 @@ void handleAnalog(uint8_t b)
|
|||||||
#endif
|
#endif
|
||||||
yield(); // keep WiFi task running - analog read may take several millis on ESP8266
|
yield(); // keep WiFi task running - analog read may take several millis on ESP8266
|
||||||
|
|
||||||
|
DEBUG_PRINT(F("Analog: Raw read = ")); DEBUG_PRINTLN(rawReading);
|
||||||
|
|
||||||
filteredReading[b] += POT_SMOOTHING * ((float(rawReading) / 16.0f) - filteredReading[b]); // filter raw input, and scale to [0..255]
|
filteredReading[b] += POT_SMOOTHING * ((float(rawReading) / 16.0f) - filteredReading[b]); // filter raw input, and scale to [0..255]
|
||||||
uint16_t aRead = max(min(int(filteredReading[b]), 255), 0); // squash into 8bit
|
uint16_t aRead = max(min(int(filteredReading[b]), 255), 0); // squash into 8bit
|
||||||
if(aRead <= POT_SENSITIVITY) aRead = 0; // make sure that 0 and 255 are used
|
if(aRead <= POT_SENSITIVITY) aRead = 0; // make sure that 0 and 255 are used
|
||||||
@ -171,6 +180,8 @@ void handleAnalog(uint8_t b)
|
|||||||
// remove noise & reduce frequency of UI updates
|
// remove noise & reduce frequency of UI updates
|
||||||
if (abs(int(aRead) - int(oldRead[b])) <= POT_SENSITIVITY) return; // no significant change in reading
|
if (abs(int(aRead) - int(oldRead[b])) <= POT_SENSITIVITY) return; // no significant change in reading
|
||||||
|
|
||||||
|
DEBUG_PRINT(F("Analog: Filtered read = ")); DEBUG_PRINTLN(aRead);
|
||||||
|
|
||||||
// Unomment the next lines if you still see flickering related to potentiometer
|
// Unomment the next lines if you still see flickering related to potentiometer
|
||||||
// This waits until strip finishes updating (why: strip was not updating at the start of handleButton() but may have started during analogRead()?)
|
// This waits until strip finishes updating (why: strip was not updating at the start of handleButton() but may have started during analogRead()?)
|
||||||
//unsigned long wait_started = millis();
|
//unsigned long wait_started = millis();
|
||||||
@ -183,6 +194,7 @@ void handleAnalog(uint8_t b)
|
|||||||
|
|
||||||
// if no macro for "short press" and "long press" is defined use brightness control
|
// if no macro for "short press" and "long press" is defined use brightness control
|
||||||
if (!macroButton[b] && !macroLongPress[b]) {
|
if (!macroButton[b] && !macroLongPress[b]) {
|
||||||
|
DEBUG_PRINT(F("Analog: Action = ")); DEBUG_PRINTLN(macroDoublePress[b]);
|
||||||
// if "double press" macro defines which option to change
|
// if "double press" macro defines which option to change
|
||||||
if (macroDoublePress[b] >= 250) {
|
if (macroDoublePress[b] >= 250) {
|
||||||
// global brightness
|
// global brightness
|
||||||
@ -218,6 +230,7 @@ void handleAnalog(uint8_t b)
|
|||||||
updateInterfaces(CALL_MODE_BUTTON);
|
updateInterfaces(CALL_MODE_BUTTON);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
DEBUG_PRINTLN(F("Analog: No action"));
|
||||||
//TODO:
|
//TODO:
|
||||||
// we can either trigger a preset depending on the level (between short and long entries)
|
// we can either trigger a preset depending on the level (between short and long entries)
|
||||||
// or use it for RGBW direct control
|
// or use it for RGBW direct control
|
||||||
@ -252,7 +265,7 @@ void handleButton()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// button is not momentary, but switch. This is only suitable on pins whose on-boot state does not matter (NOT gpio0)
|
// button is not momentary, but switch. This is only suitable on pins whose on-boot state does not matter (NOT gpio0)
|
||||||
if (buttonType[b] == BTN_TYPE_SWITCH || buttonType[b] == BTN_TYPE_PIR_SENSOR) {
|
if (buttonType[b] == BTN_TYPE_SWITCH || buttonType[b] == BTN_TYPE_TOUCH_SWITCH || buttonType[b] == BTN_TYPE_PIR_SENSOR) {
|
||||||
handleSwitch(b);
|
handleSwitch(b);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -88,11 +88,10 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
|||||||
// initialize LED pins and lengths prior to other HW (except for ethernet)
|
// initialize LED pins and lengths prior to other HW (except for ethernet)
|
||||||
JsonObject hw_led = hw["led"];
|
JsonObject hw_led = hw["led"];
|
||||||
|
|
||||||
uint8_t autoWhiteMode = RGBW_MODE_MANUAL_ONLY;
|
|
||||||
uint16_t total = hw_led[F("total")] | strip.getLengthTotal();
|
uint16_t total = hw_led[F("total")] | strip.getLengthTotal();
|
||||||
CJSON(strip.ablMilliampsMax, hw_led[F("maxpwr")]);
|
CJSON(strip.ablMilliampsMax, hw_led[F("maxpwr")]);
|
||||||
CJSON(strip.milliampsPerLed, hw_led[F("ledma")]); // no longer used
|
CJSON(strip.milliampsPerLed, hw_led[F("ledma")]); // no longer used
|
||||||
Bus::setGlobalAWMode(hw_led[F("rgbwm")] | 255);
|
Bus::setGlobalAWMode(hw_led[F("rgbwm")] | AW_GLOBAL_DISABLED);
|
||||||
CJSON(correctWB, hw_led["cct"]);
|
CJSON(correctWB, hw_led["cct"]);
|
||||||
CJSON(cctFromRgb, hw_led[F("cr")]);
|
CJSON(cctFromRgb, hw_led[F("cr")]);
|
||||||
CJSON(strip.cctBlending, hw_led[F("cb")]);
|
CJSON(strip.cctBlending, hw_led[F("cb")]);
|
||||||
@ -158,7 +157,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint16_t length = elm["len"] | 1;
|
uint16_t length = elm["len"] | 1;
|
||||||
uint8_t colorOrder = (int)elm[F("order")];
|
uint8_t colorOrder = (int)elm[F("order")]; // contains white channel swap option in upper nibble
|
||||||
uint8_t skipFirst = elm[F("skip")];
|
uint8_t skipFirst = elm[F("skip")];
|
||||||
uint16_t start = elm["start"] | 0;
|
uint16_t start = elm["start"] | 0;
|
||||||
if (length==0 || start + length > MAX_LEDS) continue; // zero length or we reached max. number of LEDs, just stop
|
if (length==0 || start + length > MAX_LEDS) continue; // zero length or we reached max. number of LEDs, just stop
|
||||||
@ -166,8 +165,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
|||||||
bool reversed = elm["rev"];
|
bool reversed = elm["rev"];
|
||||||
bool refresh = elm["ref"] | false;
|
bool refresh = elm["ref"] | false;
|
||||||
uint16_t freqkHz = elm[F("freq")] | 0; // will be in kHz for DotStar and Hz for PWM (not yet implemented fully)
|
uint16_t freqkHz = elm[F("freq")] | 0; // will be in kHz for DotStar and Hz for PWM (not yet implemented fully)
|
||||||
ledType |= refresh << 7; // hack bit 7 to indicate strip requires off refresh
|
uint8_t AWmode = elm[F("rgbwm")] | RGBW_MODE_MANUAL_ONLY;
|
||||||
uint8_t AWmode = elm[F("rgbwm")] | autoWhiteMode;
|
|
||||||
uint8_t maPerLed = elm[F("ledma")] | strip.milliampsPerLed; // replace with 55 when removing strip.milliampsPerLed
|
uint8_t maPerLed = elm[F("ledma")] | strip.milliampsPerLed; // replace with 55 when removing strip.milliampsPerLed
|
||||||
uint16_t maMax = elm[F("maxpwr")] | (strip.ablMilliampsMax * length) / total; // rough (incorrect?) per strip ABL calculation when no config exists
|
uint16_t maMax = elm[F("maxpwr")] | (strip.ablMilliampsMax * length) / total; // rough (incorrect?) per strip ABL calculation when no config exists
|
||||||
// To disable brightness limiter we either set output max current to 0 or single LED current to 0 (we choose output max current)
|
// To disable brightness limiter we either set output max current to 0 or single LED current to 0 (we choose output max current)
|
||||||
@ -175,6 +173,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
|||||||
maPerLed = 0;
|
maPerLed = 0;
|
||||||
maMax = 0;
|
maMax = 0;
|
||||||
}
|
}
|
||||||
|
ledType |= refresh << 7; // hack bit 7 to indicate strip requires off refresh
|
||||||
if (fromFS) {
|
if (fromFS) {
|
||||||
BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer, maPerLed, maMax);
|
BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer, maPerLed, maMax);
|
||||||
mem += BusManager::memUsage(bc);
|
mem += BusManager::memUsage(bc);
|
||||||
@ -377,6 +376,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
|||||||
CJSON(modeBlending, light_tr["fx"]);
|
CJSON(modeBlending, light_tr["fx"]);
|
||||||
int tdd = light_tr["dur"] | -1;
|
int tdd = light_tr["dur"] | -1;
|
||||||
if (tdd >= 0) transitionDelay = transitionDelayDefault = tdd * 100;
|
if (tdd >= 0) transitionDelay = transitionDelayDefault = tdd * 100;
|
||||||
|
strip.setTransition(fadeTransition ? transitionDelayDefault : 0);
|
||||||
CJSON(strip.paletteFade, light_tr["pal"]);
|
CJSON(strip.paletteFade, light_tr["pal"]);
|
||||||
CJSON(randomPaletteChangeTime, light_tr[F("rpc")]);
|
CJSON(randomPaletteChangeTime, light_tr[F("rpc")]);
|
||||||
|
|
||||||
|
@ -286,6 +286,7 @@
|
|||||||
#define BTN_TYPE_TOUCH 6
|
#define BTN_TYPE_TOUCH 6
|
||||||
#define BTN_TYPE_ANALOG 7
|
#define BTN_TYPE_ANALOG 7
|
||||||
#define BTN_TYPE_ANALOG_INVERTED 8
|
#define BTN_TYPE_ANALOG_INVERTED 8
|
||||||
|
#define BTN_TYPE_TOUCH_SWITCH 9
|
||||||
|
|
||||||
//Ethernet board types
|
//Ethernet board types
|
||||||
#define WLED_NUM_ETH_TYPES 11
|
#define WLED_NUM_ETH_TYPES 11
|
||||||
@ -342,8 +343,9 @@
|
|||||||
// WLED Error modes
|
// WLED Error modes
|
||||||
#define ERR_NONE 0 // All good :)
|
#define ERR_NONE 0 // All good :)
|
||||||
#define ERR_DENIED 1 // Permission denied
|
#define ERR_DENIED 1 // Permission denied
|
||||||
#define ERR_EEP_COMMIT 2 // Could not commit to EEPROM (wrong flash layout?) OBSOLETE
|
#define ERR_CONCURRENCY 2 // Conurrency (client active)
|
||||||
#define ERR_NOBUF 3 // JSON buffer was not released in time, request cannot be handled at this time
|
#define ERR_NOBUF 3 // JSON buffer was not released in time, request cannot be handled at this time
|
||||||
|
#define ERR_NOT_IMPL 4 // Not implemented
|
||||||
#define ERR_JSON 9 // JSON parsing failed (input too large?)
|
#define ERR_JSON 9 // JSON parsing failed (input too large?)
|
||||||
#define ERR_FS_BEGIN 10 // Could not init filesystem (no partition?)
|
#define ERR_FS_BEGIN 10 // Could not init filesystem (no partition?)
|
||||||
#define ERR_FS_QUOTA 11 // The FS is full or the maximum file size is reached
|
#define ERR_FS_QUOTA 11 // The FS is full or the maximum file size is reached
|
||||||
|
@ -469,6 +469,7 @@ button {
|
|||||||
height: 54px;
|
height: 54px;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
padding-bottom: 8px;
|
padding-bottom: 8px;
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* New tooltip */
|
/* New tooltip */
|
||||||
@ -1240,6 +1241,7 @@ TD .checkmark, TD .radiomark {
|
|||||||
.filter .fchkl {
|
.filter .fchkl {
|
||||||
margin: 0 4px;
|
margin: 0 4px;
|
||||||
min-width: 20px;
|
min-width: 20px;
|
||||||
|
pointer-events: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.lbl-l {
|
.lbl-l {
|
||||||
|
@ -197,33 +197,33 @@
|
|||||||
<div id="Effects" class="tabcontent">
|
<div id="Effects" class="tabcontent">
|
||||||
<div id="fx">
|
<div id="fx">
|
||||||
<p class="labels hd" id="modeLabel">Effect mode</p>
|
<p class="labels hd" id="modeLabel">Effect mode</p>
|
||||||
<div class="staytop fnd" id="fxFind">
|
<div class="staytop fnd" id="fxFind" onmousedown="preventBlur(event);">
|
||||||
<input type="text" placeholder="Search" oninput="search(this,'fxlist')" onfocus="filterFocus(event);search(this,'fxlist');" onblur="filterFocus(event);" />
|
<input type="text" placeholder="Search" oninput="search(this,'fxlist')" onfocus="filterFocus(event);search(this,'fxlist');" onblur="filterFocus(event);">
|
||||||
<i class="icons clear-icon" onclick="clean(this);"></i>
|
<i class="icons clear-icon" onclick="clean(this);"></i>
|
||||||
<i class="icons search-icon" style="cursor:pointer;"></i>
|
<i class="icons search-icon" style="cursor:pointer;"></i>
|
||||||
<div id="filters" class="filter fade">
|
<div id="filters" class="filter fade">
|
||||||
<label id="filterPal" tooltip="Uses palette" class="check fchkl">🎨
|
<label id="filterPal" tooltip="Uses palette" class="check fchkl">🎨
|
||||||
<input type="checkbox" data-flt="🎨" onchange="filterFx(this);">
|
<input type="checkbox" data-flt="🎨" onchange="filterFx();">
|
||||||
<span class="checkmark"></span>
|
<span class="checkmark"></span>
|
||||||
</label>
|
</label>
|
||||||
<label id="filter0D" tooltip="Single pixel" class="check fchkl">•
|
<label id="filter0D" tooltip="Single pixel" class="check fchkl">•
|
||||||
<input type="checkbox" data-flt="•" onchange="filterFx(this);">
|
<input type="checkbox" data-flt="•" onchange="filterFx();">
|
||||||
<span class="checkmark"></span>
|
<span class="checkmark"></span>
|
||||||
</label>
|
</label>
|
||||||
<label id="filter1D" tooltip="1D" class="check fchkl">⋮
|
<label id="filter1D" tooltip="1D" class="check fchkl">⋮
|
||||||
<input type="checkbox" data-flt="⋮" onchange="filterFx(this);">
|
<input type="checkbox" data-flt="⋮" onchange="filterFx();">
|
||||||
<span class="checkmark"></span>
|
<span class="checkmark"></span>
|
||||||
</label>
|
</label>
|
||||||
<label id="filter2D" tooltip="2D" class="check fchkl">▦
|
<label id="filter2D" tooltip="2D" class="check fchkl">▦
|
||||||
<input type="checkbox" data-flt="▦" onchange="filterFx(this);">
|
<input type="checkbox" data-flt="▦" onchange="filterFx();">
|
||||||
<span class="checkmark"></span>
|
<span class="checkmark"></span>
|
||||||
</label>
|
</label>
|
||||||
<label id="filterVol" tooltip="Volume" class="check fchkl">♪
|
<label id="filterVol" tooltip="Volume" class="check fchkl">♪
|
||||||
<input type="checkbox" data-flt="♪" onchange="filterFx(this);">
|
<input type="checkbox" data-flt="♪" onchange="filterFx();">
|
||||||
<span class="checkmark"></span>
|
<span class="checkmark"></span>
|
||||||
</label>
|
</label>
|
||||||
<label id="filterFreq" tooltip="Frequency" class="check fchkl">♫
|
<label id="filterFreq" tooltip="Frequency" class="check fchkl">♫
|
||||||
<input type="checkbox" data-flt="♫" onchange="filterFx(this);">
|
<input type="checkbox" data-flt="♫" onchange="filterFx();">
|
||||||
<span class="checkmark"></span>
|
<span class="checkmark"></span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
@ -232,6 +232,7 @@ function onLoad()
|
|||||||
|
|
||||||
tooltip();
|
tooltip();
|
||||||
resetPUtil();
|
resetPUtil();
|
||||||
|
initFilters();
|
||||||
|
|
||||||
if (localStorage.getItem('pcm') == "true" || (!/Mobi/.test(navigator.userAgent) && localStorage.getItem('pcm') == null)) togglePcMode(true);
|
if (localStorage.getItem('pcm') == "true" || (!/Mobi/.test(navigator.userAgent) && localStorage.getItem('pcm') == null)) togglePcMode(true);
|
||||||
applyCfg();
|
applyCfg();
|
||||||
@ -1505,6 +1506,8 @@ function setEffectParameters(idx)
|
|||||||
let text = slider.getAttribute("tooltip");
|
let text = slider.getAttribute("tooltip");
|
||||||
if ((!controlDefined && i<((idx<128)?2:nSliders)) || (slOnOff.length>i && slOnOff[i]!="")) {
|
if ((!controlDefined && i<((idx<128)?2:nSliders)) || (slOnOff.length>i && slOnOff[i]!="")) {
|
||||||
if (slOnOff.length>i && slOnOff[i]!="!") text = slOnOff[i];
|
if (slOnOff.length>i && slOnOff[i]!="!") text = slOnOff[i];
|
||||||
|
// restore overwritten default tooltips
|
||||||
|
if (i<2 && slOnOff[i]==="!") text = i==0 ? "Effect speed" : "Effect intensity";
|
||||||
slider.setAttribute("tooltip", text);
|
slider.setAttribute("tooltip", text);
|
||||||
slider.parentElement.classList.remove('hide');
|
slider.parentElement.classList.remove('hide');
|
||||||
} else
|
} else
|
||||||
@ -1539,7 +1542,6 @@ function setEffectParameters(idx)
|
|||||||
var cslLabel = '';
|
var cslLabel = '';
|
||||||
var sep = '';
|
var sep = '';
|
||||||
var cslCnt = 0, oCsel = csel;
|
var cslCnt = 0, oCsel = csel;
|
||||||
// for (let i=0; i<gId("csl").querySelectorAll("button"); i++) {
|
|
||||||
d.querySelectorAll("#csl button").forEach((e,i)=>{
|
d.querySelectorAll("#csl button").forEach((e,i)=>{
|
||||||
var btn = gId("csl" + i);
|
var btn = gId("csl" + i);
|
||||||
// if no controlDefined or coOnOff has a value
|
// if no controlDefined or coOnOff has a value
|
||||||
@ -2716,58 +2718,94 @@ function hideModes(txt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
function search(f,l=null)
|
function search(field, listId = null) {
|
||||||
{
|
field.nextElementSibling.style.display = (field.value !== '') ? 'block' : 'none';
|
||||||
f.nextElementSibling.style.display=(f.value!=='')?'block':'none';
|
if (!listId) return;
|
||||||
if (!l) return;
|
|
||||||
var el = gId(l).querySelectorAll('.lstI');
|
|
||||||
// filter list items but leave (Default & Solid) always visible
|
|
||||||
for (i = (l==='pcont'?0:1); i < el.length; i++) {
|
|
||||||
var it = el[i];
|
|
||||||
var itT = it.querySelector('.lstIname').innerText.toUpperCase();
|
|
||||||
it.style.display = (itT.indexOf(f.value.toUpperCase())<0) ? 'none' : '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function clean(c)
|
// clear filter if searching in fxlist
|
||||||
{
|
if (listId === 'fxlist' && field.value !== '') {
|
||||||
c.style.display='none';
|
|
||||||
var i=c.previousElementSibling;
|
|
||||||
i.value='';
|
|
||||||
i.focus();
|
|
||||||
i.dispatchEvent(new Event('input'));
|
|
||||||
if (i.parentElement.id=='fxFind') {
|
|
||||||
gId("filters").querySelectorAll("input[type=checkbox]").forEach((e) => { e.checked = false; });
|
gId("filters").querySelectorAll("input[type=checkbox]").forEach((e) => { e.checked = false; });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// do not search if filter is active
|
||||||
|
if (gId("filters").querySelectorAll("input[type=checkbox]:checked").length) return;
|
||||||
|
|
||||||
|
const listItems = gId(listId).querySelectorAll('.lstI');
|
||||||
|
// filter list items but leave (Default & Solid) always visible
|
||||||
|
for (i = (listId === 'pcont' ? 0 : 1); i < listItems.length; i++) {
|
||||||
|
const listItem = listItems[i];
|
||||||
|
const listItemName = listItem.querySelector('.lstIname').innerText.toUpperCase();
|
||||||
|
const searchIndex = listItemName.indexOf(field.value.toUpperCase());
|
||||||
|
listItem.style.display = (searchIndex < 0) ? 'none' : '';
|
||||||
|
listItem.dataset.searchIndex = searchIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterFocus(e)
|
// sort list items by search index and name
|
||||||
{
|
const sortedListItems = Array.from(listItems).sort((a, b) => {
|
||||||
let f = gId("filters");
|
const aSearchIndex = parseInt(a.dataset.searchIndex);
|
||||||
|
const bSearchIndex = parseInt(b.dataset.searchIndex);
|
||||||
|
|
||||||
|
if (aSearchIndex !== bSearchIndex) {
|
||||||
|
return aSearchIndex - bSearchIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
const aName = a.querySelector('.lstIname').innerText.toUpperCase();
|
||||||
|
const bName = b.querySelector('.lstIname').innerText.toUpperCase();
|
||||||
|
|
||||||
|
return aName.localeCompare(bName);
|
||||||
|
});
|
||||||
|
sortedListItems.forEach(item => {
|
||||||
|
gId(listId).append(item);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function clean(clearButton) {
|
||||||
|
clearButton.style.display = 'none';
|
||||||
|
const inputField = clearButton.previousElementSibling;
|
||||||
|
inputField.value = '';
|
||||||
|
search(inputField, clearButton.parentElement.nextElementSibling.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function initFilters() {
|
||||||
|
gId("filters").querySelectorAll("input[type=checkbox]").forEach((e) => { e.checked = false; });
|
||||||
|
}
|
||||||
|
|
||||||
|
function filterFocus(e) {
|
||||||
|
const f = gId("filters");
|
||||||
if (e.type === "focus") f.classList.remove('fade'); // immediately show (still has transition)
|
if (e.type === "focus") f.classList.remove('fade'); // immediately show (still has transition)
|
||||||
// compute sticky top (with delay for transition)
|
// compute sticky top (with delay for transition)
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
let sti = parseInt(getComputedStyle(d.documentElement).getPropertyValue('--sti')) + (e.type === "focus" ? 1 : -1) * f.offsetHeight;
|
const sti = parseInt(getComputedStyle(d.documentElement).getPropertyValue('--sti')) + (e.type === "focus" ? 1 : -1) * f.offsetHeight;
|
||||||
sCol('--sti', sti + "px");
|
sCol('--sti', sti + "px");
|
||||||
}, 252);
|
}, 252);
|
||||||
if (e.type === "blur") {
|
if (e.type === "blur") {
|
||||||
let t = e.relatedTarget ? e.relatedTarget : e.explicitOriginalTarget;
|
setTimeout(() => {
|
||||||
do {
|
if (e.target === document.activeElement && document.hasFocus()) return;
|
||||||
if (t.id && (t.id === "fxFind")) { setTimeout(()=>{t.firstElementChild.focus();},150); return; }
|
// do not hide if filter is active
|
||||||
t = t.parentElement;
|
if (gId("filters").querySelectorAll("input[type=checkbox]:checked").length) return;
|
||||||
} while (t.tagName !== "BODY");
|
f.classList.add('fade');
|
||||||
setTimeout(()=>{f.classList.add('fade');},255); // wait with hiding
|
}, 255); // wait with hiding
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterFx(o)
|
function filterFx() {
|
||||||
{
|
const inputField = gId('fxFind').children[0];
|
||||||
if (!o) return;
|
inputField.value = '';
|
||||||
let i = gId('fxFind').children[0];
|
inputField.focus();
|
||||||
i.value=!o.checked?'':o.dataset.flt;
|
clean(inputField.nextElementSibling);
|
||||||
i.focus();
|
const listItems = gId("fxlist").querySelectorAll('.lstI');
|
||||||
i.dispatchEvent(new Event('input'));
|
for (let i = 1; i < listItems.length; i++) {
|
||||||
gId("filters").querySelectorAll("input[type=checkbox]").forEach((e)=>{if(e!==o)e.checked=false;});
|
const listItem = listItems[i];
|
||||||
|
const listItemName = listItem.querySelector('.lstIname').innerText;
|
||||||
|
let hide = false;
|
||||||
|
gId("filters").querySelectorAll("input[type=checkbox]").forEach((e) => { if (e.checked && !listItemName.includes(e.dataset.flt)) hide = true; });
|
||||||
|
listItem.style.display = hide ? 'none' : '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function preventBlur(e) {
|
||||||
|
if (e.target === gId("fxFind").children[0] || e.target === gId("filters")) return;
|
||||||
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure "dur" and "transition" are arrays with at least the length of "ps"
|
// make sure "dur" and "transition" are arrays with at least the length of "ps"
|
||||||
|
@ -52,51 +52,55 @@
|
|||||||
maxB = b; maxV = v; maxM = m; maxPB = p; maxL = l;
|
maxB = b; maxV = v; maxM = m; maxPB = p; maxL = l;
|
||||||
}
|
}
|
||||||
function pinsOK() {
|
function pinsOK() {
|
||||||
var LCs = d.Sf.querySelectorAll("#mLC input[name^=L]"); // input fields
|
var ok = true;
|
||||||
for (i=0; i<LCs.length; i++) {
|
var nList = d.Sf.querySelectorAll("#mLC input[name^=L]");
|
||||||
var nm = LCs[i].name.substring(0,2);
|
nList.forEach((LC,i)=>{
|
||||||
|
if (!ok) return; // prevent iteration after conflict
|
||||||
|
let nm = LC.name.substring(0,2);
|
||||||
|
let n = LC.name.substring(2);
|
||||||
|
let t = parseInt(d.Sf["LT"+n].value, 10); // LED type SELECT
|
||||||
// ignore IP address
|
// ignore IP address
|
||||||
if (nm=="L0" || nm=="L1" || nm=="L2" || nm=="L3") {
|
if (nm=="L0" || nm=="L1" || nm=="L2" || nm=="L3") {
|
||||||
var n = LCs[i].name.substring(2);
|
if (t>=80) return;
|
||||||
var t = parseInt(d.getElementsByName("LT"+n)[0].value, 10); // LED type SELECT
|
|
||||||
if (t>=80) continue;
|
|
||||||
}
|
}
|
||||||
//check for pin conflicts
|
//check for pin conflicts
|
||||||
if (nm=="L0" || nm=="L1" || nm=="L2" || nm=="L3" || nm=="L4"/* || nm=="RL" || nm=="BT" || nm=="IR"*/)
|
if (nm=="L0" || nm=="L1" || nm=="L2" || nm=="L3" || nm=="L4")
|
||||||
if (LCs[i].value!="" && LCs[i].value!="-1") {
|
if (LC.value!="" && LC.value!="-1") {
|
||||||
var p = d.rsvd.concat(d.um_p); // used pin array
|
let p = d.rsvd.concat(d.um_p); // used pin array
|
||||||
d.Sf.querySelectorAll("select.pin").forEach((e)=>{if(e.value>-1)p.push(parseInt(e.value));}) // buttons, IR & relay
|
d.Sf.querySelectorAll("select.pin").forEach((e)=>{if(e.value>-1)p.push(parseInt(e.value));}) // buttons, IR & relay
|
||||||
if (p.some((e)=>e==parseInt(LCs[i].value))) {
|
if (p.some((e)=>e==parseInt(LC.value))) {
|
||||||
alert(`Sorry, pins ${JSON.stringify(p)} can't be used.`);
|
alert(`Sorry, pins ${JSON.stringify(p)} can't be used.`);
|
||||||
LCs[i].value="";
|
LC.value="";
|
||||||
LCs[i].focus();
|
LC.focus();
|
||||||
return false;
|
ok = false;
|
||||||
}
|
return;
|
||||||
else if (/*!(nm == "IR" || nm=="BT") &&*/ d.ro_gpio.some((e)=>e==parseInt(LCs[i].value))) {
|
} else if (d.ro_gpio.some((e)=>e==parseInt(LC.value))) {
|
||||||
alert(`Sorry, pins ${JSON.stringify(d.ro_gpio)} are input only.`);
|
alert(`Sorry, pins ${JSON.stringify(d.ro_gpio)} are input only.`);
|
||||||
LCs[i].value="";
|
LC.value="";
|
||||||
LCs[i].focus();
|
LC.focus();
|
||||||
return false;
|
ok = false;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
for (j=i+1; j<LCs.length; j++) {
|
for (j=i+1; j<nList.length; j++) {
|
||||||
var n2 = LCs[j].name.substring(0,2);
|
let n2 = nList[j].name.substring(0,2);
|
||||||
if (n2=="L0" || n2=="L1" || n2=="L2" || n2=="L3" || n2=="L4"/* || n2=="RL" || n2=="BT" || n2=="IR"*/) {
|
if (n2=="L0" || n2=="L1" || n2=="L2" || n2=="L3" || n2=="L4") {
|
||||||
if (n2.substring(0,1)==="L") {
|
if (n2.substring(0,1)==="L") {
|
||||||
var m = LCs[j].name.substring(2);
|
var m = nList[j].name.substring(2);
|
||||||
var t2 = parseInt(d.getElementsByName("LT"+m)[0].value, 10);
|
var t2 = parseInt(d.Sf["LT"+m].value, 10);
|
||||||
if (t2>=80) continue;
|
if (t2>=80) continue;
|
||||||
}
|
}
|
||||||
if (LCs[j].value!="" && LCs[i].value==LCs[j].value) {
|
if (nList[j].value!="" && nList[i].value==nList[j].value) {
|
||||||
alert(`Pin conflict between ${LCs[i].name}/${LCs[j].name}!`);
|
alert(`Pin conflict between ${LC.name}/${nList[j].name}!`);
|
||||||
LCs[j].value="";
|
nList[j].value="";
|
||||||
LCs[j].focus();
|
nList[j].focus();
|
||||||
return false;
|
ok = false;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
return true;
|
return ok;
|
||||||
}
|
}
|
||||||
function trySubmit(e) {
|
function trySubmit(e) {
|
||||||
d.Sf.data.value = '';
|
d.Sf.data.value = '';
|
||||||
@ -206,7 +210,7 @@
|
|||||||
|
|
||||||
// enumerate pins
|
// enumerate pins
|
||||||
for (p=1; p<5; p++) {
|
for (p=1; p<5; p++) {
|
||||||
var LK = d.getElementsByName("L"+p+n)[0]; // secondary pins
|
var LK = d.Sf["L"+p+n]; // secondary pins
|
||||||
if (!LK) continue;
|
if (!LK) continue;
|
||||||
if (((t>=80 && t<96) && p<4) || (t>49 && p==1) || (t>41 && t < 50 && (p+40 < t))) // TYPE_xxxx values from const.h
|
if (((t>=80 && t<96) && p<4) || (t>49 && p==1) || (t>41 && t < 50 && (p+40 < t))) // TYPE_xxxx values from const.h
|
||||||
{
|
{
|
||||||
@ -222,7 +226,7 @@
|
|||||||
}
|
}
|
||||||
if (change) {
|
if (change) {
|
||||||
gId("rf"+n).checked = (gId("rf"+n).checked || t == 31); // LEDs require data in off state
|
gId("rf"+n).checked = (gId("rf"+n).checked || t == 31); // LEDs require data in off state
|
||||||
if (t > 31 && t < 48) d.getElementsByName("LC"+n)[0].value = 1; // for sanity change analog count just to 1 LED
|
if (t > 31 && t < 48) d.Sf["LC"+n].value = 1; // for sanity change analog count just to 1 LED
|
||||||
d.Sf["LA"+n].min = ((t >= 80 && t < 96) || (t >= 40 && t < 48)) ? 0 : 1;
|
d.Sf["LA"+n].min = ((t >= 80 && t < 96) || (t >= 40 && t < 48)) ? 0 : 1;
|
||||||
d.Sf["MA"+n].min = ((t >= 80 && t < 96) || (t >= 40 && t < 48)) ? 0 : 250;
|
d.Sf["MA"+n].min = ((t >= 80 && t < 96) || (t >= 40 && t < 48)) ? 0 : 250;
|
||||||
}
|
}
|
||||||
@ -230,7 +234,7 @@
|
|||||||
gRGBW |= isRGBW = ((t > 17 && t < 22) || (t > 28 && t < 32) || (t > 40 && t < 46 && t != 43) || t == 88); // RGBW checkbox, TYPE_xxxx values from const.h
|
gRGBW |= isRGBW = ((t > 17 && t < 22) || (t > 28 && t < 32) || (t > 40 && t < 46 && t != 43) || t == 88); // RGBW checkbox, TYPE_xxxx values from const.h
|
||||||
gId("co"+n).style.display = ((t >= 80 && t < 96) || (t >= 40 && t < 48)) ? "none":"inline"; // hide color order for PWM
|
gId("co"+n).style.display = ((t >= 80 && t < 96) || (t >= 40 && t < 48)) ? "none":"inline"; // hide color order for PWM
|
||||||
gId("dig"+n+"w").style.display = (t > 28 && t < 32) ? "inline":"none"; // show swap channels dropdown
|
gId("dig"+n+"w").style.display = (t > 28 && t < 32) ? "inline":"none"; // show swap channels dropdown
|
||||||
if (!(t > 28 && t < 32)) d.getElementsByName("WO"+n)[0].value = 0; // reset swapping
|
if (!(t > 28 && t < 32)) d.Sf["WO"+n].value = 0; // reset swapping
|
||||||
gId("dig"+n+"c").style.display = (t >= 40 && t < 48) ? "none":"inline"; // hide count for analog
|
gId("dig"+n+"c").style.display = (t >= 40 && t < 48) ? "none":"inline"; // hide count for analog
|
||||||
gId("dig"+n+"r").style.display = (t >= 80 && t < 96) ? "none":"inline"; // hide reversed for virtual
|
gId("dig"+n+"r").style.display = (t >= 80 && t < 96) ? "none":"inline"; // hide reversed for virtual
|
||||||
gId("dig"+n+"s").style.display = ((t >= 80 && t < 96) || (t >= 40 && t < 48)) ? "none":"inline"; // hide skip 1st for virtual & analog
|
gId("dig"+n+"s").style.display = ((t >= 80 && t < 96) || (t >= 40 && t < 48)) ? "none":"inline"; // hide skip 1st for virtual & analog
|
||||||
@ -249,21 +253,21 @@
|
|||||||
d.Sf.AW.selectedIndex = 0;
|
d.Sf.AW.selectedIndex = 0;
|
||||||
d.Sf.CR.checked = false;
|
d.Sf.CR.checked = false;
|
||||||
}
|
}
|
||||||
// check for pin conflicts
|
// update start indexes, max values, calculate current, etc
|
||||||
var LCs = d.Sf.querySelectorAll("#mLC input[name^=L]"); // input fields
|
var nList = d.Sf.querySelectorAll("#mLC input[name^=L]");
|
||||||
for (i=0; i<LCs.length; i++) {
|
nList.forEach((LC,i)=>{
|
||||||
var nm = LCs[i].name.substring(0,2); // field name
|
let nm = LC.name.substring(0,2); // field name
|
||||||
var n = LCs[i].name.substring(2); // bus number
|
let n = LC.name.substring(2); // bus number
|
||||||
|
let t = parseInt(d.Sf["LT"+n].value); // LED type SELECT
|
||||||
// do we have a led count field
|
// do we have a led count field
|
||||||
if (nm=="LC") {
|
if (nm=="LC") {
|
||||||
var c=parseInt(LCs[i].value,10); //get LED count
|
let c = parseInt(LC.value,10); //get LED count
|
||||||
if (!customStarts || !startsDirty[n]) gId("ls"+n).value=sLC; //update start value
|
if (!customStarts || !startsDirty[n]) gId("ls"+n).value=sLC; //update start value
|
||||||
gId("ls"+n).disabled = !customStarts; //enable/disable field editing
|
gId("ls"+n).disabled = !customStarts; //enable/disable field editing
|
||||||
if (c) {
|
if (c) {
|
||||||
var s = parseInt(gId("ls"+n).value); //start value
|
let s = parseInt(gId("ls"+n).value); //start value
|
||||||
if (s+c > sLC) sLC = s+c; //update total count
|
if (s+c > sLC) sLC = s+c; //update total count
|
||||||
if (c > maxLC) maxLC = c; //max per output
|
if (c > maxLC) maxLC = c; //max per output
|
||||||
var t = parseInt(d.Sf["LT"+n].value); // LED type SELECT
|
|
||||||
if (t < 80) sPC += c; //virtual out busses do not count towards physical LEDs
|
if (t < 80) sPC += c; //virtual out busses do not count towards physical LEDs
|
||||||
if (!((t >= 80 && t < 96) || (t >= 40 && t < 48))) sDI += c;
|
if (!((t >= 80 && t < 96) || (t >= 40 && t < 48))) sDI += c;
|
||||||
if (!((t >= 80 && t < 96) || (t >= 40 && t < 48))) {
|
if (!((t >= 80 && t < 96) || (t >= 40 && t < 48))) {
|
||||||
@ -272,52 +276,46 @@
|
|||||||
busMA += maPL*c;
|
busMA += maPL*c;
|
||||||
}
|
}
|
||||||
} // increase led count
|
} // increase led count
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
// do we have led pins for digital leds
|
// do we have led pins for digital leds
|
||||||
if (nm=="L0" || nm=="L1") {
|
if (nm=="L0" || nm=="L1") {
|
||||||
var lc=d.Sf["LC"+n];
|
d.Sf["LC"+n].max = maxPB; // update max led count value
|
||||||
lc.max=maxPB; // update max led count value
|
|
||||||
}
|
}
|
||||||
// ignore IP address (stored in pins for virtual busses)
|
// ignore IP address (stored in pins for virtual busses)
|
||||||
if (nm=="L0" || nm=="L1" || nm=="L2" || nm=="L3") {
|
if (nm=="L0" || nm=="L1" || nm=="L2" || nm=="L3") {
|
||||||
var t = parseInt(d.Sf["LT"+n].value); // LED type SELECT
|
|
||||||
if (t>=80) {
|
if (t>=80) {
|
||||||
LCs[i].max = 255;
|
LC.max = 255;
|
||||||
LCs[i].min = 0;
|
LC.min = 0;
|
||||||
LCs[i].style.color="#fff";
|
LC.style.color="#fff";
|
||||||
continue; // do not check conflicts
|
return; // do not check conflicts
|
||||||
} else {
|
} else {
|
||||||
LCs[i].max = d.max_gpio;
|
LC.max = d.max_gpio;
|
||||||
LCs[i].min = -1;
|
LC.min = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// check for pin conflicts
|
// check for pin conflicts & color fields
|
||||||
if (nm=="L0" || nm=="L1" || nm=="L2" || nm=="L3" || nm=="L4"/* || nm=="RL" || nm=="BT" || nm=="IR"*/)
|
if (nm=="L0" || nm=="L1" || nm=="L2" || nm=="L3" || nm=="L4")
|
||||||
if (LCs[i].value!="" && LCs[i].value!="-1") {
|
if (LC.value!="" && LC.value!="-1") {
|
||||||
var p = d.rsvd.concat(d.um_p); // used pin array
|
let p = d.rsvd.concat(d.um_p); // used pin array
|
||||||
d.Sf.querySelectorAll("select.pin").forEach((e)=>{if(e.value>-1)p.push(parseInt(e.value));}) // buttons, IR & relay
|
d.Sf.querySelectorAll("select.pin").forEach((e)=>{if(e.value>-1)p.push(parseInt(e.value));}) // buttons, IR & relay
|
||||||
for (j=0; j<LCs.length; j++) {
|
for (j=0; j<nList.length; j++) {
|
||||||
if (i==j) continue;
|
if (i==j) continue;
|
||||||
var n2 = LCs[j].name.substring(0,2);
|
let n2 = nList[j].name.substring(0,2);
|
||||||
if (n2=="L0" || n2=="L1" || n2=="L2" || n2=="L3" || n2=="L4"/* || n2=="RL" || n2=="BT" || n2=="IR"*/) {
|
if (n2=="L0" || n2=="L1" || n2=="L2" || n2=="L3" || n2=="L4") {
|
||||||
if (n2.substring(0,1)==="L") {
|
if (n2.substring(0,1)==="L") {
|
||||||
var m = LCs[j].name.substring(2);
|
let m = nList[j].name.substring(2);
|
||||||
var t2 = parseInt(d.Sf["LT"+m].value, 10);
|
let t2 = parseInt(d.Sf["LT"+m].value, 10);
|
||||||
if (t2 >= 80) continue;
|
if (t2 >= 80) continue;
|
||||||
}
|
}
|
||||||
if (LCs[j].value!="" && LCs[j].value!="-1") p.push(parseInt(LCs[j].value,10)); // add current pin
|
if (nList[j].value!="" && nList[j].value!="-1") p.push(parseInt(nList[j].value,10)); // add current pin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// now check for conflicts
|
// now check for conflicts
|
||||||
if (p.some((e)=>e==parseInt(LCs[i].value))) LCs[i].style.color="red"; else LCs[i].style.color=d.ro_gpio.some((e)=>e==parseInt(LCs[i].value))?"orange":"#fff";
|
if (p.some((e)=>e==parseInt(LC.value))) LC.style.color = "red";
|
||||||
}
|
else LC.style.color = d.ro_gpio.some((e)=>e==parseInt(LC.value)) ? "orange" : "#fff";
|
||||||
// check buttons, IR & relay
|
|
||||||
//if (nm=="IR" || nm=="BT" || nm=="RL") {
|
|
||||||
// LCs[i].max = d.max_gpio;
|
|
||||||
// LCs[i].min = -1;
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
d.Sf.querySelectorAll("#mLC input[name^=LC]").forEach((s,n)=>{
|
d.Sf.querySelectorAll("#mLC input[name^=LC]").forEach((s,n)=>{
|
||||||
let c = parseInt(s.value,10); //get LED count
|
let c = parseInt(s.value,10); //get LED count
|
||||||
let t = parseInt(d.Sf["LT"+n].value);
|
let t = parseInt(d.Sf["LT"+n].value);
|
||||||
@ -512,6 +510,7 @@ Length: <input type="number" name="XC${i}" id="xc${i}" class="l" min="1" max="65
|
|||||||
c += `<option value="6" ${t==6?"selected":""}>Touch</option>`;
|
c += `<option value="6" ${t==6?"selected":""}>Touch</option>`;
|
||||||
c += `<option value="7" ${t==7?"selected":""}>Analog</option>`;
|
c += `<option value="7" ${t==7?"selected":""}>Analog</option>`;
|
||||||
c += `<option value="8" ${t==8?"selected":""}>Analog inverted</option>`;
|
c += `<option value="8" ${t==8?"selected":""}>Analog inverted</option>`;
|
||||||
|
c += `<option value="9" ${t==9?"selected":""}>Touch (switch)</option>`;
|
||||||
c += `</select>`;
|
c += `</select>`;
|
||||||
c += `<span style="cursor: pointer;" onclick="off('${bt}')"> ✕</span><br>`;
|
c += `<span style="cursor: pointer;" onclick="off('${bt}')"> ✕</span><br>`;
|
||||||
gId("btns").innerHTML = c;
|
gId("btns").innerHTML = c;
|
||||||
@ -817,10 +816,12 @@ Length: <input type="number" name="XC${i}" id="xc${i}" class="l" min="1" max="65
|
|||||||
Use Gamma value: <input name="GV" type="number" class="m" placeholder="2.8" min="1" max="3" step="0.1" required><br><br>
|
Use Gamma value: <input name="GV" type="number" class="m" placeholder="2.8" min="1" max="3" step="0.1" required><br><br>
|
||||||
Brightness factor: <input name="BF" type="number" class="m" min="1" max="255" required> %
|
Brightness factor: <input name="BF" type="number" class="m" min="1" max="255" required> %
|
||||||
<h3>Transitions</h3>
|
<h3>Transitions</h3>
|
||||||
Crossfade: <input type="checkbox" name="TF"><br>
|
Enable transitions: <input type="checkbox" name="TF" onchange="gId('tran').style.display=this.checked?'inline':'none';"><br>
|
||||||
|
<span id="tran">
|
||||||
Effect blending: <input type="checkbox" name="EB"><br>
|
Effect blending: <input type="checkbox" name="EB"><br>
|
||||||
Transition Time: <input name="TD" type="number" class="xl" min="0" max="65500"> ms<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>
|
Palette transitions: <input type="checkbox" name="PF"><br>
|
||||||
|
</span>
|
||||||
<i>Random Cycle</i> Palette Time: <input name="TP" type="number" class="m" min="1" max="255"> s<br>
|
<i>Random Cycle</i> Palette Time: <input name="TP" type="number" class="m" min="1" max="255"> s<br>
|
||||||
<h3>Timed light</h3>
|
<h3>Timed light</h3>
|
||||||
Default Duration: <input name="TL" type="number" class="m" min="1" max="255" required> min<br>
|
Default Duration: <input name="TL" type="number" class="m" min="1" max="255" required> min<br>
|
||||||
|
@ -399,10 +399,10 @@ bool isIp(String str);
|
|||||||
void createEditHandler(bool enable);
|
void createEditHandler(bool enable);
|
||||||
bool captivePortal(AsyncWebServerRequest *request);
|
bool captivePortal(AsyncWebServerRequest *request);
|
||||||
void initServer();
|
void initServer();
|
||||||
void serveIndexOrWelcome(AsyncWebServerRequest *request);
|
|
||||||
void serveIndex(AsyncWebServerRequest* request);
|
void serveIndex(AsyncWebServerRequest* request);
|
||||||
String msgProcessor(const String& var);
|
String msgProcessor(const String& var);
|
||||||
void serveMessage(AsyncWebServerRequest* request, uint16_t code, const String& headl, const String& subl="", byte optionT=255);
|
void serveMessage(AsyncWebServerRequest* request, uint16_t code, const String& headl, const String& subl="", byte optionT=255);
|
||||||
|
void serveJsonError(AsyncWebServerRequest* request, uint16_t code, uint16_t error);
|
||||||
String dmxProcessor(const String& var);
|
String dmxProcessor(const String& var);
|
||||||
void serveSettings(AsyncWebServerRequest* request, bool post = false);
|
void serveSettings(AsyncWebServerRequest* request, bool post = false);
|
||||||
void serveSettingsJS(AsyncWebServerRequest* request);
|
void serveSettingsJS(AsyncWebServerRequest* request);
|
||||||
|
File diff suppressed because it is too large
Load Diff
4087
wled00/html_ui.h
4087
wled00/html_ui.h
File diff suppressed because it is too large
Load Diff
@ -240,8 +240,9 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
|
|||||||
seg.map1D2D = M12_Pixels; // no mapping
|
seg.map1D2D = M12_Pixels; // no mapping
|
||||||
|
|
||||||
// set brightness immediately and disable transition
|
// set brightness immediately and disable transition
|
||||||
transitionDelayTemp = 0;
|
|
||||||
jsonTransitionOnce = true;
|
jsonTransitionOnce = true;
|
||||||
|
seg.stopTransition();
|
||||||
|
strip.setTransition(0);
|
||||||
strip.setBrightness(scaledBri(bri), true);
|
strip.setBrightness(scaledBri(bri), true);
|
||||||
|
|
||||||
// freeze and init to black
|
// freeze and init to black
|
||||||
@ -323,23 +324,18 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
|||||||
int tr = -1;
|
int tr = -1;
|
||||||
if (!presetId || currentPlaylist < 0) { //do not apply transition time from preset if playlist active, as it would override playlist transition times
|
if (!presetId || currentPlaylist < 0) { //do not apply transition time from preset if playlist active, as it would override playlist transition times
|
||||||
tr = root[F("transition")] | -1;
|
tr = root[F("transition")] | -1;
|
||||||
if (tr >= 0)
|
if (tr >= 0) {
|
||||||
{
|
transitionDelay = tr * 100;
|
||||||
transitionDelay = tr;
|
if (fadeTransition) strip.setTransition(transitionDelay);
|
||||||
transitionDelay *= 100;
|
|
||||||
transitionDelayTemp = transitionDelay;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// temporary transition (applies only once)
|
// temporary transition (applies only once)
|
||||||
tr = root[F("tt")] | -1;
|
tr = root[F("tt")] | -1;
|
||||||
if (tr >= 0)
|
if (tr >= 0) {
|
||||||
{
|
|
||||||
transitionDelayTemp = tr;
|
|
||||||
transitionDelayTemp *= 100;
|
|
||||||
jsonTransitionOnce = true;
|
jsonTransitionOnce = true;
|
||||||
|
if (fadeTransition) strip.setTransition(tr * 100);
|
||||||
}
|
}
|
||||||
strip.setTransition(transitionDelayTemp); // required here for color transitions to have correct duration
|
|
||||||
|
|
||||||
tr = root[F("tb")] | -1;
|
tr = root[F("tb")] | -1;
|
||||||
if (tr >= 0) strip.timebase = ((uint32_t)tr) - millis();
|
if (tr >= 0) strip.timebase = ((uint32_t)tr) - millis();
|
||||||
@ -375,8 +371,8 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
|||||||
|
|
||||||
if (root.containsKey("live")) {
|
if (root.containsKey("live")) {
|
||||||
if (root["live"].as<bool>()) {
|
if (root["live"].as<bool>()) {
|
||||||
transitionDelayTemp = 0;
|
|
||||||
jsonTransitionOnce = true;
|
jsonTransitionOnce = true;
|
||||||
|
strip.setTransition(0);
|
||||||
realtimeLock(65000);
|
realtimeLock(65000);
|
||||||
} else {
|
} else {
|
||||||
exitRealtime();
|
exitRealtime();
|
||||||
@ -962,11 +958,11 @@ void serializeNetworks(JsonObject root)
|
|||||||
|
|
||||||
for (int i = 0; i < status; i++) {
|
for (int i = 0; i < status; i++) {
|
||||||
JsonObject node = networks.createNestedObject();
|
JsonObject node = networks.createNestedObject();
|
||||||
node["ssid"] = WiFi.SSID(i);
|
node[F("ssid")] = WiFi.SSID(i);
|
||||||
node["rssi"] = WiFi.RSSI(i);
|
node[F("rssi")] = WiFi.RSSI(i);
|
||||||
node["bssid"] = WiFi.BSSIDstr(i);
|
node[F("bssid")] = WiFi.BSSIDstr(i);
|
||||||
node["channel"] = WiFi.channel(i);
|
node[F("channel")] = WiFi.channel(i);
|
||||||
node["enc"] = WiFi.encryptionType(i);
|
node[F("enc")] = WiFi.encryptionType(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
WiFi.scanDelete();
|
WiFi.scanDelete();
|
||||||
@ -1029,7 +1025,7 @@ static volatile bool servingClient = false;
|
|||||||
void serveJson(AsyncWebServerRequest* request)
|
void serveJson(AsyncWebServerRequest* request)
|
||||||
{
|
{
|
||||||
if (servingClient) {
|
if (servingClient) {
|
||||||
request->send(503, "application/json", F("{\"error\":2}")); // ERR_CONCURENCY
|
serveJsonError(request, 503, ERR_CONCURRENCY);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
servingClient = true;
|
servingClient = true;
|
||||||
@ -1061,13 +1057,13 @@ void serveJson(AsyncWebServerRequest* request)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (url.length() > 6) { //not just /json
|
else if (url.length() > 6) { //not just /json
|
||||||
request->send(501, "application/json", F("{\"error\":\"Not implemented\"}"));
|
serveJsonError(request, 501, ERR_NOT_IMPL);
|
||||||
servingClient = false;
|
servingClient = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!requestJSONBufferLock(17)) {
|
if (!requestJSONBufferLock(17)) {
|
||||||
request->send(503, "application/json", F("{\"error\":3}"));
|
serveJsonError(request, 503, ERR_NOBUF);
|
||||||
servingClient = false;
|
servingClient = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -134,11 +134,9 @@ void stateUpdated(byte callMode) {
|
|||||||
usermods.onStateChange(callMode);
|
usermods.onStateChange(callMode);
|
||||||
|
|
||||||
if (fadeTransition) {
|
if (fadeTransition) {
|
||||||
//set correct delay if not using notification delay
|
if (strip.getTransition() == 0) {
|
||||||
if (callMode != CALL_MODE_NOTIFICATION && !jsonTransitionOnce) transitionDelayTemp = transitionDelay; // load actual transition duration
|
|
||||||
jsonTransitionOnce = false;
|
jsonTransitionOnce = false;
|
||||||
strip.setTransition(transitionDelayTemp);
|
transitionActive = false;
|
||||||
if (transitionDelayTemp == 0) {
|
|
||||||
applyFinalBri();
|
applyFinalBri();
|
||||||
strip.trigger();
|
strip.trigger();
|
||||||
return;
|
return;
|
||||||
@ -152,7 +150,6 @@ void stateUpdated(byte callMode) {
|
|||||||
transitionActive = true;
|
transitionActive = true;
|
||||||
transitionStartTime = millis();
|
transitionStartTime = millis();
|
||||||
} else {
|
} else {
|
||||||
strip.setTransition(0);
|
|
||||||
applyFinalBri();
|
applyFinalBri();
|
||||||
strip.trigger();
|
strip.trigger();
|
||||||
}
|
}
|
||||||
@ -187,13 +184,14 @@ void handleTransitions()
|
|||||||
if (doPublishMqtt) publishMqtt();
|
if (doPublishMqtt) publishMqtt();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (transitionActive && transitionDelayTemp > 0)
|
if (transitionActive && strip.getTransition() > 0) {
|
||||||
{
|
float tper = (millis() - transitionStartTime)/(float)strip.getTransition();
|
||||||
float tper = (millis() - transitionStartTime)/(float)transitionDelayTemp;
|
if (tper >= 1.0f) {
|
||||||
if (tper >= 1.0f)
|
strip.setTransitionMode(false); // stop all transitions
|
||||||
{
|
// restore (global) transition time if not called from UDP notifier or single/temporary transition from JSON (also playlist)
|
||||||
strip.setTransitionMode(false);
|
if (jsonTransitionOnce) strip.setTransition(transitionDelay);
|
||||||
transitionActive = false;
|
transitionActive = false;
|
||||||
|
jsonTransitionOnce = false;
|
||||||
tperLast = 0;
|
tperLast = 0;
|
||||||
applyFinalBri();
|
applyFinalBri();
|
||||||
return;
|
return;
|
||||||
|
@ -144,7 +144,7 @@ void handlePlaylist() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
jsonTransitionOnce = true;
|
jsonTransitionOnce = true;
|
||||||
transitionDelayTemp = playlistEntries[playlistIndex].tr * 100;
|
strip.setTransition(fadeTransition ? playlistEntries[playlistIndex].tr * 100 : 0);
|
||||||
playlistEntryDur = playlistEntries[playlistIndex].dur;
|
playlistEntryDur = playlistEntries[playlistIndex].dur;
|
||||||
applyPreset(playlistEntries[playlistIndex].preset);
|
applyPreset(playlistEntries[playlistIndex].preset);
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,11 @@
|
|||||||
#define WIZMOTE_BUTTON_BRIGHT_UP 9
|
#define WIZMOTE_BUTTON_BRIGHT_UP 9
|
||||||
#define WIZMOTE_BUTTON_BRIGHT_DOWN 8
|
#define WIZMOTE_BUTTON_BRIGHT_DOWN 8
|
||||||
|
|
||||||
|
#define WIZ_SMART_BUTTON_ON 100
|
||||||
|
#define WIZ_SMART_BUTTON_OFF 101
|
||||||
|
#define WIZ_SMART_BUTTON_BRIGHT_UP 102
|
||||||
|
#define WIZ_SMART_BUTTON_BRIGHT_DOWN 103
|
||||||
|
|
||||||
// This is kind of an esoteric strucure because it's pulled from the "Wizmote"
|
// This is kind of an esoteric strucure because it's pulled from the "Wizmote"
|
||||||
// product spec. That remote is used as the baseline for behavior and availability
|
// product spec. That remote is used as the baseline for behavior and availability
|
||||||
// since it's broadly commercially available and works out of the box as a drop-in
|
// since it's broadly commercially available and works out of the box as a drop-in
|
||||||
@ -210,6 +215,10 @@ void handleRemote(uint8_t *incomingData, size_t len) {
|
|||||||
case WIZMOTE_BUTTON_NIGHT : activateNightMode(); break;
|
case WIZMOTE_BUTTON_NIGHT : activateNightMode(); break;
|
||||||
case WIZMOTE_BUTTON_BRIGHT_UP : brightnessUp(); break;
|
case WIZMOTE_BUTTON_BRIGHT_UP : brightnessUp(); break;
|
||||||
case WIZMOTE_BUTTON_BRIGHT_DOWN : brightnessDown(); break;
|
case WIZMOTE_BUTTON_BRIGHT_DOWN : brightnessDown(); break;
|
||||||
|
case WIZ_SMART_BUTTON_ON : setOn(); break;
|
||||||
|
case WIZ_SMART_BUTTON_OFF : setOff(); break;
|
||||||
|
case WIZ_SMART_BUTTON_BRIGHT_UP : brightnessUp(); break;
|
||||||
|
case WIZ_SMART_BUTTON_BRIGHT_DOWN : brightnessDown(); break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
last_seq = cur_seq;
|
last_seq = cur_seq;
|
||||||
|
@ -136,7 +136,6 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
pins[i] = (request->arg(lp).length() > 0) ? request->arg(lp).toInt() : 255;
|
pins[i] = (request->arg(lp).length() > 0) ? request->arg(lp).toInt() : 255;
|
||||||
}
|
}
|
||||||
type = request->arg(lt).toInt();
|
type = request->arg(lt).toInt();
|
||||||
type |= request->hasArg(rf) << 7; // off refresh override
|
|
||||||
skip = request->arg(sl).toInt();
|
skip = request->arg(sl).toInt();
|
||||||
colorOrder = request->arg(co).toInt();
|
colorOrder = request->arg(co).toInt();
|
||||||
start = (request->hasArg(ls)) ? request->arg(ls).toInt() : t;
|
start = (request->hasArg(ls)) ? request->arg(ls).toInt() : t;
|
||||||
@ -168,7 +167,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
} else {
|
} else {
|
||||||
freqHz = 0;
|
freqHz = 0;
|
||||||
}
|
}
|
||||||
channelSwap = (type == TYPE_SK6812_RGBW || type == TYPE_TM1814) ? request->arg(wo).toInt() : 0;
|
channelSwap = Bus::hasWhite(type) ? request->arg(wo).toInt() : 0;
|
||||||
if ((type > TYPE_TM1814 && type < TYPE_WS2801) || type >= TYPE_NET_DDP_RGB) { // analog and virtual
|
if ((type > TYPE_TM1814 && type < TYPE_WS2801) || type >= TYPE_NET_DDP_RGB) { // analog and virtual
|
||||||
maPerLed = 0;
|
maPerLed = 0;
|
||||||
maMax = 0;
|
maMax = 0;
|
||||||
@ -176,6 +175,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
maPerLed = request->arg(la).toInt();
|
maPerLed = request->arg(la).toInt();
|
||||||
maMax = request->arg(ma).toInt(); // if ABL is disabled this will be 0
|
maMax = request->arg(ma).toInt(); // if ABL is disabled this will be 0
|
||||||
}
|
}
|
||||||
|
type |= request->hasArg(rf) << 7; // off refresh override
|
||||||
// actual finalization is done in WLED::loop() (removing old busses and adding new)
|
// actual finalization is done in WLED::loop() (removing old busses and adding new)
|
||||||
// this may happen even before this loop is finished so we do "doInitBusses" after the loop
|
// this may happen even before this loop is finished so we do "doInitBusses" after the loop
|
||||||
if (busConfigs[s] != nullptr) delete busConfigs[s];
|
if (busConfigs[s] != nullptr) delete busConfigs[s];
|
||||||
@ -221,15 +221,22 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
char bt[4] = "BT"; bt[2] = (i<10?48:55)+i; bt[3] = 0; // button pin (use A,B,C,... if WLED_MAX_BUTTONS>10)
|
char bt[4] = "BT"; bt[2] = (i<10?48:55)+i; bt[3] = 0; // button pin (use A,B,C,... if WLED_MAX_BUTTONS>10)
|
||||||
char be[4] = "BE"; be[2] = (i<10?48:55)+i; be[3] = 0; // button type (use A,B,C,... if WLED_MAX_BUTTONS>10)
|
char be[4] = "BE"; be[2] = (i<10?48:55)+i; be[3] = 0; // button type (use A,B,C,... if WLED_MAX_BUTTONS>10)
|
||||||
int hw_btn_pin = request->arg(bt).toInt();
|
int hw_btn_pin = request->arg(bt).toInt();
|
||||||
if (pinManager.allocatePin(hw_btn_pin,false,PinOwner::Button)) {
|
if (hw_btn_pin >= 0 && pinManager.allocatePin(hw_btn_pin,false,PinOwner::Button)) {
|
||||||
btnPin[i] = hw_btn_pin;
|
btnPin[i] = hw_btn_pin;
|
||||||
buttonType[i] = request->arg(be).toInt();
|
buttonType[i] = request->arg(be).toInt();
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
// ESP32 only: check that analog button pin is a valid ADC gpio
|
// ESP32 only: check that button pin is a valid gpio
|
||||||
if (((buttonType[i] == BTN_TYPE_ANALOG) || (buttonType[i] == BTN_TYPE_ANALOG_INVERTED)) && (digitalPinToAnalogChannel(btnPin[i]) < 0))
|
if (((buttonType[i] == BTN_TYPE_ANALOG) || (buttonType[i] == BTN_TYPE_ANALOG_INVERTED)) && (digitalPinToAnalogChannel(btnPin[i]) < 0))
|
||||||
{
|
{
|
||||||
// not an ADC analog pin
|
// not an ADC analog pin
|
||||||
if (btnPin[i] >= 0) DEBUG_PRINTF("PIN ALLOC error: GPIO%d for analog button #%d is not an analog pin!\n", btnPin[i], i);
|
DEBUG_PRINTF("PIN ALLOC error: GPIO%d for analog button #%d is not an analog pin!\n", btnPin[i], i);
|
||||||
|
btnPin[i] = -1;
|
||||||
|
pinManager.deallocatePin(hw_btn_pin,PinOwner::Button);
|
||||||
|
}
|
||||||
|
else if ((buttonType[i] == BTN_TYPE_TOUCH || buttonType[i] == BTN_TYPE_TOUCH_SWITCH) && digitalPinToTouchChannel(btnPin[i]) < 0)
|
||||||
|
{
|
||||||
|
// not a touch pin
|
||||||
|
DEBUG_PRINTF("PIN ALLOC error: GPIO%d for touch button #%d is not an touch pin!\n", btnPin[i], i);
|
||||||
btnPin[i] = -1;
|
btnPin[i] = -1;
|
||||||
pinManager.deallocatePin(hw_btn_pin,PinOwner::Button);
|
pinManager.deallocatePin(hw_btn_pin,PinOwner::Button);
|
||||||
}
|
}
|
||||||
@ -1089,6 +1096,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
|||||||
|
|
||||||
pos = req.indexOf(F("TT="));
|
pos = req.indexOf(F("TT="));
|
||||||
if (pos > 0) transitionDelay = getNumVal(&req, pos);
|
if (pos > 0) transitionDelay = getNumVal(&req, pos);
|
||||||
|
if (fadeTransition) strip.setTransition(transitionDelay);
|
||||||
|
|
||||||
//set time (unix timestamp)
|
//set time (unix timestamp)
|
||||||
pos = req.indexOf(F("ST="));
|
pos = req.indexOf(F("ST="));
|
||||||
|
@ -139,9 +139,9 @@ void notify(byte callMode, bool followUp)
|
|||||||
udpOut[29+ofs] = selseg.custom1;
|
udpOut[29+ofs] = selseg.custom1;
|
||||||
udpOut[30+ofs] = selseg.custom2;
|
udpOut[30+ofs] = selseg.custom2;
|
||||||
udpOut[31+ofs] = selseg.custom3 | (selseg.check1<<5) | (selseg.check2<<6) | (selseg.check3<<7);
|
udpOut[31+ofs] = selseg.custom3 | (selseg.check1<<5) | (selseg.check2<<6) | (selseg.check3<<7);
|
||||||
udpOut[32+ofs] = selseg.startY >> 8;
|
udpOut[32+ofs] = selseg.startY >> 8; // ATM always 0 as Segment::startY is 8-bit
|
||||||
udpOut[33+ofs] = selseg.startY & 0xFF;
|
udpOut[33+ofs] = selseg.startY & 0xFF;
|
||||||
udpOut[34+ofs] = selseg.stopY >> 8;
|
udpOut[34+ofs] = selseg.stopY >> 8; // ATM always 0 as Segment::stopY is 8-bit
|
||||||
udpOut[35+ofs] = selseg.stopY & 0xFF;
|
udpOut[35+ofs] = selseg.stopY & 0xFF;
|
||||||
++s;
|
++s;
|
||||||
}
|
}
|
||||||
@ -211,6 +211,14 @@ void parseNotifyPacket(uint8_t *udpIn) {
|
|||||||
|
|
||||||
bool someSel = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects);
|
bool someSel = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects);
|
||||||
|
|
||||||
|
// set transition time before making any segment changes
|
||||||
|
if (version > 3) {
|
||||||
|
if (fadeTransition) {
|
||||||
|
jsonTransitionOnce = true;
|
||||||
|
strip.setTransition(((udpIn[17] << 0) & 0xFF) + ((udpIn[18] << 8) & 0xFF00));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//apply colors from notification to main segment, only if not syncing full segments
|
//apply colors from notification to main segment, only if not syncing full segments
|
||||||
if ((receiveNotificationColor || !someSel) && (version < 11 || !receiveSegmentOptions)) {
|
if ((receiveNotificationColor || !someSel) && (version < 11 || !receiveSegmentOptions)) {
|
||||||
// primary color, only apply white if intented (version > 0)
|
// primary color, only apply white if intented (version > 0)
|
||||||
@ -264,6 +272,7 @@ void parseNotifyPacket(uint8_t *udpIn) {
|
|||||||
if (!receiveSegmentBounds) {
|
if (!receiveSegmentBounds) {
|
||||||
if (!selseg.isActive()) {
|
if (!selseg.isActive()) {
|
||||||
inactiveSegs++;
|
inactiveSegs++;
|
||||||
|
DEBUG_PRINTLN(F("Inactive segment."));
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
id += inactiveSegs; // adjust id
|
id += inactiveSegs; // adjust id
|
||||||
@ -271,24 +280,29 @@ void parseNotifyPacket(uint8_t *udpIn) {
|
|||||||
}
|
}
|
||||||
DEBUG_PRINT(F("UDP segment processing: ")); DEBUG_PRINTLN(id);
|
DEBUG_PRINT(F("UDP segment processing: ")); DEBUG_PRINTLN(id);
|
||||||
|
|
||||||
uint16_t startY = 0, start = (udpIn[1+ofs] << 8 | udpIn[2+ofs]);
|
uint16_t start = (udpIn[1+ofs] << 8 | udpIn[2+ofs]);
|
||||||
uint16_t stopY = 1, stop = (udpIn[3+ofs] << 8 | udpIn[4+ofs]);
|
uint16_t stop = (udpIn[3+ofs] << 8 | udpIn[4+ofs]);
|
||||||
|
uint16_t startY = version > 11 ? (udpIn[32+ofs] << 8 | udpIn[33+ofs]) : 0;
|
||||||
|
uint16_t stopY = version > 11 ? (udpIn[34+ofs] << 8 | udpIn[35+ofs]) : 1;
|
||||||
uint16_t offset = (udpIn[7+ofs] << 8 | udpIn[8+ofs]);
|
uint16_t offset = (udpIn[7+ofs] << 8 | udpIn[8+ofs]);
|
||||||
if (!receiveSegmentOptions) {
|
if (!receiveSegmentOptions) {
|
||||||
//selseg.setUp(start, stop, selseg.grouping, selseg.spacing, offset, startY, stopY);
|
//selseg.setUp(start, stop, selseg.grouping, selseg.spacing, offset, startY, stopY);
|
||||||
// we have to use strip.setSegment() instead of selseg.setUp() to prevent crash if segment would change during drawing
|
// we have to use strip.setSegment() instead of selseg.setUp() to prevent crash if segment would change during drawing
|
||||||
|
DEBUG_PRINTF("Set segment w/o options: %d [%d,%d;%d,%d]\n", id, (int)start, (int)stop, (int)startY, (int)stopY);
|
||||||
strip.setSegment(id, start, stop, selseg.grouping, selseg.spacing, offset, startY, stopY);
|
strip.setSegment(id, start, stop, selseg.grouping, selseg.spacing, offset, startY, stopY);
|
||||||
continue; // we do receive bounds, but not options
|
continue; // we do receive bounds, but not options
|
||||||
}
|
}
|
||||||
selseg.options = (selseg.options & 0x0071U) | (udpIn[9 +ofs] & 0x0E); // ignore selected, freeze, reset & transitional
|
selseg.options = (selseg.options & 0x0071U) | (udpIn[9 +ofs] & 0x0E); // ignore selected, freeze, reset & transitional
|
||||||
selseg.setOpacity(udpIn[10+ofs]);
|
selseg.setOpacity(udpIn[10+ofs]);
|
||||||
if (applyEffects) {
|
if (applyEffects) {
|
||||||
|
DEBUG_PRINT(F("Apply effect: ")); DEBUG_PRINTLN(id);
|
||||||
selseg.setMode(udpIn[11+ofs]);
|
selseg.setMode(udpIn[11+ofs]);
|
||||||
selseg.speed = udpIn[12+ofs];
|
selseg.speed = udpIn[12+ofs];
|
||||||
selseg.intensity = udpIn[13+ofs];
|
selseg.intensity = udpIn[13+ofs];
|
||||||
selseg.palette = udpIn[14+ofs];
|
selseg.palette = udpIn[14+ofs];
|
||||||
}
|
}
|
||||||
if (receiveNotificationColor || !someSel) {
|
if (receiveNotificationColor || !someSel) {
|
||||||
|
DEBUG_PRINT(F("Apply color: ")); DEBUG_PRINTLN(id);
|
||||||
selseg.setColor(0, RGBW32(udpIn[15+ofs],udpIn[16+ofs],udpIn[17+ofs],udpIn[18+ofs]));
|
selseg.setColor(0, RGBW32(udpIn[15+ofs],udpIn[16+ofs],udpIn[17+ofs],udpIn[18+ofs]));
|
||||||
selseg.setColor(1, RGBW32(udpIn[19+ofs],udpIn[20+ofs],udpIn[21+ofs],udpIn[22+ofs]));
|
selseg.setColor(1, RGBW32(udpIn[19+ofs],udpIn[20+ofs],udpIn[21+ofs],udpIn[22+ofs]));
|
||||||
selseg.setColor(2, RGBW32(udpIn[23+ofs],udpIn[24+ofs],udpIn[25+ofs],udpIn[26+ofs]));
|
selseg.setColor(2, RGBW32(udpIn[23+ofs],udpIn[24+ofs],udpIn[25+ofs],udpIn[26+ofs]));
|
||||||
@ -298,8 +312,10 @@ void parseNotifyPacket(uint8_t *udpIn) {
|
|||||||
// when applying synced options ignore selected as it may be used as indicator of which segments to sync
|
// when applying synced options ignore selected as it may be used as indicator of which segments to sync
|
||||||
// freeze, reset should never be synced
|
// 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)
|
// LSB to MSB: select, reverse, on, mirror, freeze, reset, reverse_y, mirror_y, transpose, map1d2d (3), ssim (2), set (2)
|
||||||
|
DEBUG_PRINT(F("Apply options: ")); DEBUG_PRINTLN(id);
|
||||||
selseg.options = (selseg.options & 0b0000000000110001U) | (udpIn[28+ofs]<<8) | (udpIn[9 +ofs] & 0b11001110U); // ignore selected, freeze, reset
|
selseg.options = (selseg.options & 0b0000000000110001U) | (udpIn[28+ofs]<<8) | (udpIn[9 +ofs] & 0b11001110U); // ignore selected, freeze, reset
|
||||||
if (applyEffects) {
|
if (applyEffects) {
|
||||||
|
DEBUG_PRINT(F("Apply sliders: ")); DEBUG_PRINTLN(id);
|
||||||
selseg.custom1 = udpIn[29+ofs];
|
selseg.custom1 = udpIn[29+ofs];
|
||||||
selseg.custom2 = udpIn[30+ofs];
|
selseg.custom2 = udpIn[30+ofs];
|
||||||
selseg.custom3 = udpIn[31+ofs] & 0x1F;
|
selseg.custom3 = udpIn[31+ofs] & 0x1F;
|
||||||
@ -307,14 +323,14 @@ void parseNotifyPacket(uint8_t *udpIn) {
|
|||||||
selseg.check1 = (udpIn[31+ofs]>>6) & 0x1;
|
selseg.check1 = (udpIn[31+ofs]>>6) & 0x1;
|
||||||
selseg.check1 = (udpIn[31+ofs]>>7) & 0x1;
|
selseg.check1 = (udpIn[31+ofs]>>7) & 0x1;
|
||||||
}
|
}
|
||||||
startY = (udpIn[32+ofs] << 8 | udpIn[33+ofs]);
|
|
||||||
stopY = (udpIn[34+ofs] << 8 | udpIn[35+ofs]);
|
|
||||||
}
|
}
|
||||||
if (receiveSegmentBounds) {
|
if (receiveSegmentBounds) {
|
||||||
|
DEBUG_PRINTF("Set segment w/ options: %d [%d,%d;%d,%d]\n", id, (int)start, (int)stop, (int)startY, (int)stopY);
|
||||||
// we have to use strip.setSegment() instead of selseg.setUp() to prevent crash if segment would change during drawing
|
// we have to use strip.setSegment() instead of selseg.setUp() to prevent crash if segment would change during drawing
|
||||||
strip.setSegment(id, start, stop, udpIn[5+ofs], udpIn[6+ofs], offset, startY, stopY);
|
strip.setSegment(id, start, stop, udpIn[5+ofs], udpIn[6+ofs], offset, startY, stopY);
|
||||||
} else {
|
} else {
|
||||||
// we have to use strip.setSegment() instead of selseg.setUp() to prevent crash if segment would change during drawing
|
// we have to use strip.setSegment() instead of selseg.setUp() to prevent crash if segment would change during drawing
|
||||||
|
DEBUG_PRINTF("Set segment grouping: %d [%d,%d]\n", id, (int)udpIn[5+ofs], (int)udpIn[6+ofs]);
|
||||||
strip.setSegment(id, selseg.start, selseg.stop, udpIn[5+ofs], udpIn[6+ofs], selseg.offset, selseg.startY, selseg.stopY);
|
strip.setSegment(id, selseg.start, selseg.stop, udpIn[5+ofs], udpIn[6+ofs], selseg.offset, selseg.startY, selseg.stopY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -365,10 +381,6 @@ void parseNotifyPacket(uint8_t *udpIn) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (version > 3) {
|
|
||||||
transitionDelayTemp = ((udpIn[17] << 0) & 0xFF) + ((udpIn[18] << 8) & 0xFF00);
|
|
||||||
}
|
|
||||||
|
|
||||||
nightlightActive = udpIn[6];
|
nightlightActive = udpIn[6];
|
||||||
if (nightlightActive) nightlightDelayMins = udpIn[7];
|
if (nightlightActive) nightlightDelayMins = udpIn[7];
|
||||||
|
|
||||||
|
@ -373,7 +373,7 @@ uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxL
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// extracts mode parameter defaults from last section of mode data (e.g. "Juggle@!,Trail;!,!,;!;sx=16,ix=240,1d")
|
// extracts mode parameter defaults from last section of mode data (e.g. "Juggle@!,Trail;!,!,;!;012;sx=16,ix=240")
|
||||||
int16_t extractModeDefaults(uint8_t mode, const char *segVar)
|
int16_t extractModeDefaults(uint8_t mode, const char *segVar)
|
||||||
{
|
{
|
||||||
if (mode < strip.getModeCount()) {
|
if (mode < strip.getModeCount()) {
|
||||||
|
@ -512,6 +512,16 @@ void WLED::setup()
|
|||||||
initServer();
|
initServer();
|
||||||
DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap());
|
DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap());
|
||||||
|
|
||||||
|
// Seed FastLED random functions with an esp random value, which already works properly at this point.
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32)
|
||||||
|
const uint32_t seed32 = esp_random();
|
||||||
|
#elif defined(ARDUINO_ARCH_ESP8266)
|
||||||
|
const uint32_t seed32 = RANDOM_REG32;
|
||||||
|
#else
|
||||||
|
const uint32_t seed32 = random(std::numeric_limits<long>::max());
|
||||||
|
#endif
|
||||||
|
random16_set_seed((uint16_t)((seed32 & 0xFFFF) ^ (seed32 >> 16)));
|
||||||
|
|
||||||
#if WLED_WATCHDOG_TIMEOUT > 0
|
#if WLED_WATCHDOG_TIMEOUT > 0
|
||||||
enableWatchdog();
|
enableWatchdog();
|
||||||
#endif
|
#endif
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// version code in format yymmddb (b = daily build)
|
// version code in format yymmddb (b = daily build)
|
||||||
#define VERSION 2311150
|
#define VERSION 2312160
|
||||||
|
|
||||||
//uncomment this if you have a "my_config.h" file you'd like to use
|
//uncomment this if you have a "my_config.h" file you'd like to use
|
||||||
//#define WLED_USE_MY_CONFIG
|
//#define WLED_USE_MY_CONFIG
|
||||||
@ -354,9 +354,6 @@ WLED_GLOBAL byte briS _INIT(128); // default brightness
|
|||||||
WLED_GLOBAL byte nightlightTargetBri _INIT(0); // brightness after nightlight is over
|
WLED_GLOBAL byte nightlightTargetBri _INIT(0); // brightness after nightlight is over
|
||||||
WLED_GLOBAL byte nightlightDelayMins _INIT(60);
|
WLED_GLOBAL byte nightlightDelayMins _INIT(60);
|
||||||
WLED_GLOBAL byte nightlightMode _INIT(NL_MODE_FADE); // See const.h for available modes. Was nightlightFade
|
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)
|
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)
|
||||||
|
|
||||||
@ -534,9 +531,11 @@ WLED_GLOBAL bool wasConnected _INIT(false);
|
|||||||
WLED_GLOBAL byte lastRandomIndex _INIT(0); // used to save last random color so the new one is not the same
|
WLED_GLOBAL byte lastRandomIndex _INIT(0); // used to save last random color so the new one is not the same
|
||||||
|
|
||||||
// transitions
|
// transitions
|
||||||
|
WLED_GLOBAL bool fadeTransition _INIT(true); // enable crossfading brightness/color
|
||||||
|
WLED_GLOBAL bool modeBlending _INIT(true); // enable effect blending
|
||||||
WLED_GLOBAL bool transitionActive _INIT(false);
|
WLED_GLOBAL bool transitionActive _INIT(false);
|
||||||
WLED_GLOBAL uint16_t transitionDelayDefault _INIT(transitionDelay); // default transition time (storec in cfg.json)
|
WLED_GLOBAL uint16_t transitionDelay _INIT(750); // global transition duration
|
||||||
WLED_GLOBAL uint16_t transitionDelayTemp _INIT(transitionDelay); // actual transition duration (overrides transitionDelay in certain cases)
|
WLED_GLOBAL uint16_t transitionDelayDefault _INIT(750); // default transition time (stored in cfg.json)
|
||||||
WLED_GLOBAL unsigned long transitionStartTime;
|
WLED_GLOBAL unsigned long transitionStartTime;
|
||||||
WLED_GLOBAL float tperLast _INIT(0.0f); // crossfade transition progress, 0.0f - 1.0f
|
WLED_GLOBAL float tperLast _INIT(0.0f); // crossfade transition progress, 0.0f - 1.0f
|
||||||
WLED_GLOBAL bool jsonTransitionOnce _INIT(false); // flag to override transitionDelay (playlist, JSON API: "live" & "seg":{"i"} & "tt")
|
WLED_GLOBAL bool jsonTransitionOnce _INIT(false); // flag to override transitionDelay (playlist, JSON API: "live" & "seg":{"i"} & "tt")
|
||||||
|
@ -183,7 +183,7 @@ void initServer()
|
|||||||
JsonObject root = doc.as<JsonObject>();
|
JsonObject root = doc.as<JsonObject>();
|
||||||
if (error || root.isNull()) {
|
if (error || root.isNull()) {
|
||||||
releaseJSONBufferLock();
|
releaseJSONBufferLock();
|
||||||
request->send(400, "application/json", F("{\"error\":9}")); // ERR_JSON
|
serveJsonError(request, 400, ERR_JSON);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (root.containsKey("pin")) checkSettingsPIN(root["pin"].as<const char*>());
|
if (root.containsKey("pin")) checkSettingsPIN(root["pin"].as<const char*>());
|
||||||
@ -201,8 +201,8 @@ void initServer()
|
|||||||
verboseResponse = deserializeState(root);
|
verboseResponse = deserializeState(root);
|
||||||
} else {
|
} else {
|
||||||
if (!correctPIN && strlen(settingsPIN)>0) {
|
if (!correctPIN && strlen(settingsPIN)>0) {
|
||||||
request->send(401, "application/json", F("{\"error\":1}")); // ERR_DENIED
|
|
||||||
releaseJSONBufferLock();
|
releaseJSONBufferLock();
|
||||||
|
serveJsonError(request, 401, ERR_DENIED);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
verboseResponse = deserializeConfig(root); //use verboseResponse to determine whether cfg change should be saved immediately
|
verboseResponse = deserializeConfig(root); //use verboseResponse to determine whether cfg change should be saved immediately
|
||||||
@ -509,6 +509,18 @@ void serveMessage(AsyncWebServerRequest* request, uint16_t code, const String& h
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void serveJsonError(AsyncWebServerRequest* request, uint16_t code, uint16_t error)
|
||||||
|
{
|
||||||
|
AsyncJsonResponse *response = new AsyncJsonResponse(64);
|
||||||
|
if (error < ERR_NOT_IMPL) response->addHeader("Retry-After", "1");
|
||||||
|
response->setContentType("application/json");
|
||||||
|
response->setCode(code);
|
||||||
|
JsonObject obj = response->getRoot();
|
||||||
|
obj[F("error")] = error;
|
||||||
|
response->setLength();
|
||||||
|
request->send(response);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef WLED_ENABLE_DMX
|
#ifdef WLED_ENABLE_DMX
|
||||||
String dmxProcessor(const String& var)
|
String dmxProcessor(const String& var)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user