Merge branch 'main' into usermod-battery-update2023

This commit is contained in:
Maximilian Mewes 2023-01-20 23:25:13 +01:00
commit 42c8a77755
77 changed files with 5435 additions and 5107 deletions

View File

@ -390,7 +390,8 @@ build_flags = ${common.build_flags} ${esp32s2.build_flags} #-D WLED_RELEASE_NAME
lib_deps = ${esp32s2.lib_deps} lib_deps = ${esp32s2.lib_deps}
[env:esp32c3] [env:esp32c3]
platform = espressif32@5.1.1 platform = espressif32@5.1.1 ;; well-tested on -C3, good compatibility with WLED
; platform = espressif32@~5.2.0 ;; might help in case you experience bootloops due to corrupted flash filesystem
framework = arduino framework = arduino
board = esp32-c3-devkitm-1 board = esp32-c3-devkitm-1
board_build.partitions = tools/WLED_ESP32_4MB_1MB_FS.csv board_build.partitions = tools/WLED_ESP32_4MB_1MB_FS.csv

View File

@ -92,12 +92,14 @@ class Animated_Staircase : public Usermod {
static const char _bottomEchoCm[]; static const char _bottomEchoCm[];
void publishMqtt(bool bottom, const char* state) { void publishMqtt(bool bottom, const char* state) {
#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 subuf[64]; char subuf[64];
sprintf_P(subuf, PSTR("%s/motion/%d"), mqttDeviceTopic, (int)bottom); sprintf_P(subuf, PSTR("%s/motion/%d"), mqttDeviceTopic, (int)bottom);
mqtt->publish(subuf, 0, false, state); mqtt->publish(subuf, 0, false, state);
} }
#endif
} }
void updateSegments() { void updateSegments() {
@ -345,6 +347,7 @@ class Animated_Staircase : public Usermod {
uint16_t getId() { return USERMOD_ID_ANIMATED_STAIRCASE; } uint16_t getId() { return USERMOD_ID_ANIMATED_STAIRCASE; }
#ifndef WLED_DISABLE_MQTT
/** /**
* handling of MQTT message * handling of MQTT message
* topic only contains stripped topic (part after /wled/MAC) * topic only contains stripped topic (part after /wled/MAC)
@ -382,6 +385,7 @@ class Animated_Staircase : public Usermod {
mqtt->subscribe(subuf, 0); mqtt->subscribe(subuf, 0);
} }
} }
#endif
void addToJsonState(JsonObject& root) { void addToJsonState(JsonObject& root) {
JsonObject staircase = root[FPSTR(_name)]; JsonObject staircase = root[FPSTR(_name)];

View File

@ -1,6 +1,10 @@
// force the compiler to show a warning to confirm that this file is included // force the compiler to show a warning to confirm that this file is included
#warning **** Included USERMOD_BH1750 **** #warning **** Included USERMOD_BH1750 ****
#ifndef WLED_ENABLE_MQTT
#error "This user mod requires MQTT to be enabled."
#endif
#pragma once #pragma once
#include "wled.h" #include "wled.h"
@ -156,6 +160,7 @@ public:
{ {
lastLux = lux; lastLux = lux;
lastSend = millis(); lastSend = millis();
#ifndef WLED_DISABLE_MQTT
if (WLED_MQTT_CONNECTED) if (WLED_MQTT_CONNECTED)
{ {
if (!mqttInitialized) if (!mqttInitialized)
@ -170,6 +175,7 @@ public:
{ {
DEBUG_PRINTLN(F("Missing MQTT connection. Not publishing data")); DEBUG_PRINTLN(F("Missing MQTT connection. Not publishing data"));
} }
#endif
} }
} }

View File

@ -1,6 +1,10 @@
// force the compiler to show a warning to confirm that this file is included // force the compiler to show a warning to confirm that this file is included
#warning **** Included USERMOD_BME280 version 2.0 **** #warning **** Included USERMOD_BME280 version 2.0 ****
#ifndef WLED_ENABLE_MQTT
#error "This user mod requires MQTT to be enabled."
#endif
#pragma once #pragma once
#include "wled.h" #include "wled.h"

View File

@ -194,6 +194,7 @@ class UsermodBattery : public Usermod
if (autoOffEnabled && (autoOffThreshold >= bat->getLevel())) if (autoOffEnabled && (autoOffThreshold >= bat->getLevel()))
turnOff(); turnOff();
#ifndef WLED_DISABLE_MQTT
// SmartHome stuff // SmartHome stuff
// still don't know much about MQTT and/or HA // still don't know much about MQTT and/or HA
if (WLED_MQTT_CONNECTED) { if (WLED_MQTT_CONNECTED) {
@ -201,6 +202,7 @@ class UsermodBattery : public Usermod
snprintf_P(buf, 63, PSTR("%s/voltage"), mqttDeviceTopic); snprintf_P(buf, 63, PSTR("%s/voltage"), mqttDeviceTopic);
mqtt->publish(buf, 0, false, String(voltage).c_str()); mqtt->publish(buf, 0, false, String(voltage).c_str());
} }
#endif
} }

View File

@ -1,6 +1,10 @@
#pragma once #pragma once
#include "wled.h" #include "wled.h"
#ifndef WLED_ENABLE_MQTT
#error "This user mod requires MQTT to be enabled."
#endif
#include <dht_nonblocking.h> #include <dht_nonblocking.h>

View File

@ -1,3 +1,7 @@
#ifndef WLED_ENABLE_MQTT
#error "This user mod requires MQTT to be enabled."
#endif
#include "wled.h" #include "wled.h"
#include <Arduino.h> #include <Arduino.h>
#include <U8x8lib.h> // from https://github.com/olikraus/u8g2/ #include <U8x8lib.h> // from https://github.com/olikraus/u8g2/

View File

@ -1,3 +1,7 @@
#ifndef WLED_ENABLE_MQTT
#error "This user mod requires MQTT to be enabled."
#endif
#include "wled.h" #include "wled.h"
#include <Arduino.h> #include <Arduino.h>
#include <U8x8lib.h> // from https://github.com/olikraus/u8g2/ #include <U8x8lib.h> // from https://github.com/olikraus/u8g2/

View File

@ -136,7 +136,7 @@ private:
} }
} else { } else {
if (m_offPreset) { if (m_offPreset) {
if (currentPreset==m_onPreset || currentPlaylist==m_onPreset) applyPreset(m_offPreset, NotifyUpdateMode); applyPreset(m_offPreset, NotifyUpdateMode);
return; return;
} else if (prevPlaylist) { } else if (prevPlaylist) {
if (currentPreset==m_onPreset || currentPlaylist==m_onPreset) applyPreset(prevPlaylist, NotifyUpdateMode); if (currentPreset==m_onPreset || currentPlaylist==m_onPreset) applyPreset(prevPlaylist, NotifyUpdateMode);
@ -159,6 +159,7 @@ private:
void publishMqtt(const char* state) void publishMqtt(const char* state)
{ {
#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 subuf[64]; char subuf[64];
@ -166,11 +167,13 @@ private:
strcat_P(subuf, PSTR("/motion")); strcat_P(subuf, PSTR("/motion"));
mqtt->publish(subuf, 0, false, state); mqtt->publish(subuf, 0, false, state);
} }
#endif
} }
// Create an MQTT Binary Sensor for Home Assistant Discovery purposes, this includes a pointer to the topic that is published to in the Loop. // Create an MQTT Binary Sensor for Home Assistant Discovery purposes, this includes a pointer to the topic that is published to in the Loop.
void publishHomeAssistantAutodiscovery() void publishHomeAssistantAutodiscovery()
{ {
#ifndef WLED_DISABLE_MQTT
if (WLED_MQTT_CONNECTED) { if (WLED_MQTT_CONNECTED) {
StaticJsonDocument<600> doc; StaticJsonDocument<600> doc;
char uid[24], json_str[1024], buf[128]; char uid[24], json_str[1024], buf[128];
@ -200,6 +203,7 @@ private:
mqtt->publish(buf, 0, true, json_str, payload_size); // do we really need to retain? mqtt->publish(buf, 0, true, json_str, payload_size); // do we really need to retain?
} }
#endif
} }
/** /**

View File

@ -109,6 +109,7 @@ public:
{ {
lastLDRValue = currentLDRValue; lastLDRValue = currentLDRValue;
#ifndef WLED_DISABLE_MQTT
if (WLED_MQTT_CONNECTED) if (WLED_MQTT_CONNECTED)
{ {
char subuf[45]; char subuf[45];
@ -121,6 +122,7 @@ public:
DEBUG_PRINTLN("Missing MQTT connection. Not publishing data"); DEBUG_PRINTLN("Missing MQTT connection. Not publishing data");
} }
} }
#endif
} }
uint16_t getLastLDRValue() uint16_t getLastLDRValue()

View File

@ -1,3 +1,7 @@
#ifndef WLED_ENABLE_MQTT
#error "This user mod requires MQTT to be enabled."
#endif
#pragma once #pragma once
// this is remixed from usermod_v2_SensorsToMqtt.h (sensors_to_mqtt usermod) // this is remixed from usermod_v2_SensorsToMqtt.h (sensors_to_mqtt usermod)

View File

@ -29,6 +29,7 @@ class UsermodTemperature : public Usermod {
bool degC = true; bool degC = true;
// using parasite power on the sensor // using parasite power on the sensor
bool parasite = false; bool parasite = false;
int8_t parasitePin = -1;
// how often do we read from sensor? // how often do we read from sensor?
unsigned long readingInterval = USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL; unsigned long readingInterval = USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL;
// set last reading as "40 sec before boot", so first reading is taken after 20 sec // set last reading as "40 sec before boot", so first reading is taken after 20 sec
@ -53,6 +54,7 @@ class UsermodTemperature : public Usermod {
static const char _enabled[]; static const char _enabled[];
static const char _readInterval[]; static const char _readInterval[];
static const char _parasite[]; static const char _parasite[];
static const char _parasitePin[];
//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() {
@ -94,12 +96,14 @@ class UsermodTemperature : public Usermod {
DEBUG_PRINTLN(F("Requesting temperature.")); DEBUG_PRINTLN(F("Requesting temperature."));
oneWire->reset(); oneWire->reset();
oneWire->skip(); // skip ROM oneWire->skip(); // skip ROM
oneWire->write(0x44,parasite); // request new temperature reading (TODO: parasite would need special handling) oneWire->write(0x44,parasite); // request new temperature reading
if (parasite && parasitePin >=0 ) digitalWrite(parasitePin, HIGH); // has to happen within 10us (open MOSFET)
lastTemperaturesRequest = millis(); lastTemperaturesRequest = millis();
waitingForConversion = true; waitingForConversion = true;
} }
void readTemperature() { void readTemperature() {
if (parasite && parasitePin >=0 ) digitalWrite(parasitePin, LOW); // deactivate power (close MOSFET)
temperature = readDallas(); temperature = readDallas();
lastMeasurement = millis(); lastMeasurement = millis();
waitingForConversion = false; waitingForConversion = false;
@ -134,6 +138,7 @@ class UsermodTemperature : public Usermod {
return false; return false;
} }
#ifndef WLED_DISABLE_MQTT
void publishHomeAssistantAutodiscovery() { void publishHomeAssistantAutodiscovery() {
if (!WLED_MQTT_CONNECTED) return; if (!WLED_MQTT_CONNECTED) return;
@ -155,6 +160,7 @@ class UsermodTemperature : public Usermod {
mqtt->publish(buf, 0, true, json_str, payload_size); mqtt->publish(buf, 0, true, json_str, payload_size);
HApublished = true; HApublished = true;
} }
#endif
public: public:
@ -173,6 +179,12 @@ class UsermodTemperature : public Usermod {
delay(25); // try to find sensor delay(25); // try to find sensor
} }
} }
if (parasite && pinManager.allocatePin(parasitePin, true, PinOwner::UM_Temperature)) {
pinMode(parasitePin, OUTPUT);
digitalWrite(parasitePin, LOW); // deactivate power (close MOSFET)
} else {
parasitePin = -1;
}
} else { } else {
if (temperaturePin >= 0) { if (temperaturePin >= 0) {
DEBUG_PRINTLN(F("Temperature pin allocation failed.")); DEBUG_PRINTLN(F("Temperature pin allocation failed."));
@ -212,6 +224,7 @@ class UsermodTemperature : public Usermod {
} }
errorCount = 0; errorCount = 0;
#ifndef WLED_DISABLE_MQTT
if (WLED_MQTT_CONNECTED) { if (WLED_MQTT_CONNECTED) {
char subuf[64]; char subuf[64];
strcpy(subuf, mqttDeviceTopic); strcpy(subuf, mqttDeviceTopic);
@ -227,6 +240,7 @@ class UsermodTemperature : public Usermod {
// publish something else to indicate status? // publish something else to indicate status?
} }
} }
#endif
} }
} }
@ -236,6 +250,7 @@ class UsermodTemperature : public Usermod {
*/ */
//void connected() {} //void connected() {}
#ifndef WLED_DISABLE_MQTT
/** /**
* subscribe to MQTT topic if needed * subscribe to MQTT topic if needed
*/ */
@ -246,6 +261,7 @@ class UsermodTemperature : public Usermod {
publishHomeAssistantAutodiscovery(); publishHomeAssistantAutodiscovery();
} }
} }
#endif
/* /*
* API calls te enable data exchange between WLED modules * API calls te enable data exchange between WLED modules
@ -315,6 +331,7 @@ class UsermodTemperature : public Usermod {
top["degC"] = degC; // usermodparam top["degC"] = degC; // usermodparam
top[FPSTR(_readInterval)] = readingInterval / 1000; top[FPSTR(_readInterval)] = readingInterval / 1000;
top[FPSTR(_parasite)] = parasite; top[FPSTR(_parasite)] = parasite;
top[FPSTR(_parasitePin)] = parasitePin;
DEBUG_PRINTLN(F("Temperature config saved.")); DEBUG_PRINTLN(F("Temperature config saved."));
} }
@ -340,6 +357,7 @@ class UsermodTemperature : public Usermod {
readingInterval = top[FPSTR(_readInterval)] | readingInterval/1000; readingInterval = top[FPSTR(_readInterval)] | readingInterval/1000;
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;
if (!initDone) { if (!initDone) {
// first run: reading from cfg.json // first run: reading from cfg.json
@ -354,12 +372,21 @@ class UsermodTemperature : public Usermod {
delete oneWire; delete oneWire;
pinManager.deallocatePin(temperaturePin, PinOwner::UM_Temperature); pinManager.deallocatePin(temperaturePin, PinOwner::UM_Temperature);
temperaturePin = newTemperaturePin; temperaturePin = newTemperaturePin;
pinManager.deallocatePin(parasitePin, PinOwner::UM_Temperature);
// initialise // initialise
setup(); setup();
} }
} }
// 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(_parasite)].isNull(); return !top[FPSTR(_parasitePin)].isNull();
}
void appendConfigData()
{
oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":")); oappend(String(FPSTR(_parasite)).c_str());
oappend(SET_F("',1,'<i>(if no Vcc connected)</i>');")); // 0 is field type, 1 is actual field
oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":")); oappend(String(FPSTR(_parasitePin)).c_str());
oappend(SET_F("',1,'<i>(for external MOSFET)</i>');")); // 0 is field type, 1 is actual field
} }
uint16_t getId() uint16_t getId()
@ -373,3 +400,4 @@ const char UsermodTemperature::_name[] PROGMEM = "Temperature";
const char UsermodTemperature::_enabled[] PROGMEM = "enabled"; 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";

View File

@ -101,6 +101,7 @@ void userLoop() {
if (temptimer - lastMeasure > 60000) if (temptimer - lastMeasure > 60000)
{ {
lastMeasure = temptimer; lastMeasure = temptimer;
#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 (mqtt != nullptr) if (mqtt != nullptr)
{ {
@ -116,6 +117,7 @@ void userLoop() {
t += "/temperature"; t += "/temperature";
mqtt->publish(t.c_str(), 0, true, String(board_temperature).c_str()); mqtt->publish(t.c_str(), 0, true, String(board_temperature).c_str());
} }
#endif
} }
// Check if we time interval for redrawing passes. // Check if we time interval for redrawing passes.

View File

@ -103,6 +103,7 @@ void userLoop() {
{ {
lastMeasure = tempTimer; lastMeasure = tempTimer;
#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 (mqtt != nullptr) if (mqtt != nullptr)
{ {
@ -122,6 +123,7 @@ void userLoop() {
h += "/humidity"; h += "/humidity";
mqtt->publish(h.c_str(), 0, true, String(board_humidity).c_str()); mqtt->publish(h.c_str(), 0, true, String(board_humidity).c_str());
} }
#endif
} }
// Check if we time interval for redrawing passes. // Check if we time interval for redrawing passes.

View File

@ -219,6 +219,7 @@ class BobLightUsermod : public Usermod {
void enable(bool en) { enabled = en; } void enable(bool en) { enabled = en; }
#ifndef WLED_DISABLE_MQTT
/** /**
* handling of MQTT message * handling of MQTT message
* topic only contains stripped topic (part after /wled/MAC) * topic only contains stripped topic (part after /wled/MAC)
@ -249,6 +250,7 @@ class BobLightUsermod : public Usermod {
// mqtt->subscribe(subuf, 0); // mqtt->subscribe(subuf, 0);
//} //}
} }
#endif
void addToJsonInfo(JsonObject& root) void addToJsonInfo(JsonObject& root)
{ {

View File

@ -66,12 +66,14 @@ class MultiRelay : public Usermod {
static const char _HAautodiscovery[]; static const char _HAautodiscovery[];
void publishMqtt(int relay) { void publishMqtt(int relay) {
#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 subuf[64]; char subuf[64];
sprintf_P(subuf, PSTR("%s/relay/%d"), mqttDeviceTopic, relay); sprintf_P(subuf, PSTR("%s/relay/%d"), mqttDeviceTopic, relay);
mqtt->publish(subuf, 0, false, _relay[relay].state ? "on" : "off"); mqtt->publish(subuf, 0, false, _relay[relay].state ? "on" : "off");
} }
#endif
} }
/** /**
@ -182,7 +184,7 @@ class MultiRelay : public Usermod {
*/ */
MultiRelay() { MultiRelay() {
const int8_t defPins[] = {MULTI_RELAY_PINS}; const int8_t defPins[] = {MULTI_RELAY_PINS};
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) { for (size_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
_relay[i].pin = i<sizeof(defPins) ? defPins[i] : -1; _relay[i].pin = i<sizeof(defPins) ? defPins[i] : -1;
_relay[i].delay = 0; _relay[i].delay = 0;
_relay[i].mode = false; _relay[i].mode = false;
@ -232,6 +234,7 @@ class MultiRelay : public Usermod {
//Functions called by WLED //Functions called by WLED
#ifndef WLED_DISABLE_MQTT
/** /**
* handling of MQTT message * handling of MQTT message
* topic only contains stripped topic (part after /wled/MAC) * topic only contains stripped topic (part after /wled/MAC)
@ -313,6 +316,7 @@ class MultiRelay : public Usermod {
mqtt->publish(buf, 0, true, json_str, payload_size); mqtt->publish(buf, 0, true, json_str, payload_size);
} }
} }
#endif
/** /**
* setup() is called once at boot. WiFi is not yet connected at this point. * setup() is called once at boot. WiFi is not yet connected at this point.

View File

@ -1,3 +1,7 @@
#ifndef WLED_ENABLE_MQTT
#error "This user mod requires MQTT to be enabled."
#endif
#pragma once #pragma once
#include "wled.h" #include "wled.h"

View File

@ -1,3 +1,7 @@
#ifndef WLED_ENABLE_MQTT
#error "This user mod requires MQTT to be enabled."
#endif
#pragma once #pragma once
#include "wled.h" #include "wled.h"

View File

@ -1,3 +1,7 @@
#ifndef WLED_ENABLE_MQTT
#error "This user mod requires MQTT to be enabled."
#endif
#pragma once #pragma once
#include "wled.h" #include "wled.h"

View File

@ -1,3 +1,7 @@
#ifndef WLED_ENABLE_MQTT
#error "This user mod requires MQTT to be enabled."
#endif
#pragma once #pragma once
#include "SHT85.h" #include "SHT85.h"

View File

@ -1,3 +1,7 @@
#ifndef WLED_ENABLE_MQTT
#error "This user mod requires MQTT to be enabled."
#endif
#pragma once #pragma once
#include "wled.h" #include "wled.h"

View File

@ -378,7 +378,7 @@ uint16_t scan(bool dual)
uint16_t size = 1 + ((SEGMENT.intensity * SEGLEN) >> 9); uint16_t size = 1 + ((SEGMENT.intensity * SEGLEN) >> 9);
uint16_t ledIndex = (prog * ((SEGLEN *2) - size *2)) >> 16; uint16_t ledIndex = (prog * ((SEGLEN *2) - size *2)) >> 16;
SEGMENT.fill(SEGCOLOR(1)); if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1));
int led_offset = ledIndex - (SEGLEN - size); int led_offset = ledIndex - (SEGLEN - size);
led_offset = abs(led_offset); led_offset = abs(led_offset);
@ -404,7 +404,7 @@ uint16_t scan(bool dual)
uint16_t mode_scan(void) { uint16_t mode_scan(void) {
return scan(false); return scan(false);
} }
static const char _data_FX_MODE_SCAN[] PROGMEM = "Scan@!,# of dots;!,!,!;!"; static const char _data_FX_MODE_SCAN[] PROGMEM = "Scan@!,# of dots,,,,,Overlay;!,!,!;!";
/* /*
@ -413,7 +413,7 @@ static const char _data_FX_MODE_SCAN[] PROGMEM = "Scan@!,# of dots;!,!,!;!";
uint16_t mode_dual_scan(void) { uint16_t mode_dual_scan(void) {
return scan(true); return scan(true);
} }
static const char _data_FX_MODE_DUAL_SCAN[] PROGMEM = "Scan Dual@!,# of dots;!,!,!;!"; static const char _data_FX_MODE_DUAL_SCAN[] PROGMEM = "Scan Dual@!,# of dots,,,,,Overlay;!,!,!;!";
/* /*
@ -530,6 +530,7 @@ uint16_t running_base(bool saw, bool dual=false) {
} }
SEGMENT.setPixelColor(i, ca); SEGMENT.setPixelColor(i, ca);
} }
return FRAMETIME; return FRAMETIME;
} }
@ -567,7 +568,6 @@ static const char _data_FX_MODE_SAW[] PROGMEM = "Saw@!,Width;!,!;!";
* Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
*/ */
uint16_t mode_twinkle(void) { uint16_t mode_twinkle(void) {
//SEGMENT.fill(SEGCOLOR(1));
SEGMENT.fade_out(224); SEGMENT.fade_out(224);
uint32_t cycleTime = 20 + (255 - SEGMENT.speed)*5; uint32_t cycleTime = 20 + (255 - SEGMENT.speed)*5;
@ -659,7 +659,7 @@ static const char _data_FX_MODE_DISSOLVE_RANDOM[] PROGMEM = "Dissolve Rnd@Repeat
* Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
*/ */
uint16_t mode_sparkle(void) { uint16_t mode_sparkle(void) {
for(int i = 0; i < SEGLEN; i++) { if (!SEGMENT.check2) for(int i = 0; i < SEGLEN; i++) {
SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1)); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1));
} }
uint32_t cycleTime = 10 + (255 - SEGMENT.speed)*2; uint32_t cycleTime = 10 + (255 - SEGMENT.speed)*2;
@ -673,7 +673,7 @@ uint16_t mode_sparkle(void) {
SEGMENT.setPixelColor(SEGENV.aux0, SEGCOLOR(0)); SEGMENT.setPixelColor(SEGENV.aux0, SEGCOLOR(0));
return FRAMETIME; return FRAMETIME;
} }
static const char _data_FX_MODE_SPARKLE[] PROGMEM = "Sparkle@!;!,!;!;;m12=0"; static const char _data_FX_MODE_SPARKLE[] PROGMEM = "Sparkle@!,,,,,,Overlay;!,!;!;;m12=0";
/* /*
@ -681,7 +681,7 @@ static const char _data_FX_MODE_SPARKLE[] PROGMEM = "Sparkle@!;!,!;!;;m12=0";
* Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
*/ */
uint16_t mode_flash_sparkle(void) { uint16_t mode_flash_sparkle(void) {
for(uint16_t i = 0; i < SEGLEN; i++) { if (!SEGMENT.check2) for(uint16_t i = 0; i < SEGLEN; i++) {
SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
} }
@ -694,7 +694,7 @@ uint16_t mode_flash_sparkle(void) {
} }
return FRAMETIME; return FRAMETIME;
} }
static const char _data_FX_MODE_FLASH_SPARKLE[] PROGMEM = "Sparkle Dark@!,!;Bg,Fx;!;;m12=0"; static const char _data_FX_MODE_FLASH_SPARKLE[] PROGMEM = "Sparkle Dark@!,!,,,,,Overlay;Bg,Fx;!;;m12=0";
/* /*
@ -702,7 +702,7 @@ static const char _data_FX_MODE_FLASH_SPARKLE[] PROGMEM = "Sparkle Dark@!,!;Bg,F
* Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
*/ */
uint16_t mode_hyper_sparkle(void) { uint16_t mode_hyper_sparkle(void) {
for (int i = 0; i < SEGLEN; i++) { if (!SEGMENT.check2) for (int i = 0; i < SEGLEN; i++) {
SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
} }
@ -717,7 +717,7 @@ uint16_t mode_hyper_sparkle(void) {
} }
return FRAMETIME; return FRAMETIME;
} }
static const char _data_FX_MODE_HYPER_SPARKLE[] PROGMEM = "Sparkle+@!,!;Bg,Fx;!;;m12=0"; static const char _data_FX_MODE_HYPER_SPARKLE[] PROGMEM = "Sparkle+@!,!,,,,,Overlay;Bg,Fx;!;;m12=0";
/* /*
@ -1366,12 +1366,11 @@ uint16_t police_base(uint32_t color1, uint32_t color2)
//Police Lights with custom colors //Police Lights with custom colors
uint16_t mode_two_dots() uint16_t mode_two_dots()
{ {
SEGMENT.fill(SEGCOLOR(2)); if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(2));
uint32_t color2 = (SEGCOLOR(1) == SEGCOLOR(2)) ? SEGCOLOR(0) : SEGCOLOR(1); uint32_t color2 = (SEGCOLOR(1) == SEGCOLOR(2)) ? SEGCOLOR(0) : SEGCOLOR(1);
return police_base(SEGCOLOR(0), color2); return police_base(SEGCOLOR(0), color2);
} }
static const char _data_FX_MODE_TWO_DOTS[] PROGMEM = "Two Dots@!,Dot size;1,2,Bg;!"; static const char _data_FX_MODE_TWO_DOTS[] PROGMEM = "Two Dots@!,Dot size,,,,,Overlay;1,2,Bg;!";
/* /*
@ -1549,7 +1548,7 @@ uint16_t mode_icu(void) {
uint16_t dest = SEGENV.step & 0xFFFF; uint16_t dest = SEGENV.step & 0xFFFF;
uint8_t space = (SEGMENT.intensity >> 3) +2; uint8_t space = (SEGMENT.intensity >> 3) +2;
SEGMENT.fill(SEGCOLOR(1)); if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1));
byte pindex = map(dest, 0, SEGLEN-SEGLEN/space, 0, 255); byte pindex = map(dest, 0, SEGLEN-SEGLEN/space, 0, 255);
uint32_t col = SEGMENT.color_from_palette(pindex, false, false, 0); uint32_t col = SEGMENT.color_from_palette(pindex, false, false, 0);
@ -1580,7 +1579,7 @@ uint16_t mode_icu(void) {
return SPEED_FORMULA_L; return SPEED_FORMULA_L;
} }
static const char _data_FX_MODE_ICU[] PROGMEM = "ICU@!,!;!,!;!"; static const char _data_FX_MODE_ICU[] PROGMEM = "ICU@!,!,,,,,Overlay;!,!;!";
/* /*
@ -1823,7 +1822,7 @@ uint16_t mode_lightning(void)
SEGENV.aux0 = 200; //200ms delay after leader SEGENV.aux0 = 200; //200ms delay after leader
} }
SEGMENT.fill(SEGCOLOR(1)); if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1));
if (SEGENV.aux1 > 3 && !(SEGENV.aux1 & 0x01)) { //flash on even number >2 if (SEGENV.aux1 > 3 && !(SEGENV.aux1 & 0x01)) { //flash on even number >2
for (int i = ledstart; i < ledstart + ledlen; i++) for (int i = ledstart; i < ledstart + ledlen; i++)
@ -1848,7 +1847,7 @@ uint16_t mode_lightning(void)
} }
return FRAMETIME; return FRAMETIME;
} }
static const char _data_FX_MODE_LIGHTNING[] PROGMEM = "Lightning@!,!;!,!;!"; static const char _data_FX_MODE_LIGHTNING[] PROGMEM = "Lightning@!,!,,,,,Overlay;!,!;!";
// Pride2015 // Pride2015
@ -1892,6 +1891,7 @@ uint16_t mode_pride_2015(void)
} }
SEGENV.step = sPseudotime; SEGENV.step = sPseudotime;
SEGENV.aux0 = sHue16; SEGENV.aux0 = sHue16;
return FRAMETIME; return FRAMETIME;
} }
static const char _data_FX_MODE_PRIDE_2015[] PROGMEM = "Pride 2015@!;;"; static const char _data_FX_MODE_PRIDE_2015[] PROGMEM = "Pride 2015@!;;";
@ -1929,9 +1929,10 @@ uint16_t mode_palette()
uint8_t colorIndex = (i * 255 / SEGLEN) - counter; uint8_t colorIndex = (i * 255 / SEGLEN) - counter;
SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(colorIndex, false, noWrap, 255)); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(colorIndex, false, noWrap, 255));
} }
return FRAMETIME; return FRAMETIME;
} }
static const char _data_FX_MODE_PALETTE[] PROGMEM = "Palette@Cycle speed;;!"; static const char _data_FX_MODE_PALETTE[] PROGMEM = "Palette@Cycle speed;;!;;c3=0,o2=0";
// WLED limitation: Analog Clock overlay will NOT work when Fire2012 is active // WLED limitation: Analog Clock overlay will NOT work when Fire2012 is active
@ -2069,6 +2070,7 @@ uint16_t mode_colorwaves()
} }
SEGENV.step = sPseudotime; SEGENV.step = sPseudotime;
SEGENV.aux0 = sHue16; SEGENV.aux0 = sHue16;
return FRAMETIME; return FRAMETIME;
} }
static const char _data_FX_MODE_COLORWAVES[] PROGMEM = "Colorwaves@!,Hue;!;!"; static const char _data_FX_MODE_COLORWAVES[] PROGMEM = "Colorwaves@!,Hue;!;!";
@ -2085,6 +2087,7 @@ uint16_t mode_bpm()
//SEGMENT.setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue); //SEGMENT.setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(stp + (i * 2), false, PALETTE_SOLID_WRAP, 0, beat - stp + (i * 10))); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(stp + (i * 2), false, PALETTE_SOLID_WRAP, 0, beat - stp + (i * 10)));
} }
return FRAMETIME; return FRAMETIME;
} }
static const char _data_FX_MODE_BPM[] PROGMEM = "Bpm@!;!;!;;sx=64"; static const char _data_FX_MODE_BPM[] PROGMEM = "Bpm@!;!;!;;sx=64";
@ -2267,6 +2270,7 @@ uint16_t mode_lake() {
//SEGMENT.setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue); //SEGMENT.setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, false, 0, lum)); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, false, 0, lum));
} }
return FRAMETIME; return FRAMETIME;
} }
static const char _data_FX_MODE_LAKE[] PROGMEM = "Lake@!;Fx;!"; static const char _data_FX_MODE_LAKE[] PROGMEM = "Lake@!;Fx;!";
@ -2396,7 +2400,7 @@ typedef struct Ripple {
#else #else
#define MAX_RIPPLES 100 #define MAX_RIPPLES 100
#endif #endif
uint16_t ripple_base(bool rainbow) uint16_t ripple_base()
{ {
uint16_t maxRipples = min(1 + (SEGLEN >> 2), MAX_RIPPLES); // 56 max for 16 segment ESP8266 uint16_t maxRipples = min(1 + (SEGLEN >> 2), MAX_RIPPLES); // 56 max for 16 segment ESP8266
uint16_t dataSize = sizeof(ripple) * maxRipples; uint16_t dataSize = sizeof(ripple) * maxRipples;
@ -2405,80 +2409,74 @@ uint16_t ripple_base(bool rainbow)
Ripple* ripples = reinterpret_cast<Ripple*>(SEGENV.data); Ripple* ripples = reinterpret_cast<Ripple*>(SEGENV.data);
// ranbow background or chosen background, all very dim.
if (rainbow) {
if (SEGENV.call ==0) {
SEGENV.aux0 = random8();
SEGENV.aux1 = random8();
}
if (SEGENV.aux0 == SEGENV.aux1) {
SEGENV.aux1 = random8();
}
else if (SEGENV.aux1 > SEGENV.aux0) {
SEGENV.aux0++;
} else {
SEGENV.aux0--;
}
SEGMENT.fill(color_blend(SEGMENT.color_wheel(SEGENV.aux0),BLACK,235));
} else {
SEGMENT.fill(SEGCOLOR(1));
}
//draw wave //draw wave
for (int i = 0; i < maxRipples; i++) for (int i = 0; i < maxRipples; i++) {
{
uint16_t ripplestate = ripples[i].state; uint16_t ripplestate = ripples[i].state;
if (ripplestate) if (ripplestate) {
{
uint8_t rippledecay = (SEGMENT.speed >> 4) +1; //faster decay if faster propagation uint8_t rippledecay = (SEGMENT.speed >> 4) +1; //faster decay if faster propagation
uint16_t rippleorigin = ripples[i].pos; uint16_t rippleorigin = ripples[i].pos;
uint32_t col = SEGMENT.color_from_palette(ripples[i].color, false, false, 255); uint32_t col = SEGMENT.color_from_palette(ripples[i].color, false, false, 255);
uint16_t propagation = ((ripplestate/rippledecay -1) * SEGMENT.speed); uint16_t propagation = ((ripplestate/rippledecay - 1) * (SEGMENT.speed + 1));
int16_t propI = propagation >> 8; int16_t propI = propagation >> 8;
uint8_t propF = propagation & 0xFF; uint8_t propF = propagation & 0xFF;
int16_t left = rippleorigin - propI -1;
uint8_t amp = (ripplestate < 17) ? triwave8((ripplestate-1)*8) : map(ripplestate,17,255,255,2); uint8_t amp = (ripplestate < 17) ? triwave8((ripplestate-1)*8) : map(ripplestate,17,255,255,2);
for (int16_t v = left; v < left +4; v++) #ifndef WLED_DISABLE_2D
if (SEGMENT.is2D()) {
uint16_t cx = rippleorigin >> 8;
uint16_t cy = rippleorigin & 0xFF;
uint8_t mag = scale8(cubicwave8((propF>>2)), amp);
if (propI > 0) SEGMENT.draw_circle(cx, cy, propI, color_blend(SEGMENT.getPixelColorXY(cx + propI, cy), col, mag));
} else
#endif
{ {
int16_t left = rippleorigin - propI -1;
for (int16_t v = left; v < left +4; v++) {
uint8_t mag = scale8(cubicwave8((propF>>2)+(v-left)*64), amp); uint8_t mag = scale8(cubicwave8((propF>>2)+(v-left)*64), amp);
if (v < SEGLEN && v >= 0)
{
SEGMENT.setPixelColor(v, color_blend(SEGMENT.getPixelColor(v), col, mag)); // TODO SEGMENT.setPixelColor(v, color_blend(SEGMENT.getPixelColor(v), col, mag)); // TODO
}
int16_t w = left + propI*2 + 3 -(v-left); int16_t w = left + propI*2 + 3 -(v-left);
if (w < SEGLEN && w >= 0)
{
SEGMENT.setPixelColor(w, color_blend(SEGMENT.getPixelColor(w), col, mag)); // TODO SEGMENT.setPixelColor(w, color_blend(SEGMENT.getPixelColor(w), col, mag)); // TODO
} }
} }
ripplestate += rippledecay; ripplestate += rippledecay;
ripples[i].state = (ripplestate > 254) ? 0 : ripplestate; ripples[i].state = (ripplestate > 254) ? 0 : ripplestate;
} else //randomly create new wave } else {//randomly create new wave
{ if (random16(IBN + 10000) <= SEGMENT.intensity) {
if (random16(IBN + 10000) <= SEGMENT.intensity)
{
ripples[i].state = 1; ripples[i].state = 1;
ripples[i].pos = random16(SEGLEN); ripples[i].pos = SEGMENT.is2D() ? ((random8(SEGENV.virtualWidth())<<8) | (random8(SEGENV.virtualHeight()))) : random16(SEGLEN);
ripples[i].color = random8(); //color ripples[i].color = random8(); //color
} }
} }
} }
return FRAMETIME; return FRAMETIME;
} }
#undef MAX_RIPPLES #undef MAX_RIPPLES
uint16_t mode_ripple(void) { uint16_t mode_ripple(void) {
return ripple_base(false); if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1));
return ripple_base();
} }
static const char _data_FX_MODE_RIPPLE[] PROGMEM = "Ripple@!,Wave #;,!;!"; static const char _data_FX_MODE_RIPPLE[] PROGMEM = "Ripple@!,Wave #,,,,,Overlay;,!;!;12";
uint16_t mode_ripple_rainbow(void) { uint16_t mode_ripple_rainbow(void) {
return ripple_base(true); if (SEGENV.call ==0) {
SEGENV.aux0 = random8();
SEGENV.aux1 = random8();
}
if (SEGENV.aux0 == SEGENV.aux1) {
SEGENV.aux1 = random8();
} else if (SEGENV.aux1 > SEGENV.aux0) {
SEGENV.aux0++;
} else {
SEGENV.aux0--;
}
SEGMENT.fill(color_blend(SEGMENT.color_wheel(SEGENV.aux0),BLACK,235));
return ripple_base();
} }
static const char _data_FX_MODE_RIPPLE_RAINBOW[] PROGMEM = "Ripple Rainbow@!,Wave #;;!"; static const char _data_FX_MODE_RIPPLE_RAINBOW[] PROGMEM = "Ripple Rainbow@!,Wave #;;!;12";
// TwinkleFOX by Mark Kriegsman: https://gist.github.com/kriegsman/756ea6dcae8e30845b5a // TwinkleFOX by Mark Kriegsman: https://gist.github.com/kriegsman/756ea6dcae8e30845b5a
@ -2634,7 +2632,7 @@ uint16_t mode_halloween_eyes()
uint16_t eyeLength = (2*HALLOWEEN_EYE_WIDTH) + HALLOWEEN_EYE_SPACE; uint16_t eyeLength = (2*HALLOWEEN_EYE_WIDTH) + HALLOWEEN_EYE_SPACE;
if (eyeLength >= maxWidth) return mode_static(); //bail if segment too short if (eyeLength >= maxWidth) return mode_static(); //bail if segment too short
SEGMENT.fill(SEGCOLOR(1)); //fill background if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1)); //fill background
uint8_t state = SEGENV.aux1 >> 8; uint8_t state = SEGENV.aux1 >> 8;
uint16_t stateTime = SEGENV.call; uint16_t stateTime = SEGENV.call;
@ -2684,7 +2682,7 @@ uint16_t mode_halloween_eyes()
return FRAMETIME; return FRAMETIME;
} }
static const char _data_FX_MODE_HALLOWEEN_EYES[] PROGMEM = "Halloween Eyes@Duration,Eye fade time;!,!;!;12"; static const char _data_FX_MODE_HALLOWEEN_EYES[] PROGMEM = "Halloween Eyes@Duration,Eye fade time,,,,,Overlay;!,!;!;12";
//Speed slider sets amount of LEDs lit, intensity sets unlit //Speed slider sets amount of LEDs lit, intensity sets unlit
@ -2737,7 +2735,7 @@ static const char _data_FX_MODE_TRI_STATIC_PATTERN[] PROGMEM = "Solid Pattern Tr
uint16_t spots_base(uint16_t threshold) uint16_t spots_base(uint16_t threshold)
{ {
SEGMENT.fill(SEGCOLOR(1)); if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1));
uint16_t maxZones = SEGLEN >> 2; uint16_t maxZones = SEGLEN >> 2;
uint16_t zones = 1 + ((SEGMENT.intensity * maxZones) >> 8); uint16_t zones = 1 + ((SEGMENT.intensity * maxZones) >> 8);
@ -2767,7 +2765,7 @@ uint16_t mode_spots()
{ {
return spots_base((255 - SEGMENT.speed) << 8); return spots_base((255 - SEGMENT.speed) << 8);
} }
static const char _data_FX_MODE_SPOTS[] PROGMEM = "Spots@,Width;!,!;!"; static const char _data_FX_MODE_SPOTS[] PROGMEM = "Spots@,Width,,,,,Overlay;!,!;!";
//Intensity slider sets number of "lights", LEDs per light fade in and out //Intensity slider sets number of "lights", LEDs per light fade in and out
@ -2778,7 +2776,7 @@ uint16_t mode_spots_fade()
uint16_t tr = (t >> 1) + (t >> 2); uint16_t tr = (t >> 1) + (t >> 2);
return spots_base(tr); return spots_base(tr);
} }
static const char _data_FX_MODE_SPOTS_FADE[] PROGMEM = "Spots Fade@Spread,Width;!,!;!"; static const char _data_FX_MODE_SPOTS_FADE[] PROGMEM = "Spots Fade@Spread,Width,,,,,Overlay;!,!;!";
//each needs 12 bytes //each needs 12 bytes
@ -2800,7 +2798,7 @@ uint16_t mode_bouncing_balls(void) {
Ball* balls = reinterpret_cast<Ball*>(SEGENV.data); Ball* balls = reinterpret_cast<Ball*>(SEGENV.data);
SEGMENT.fill(SEGCOLOR(2) ? BLACK : SEGCOLOR(1)); if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(2) ? BLACK : SEGCOLOR(1));
// virtualStrip idea by @ewowi (Ewoud Wijma) // virtualStrip idea by @ewowi (Ewoud Wijma)
// requires virtual strip # to be embedded into upper 16 bits of index in setPixelColor() // requires virtual strip # to be embedded into upper 16 bits of index in setPixelColor()
@ -2857,7 +2855,7 @@ uint16_t mode_bouncing_balls(void) {
return FRAMETIME; return FRAMETIME;
} }
static const char _data_FX_MODE_BOUNCINGBALLS[] PROGMEM = "Bouncing Balls@Gravity,# of balls;!,!,!;!;1;m12=1"; //bar static const char _data_FX_MODE_BOUNCINGBALLS[] PROGMEM = "Bouncing Balls@Gravity,# of balls,,,,,Overlay;!,!,!;!;1;m12=1"; //bar
/* /*
@ -2915,19 +2913,35 @@ uint16_t mode_sinelon_rainbow(void) {
static const char _data_FX_MODE_SINELON_RAINBOW[] PROGMEM = "Sinelon Rainbow@!,Trail;,,!;!"; static const char _data_FX_MODE_SINELON_RAINBOW[] PROGMEM = "Sinelon Rainbow@!,Trail;,,!;!";
//Rainbow with glitter, inspired by https://gist.github.com/kriegsman/062e10f7f07ba8518af6 // utility function that will add random glitter to SEGMENT
void glitter_base(uint8_t intensity, uint32_t col = ULTRAWHITE) {
if (intensity > random8()) {
if (SEGMENT.is2D()) {
SEGMENT.setPixelColorXY(random16(SEGMENT.virtualWidth()),random16(SEGMENT.virtualHeight()), col);
} else {
SEGMENT.setPixelColor(random16(SEGLEN), col);
}
}
}
//Glitter with palette background, inspired by https://gist.github.com/kriegsman/062e10f7f07ba8518af6
uint16_t mode_glitter() uint16_t mode_glitter()
{ {
mode_palette(); if (!SEGMENT.check2) mode_palette(); // use "* Color 1" palette for solid background (replacing "Solid glitter")
glitter_base(SEGMENT.intensity, SEGCOLOR(2) ? SEGCOLOR(2) : ULTRAWHITE);
if (SEGMENT.intensity > random8())
{
SEGMENT.setPixelColor(random16(SEGLEN), ULTRAWHITE);
}
return FRAMETIME; return FRAMETIME;
} }
static const char _data_FX_MODE_GLITTER[] PROGMEM = "Glitter@!,!;;!;;m12=0"; //pixels static const char _data_FX_MODE_GLITTER[] PROGMEM = "Glitter@!,!,,,,,Overlay;1,2,Glitter color;!;;pal=0,m12=0"; //pixels
//Solid colour background with glitter
uint16_t mode_solid_glitter()
{
SEGMENT.fill(SEGCOLOR(0));
glitter_base(SEGMENT.intensity, SEGCOLOR(2) ? SEGCOLOR(2) : ULTRAWHITE);
return FRAMETIME;
}
static const char _data_FX_MODE_SOLID_GLITTER[] PROGMEM = "Solid Glitter@,!;Bg,,Glitter color;;;m12=0";
//each needs 19 bytes //each needs 19 bytes
@ -2953,7 +2967,7 @@ uint16_t mode_popcorn(void) {
Spark* popcorn = reinterpret_cast<Spark*>(SEGENV.data); Spark* popcorn = reinterpret_cast<Spark*>(SEGENV.data);
bool hasCol2 = SEGCOLOR(2); bool hasCol2 = SEGCOLOR(2);
SEGMENT.fill(hasCol2 ? BLACK : SEGCOLOR(1)); if (!SEGMENT.check2) SEGMENT.fill(hasCol2 ? BLACK : SEGCOLOR(1));
struct virtualStrip { struct virtualStrip {
static void runStrip(uint16_t stripNr, Spark* popcorn) { static void runStrip(uint16_t stripNr, Spark* popcorn) {
@ -3000,7 +3014,7 @@ uint16_t mode_popcorn(void) {
return FRAMETIME; return FRAMETIME;
} }
static const char _data_FX_MODE_POPCORN[] PROGMEM = "Popcorn@!,!;!,!,!;!;;m12=1"; //bar static const char _data_FX_MODE_POPCORN[] PROGMEM = "Popcorn@!,!,,,,,Overlay;!,!,!;!;;m12=1"; //bar
//values close to 100 produce 5Hz flicker, which looks very candle-y //values close to 100 produce 5Hz flicker, which looks very candle-y
@ -3162,7 +3176,7 @@ uint16_t mode_starburst(void) {
} }
} }
SEGMENT.fill(SEGCOLOR(1)); if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1));
for (int j=0; j<numStars; j++) for (int j=0; j<numStars; j++)
{ {
@ -3227,7 +3241,7 @@ uint16_t mode_starburst(void) {
return FRAMETIME; return FRAMETIME;
} }
#undef STARBURST_MAX_FRAG #undef STARBURST_MAX_FRAG
static const char _data_FX_MODE_STARBURST[] PROGMEM = "Fireworks Starburst@Chance,Fragments;,!;!;;pal=11,m12=0"; static const char _data_FX_MODE_STARBURST[] PROGMEM = "Fireworks Starburst@Chance,Fragments,,,,,Overlay;,!;!;;pal=11,m12=0";
/* /*
@ -3258,7 +3272,6 @@ uint16_t mode_exploding_fireworks(void)
SEGENV.aux1 = dataSize; SEGENV.aux1 = dataSize;
} }
//SEGMENT.fill(BLACK);
SEGMENT.fade_out(252); SEGMENT.fade_out(252);
Spark* sparks = reinterpret_cast<Spark*>(SEGENV.data); Spark* sparks = reinterpret_cast<Spark*>(SEGENV.data);
@ -3379,7 +3392,7 @@ uint16_t mode_drip(void)
if (!SEGENV.allocateData(dataSize * strips)) return mode_static(); //allocation failed if (!SEGENV.allocateData(dataSize * strips)) return mode_static(); //allocation failed
Spark* drops = reinterpret_cast<Spark*>(SEGENV.data); Spark* drops = reinterpret_cast<Spark*>(SEGENV.data);
SEGMENT.fill(SEGCOLOR(1)); if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1));
struct virtualStrip { struct virtualStrip {
static void runStrip(uint16_t stripNr, Spark* drops) { static void runStrip(uint16_t stripNr, Spark* drops) {
@ -3449,7 +3462,7 @@ uint16_t mode_drip(void)
return FRAMETIME; return FRAMETIME;
} }
static const char _data_FX_MODE_DRIP[] PROGMEM = "Drip@Gravity,# of drips;!,!;!;;m12=1"; //bar static const char _data_FX_MODE_DRIP[] PROGMEM = "Drip@Gravity,# of drips,,,,,Overlay;!,!;!;;m12=1"; //bar
/* /*
@ -3472,7 +3485,7 @@ uint16_t mode_tetrix(void) {
if (!SEGENV.allocateData(dataSize * strips)) return mode_static(); //allocation failed if (!SEGENV.allocateData(dataSize * strips)) return mode_static(); //allocation failed
Tetris* drops = reinterpret_cast<Tetris*>(SEGENV.data); Tetris* drops = reinterpret_cast<Tetris*>(SEGENV.data);
if (SEGENV.call == 0) SEGMENT.fill(SEGCOLOR(1)); // will fill entire segment (1D or 2D) //if (SEGENV.call == 0) SEGMENT.fill(SEGCOLOR(1)); // will fill entire segment (1D or 2D), then use drop->step = 0 below
// virtualStrip idea by @ewowi (Ewoud Wijma) // virtualStrip idea by @ewowi (Ewoud Wijma)
// requires virtual strip # to be embedded into upper 16 bits of index in setPixelcolor() // requires virtual strip # to be embedded into upper 16 bits of index in setPixelcolor()
@ -3482,9 +3495,8 @@ uint16_t mode_tetrix(void) {
// initialize dropping on first call or segment full // initialize dropping on first call or segment full
if (SEGENV.call == 0) { if (SEGENV.call == 0) {
drop->stack = 0; // reset brick stack size drop->stack = 0; // reset brick stack size
drop->step = 0; drop->step = millis() + 2000; // start by fading out strip
if (SEGMENT.check1) drop->col = 0;// use only one color from palette if (SEGMENT.check1) drop->col = 0;// use only one color from palette
//for (int i=0; i<SEGLEN; i++) SEGMENT.setPixelColor(indexToVStrip(i, stripNr), SEGCOLOR(1)); // will fill virtual strip only
} }
if (drop->step == 0) { // init brick if (drop->step == 0) { // init brick
@ -3772,21 +3784,6 @@ uint16_t mode_pacifica()
static const char _data_FX_MODE_PACIFICA[] PROGMEM = "Pacifica@!,Angle;;!;;pal=51"; static const char _data_FX_MODE_PACIFICA[] PROGMEM = "Pacifica@!,Angle;;!;;pal=51";
//Solid colour background with glitter
uint16_t mode_solid_glitter()
{
SEGMENT.fill(SEGCOLOR(0));
if (SEGMENT.intensity > random8())
{
SEGMENT.setPixelColor(random16(SEGLEN), ULTRAWHITE);
}
return FRAMETIME;
}
static const char _data_FX_MODE_SOLID_GLITTER[] PROGMEM = "Solid Glitter@,!;!;;;m12=0";
/* /*
* Mode simulates a gradual sunrise * Mode simulates a gradual sunrise
*/ */
@ -3800,7 +3797,7 @@ uint16_t mode_sunrise() {
SEGENV.aux0 = SEGMENT.speed; SEGENV.aux0 = SEGMENT.speed;
} }
SEGMENT.fill(0); SEGMENT.fill(BLACK);
uint16_t stage = 0xFFFF; uint16_t stage = 0xFFFF;
uint32_t s10SinceStart = (millis() - SEGENV.step) /100; //tenths of seconds uint32_t s10SinceStart = (millis() - SEGENV.step) /100; //tenths of seconds
@ -4001,7 +3998,6 @@ static const char _data_FX_MODE_FLOW[] PROGMEM = "Flow@!,Zones;;!;;m12=1"; //ver
*/ */
uint16_t mode_chunchun(void) uint16_t mode_chunchun(void)
{ {
//SEGMENT.fill(SEGCOLOR(1));
SEGMENT.fade_out(254); // add a bit of trail SEGMENT.fade_out(254); // add a bit of trail
uint16_t counter = strip.now * (6 + (SEGMENT.speed >> 4)); uint16_t counter = strip.now * (6 + (SEGMENT.speed >> 4));
uint16_t numBirds = 2 + (SEGLEN >> 3); // 2 + 1/8 of a segment uint16_t numBirds = 2 + (SEGLEN >> 3); // 2 + 1/8 of a segment
@ -4629,8 +4625,8 @@ uint16_t mode_2DColoredBursts() { // By: ldirko https://editor.so
SEGENV.aux0 = 0; // start with red hue SEGENV.aux0 = 0; // start with red hue
} }
bool dot = false; bool dot = SEGMENT.check3;
bool grad = true; bool grad = SEGMENT.check1;
byte numLines = SEGMENT.intensity/16 + 1; byte numLines = SEGMENT.intensity/16 + 1;
@ -4646,24 +4642,26 @@ uint16_t mode_2DColoredBursts() { // By: ldirko https://editor.so
byte xsteps = abs8(x1 - y1) + 1; byte xsteps = abs8(x1 - y1) + 1;
byte ysteps = abs8(x2 - y2) + 1; byte ysteps = abs8(x2 - y2) + 1;
byte steps = xsteps >= ysteps ? xsteps : ysteps; byte steps = xsteps >= ysteps ? xsteps : ysteps;
//Draw gradient line
for (size_t i = 1; i <= steps; i++) { for (size_t i = 1; i <= steps; i++) {
byte dx = lerp8by8(x1, y1, i * 255 / steps); uint8_t rate = i * 255 / steps;
byte dy = lerp8by8(x2, y2, i * 255 / steps); byte dx = lerp8by8(x1, y1, rate);
byte dy = lerp8by8(x2, y2, rate);
//SEGMENT.setPixelColorXY(dx, dy, grad ? color.nscale8_video(255-rate) : color); // use addPixelColorXY for different look
SEGMENT.addPixelColorXY(dx, dy, color); // use setPixelColorXY for different look SEGMENT.addPixelColorXY(dx, dy, color); // use setPixelColorXY for different look
if (grad) SEGMENT.fadePixelColorXY(dx, dy, (i * 255 / steps)); //Draw gradient line if (grad) SEGMENT.fadePixelColorXY(dx, dy, rate);
} }
if (dot) { //add white point at the ends of line if (dot) { //add white point at the ends of line
SEGMENT.addPixelColorXY(x1, x2, WHITE); SEGMENT.setPixelColorXY(x1, x2, WHITE);
SEGMENT.addPixelColorXY(y1, y2, WHITE); SEGMENT.setPixelColorXY(y1, y2, DARKSLATEGRAY);
} }
} }
SEGMENT.blur(4); if (SEGMENT.custom3) SEGMENT.blur(SEGMENT.custom3/2);
return FRAMETIME; return FRAMETIME;
} // mode_2DColoredBursts() } // mode_2DColoredBursts()
static const char _data_FX_MODE_2DCOLOREDBURSTS[] PROGMEM = "Colored Bursts@Speed,# of lines;;!;2"; static const char _data_FX_MODE_2DCOLOREDBURSTS[] PROGMEM = "Colored Bursts@Speed,# of lines,,,Blur,Gradient,,Dots;;!;2;c3=16";
///////////////////// /////////////////////
@ -4705,10 +4703,9 @@ uint16_t mode_2DDNASpiral() { // By: ldirko https://editor.soulma
if (SEGENV.call == 0) { if (SEGENV.call == 0) {
SEGMENT.setUpLeds(); SEGMENT.setUpLeds();
SEGMENT.fill(BLACK); SEGMENT.fill(BLACK);
SEGENV.aux0 = 0; // hue
} }
uint8_t speeds = SEGMENT.speed/2; uint8_t speeds = SEGMENT.speed/2 + 1;
uint8_t freq = SEGMENT.intensity/8; uint8_t freq = SEGMENT.intensity/8;
uint32_t ms = millis() / 20; uint32_t ms = millis() / 20;
@ -4717,17 +4714,21 @@ uint16_t mode_2DDNASpiral() { // By: ldirko https://editor.soulma
for (int i = 0; i < rows; i++) { for (int i = 0; i < rows; i++) {
uint16_t x = beatsin8(speeds, 0, cols - 1, 0, i * freq) + beatsin8(speeds - 7, 0, cols - 1, 0, i * freq + 128); uint16_t x = beatsin8(speeds, 0, cols - 1, 0, i * freq) + beatsin8(speeds - 7, 0, cols - 1, 0, i * freq + 128);
uint16_t x1 = beatsin8(speeds, 0, cols - 1, 0, 128 + i * freq) + beatsin8(speeds - 7, 0, cols - 1, 0, 128 + 64 + i * freq); uint16_t x1 = beatsin8(speeds, 0, cols - 1, 0, 128 + i * freq) + beatsin8(speeds - 7, 0, cols - 1, 0, 128 + 64 + i * freq);
SEGENV.aux0 = i * 128 / cols + ms; //ewowi20210629: not width - 1 to avoid crash if width = 1 uint8_t hue = (i * 128 / rows) + ms;
// skip every 4th row every now and then (fade it more)
if ((i + ms / 8) & 3) { if ((i + ms / 8) & 3) {
// draw a gradient line between x and x1
x = x / 2; x1 = x1 / 2; x = x / 2; x1 = x1 / 2;
byte steps = abs8(x - x1) + 1; uint8_t steps = abs8(x - x1) + 1;
for (size_t k = 1; k <= steps; k++) { for (size_t k = 1; k <= steps; k++) {
byte dx = lerp8by8(x, x1, k * 255 / steps); uint8_t rate = k * 255 / steps;
SEGMENT.addPixelColorXY(dx, i, ColorFromPalette(SEGPALETTE, SEGENV.aux0, 255, LINEARBLEND)); uint8_t dx = lerp8by8(x, x1, rate);
SEGMENT.fadePixelColorXY(dx, i, (k * 255 / steps)); //SEGMENT.setPixelColorXY(dx, i, ColorFromPalette(SEGPALETTE, hue, 255, LINEARBLEND).nscale8_video(rate));
SEGMENT.addPixelColorXY(dx, i, ColorFromPalette(SEGPALETTE, hue, 255, LINEARBLEND)); // use setPixelColorXY for different look
SEGMENT.fadePixelColorXY(dx, i, rate);
} }
SEGMENT.addPixelColorXY(x, i, DARKSLATEGRAY); SEGMENT.setPixelColorXY(x, i, DARKSLATEGRAY);
SEGMENT.addPixelColorXY(x1, i, WHITE); SEGMENT.setPixelColorXY(x1, i, WHITE);
} }
} }
@ -4843,17 +4844,18 @@ uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https:
const uint16_t cols = SEGMENT.virtualWidth(); const uint16_t cols = SEGMENT.virtualWidth();
const uint16_t rows = SEGMENT.virtualHeight(); const uint16_t rows = SEGMENT.virtualHeight();
const uint16_t dataSize = sizeof(CRGB) * SEGMENT.length(); // using width*height prevents reallocation if mirroring is enabled const uint16_t dataSize = sizeof(CRGB) * SEGMENT.length(); // using width*height prevents reallocation if mirroring is enabled
const uint16_t crcBufferLen = (SEGMENT.width() + SEGMENT.height())*71/100; // roughly sqrt(2)/2 for better repetition detection (Ewowi)
if (!SEGENV.allocateData(dataSize + sizeof(unsigned long))) return mode_static(); //allocation failed if (!SEGENV.allocateData(dataSize + sizeof(uint16_t)*crcBufferLen)) return mode_static(); //allocation failed
CRGB *prevLeds = reinterpret_cast<CRGB*>(SEGENV.data); CRGB *prevLeds = reinterpret_cast<CRGB*>(SEGENV.data);
unsigned long *resetMillis = reinterpret_cast<unsigned long*>(SEGENV.data + dataSize); // triggers reset uint16_t *crcBuffer = reinterpret_cast<uint16_t*>(SEGENV.data + dataSize);
CRGB backgroundColor = SEGCOLOR(1); CRGB backgroundColor = SEGCOLOR(1);
if (SEGENV.call == 0 || strip.now - *resetMillis > 5000) { if (SEGENV.call == 0 || strip.now - SEGMENT.step > 5000) {
*resetMillis = strip.now; SEGENV.step = strip.now;
SEGENV.aux0 = 0;
random16_set_seed(strip.now); //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++) {
@ -4861,17 +4863,18 @@ uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https:
if (state == 0) if (state == 0)
SEGMENT.setPixelColorXY(x,y, backgroundColor); SEGMENT.setPixelColorXY(x,y, backgroundColor);
else else
SEGMENT.setPixelColorXY(x,y, SEGMENT.color_from_palette(random8(), false, PALETTE_SOLID_WRAP, 0)); SEGMENT.setPixelColorXY(x,y, SEGMENT.color_from_palette(random8(), false, PALETTE_SOLID_WRAP, 255));
} }
for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) prevLeds[XY(x,y)] = CRGB::Black; for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) prevLeds[XY(x,y)] = CRGB::Black;
memset(crcBuffer, 0, sizeof(uint16_t)*crcBufferLen);
} else if (strip.now - SEGENV.step < FRAMETIME_FIXED * (uint32_t)map(SEGMENT.speed,0,255,64,4)) {
SEGENV.aux1 = 0; // update only when appropriate time passes (in 42 FPS slots)
SEGENV.aux0 = 0xFFFF; return FRAMETIME;
} }
//copy previous leds (save previous generation) //copy previous leds (save previous generation)
//NOTE: using lossy getPixelColor() is a benefit as endlessly repeating patterns will eventually fade out causing a reset
for (int x = 0; x < cols; x++) for (int y = 0; y < rows; y++) prevLeds[XY(x,y)] = SEGMENT.getPixelColorXY(x,y); for (int x = 0; x < cols; x++) for (int y = 0; y < rows; y++) prevLeds[XY(x,y)] = SEGMENT.getPixelColorXY(x,y);
//calculate new leds //calculate new leds
@ -4909,7 +4912,7 @@ uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https:
if ((col != bgc) && (neighbors < 2)) SEGMENT.setPixelColorXY(x,y, bgc); // Loneliness if ((col != bgc) && (neighbors < 2)) SEGMENT.setPixelColorXY(x,y, bgc); // Loneliness
else if ((col != bgc) && (neighbors > 3)) SEGMENT.setPixelColorXY(x,y, bgc); // Overpopulation else if ((col != bgc) && (neighbors > 3)) SEGMENT.setPixelColorXY(x,y, bgc); // Overpopulation
else if ((col == bgc) && (neighbors == 3)) { // Reproduction else if ((col == bgc) && (neighbors == 3)) { // Reproduction
//find dominantcolor and assign to cell //find dominant color and assign to cell
colorCount dominantColorCount = {backgroundColor, 0}; colorCount dominantColorCount = {backgroundColor, 0};
for (int i=0; i<9 && colorsCount[i].count != 0; i++) for (int i=0; i<9 && colorsCount[i].count != 0; i++)
if (colorsCount[i].count > dominantColorCount.count) dominantColorCount = colorsCount[i]; if (colorsCount[i].count > dominantColorCount.count) dominantColorCount = colorsCount[i];
@ -4919,16 +4922,17 @@ uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https:
} //x,y } //x,y
// calculate CRC16 of leds // calculate CRC16 of leds
uint16_t crc = crc16((const unsigned char*)prevLeds, dataSize-1); //ewowi: prevLeds instead of leds work as well, tbd: compare more patterns, see SR! uint16_t crc = crc16((const unsigned char*)prevLeds, dataSize);
// check if we had same CRC and reset if needed // check if we had same CRC and reset if needed
bool repetition = false;
for (int i=0; i<crcBufferLen && !repetition; i++) repetition = (crc == crcBuffer[i]); // (Ewowi)
// same CRC would mean image did not change or was repeating itself // same CRC would mean image did not change or was repeating itself
if (!(crc == SEGENV.aux0 || crc == SEGENV.aux1)) *resetMillis = strip.now; //if no repetition avoid reset if (!repetition) SEGENV.step = strip.now; //if no repetition avoid reset
// remember last two // remember CRCs across frames
SEGENV.aux1 = SEGENV.aux0; crcBuffer[SEGENV.aux0] = crc;
SEGENV.aux0 = crc; ++SEGENV.aux0 %= crcBufferLen;
return FRAMETIME_FIXED * (128-(SEGMENT.speed>>1)); // update only when appropriate time passes (in 42 FPS slots) return FRAMETIME;
} // mode_2Dgameoflife() } // mode_2Dgameoflife()
static const char _data_FX_MODE_2DGAMEOFLIFE[] PROGMEM = "Game Of Life@!;!,!;!;2"; static const char _data_FX_MODE_2DGAMEOFLIFE[] PROGMEM = "Game Of Life@!;!,!;!;2";
@ -5086,11 +5090,11 @@ uint16_t mode_2DLissajous(void) { // By: Andrew Tuline
for (int i=0; i < 256; i ++) { for (int i=0; i < 256; i ++) {
//float xlocn = float(sin8(now/4+i*(SEGMENT.speed>>5))) / 255.0f; //float xlocn = float(sin8(now/4+i*(SEGMENT.speed>>5))) / 255.0f;
//float ylocn = float(cos8(now/4+i*2)) / 255.0f; //float ylocn = float(cos8(now/4+i*2)) / 255.0f;
uint8_t xlocn = sin8(strip.now/2+i*(SEGMENT.speed>>5)); uint8_t xlocn = sin8(millis()/4+i*(SEGMENT.speed>>5));
uint8_t ylocn = cos8(strip.now/2+i*2); uint8_t ylocn = cos8(millis()/4+i*2);
xlocn = map(xlocn,0,255,0,cols-1); xlocn = map(xlocn,0,255,0,cols-1);
ylocn = map(ylocn,0,255,0,rows-1); ylocn = map(ylocn,0,255,0,rows-1);
SEGMENT.setPixelColorXY(xlocn, ylocn, SEGMENT.color_from_palette(strip.now/100+i, false, PALETTE_SOLID_WRAP, 0)); SEGMENT.setPixelColorXY(xlocn, ylocn, SEGMENT.color_from_palette(millis()/100+i, false, PALETTE_SOLID_WRAP, 0));
} }
return FRAMETIME; return FRAMETIME;
@ -5173,15 +5177,15 @@ uint16_t mode_2Dmetaballs(void) { // Metaballs by Stefan Petrick. Cannot have
float speed = 0.25f * (1+(SEGMENT.speed>>6)); float speed = 0.25f * (1+(SEGMENT.speed>>6));
// get some 2 random moving points // get some 2 random moving points
uint8_t x2 = inoise8(strip.now * speed, 25355, 685 ) / 16; uint8_t x2 = map(inoise8(strip.now * speed, 25355, 685), 0, 255, 0, cols-1);
uint8_t y2 = inoise8(strip.now * speed, 355, 11685 ) / 16; uint8_t y2 = map(inoise8(strip.now * speed, 355, 11685), 0, 255, 0, rows-1);
uint8_t x3 = inoise8(strip.now * speed, 55355, 6685 ) / 16; uint8_t x3 = map(inoise8(strip.now * speed, 55355, 6685), 0, 255, 0, cols-1);
uint8_t y3 = inoise8(strip.now * speed, 25355, 22685 ) / 16; uint8_t y3 = map(inoise8(strip.now * speed, 25355, 22685), 0, 255, 0, rows-1);
// and one Lissajou function // and one Lissajou function
uint8_t x1 = beatsin8(23 * speed, 0, 15); uint8_t x1 = beatsin8(23 * speed, 0, cols-1);
uint8_t y1 = beatsin8(28 * speed, 0, 15); uint8_t y1 = beatsin8(28 * speed, 0, rows-1);
for (int y = 0; y < rows; y++) { for (int y = 0; y < rows; y++) {
for (int x = 0; x < cols; x++) { for (int x = 0; x < cols; x++) {
@ -5200,7 +5204,7 @@ uint16_t mode_2Dmetaballs(void) { // Metaballs by Stefan Petrick. Cannot have
dist += sqrt16((dx * dx) + (dy * dy)); dist += sqrt16((dx * dx) + (dy * dy));
// inverse result // inverse result
byte color = 1000 / dist; byte color = dist ? 1000 / dist : 255;
// map color between thresholds // map color between thresholds
if (color > 0 and color < 60) { if (color > 0 and color < 60) {
@ -5882,20 +5886,27 @@ uint16_t mode_2Dscrollingtext(void) {
else SEGENV.aux0 = (cols + (numberOfLetters * letterWidth))/2; else SEGENV.aux0 = (cols + (numberOfLetters * letterWidth))/2;
++SEGENV.aux1 &= 0xFF; // color shift ++SEGENV.aux1 &= 0xFF; // color shift
SEGENV.step = millis() + map(SEGMENT.speed, 0, 255, 10*FRAMETIME_FIXED, 2*FRAMETIME_FIXED); SEGENV.step = millis() + map(SEGMENT.speed, 0, 255, 10*FRAMETIME_FIXED, 2*FRAMETIME_FIXED);
if (!SEGMENT.check2) {
// we need it 3 times // we need it 3 times
SEGMENT.fade_out(255 - (SEGMENT.custom1>>5)); // fade to background color SEGMENT.fade_out(255 - (SEGMENT.custom1>>5)); // fade to background color
SEGMENT.fade_out(255 - (SEGMENT.custom1>>5)); // fade to background color SEGMENT.fade_out(255 - (SEGMENT.custom1>>5)); // fade to background color
SEGMENT.fade_out(255 - (SEGMENT.custom1>>5)); // fade to background color SEGMENT.fade_out(255 - (SEGMENT.custom1>>5)); // fade to background color
}
}
for (int i = 0; i < numberOfLetters; i++) { for (int i = 0; i < numberOfLetters; i++) {
if (int(cols) - int(SEGENV.aux0) + letterWidth*(i+1) < 0) continue; // don't draw characters off-screen if (int(cols) - int(SEGENV.aux0) + letterWidth*(i+1) < 0) continue; // don't draw characters off-screen
SEGMENT.drawCharacter(text[i], int(cols) - int(SEGENV.aux0) + letterWidth*i, yoffset, letterWidth, letterHeight, SEGMENT.color_from_palette(SEGENV.aux1, false, PALETTE_SOLID_WRAP, 0)); uint32_t col1 = SEGMENT.color_from_palette(SEGENV.aux1, false, PALETTE_SOLID_WRAP, 0);
uint32_t col2 = BLACK;
if (SEGMENT.check1 && SEGMENT.palette == 0) {
col1 = SEGCOLOR(0);
col2 = SEGCOLOR(2);
} }
SEGMENT.drawCharacter(text[i], int(cols) - int(SEGENV.aux0) + letterWidth*i, yoffset, letterWidth, letterHeight, col1, col2);
} }
return FRAMETIME; return FRAMETIME;
} }
static const char _data_FX_MODE_2DSCROLLTEXT[] PROGMEM = "Scrolling Text@!,Y Offset,Trail,Font size;!,!;!;2;ix=128,c1=0,rev=0,mi=0,rY=0,mY=0"; static const char _data_FX_MODE_2DSCROLLTEXT[] PROGMEM = "Scrolling Text@!,Y Offset,Trail,Font size,,Gradient,Overlay;!,!,Gradient;!;2;ix=128,c1=0,rev=0,mi=0,rY=0,mY=0";
//////////////////////////// ////////////////////////////
@ -7305,6 +7316,61 @@ uint16_t mode_2DAkemi(void) {
return FRAMETIME; return FRAMETIME;
} // mode_2DAkemi } // mode_2DAkemi
static const char _data_FX_MODE_2DAKEMI[] PROGMEM = "Akemi@Color speed,Dance;Head palette,Arms & Legs,Eyes & Mouth;Face palette;2f;si=0"; //beatsin static const char _data_FX_MODE_2DAKEMI[] PROGMEM = "Akemi@Color speed,Dance;Head palette,Arms & Legs,Eyes & Mouth;Face palette;2f;si=0"; //beatsin
// Distortion waves - ldirko
// https://editor.soulmatelights.com/gallery/1089-distorsion-waves
// apated for WLD by @blazoncek
uint16_t mode_2Ddistortionwaves() {
if (!strip.isMatrix) return mode_static(); // not a 2D set-up
const uint16_t cols = SEGMENT.virtualWidth();
const uint16_t rows = SEGMENT.virtualHeight();
uint8_t speed = SEGMENT.speed/32;
uint8_t scale = SEGMENT.intensity/32;
uint8_t w = 2;
uint16_t a = millis()/32;
uint16_t a2 = a/2;
uint16_t a3 = a/3;
uint16_t cx = beatsin8(10-speed,0,cols-1)*scale;
uint16_t cy = beatsin8(12-speed,0,rows-1)*scale;
uint16_t cx1 = beatsin8(13-speed,0,cols-1)*scale;
uint16_t cy1 = beatsin8(15-speed,0,rows-1)*scale;
uint16_t cx2 = beatsin8(17-speed,0,cols-1)*scale;
uint16_t cy2 = beatsin8(14-speed,0,rows-1)*scale;
uint16_t xoffs = 0;
for (int x = 0; x < cols; x++) {
xoffs += scale;
uint16_t yoffs = 0;
for (int y = 0; y < rows; y++) {
yoffs += scale;
byte rdistort = cos8((cos8(((x<<3)+a )&255)+cos8(((y<<3)-a2)&255)+a3 )&255)>>1;
byte gdistort = cos8((cos8(((x<<3)-a2)&255)+cos8(((y<<3)+a3)&255)+a+32 )&255)>>1;
byte bdistort = cos8((cos8(((x<<3)+a3)&255)+cos8(((y<<3)-a) &255)+a2+64)&255)>>1;
byte valueR = rdistort+ w* (a- ( ((xoffs - cx) * (xoffs - cx) + (yoffs - cy) * (yoffs - cy))>>7 ));
byte valueG = gdistort+ w* (a2-( ((xoffs - cx1) * (xoffs - cx1) + (yoffs - cy1) * (yoffs - cy1))>>7 ));
byte valueB = bdistort+ w* (a3-( ((xoffs - cx2) * (xoffs - cx2) + (yoffs - cy2) * (yoffs - cy2))>>7 ));
valueR = gamma8(cos8(valueR));
valueG = gamma8(cos8(valueG));
valueB = gamma8(cos8(valueB));
SEGMENT.setPixelColorXY(x, y, RGBW32(valueR, valueG, valueB, 0));
}
}
return FRAMETIME;
}
static const char _data_FX_MODE_2DDISTORTIONWAVES[] PROGMEM = "Distortion Waves@!,Scale;;;2;";
#endif // WLED_DISABLE_2D #endif // WLED_DISABLE_2D
@ -7503,6 +7569,7 @@ void WS2812FX::setupEffectData() {
addEffect(FX_MODE_2DBLOBS, &mode_2Dfloatingblobs, _data_FX_MODE_2DBLOBS); addEffect(FX_MODE_2DBLOBS, &mode_2Dfloatingblobs, _data_FX_MODE_2DBLOBS);
addEffect(FX_MODE_2DSCROLLTEXT, &mode_2Dscrollingtext, _data_FX_MODE_2DSCROLLTEXT); addEffect(FX_MODE_2DSCROLLTEXT, &mode_2Dscrollingtext, _data_FX_MODE_2DSCROLLTEXT);
addEffect(FX_MODE_2DDRIFTROSE, &mode_2Ddriftrose, _data_FX_MODE_2DDRIFTROSE); addEffect(FX_MODE_2DDRIFTROSE, &mode_2Ddriftrose, _data_FX_MODE_2DDRIFTROSE);
addEffect(FX_MODE_2DDISTORTIONWAVES, &mode_2Ddistortionwaves, _data_FX_MODE_2DDISTORTIONWAVES);
addEffect(FX_MODE_2DGEQ, &mode_2DGEQ, _data_FX_MODE_2DGEQ); // audio addEffect(FX_MODE_2DGEQ, &mode_2DGEQ, _data_FX_MODE_2DGEQ); // audio

View File

@ -250,6 +250,7 @@
#define FX_MODE_2DBLOBS 121 //gap fill #define FX_MODE_2DBLOBS 121 //gap fill
#define FX_MODE_2DSCROLLTEXT 122 //gap fill #define FX_MODE_2DSCROLLTEXT 122 //gap fill
#define FX_MODE_2DDRIFTROSE 123 //gap fill #define FX_MODE_2DDRIFTROSE 123 //gap fill
#define FX_MODE_2DDISTORTIONWAVES 124
// WLED-SR effects (SR compatible IDs !!!) // WLED-SR effects (SR compatible IDs !!!)
#define FX_MODE_PIXELS 128 #define FX_MODE_PIXELS 128
@ -588,11 +589,13 @@ typedef struct Segment {
void moveX(int8_t delta); void moveX(int8_t delta);
void moveY(int8_t delta); void moveY(int8_t delta);
void move(uint8_t dir, uint8_t delta); void move(uint8_t dir, uint8_t delta);
void draw_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c);
void fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c); void fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c);
void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c); void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c);
void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c) { drawLine(x0, y0, x1, y1, RGBW32(c.r,c.g,c.b,0)); } // automatic inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c) { drawLine(x0, y0, x1, y1, RGBW32(c.r,c.g,c.b,0)); } // automatic inline
void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color); void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2 = 0);
void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0)); } // automatic inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0)); } // automatic inline
void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0), RGBW32(c2.r,c2.g,c2.b,0)); } // automatic inline
void wu_pixel(uint32_t x, uint32_t y, CRGB c); void wu_pixel(uint32_t x, uint32_t y, CRGB c);
void blur1d(fract8 blur_amount); // blur all rows in 1 dimension void blur1d(fract8 blur_amount); // blur all rows in 1 dimension
void blur2d(fract8 blur_amount) { blur(blur_amount); } void blur2d(fract8 blur_amount) { blur(blur_amount); }

View File

@ -164,6 +164,7 @@ void IRAM_ATTR Segment::setPixelColorXY(int x, int y, uint32_t col)
if (leds) leds[XY(x,y)] = col; if (leds) leds[XY(x,y)] = col;
uint8_t _bri_t = currentBri(on ? opacity : 0); uint8_t _bri_t = currentBri(on ? opacity : 0);
if (!_bri_t && !transitional) return;
if (_bri_t < 255) { if (_bri_t < 255) {
byte r = scale8(R(col), _bri_t); byte r = scale8(R(col), _bri_t);
byte g = scale8(G(col), _bri_t); byte g = scale8(G(col), _bri_t);
@ -271,7 +272,7 @@ void Segment::addPixelColorXY(int x, int y, uint32_t color) {
void Segment::fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { void Segment::fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) {
CRGB pix = CRGB(getPixelColorXY(x,y)).nscale8_video(fade); CRGB pix = CRGB(getPixelColorXY(x,y)).nscale8_video(fade);
setPixelColor(x, y, pix); setPixelColorXY(x, y, pix);
} }
// blurRow: perform a blur on a row of a rectangular matrix // blurRow: perform a blur on a row of a rectangular matrix
@ -428,6 +429,29 @@ void Segment::move(uint8_t dir, uint8_t delta) {
} }
} }
void Segment::draw_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) {
// Bresenhams Algorithm
int d = 3 - (2*radius);
int y = radius, x = 0;
while (y >= x) {
setPixelColorXY(cx+x, cy+y, col);
setPixelColorXY(cx-x, cy+y, col);
setPixelColorXY(cx+x, cy-y, col);
setPixelColorXY(cx-x, cy-y, col);
setPixelColorXY(cx+y, cy+x, col);
setPixelColorXY(cx-y, cy+x, col);
setPixelColorXY(cx+y, cy-x, col);
setPixelColorXY(cx-y, cy-x, col);
x++;
if (d > 0) {
y--;
d += 4 * (x - y) + 10;
} else {
d += 4 * x + 6;
}
}
}
// by stepko, taken from https://editor.soulmatelights.com/gallery/573-blobs // by stepko, taken from https://editor.soulmatelights.com/gallery/573-blobs
void Segment::fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) { void Segment::fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) {
const uint16_t cols = virtualWidth(); const uint16_t cols = virtualWidth();
@ -437,7 +461,7 @@ void Segment::fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) {
if (x * x + y * y <= radius * radius && if (x * x + y * y <= radius * radius &&
int16_t(cx)+x>=0 && int16_t(cy)+y>=0 && int16_t(cx)+x>=0 && int16_t(cy)+y>=0 &&
int16_t(cx)+x<cols && int16_t(cy)+y<rows) int16_t(cx)+x<cols && int16_t(cy)+y<rows)
addPixelColorXY(cx + x, cy + y, col); setPixelColorXY(cx + x, cy + y, col);
} }
} }
} }
@ -459,7 +483,7 @@ void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint3
const int16_t dy = abs(y1-y0), sy = y0<y1 ? 1 : -1; const int16_t dy = abs(y1-y0), sy = y0<y1 ? 1 : -1;
int16_t err = (dx>dy ? dx : -dy)/2, e2; int16_t err = (dx>dy ? dx : -dy)/2, e2;
for (;;) { for (;;) {
addPixelColorXY(x0,y0,c); setPixelColorXY(x0,y0,c);
if (x0==x1 && y0==y1) break; if (x0==x1 && y0==y1) break;
e2 = err; e2 = err;
if (e2 >-dx) { err -= dy; x0 += sx; } if (e2 >-dx) { err -= dy; x0 += sx; }
@ -475,13 +499,16 @@ void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint3
// draws a raster font character on canvas // draws a raster font character on canvas
// only supports: 4x6=24, 5x8=40, 5x12=60, 6x8=48 and 7x9=63 fonts ATM // only supports: 4x6=24, 5x8=40, 5x12=60, 6x8=48 and 7x9=63 fonts ATM
void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color) { void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2) {
if (chr < 32 || chr > 126) return; // only ASCII 32-126 supported if (chr < 32 || chr > 126) return; // only ASCII 32-126 supported
chr -= 32; // align with font table entries chr -= 32; // align with font table entries
const uint16_t cols = virtualWidth(); const uint16_t cols = virtualWidth();
const uint16_t rows = virtualHeight(); const uint16_t rows = virtualHeight();
const int font = w*h; const int font = w*h;
CRGB col = CRGB(color);
CRGBPalette16 grad = CRGBPalette16(col, col2 ? CRGB(col2) : col);
//if (w<5 || w>6 || h!=8) return; //if (w<5 || w>6 || h!=8) return;
for (int i = 0; i<h; i++) { // character height for (int i = 0; i<h; i++) { // character height
int16_t y0 = y + i; int16_t y0 = y + i;
@ -496,10 +523,11 @@ void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w,
case 60: bits = pgm_read_byte_near(&console_font_5x12[(chr * h) + i]); break; // 5x12 font case 60: bits = pgm_read_byte_near(&console_font_5x12[(chr * h) + i]); break; // 5x12 font
default: return; default: return;
} }
col = ColorFromPalette(grad, (i+1)*255/h, 255, NOBLEND);
for (int j = 0; j<w; j++) { // character width for (int j = 0; j<w; j++) { // character width
int16_t x0 = x + (w-1) - j; int16_t x0 = x + (w-1) - j;
if ((x0 >= 0 || x0 < cols) && ((bits>>(j+(8-w))) & 0x01)) { // bit set & drawing on-screen if ((x0 >= 0 || x0 < cols) && ((bits>>(j+(8-w))) & 0x01)) { // bit set & drawing on-screen
addPixelColorXY(x0, y0, color); addPixelColorXY(x0, y0, col);
} }
} }
} }

View File

@ -243,12 +243,12 @@ CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) {
_lastPaletteChange = millis(); _lastPaletteChange = millis();
timeSinceLastChange = 0; timeSinceLastChange = 0;
} }
if (timeSinceLastChange <= 500) { if (timeSinceLastChange <= 250) {
targetPalette = prevRandomPalette; targetPalette = prevRandomPalette;
// there needs to be 255 palette blends (48) for full blend but that is too resource intensive // there needs to be 255 palette blends (48) for full blend but that is too resource intensive
// so 128 is a compromise (we need to perform full blend of the two palettes as each segment can have random // so 128 is a compromise (we need to perform full blend of the two palettes as each segment can have random
// palette selected but only 2 static palettes are used) // palette selected but only 2 static palettes are used)
size_t noOfBlends = ((128U * timeSinceLastChange) / 500U); size_t noOfBlends = ((128U * timeSinceLastChange) / 250U);
for (size_t i=0; i<noOfBlends; i++) nblendPaletteTowardPalette(targetPalette, randomPalette, 48); for (size_t i=0; i<noOfBlends; i++) nblendPaletteTowardPalette(targetPalette, randomPalette, 48);
} else { } else {
targetPalette = randomPalette; targetPalette = randomPalette;
@ -459,18 +459,21 @@ void Segment::setMode(uint8_t fx, bool loadDefaults) {
// load default values from effect string // load default values from effect string
if (loadDefaults) { if (loadDefaults) {
int16_t sOpt; int16_t sOpt;
sOpt = extractModeDefaults(fx, "sx"); if (sOpt >= 0) speed = sOpt; sOpt = extractModeDefaults(fx, "sx"); speed = (sOpt >= 0) ? sOpt : DEFAULT_SPEED;
sOpt = extractModeDefaults(fx, "ix"); if (sOpt >= 0) intensity = sOpt; sOpt = extractModeDefaults(fx, "ix"); intensity = (sOpt >= 0) ? sOpt : DEFAULT_INTENSITY;
sOpt = extractModeDefaults(fx, "c1"); if (sOpt >= 0) custom1 = sOpt; sOpt = extractModeDefaults(fx, "c1"); custom1 = (sOpt >= 0) ? sOpt : DEFAULT_C1;
sOpt = extractModeDefaults(fx, "c2"); if (sOpt >= 0) custom2 = sOpt; sOpt = extractModeDefaults(fx, "c2"); custom2 = (sOpt >= 0) ? sOpt : DEFAULT_C2;
sOpt = extractModeDefaults(fx, "c3"); if (sOpt >= 0) custom3 = sOpt; sOpt = extractModeDefaults(fx, "c3"); custom3 = (sOpt >= 0) ? sOpt : DEFAULT_C3;
sOpt = extractModeDefaults(fx, "o1"); check1 = (sOpt >= 0) ? (bool)sOpt : false;
sOpt = extractModeDefaults(fx, "o2"); check2 = (sOpt >= 0) ? (bool)sOpt : false;
sOpt = extractModeDefaults(fx, "o3"); check3 = (sOpt >= 0) ? (bool)sOpt : false;
sOpt = extractModeDefaults(fx, "m12"); if (sOpt >= 0) map1D2D = constrain(sOpt, 0, 7); sOpt = extractModeDefaults(fx, "m12"); if (sOpt >= 0) map1D2D = constrain(sOpt, 0, 7);
sOpt = extractModeDefaults(fx, "si"); if (sOpt >= 0) soundSim = constrain(sOpt, 0, 7); sOpt = extractModeDefaults(fx, "si"); if (sOpt >= 0) soundSim = constrain(sOpt, 0, 7);
sOpt = extractModeDefaults(fx, "rev"); if (sOpt >= 0) reverse = (bool)sOpt; sOpt = extractModeDefaults(fx, "rev"); if (sOpt >= 0) reverse = (bool)sOpt;
sOpt = extractModeDefaults(fx, "mi"); if (sOpt >= 0) mirror = (bool)sOpt; // NOTE: setting this option is a risky business sOpt = extractModeDefaults(fx, "mi"); if (sOpt >= 0) mirror = (bool)sOpt; // NOTE: setting this option is a risky business
sOpt = extractModeDefaults(fx, "rY"); if (sOpt >= 0) reverse_y = (bool)sOpt; sOpt = extractModeDefaults(fx, "rY"); if (sOpt >= 0) reverse_y = (bool)sOpt;
sOpt = extractModeDefaults(fx, "mY"); if (sOpt >= 0) mirror_y = (bool)sOpt; // NOTE: setting this option is a risky business sOpt = extractModeDefaults(fx, "mY"); if (sOpt >= 0) mirror_y = (bool)sOpt; // NOTE: setting this option is a risky business
sOpt = extractModeDefaults(fx, "pal"); if (sOpt >= 0) setPalette(sOpt); sOpt = extractModeDefaults(fx, "pal"); if (sOpt >= 0) setPalette(sOpt); //else setPalette(0);
} }
stateChanged = true; // send UDP/WS broadcast stateChanged = true; // send UDP/WS broadcast
} }
@ -574,6 +577,20 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col)
int y = roundf(cos_t(rad) * i); int y = roundf(cos_t(rad) * i);
setPixelColorXY(x, y, col); setPixelColorXY(x, y, col);
} }
// Bresenhams Algorithm (may not fill every pixel)
//int d = 3 - (2*i);
//int y = i, x = 0;
//while (y >= x) {
// setPixelColorXY(x, y, col);
// setPixelColorXY(y, x, col);
// x++;
// if (d > 0) {
// y--;
// d += 4 * (x - y) + 10;
// } else {
// d += 4 * x + 6;
// }
//}
} }
break; break;
case M12_pCorner: case M12_pCorner:
@ -596,6 +613,7 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col)
uint16_t len = length(); uint16_t len = length();
uint8_t _bri_t = currentBri(on ? opacity : 0); uint8_t _bri_t = currentBri(on ? opacity : 0);
if (!_bri_t && !transitional) return;
if (_bri_t < 255) { if (_bri_t < 255) {
byte r = scale8(R(col), _bri_t); byte r = scale8(R(col), _bri_t);
byte g = scale8(G(col), _bri_t); byte g = scale8(G(col), _bri_t);
@ -908,7 +926,7 @@ uint8_t Segment::get_random_wheel_index(uint8_t pos) {
* Gets a single color from the currently selected palette. * Gets a single color from the currently selected palette.
* @param i Palette Index (if mapping is true, the full palette will be _virtualSegmentLength long, if false, 255). Will wrap around automatically. * @param i Palette Index (if mapping is true, the full palette will be _virtualSegmentLength long, if false, 255). Will wrap around automatically.
* @param mapping if true, LED position in segment is considered for color * @param mapping if true, LED position in segment is considered for color
* @param wrap FastLED palettes will usally wrap back to the start smoothly. Set false to get a hard edge * @param wrap FastLED palettes will usually wrap back to the start smoothly. Set false to get a hard edge
* @param mcol If the default palette 0 is selected, return the standard color 0, 1 or 2 instead. If >2, Party palette is used instead * @param mcol If the default palette 0 is selected, return the standard color 0, 1 or 2 instead. If >2, Party palette is used instead
* @param pbri Value to scale the brightness of the returned color by. Default is 255. (no scaling) * @param pbri Value to scale the brightness of the returned color by. Default is 255. (no scaling)
* @returns Single color from palette * @returns Single color from palette
@ -1056,7 +1074,7 @@ void WS2812FX::service() {
//if (seg.transitional && seg._modeP) (*_mode[seg._modeP])(progress()); //if (seg.transitional && seg._modeP) (*_mode[seg._modeP])(progress());
delay = (*_mode[seg.currentMode(seg.mode)])(); delay = (*_mode[seg.currentMode(seg.mode)])();
if (seg.mode != FX_MODE_HALLOWEEN_EYES) seg.call++; if (seg.mode != FX_MODE_HALLOWEEN_EYES) seg.call++;
if (seg.transitional && delay > FRAMETIME) delay = FRAMETIME; // foce faster updates during transition if (seg.transitional && delay > FRAMETIME) delay = FRAMETIME; // force faster updates during transition
seg.handleTransition(); seg.handleTransition();
} }

View File

@ -24,12 +24,14 @@ void shortPressAction(uint8_t b)
applyPreset(macroButton[b], CALL_MODE_BUTTON_PRESET); applyPreset(macroButton[b], CALL_MODE_BUTTON_PRESET);
} }
#ifndef WLED_DISABLE_MQTT
// publish MQTT message // publish MQTT message
if (buttonPublishMqtt && WLED_MQTT_CONNECTED) { if (buttonPublishMqtt && WLED_MQTT_CONNECTED) {
char subuf[64]; char subuf[64];
sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b); sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b);
mqtt->publish(subuf, 0, false, "short"); mqtt->publish(subuf, 0, false, "short");
} }
#endif
} }
void longPressAction(uint8_t b) void longPressAction(uint8_t b)
@ -43,12 +45,14 @@ void longPressAction(uint8_t b)
applyPreset(macroLongPress[b], CALL_MODE_BUTTON_PRESET); applyPreset(macroLongPress[b], CALL_MODE_BUTTON_PRESET);
} }
#ifndef WLED_DISABLE_MQTT
// publish MQTT message // publish MQTT message
if (buttonPublishMqtt && WLED_MQTT_CONNECTED) { if (buttonPublishMqtt && WLED_MQTT_CONNECTED) {
char subuf[64]; char subuf[64];
sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b); sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b);
mqtt->publish(subuf, 0, false, "long"); mqtt->publish(subuf, 0, false, "long");
} }
#endif
} }
void doublePressAction(uint8_t b) void doublePressAction(uint8_t b)
@ -62,12 +66,14 @@ void doublePressAction(uint8_t b)
applyPreset(macroDoublePress[b], CALL_MODE_BUTTON_PRESET); applyPreset(macroDoublePress[b], CALL_MODE_BUTTON_PRESET);
} }
#ifndef WLED_DISABLE_MQTT
// publish MQTT message // publish MQTT message
if (buttonPublishMqtt && WLED_MQTT_CONNECTED) { if (buttonPublishMqtt && WLED_MQTT_CONNECTED) {
char subuf[64]; char subuf[64];
sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b); sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b);
mqtt->publish(subuf, 0, false, "double"); mqtt->publish(subuf, 0, false, "double");
} }
#endif
} }
bool isButtonPressed(uint8_t i) bool isButtonPressed(uint8_t i)
@ -119,6 +125,7 @@ void handleSwitch(uint8_t b)
} }
} }
#ifndef WLED_DISABLE_MQTT
// publish MQTT message // publish MQTT message
if (buttonPublishMqtt && WLED_MQTT_CONNECTED) { if (buttonPublishMqtt && WLED_MQTT_CONNECTED) {
char subuf[64]; char subuf[64];
@ -126,6 +133,7 @@ void handleSwitch(uint8_t b)
else sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b); else sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b);
mqtt->publish(subuf, 0, false, !buttonPressedBefore[b] ? "off" : "on"); mqtt->publish(subuf, 0, false, !buttonPressedBefore[b] ? "off" : "on");
} }
#endif
buttonLongPressed[b] = buttonPressedBefore[b]; //save the last "long term" switch state buttonLongPressed[b] = buttonPressedBefore[b]; //save the last "long term" switch state
} }

View File

@ -404,6 +404,8 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
CJSON(e131SkipOutOfSequence, if_live_dmx[F("seqskip")]); CJSON(e131SkipOutOfSequence, if_live_dmx[F("seqskip")]);
CJSON(DMXAddress, if_live_dmx[F("addr")]); CJSON(DMXAddress, if_live_dmx[F("addr")]);
if (!DMXAddress || DMXAddress > 510) DMXAddress = 1; if (!DMXAddress || DMXAddress > 510) DMXAddress = 1;
CJSON(DMXSegmentSpacing, if_live_dmx[F("dss")]);
if (DMXSegmentSpacing > 150) DMXSegmentSpacing = 0;
CJSON(DMXMode, if_live_dmx["mode"]); CJSON(DMXMode, if_live_dmx["mode"]);
tdd = if_live[F("timeout")] | -1; tdd = if_live[F("timeout")] | -1;
@ -864,6 +866,7 @@ void serializeConfig() {
if_live_dmx[F("uni")] = e131Universe; if_live_dmx[F("uni")] = e131Universe;
if_live_dmx[F("seqskip")] = e131SkipOutOfSequence; if_live_dmx[F("seqskip")] = e131SkipOutOfSequence;
if_live_dmx[F("addr")] = DMXAddress; if_live_dmx[F("addr")] = DMXAddress;
if_live_dmx[F("dss")] = DMXSegmentSpacing;
if_live_dmx["mode"] = DMXMode; if_live_dmx["mode"] = DMXMode;
if_live[F("timeout")] = realtimeTimeoutMs / 100; if_live[F("timeout")] = realtimeTimeoutMs / 100;

View File

@ -169,10 +169,14 @@
#define DMX_MODE_DISABLED 0 //not used #define DMX_MODE_DISABLED 0 //not used
#define DMX_MODE_SINGLE_RGB 1 //all LEDs same RGB color (3 channels) #define DMX_MODE_SINGLE_RGB 1 //all LEDs same RGB color (3 channels)
#define DMX_MODE_SINGLE_DRGB 2 //all LEDs same RGB color and master dimmer (4 channels) #define DMX_MODE_SINGLE_DRGB 2 //all LEDs same RGB color and master dimmer (4 channels)
#define DMX_MODE_EFFECT 3 //trigger standalone effects of WLED (11 channels) #define DMX_MODE_EFFECT 3 //trigger standalone effects of WLED (15 channels)
#define DMX_MODE_EFFECT_W 7 //trigger standalone effects of WLED (18 channels)
#define DMX_MODE_MULTIPLE_RGB 4 //every LED is addressed with its own RGB (ledCount * 3 channels) #define DMX_MODE_MULTIPLE_RGB 4 //every LED is addressed with its own RGB (ledCount * 3 channels)
#define DMX_MODE_MULTIPLE_DRGB 5 //every LED is addressed with its own RGB and share a master dimmer (ledCount * 3 + 1 channels) #define DMX_MODE_MULTIPLE_DRGB 5 //every LED is addressed with its own RGB and share a master dimmer (ledCount * 3 + 1 channels)
#define DMX_MODE_MULTIPLE_RGBW 6 //every LED is addressed with its own RGBW (ledCount * 4 channels) #define DMX_MODE_MULTIPLE_RGBW 6 //every LED is addressed with its own RGBW (ledCount * 4 channels)
#define DMX_MODE_EFFECT_SEGMENT 8 //trigger standalone effects of WLED (15 channels per segement)
#define DMX_MODE_EFFECT_SEGMENT_W 9 //trigger standalone effects of WLED (18 channels per segement)
#define DMX_MODE_PRESET 10 //apply presets (1 channel)
//Light capability byte (unused) 0bRCCCTTTT //Light capability byte (unused) 0bRCCCTTTT
//bits 0/1/2/3: specifies a type of LED driver. A single "driver" may have different chip models but must have the same protocol/behavior //bits 0/1/2/3: specifies a type of LED driver. A single "driver" may have different chip models but must have the same protocol/behavior

View File

@ -436,6 +436,9 @@ button {
left: 50%; left: 50%;
margin-left: -92px; margin-left: -92px;
/* Ensure tooltip goes away when mouse leaves control */
pointer-events: none;
/* Fade in tooltip */ /* Fade in tooltip */
opacity: 0; opacity: 0;
transition: opacity 0.75s; transition: opacity 0.75s;

View File

@ -807,7 +807,7 @@ function populateSegments(s)
if (!isM && !noNewSegs && (cfg.comp.seglen?parseInt(gId(`seg${lSeg}s`).value):0)+parseInt(gId(`seg${lSeg}e`).value)<ledCount) gId(`segr${lSeg}`).style.display = "inline"; if (!isM && !noNewSegs && (cfg.comp.seglen?parseInt(gId(`seg${lSeg}s`).value):0)+parseInt(gId(`seg${lSeg}e`).value)<ledCount) gId(`segr${lSeg}`).style.display = "inline";
gId('segutil2').style.display = (segCount > 1) ? "block":"none"; // rsbtn parent gId('segutil2').style.display = (segCount > 1) ? "block":"none"; // rsbtn parent
if (Array.isArray(li.maps) && li.maps.length>1) { if (!isM && Array.isArray(li.maps) && li.maps.length>1) {
let cont = `Ledmap:&nbsp;<select class="sel-sg" onchange="requestJson({'ledmap':parseInt(this.value)})"><option value="" selected>Unchanged</option>`; let cont = `Ledmap:&nbsp;<select class="sel-sg" onchange="requestJson({'ledmap':parseInt(this.value)})"><option value="" selected>Unchanged</option>`;
for (const k of (li.maps||[])) cont += `<option value="${k}">${k==0?'Default':'ledmap'+k+'.json'}</option>`; for (const k of (li.maps||[])) cont += `<option value="${k}">${k==0?'Default':'ledmap'+k+'.json'}</option>`;
cont += "</select></div>"; cont += "</select></div>";
@ -837,7 +837,7 @@ function populateEffects()
}); });
for (let ef of effects) { for (let ef of effects) {
// WLEDSR: add slider and color control to setFX (used by requestjson) // add slider and color control to setFX (used by requestjson)
let id = ef.id; let id = ef.id;
let nm = ef.name+" "; let nm = ef.name+" ";
let fd = ""; let fd = "";
@ -1362,7 +1362,7 @@ function readState(s,command=false)
return true; return true;
} }
// WLEDSR: control HTML elements for Slider and Color Control // control HTML elements for Slider and Color Control (original ported form WLED-SR)
// Technical notes // Technical notes
// =============== // ===============
// If an effect name is followed by an @, slider and color control is effective. // If an effect name is followed by an @, slider and color control is effective.
@ -1485,6 +1485,14 @@ function setEffectParameters(idx)
pall.innerHTML = '<i class="icons sel-icon" onclick="tglHex()">&#xe2b3;</i> Color palette not used'; pall.innerHTML = '<i class="icons sel-icon" onclick="tglHex()">&#xe2b3;</i> Color palette not used';
palw.style.display = "none"; palw.style.display = "none";
} }
// not all color selectors shown, hide palettes created from color selectors
// NOTE: this will disallow user to select "* Color ..." palettes which may be undesirable in some cases or for some users
//for (let e of (gId('pallist').querySelectorAll('.lstI')||[])) {
// let fltr = "* C";
// if (cslCnt==1 && csel==0) fltr = "* Colors";
// else if (cslCnt==2) fltr = "* Colors Only";
// if (cslCnt < 3 && e.querySelector('.lstIname').innerText.indexOf(fltr)>=0) e.classList.add('hide'); else e.classList.remove('hide');
//}
} }
var jsonTimeout; var jsonTimeout;
@ -1840,7 +1848,7 @@ ${makePlSel(plJson[i].end?plJson[i].end:0, true)}
<input type="checkbox" id="p${i}sbchk"> <input type="checkbox" id="p${i}sbchk">
<span class="checkmark"></span> <span class="checkmark"></span>
</label>`; </label>`;
if (Array.isArray(lastinfo.maps) && lastinfo.maps.length>1) { if (!isM && Array.isArray(lastinfo.maps) && lastinfo.maps.length>1) {
content += `<div class="lbl-l">Ledmap:&nbsp;<div class="sel-p"><select class="sel-p" id="p${i}lmp"><option value="">Unchanged</option>`; content += `<div class="lbl-l">Ledmap:&nbsp;<div class="sel-p"><select class="sel-p" id="p${i}lmp"><option value="">Unchanged</option>`;
for (const k of (lastinfo.maps||[])) content += `<option value="${k}"${(i>0 && pJson[i].ledmap==k)?" selected":""}>${k==0?'Default':'ledmap'+k+'.json'}</option>`; for (const k of (lastinfo.maps||[])) content += `<option value="${k}"${(i>0 && pJson[i].ledmap==k)?" selected":""}>${k==0?'Default':'ledmap'+k+'.json'}</option>`;
content += "</select></div></div>"; content += "</select></div></div>";

View File

@ -68,9 +68,9 @@
<button type=submit id="b" onclick="window.location='/'">Back</button> <button type=submit id="b" onclick="window.location='/'">Back</button>
<button type="submit" onclick="window.location='./settings/wifi'">WiFi Setup</button> <button type="submit" onclick="window.location='./settings/wifi'">WiFi Setup</button>
<button type="submit" onclick="window.location='./settings/leds'">LED Preferences</button> <button type="submit" onclick="window.location='./settings/leds'">LED Preferences</button>
<button type="submit" onclick="window.location='./settings/2D'">2D Configuration</button> <button id="2dbtn" style="display:none;" type="submit" onclick="window.location='./settings/2D'">2D Configuration</button>
<button type="submit" onclick="window.location='./settings/ui'">User Interface</button> <button type="submit" onclick="window.location='./settings/ui'">User Interface</button>
<button id="dmxbtn" style="display: none;" type="submit" onclick="window.location='./settings/dmx'">DMX Output</button> <button id="dmxbtn" style="display:none;" type="submit" onclick="window.location='./settings/dmx'">DMX Output</button>
<button type="submit" onclick="window.location='./settings/sync'">Sync Interfaces</button> <button type="submit" onclick="window.location='./settings/sync'">Sync Interfaces</button>
<button type="submit" onclick="window.location='./settings/time'">Time & Macros</button> <button type="submit" onclick="window.location='./settings/time'">Time & Macros</button>
<button type="submit" onclick="window.location='./settings/um'">Usermods</button> <button type="submit" onclick="window.location='./settings/um'">Usermods</button>

View File

@ -9,6 +9,10 @@
var d=document,laprev=55,maxB=1,maxV=0,maxM=4000,maxPB=4096,maxL=1333,maxLbquot=0; //maximum bytes for LED allocation: 4kB for 8266, 32kB for 32 var d=document,laprev=55,maxB=1,maxV=0,maxM=4000,maxPB=4096,maxL=1333,maxLbquot=0; //maximum bytes for LED allocation: 4kB for 8266, 32kB for 32
var customStarts=false,startsDirty=[],maxCOOverrides=5; var customStarts=false,startsDirty=[],maxCOOverrides=5;
var loc = false, locip; var loc = false, locip;
d.um_p = [];
d.rsvd = [];
d.ro_gpio = [];
d.max_gpio = 39;
function H(){window.open("https://kno.wled.ge/features/settings/#led-settings");} function H(){window.open("https://kno.wled.ge/features/settings/#led-settings");}
function B(){window.open("/settings","_self");} function B(){window.open("/settings","_self");}
function gId(n){return d.getElementById(n);} function gId(n){return d.getElementById(n);}
@ -23,10 +27,6 @@
// success event // success event
scE.addEventListener("load", () => { scE.addEventListener("load", () => {
//console.log("File loaded"); //console.log("File loaded");
d.um_p = [];
d.rsvd = [];
d.ro_pins = [];
d.max_gpio = 39;
GetV();checkSi();setABL(); GetV();checkSi();setABL();
if (d.um_p[0]==-1) d.um_p.shift(); if (d.um_p[0]==-1) d.um_p.shift();
}); });
@ -66,7 +66,7 @@
for (k=0;k<d.rsvd.length;k++) p.push(d.rsvd[k]); // fill with reservations for (k=0;k<d.rsvd.length;k++) p.push(d.rsvd[k]); // fill with reservations
for (k=0;k<d.um_p.length;k++) p.push(d.um_p[k]); // fill with usermod pins for (k=0;k<d.um_p.length;k++) p.push(d.um_p[k]); // fill with usermod pins
if (p.some((e)=>e==parseInt(LCs[i].value,10))) {alert(`Sorry, pins ${JSON.stringify(p)} can't be used.`);LCs[i].value="";LCs[i].focus();return false;} if (p.some((e)=>e==parseInt(LCs[i].value,10))) {alert(`Sorry, pins ${JSON.stringify(p)} can't be used.`);LCs[i].value="";LCs[i].focus();return false;}
else if (!(nm == "IR" || nm=="BT") && d.ro_pins.some((e)=>e==parseInt(LCs[i].value,10))) {alert(`Sorry, pins ${JSON.stringify(d.ro_gpio)} are input only.`);LCs[i].value="";LCs[i].focus();return false;} else if (!(nm == "IR" || nm=="BT") && d.ro_gpio.some((e)=>e==parseInt(LCs[i].value,10))) {alert(`Sorry, pins ${JSON.stringify(d.ro_gpio)} are input only.`);LCs[i].value="";LCs[i].focus();return false;}
for (j=i+1; j<LCs.length; j++) for (j=i+1; j<LCs.length; j++)
{ {
var n2 = LCs[j].name.substring(0,2); var n2 = LCs[j].name.substring(0,2);

View File

@ -148,15 +148,20 @@ Start universe: <input name="EU" type="number" min="0" max="63999" required><br>
<i>Reboot required.</i> Check out <a href="https://github.com/LedFx/LedFx" target="_blank">LedFx</a>!<br> <i>Reboot required.</i> Check out <a href="https://github.com/LedFx/LedFx" target="_blank">LedFx</a>!<br>
Skip out-of-sequence packets: <input type="checkbox" name="ES"><br> Skip out-of-sequence packets: <input type="checkbox" name="ES"><br>
DMX start address: <input name="DA" type="number" min="1" max="510" required><br> DMX start address: <input name="DA" type="number" min="1" max="510" required><br>
DMX segment spacing: <input name="XX" type="number" min="0" max="150" required><br>
DMX mode: DMX mode:
<select name=DM> <select name=DM>
<option value=0>Disabled</option> <option value=0>Disabled</option>
<option value=1>Single RGB</option> <option value=1>Single RGB</option>
<option value=2>Single DRGB</option> <option value=2>Single DRGB</option>
<option value=3>Effect</option> <option value=3>Effect</option>
<option value=7>Effect + White</option>
<option value=8>Effect Segment</option>
<option value=9>Effect Segment + White</option>
<option value=4>Multi RGB</option> <option value=4>Multi RGB</option>
<option value=5>Dimmer + Multi RGB</option> <option value=5>Dimmer + Multi RGB</option>
<option value=6>Multi RGBW</option> <option value=6>Multi RGBW</option>
<option value=10>Preset</option>
</select><br> </select><br>
<a href="https://kno.wled.ge/interfaces/e1.31-dmx/" target="_blank">E1.31 info</a><br> <a href="https://kno.wled.ge/interfaces/e1.31-dmx/" target="_blank">E1.31 info</a><br>
Timeout: <input name="ET" type="number" min="1" max="65000" required> ms<br> Timeout: <input name="ET" type="number" min="1" max="65000" required> ms<br>

View File

@ -7,6 +7,10 @@
<title>Usermod Settings</title> <title>Usermod Settings</title>
<script> <script>
var d = document; var d = document;
d.max_gpio = 39;
d.um_p = [];
d.rsvd = [];
d.ro_gpio = [];
var umCfg = {}; var umCfg = {};
var pins = [], pinO = [], owner; var pins = [], pinO = [], owner;
var loc = false, locip; var loc = false, locip;
@ -25,11 +29,6 @@
d.body.appendChild(scE); d.body.appendChild(scE);
// success event // success event
scE.addEventListener("load", () => { scE.addEventListener("load", () => {
//console.log("File loaded");
d.um_p = [];
d.rsvd = [];
d.ro_pins = [];
d.max_gpio = 39;
GetV(); GetV();
for (let k=0; k<d.rsvd.length; k++) { pins.push(d.rsvd[k]); pinO.push("rsvd"); } for (let k=0; k<d.rsvd.length; k++) { pins.push(d.rsvd[k]); pinO.push("rsvd"); }
if (d.um_p[0]==-1) d.um_p.shift(); if (d.um_p[0]==-1) d.um_p.shift();
@ -38,6 +37,8 @@
d.Sf.MOSI.max = d.max_gpio; d.Sf.MOSI.max = d.max_gpio;
d.Sf.SCLK.max = d.max_gpio; d.Sf.SCLK.max = d.max_gpio;
d.Sf.MISO.max = d.max_gpio; d.Sf.MISO.max = d.max_gpio;
let inp = d.getElementsByTagName("input");
for (let i of inp) if (i.type === "number" && i.name.replace("[]","").substr(-3) === "pin") i.max = d.max_gpio;
}); });
// error event // error event
scE.addEventListener("error", (ev) => { scE.addEventListener("error", (ev) => {

View File

@ -132,7 +132,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
return; // nothing to do return; // nothing to do
break; break;
case DMX_MODE_SINGLE_RGB: // RGB only case DMX_MODE_SINGLE_RGB: // 3 channel: [R,G,B]
if (uni != e131Universe) return; if (uni != e131Universe) return;
if (availDMXLen < 3) return; if (availDMXLen < 3) return;
@ -145,7 +145,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
setRealtimePixel(i, e131_data[dataOffset+0], e131_data[dataOffset+1], e131_data[dataOffset+2], wChannel); setRealtimePixel(i, e131_data[dataOffset+0], e131_data[dataOffset+1], e131_data[dataOffset+2], wChannel);
break; break;
case DMX_MODE_SINGLE_DRGB: // Dimmer + RGB case DMX_MODE_SINGLE_DRGB: // 4 channel: [Dimmer,R,G,B]
if (uni != e131Universe) return; if (uni != e131Universe) return;
if (availDMXLen < 4) return; if (availDMXLen < 4) return;
@ -162,38 +162,77 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
setRealtimePixel(i, e131_data[dataOffset+1], e131_data[dataOffset+2], e131_data[dataOffset+3], wChannel); setRealtimePixel(i, e131_data[dataOffset+1], e131_data[dataOffset+2], e131_data[dataOffset+3], wChannel);
break; break;
case DMX_MODE_EFFECT: // Length 1: Apply Preset ID, length 11-13: apply effect config case DMX_MODE_PRESET: // 2 channel: [Dimmer,Preset]
if (uni != e131Universe) return; if (uni != e131Universe || availDMXLen < 2) return;
if (availDMXLen < 11) { applyPreset(e131_data[dataOffset+1], CALL_MODE_NOTIFICATION);
if (availDMXLen > 1) return; if (bri != e131_data[dataOffset]) {
applyPreset(e131_data[dataOffset+0], CALL_MODE_NOTIFICATION); bri = e131_data[dataOffset];
strip.setBrightness(bri, true);
}
return; return;
}
if (bri != e131_data[dataOffset+0]) {
bri = e131_data[dataOffset+0];
}
if (e131_data[dataOffset+1] < strip.getModeCount())
effectCurrent = e131_data[dataOffset+ 1];
effectSpeed = e131_data[dataOffset+ 2]; // flickers
effectIntensity = e131_data[dataOffset+ 3];
effectPalette = e131_data[dataOffset+ 4];
col[0] = e131_data[dataOffset+ 5];
col[1] = e131_data[dataOffset+ 6];
col[2] = e131_data[dataOffset+ 7];
colSec[0] = e131_data[dataOffset+ 8];
colSec[1] = e131_data[dataOffset+ 9];
colSec[2] = e131_data[dataOffset+10];
if (availDMXLen > 11)
{
col[3] = e131_data[dataOffset+11]; //white
colSec[3] = e131_data[dataOffset+12];
}
transitionDelayTemp = 0; // act fast
colorUpdated(CALL_MODE_NOTIFICATION); // don't send UDP
return; // don't activate realtime live mode
break; break;
case DMX_MODE_EFFECT: // 15 channels [bri,effectCurrent,effectSpeed,effectIntensity,effectPalette,effectOption,R,G,B,R2,G2,B2,R3,G3,B3]
case DMX_MODE_EFFECT_W: // 18 channels, same as above but with extra +3 white channels [..,W,W2,W3]
case DMX_MODE_EFFECT_SEGMENT: // 15 channels per segment;
case DMX_MODE_EFFECT_SEGMENT_W: // 18 Channels per segment;
{
if (uni != e131Universe) return;
bool isSegmentMode = DMXMode == DMX_MODE_EFFECT_SEGMENT || DMXMode == DMX_MODE_EFFECT_SEGMENT_W;
uint8_t dmxEffectChannels = (DMXMode == DMX_MODE_EFFECT || DMXMode == DMX_MODE_EFFECT_SEGMENT) ? 15 : 18;
for (uint8_t id = 0; id < strip.getSegmentsNum(); id++) {
Segment& seg = strip.getSegment(id);
if (isSegmentMode)
dataOffset = DMXAddress + id * (dmxEffectChannels + DMXSegmentSpacing);
else
dataOffset = DMXAddress;
// Modify address for Art-Net data
if (protocol == P_ARTNET && dataOffset > 0)
dataOffset--;
// Skip out of universe addresses
if (dataOffset > dmxChannels - dmxEffectChannels + 1)
return;
if (e131_data[dataOffset+1] < strip.getModeCount())
if (e131_data[dataOffset+1] != seg.mode) seg.setMode( e131_data[dataOffset+1]);
if (e131_data[dataOffset+2] != seg.speed) seg.speed = e131_data[dataOffset+2];
if (e131_data[dataOffset+3] != seg.intensity) seg.intensity = e131_data[dataOffset+3];
if (e131_data[dataOffset+4] != seg.palette) seg.setPalette(e131_data[dataOffset+4]);
uint8_t segOption = (uint8_t)floor(e131_data[dataOffset+5]/64.0);
if (segOption == 0 && (seg.mirror || seg.reverse )) {seg.setOption(SEG_OPTION_MIRROR, false); seg.setOption(SEG_OPTION_REVERSED, false);}
if (segOption == 1 && (seg.mirror || !seg.reverse)) {seg.setOption(SEG_OPTION_MIRROR, false); seg.setOption(SEG_OPTION_REVERSED, true);}
if (segOption == 2 && (!seg.mirror || seg.reverse )) {seg.setOption(SEG_OPTION_MIRROR, true); seg.setOption(SEG_OPTION_REVERSED, false);}
if (segOption == 3 && (!seg.mirror || !seg.reverse)) {seg.setOption(SEG_OPTION_MIRROR, true); seg.setOption(SEG_OPTION_REVERSED, true);}
uint32_t colors[3];
byte whites[3] = {0,0,0};
if (dmxEffectChannels == 18) {
whites[0] = e131_data[dataOffset+15];
whites[1] = e131_data[dataOffset+16];
whites[2] = e131_data[dataOffset+17];
}
colors[0] = RGBW32(e131_data[dataOffset+ 6], e131_data[dataOffset+ 7], e131_data[dataOffset+ 8], whites[0]);
colors[1] = RGBW32(e131_data[dataOffset+ 9], e131_data[dataOffset+10], e131_data[dataOffset+11], whites[1]);
colors[2] = RGBW32(e131_data[dataOffset+12], e131_data[dataOffset+13], e131_data[dataOffset+14], whites[2]);
if (colors[0] != seg.colors[0]) seg.setColor(0, colors[0]);
if (colors[1] != seg.colors[1]) seg.setColor(1, colors[1]);
if (colors[2] != seg.colors[2]) seg.setColor(2, colors[2]);
// Set segment opacity or global brightness
if (isSegmentMode) {
if (e131_data[dataOffset] != seg.opacity) seg.setOpacity(e131_data[dataOffset]);
} else if ( id == strip.getSegmentsNum()-1 ) {
if (bri != e131_data[dataOffset]) {
bri = e131_data[dataOffset];
strip.setBrightness(bri, true);
}
}
}
return;
break;
}
case DMX_MODE_MULTIPLE_DRGB: case DMX_MODE_MULTIPLE_DRGB:
case DMX_MODE_MULTIPLE_RGB: case DMX_MODE_MULTIPLE_RGB:
case DMX_MODE_MULTIPLE_RGBW: case DMX_MODE_MULTIPLE_RGBW:
@ -279,7 +318,11 @@ void handleArtnetPollReply(IPAddress ipAddress) {
case DMX_MODE_SINGLE_RGB: case DMX_MODE_SINGLE_RGB:
case DMX_MODE_SINGLE_DRGB: case DMX_MODE_SINGLE_DRGB:
case DMX_MODE_PRESET:
case DMX_MODE_EFFECT: case DMX_MODE_EFFECT:
case DMX_MODE_EFFECT_W:
case DMX_MODE_EFFECT_SEGMENT:
case DMX_MODE_EFFECT_SEGMENT_W:
break; // 1 universe is enough break; // 1 universe is enough
case DMX_MODE_MULTIPLE_DRGB: case DMX_MODE_MULTIPLE_DRGB:

View File

@ -1,18 +1,17 @@
#ifndef WLED_FCN_DECLARE_H #ifndef WLED_FCN_DECLARE_H
#define WLED_FCN_DECLARE_H #define WLED_FCN_DECLARE_H
#include <Arduino.h>
#include "src/dependencies/espalexa/EspalexaDevice.h"
#include "src/dependencies/e131/ESPAsyncE131.h"
/* /*
* All globally accessible functions are declared here * All globally accessible functions are declared here
*/ */
//alexa.cpp //alexa.cpp
#ifndef WLED_DISABLE_ALEXA
void onAlexaChange(EspalexaDevice* dev); void onAlexaChange(EspalexaDevice* dev);
void alexaInit(); void alexaInit();
void handleAlexa(); void handleAlexa();
void onAlexaChange(EspalexaDevice* dev); void onAlexaChange(EspalexaDevice* dev);
#endif
//blynk.cpp //blynk.cpp
#ifndef WLED_DISABLE_BLYNK #ifndef WLED_DISABLE_BLYNK

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -170,13 +170,20 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
} }
#endif #endif
#ifndef WLED_DISABLE_2D
bool reverse = seg.reverse;
bool mirror = seg.mirror;
#endif
seg.selected = elem["sel"] | seg.selected; seg.selected = elem["sel"] | seg.selected;
seg.reverse = elem["rev"] | seg.reverse; seg.reverse = elem["rev"] | seg.reverse;
seg.mirror = elem["mi"] | seg.mirror; seg.mirror = elem["mi"] | seg.mirror;
#ifndef WLED_DISABLE_2D #ifndef WLED_DISABLE_2D
bool reverse_y = seg.reverse_y;
bool mirror_y = seg.mirror_y;
seg.reverse_y = elem["rY"] | seg.reverse_y; seg.reverse_y = elem["rY"] | seg.reverse_y;
seg.mirror_y = elem["mY"] | seg.mirror_y; seg.mirror_y = elem["mY"] | seg.mirror_y;
seg.transpose = elem[F("tp")] | seg.transpose; seg.transpose = elem[F("tp")] | seg.transpose;
if (seg.is2D() && seg.map1D2D == M12_pArc && (reverse != seg.reverse || reverse_y != seg.reverse_y || mirror != seg.mirror || mirror_y != seg.mirror_y)) seg.fill(BLACK); // clear entire segment (in case of Arc 1D to 2D expansion)
#endif #endif
byte fx = seg.mode; byte fx = seg.mode;
@ -221,11 +228,11 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
for (size_t i = 0; i < iarr.size(); i++) { for (size_t i = 0; i < iarr.size(); i++) {
if(iarr[i].is<JsonInteger>()) { if(iarr[i].is<JsonInteger>()) {
if (!set) { if (!set) {
start = iarr[i]; start = abs(iarr[i].as<int>());
set = 1; set++;
} else { } else {
stop = iarr[i]; stop = abs(iarr[i].as<int>());
set = 2; set++;
} }
} else { //color } else { //color
uint8_t rgbw[] = {0,0,0,0}; uint8_t rgbw[] = {0,0,0,0};
@ -241,16 +248,13 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
} }
} }
if (set < 2) stop = start + 1; if (set < 2 || stop <= start) stop = start + 1;
uint32_t c = gamma32(RGBW32(rgbw[0], rgbw[1], rgbw[2], rgbw[3])); uint32_t c = gamma32(RGBW32(rgbw[0], rgbw[1], rgbw[2], rgbw[3]));
for (int i = start; i < stop; i++) { while (start < stop) seg.setPixelColor(start++, c);
seg.setPixelColor(i, c);
}
if (!set) start++;
set = 0; set = 0;
} }
} }
strip.trigger(); strip.trigger(); // force segment update
} }
// send UDP/WS if segment options changed (except selection; will also deselect current preset) // send UDP/WS if segment options changed (except selection; will also deselect current preset)
if (seg.differs(prev) & 0x7F) stateChanged = true; if (seg.differs(prev) & 0x7F) stateChanged = true;
@ -477,11 +481,13 @@ void serializeSegment(JsonObject& root, Segment& seg, byte id, bool forPreset, b
root["sel"] = seg.isSelected(); root["sel"] = seg.isSelected();
root["rev"] = seg.reverse; root["rev"] = seg.reverse;
root["mi"] = seg.mirror; root["mi"] = seg.mirror;
#ifndef WLED_DISABLE_2D
if (strip.isMatrix) { if (strip.isMatrix) {
root["rY"] = seg.reverse_y; root["rY"] = seg.reverse_y;
root["mY"] = seg.mirror_y; root["mY"] = seg.mirror_y;
root[F("tp")] = seg.transpose; root[F("tp")] = seg.transpose;
} }
#endif
root["o1"] = seg.check1; root["o1"] = seg.check1;
root["o2"] = seg.check2; root["o2"] = seg.check2;
root["o3"] = seg.check3; root["o3"] = seg.check3;

View File

@ -180,7 +180,9 @@ void handleTransitions()
{ {
//handle still pending interface update //handle still pending interface update
if (interfaceUpdateCallMode && millis() - lastInterfaceUpdate > INTERFACE_UPDATE_COOLDOWN) updateInterfaces(interfaceUpdateCallMode); if (interfaceUpdateCallMode && millis() - lastInterfaceUpdate > INTERFACE_UPDATE_COOLDOWN) updateInterfaces(interfaceUpdateCallMode);
#ifndef WLED_DISABLE_MQTT
if (doPublishMqtt) publishMqtt(); if (doPublishMqtt) publishMqtt();
#endif
if (transitionActive && transitionDelayTemp > 0) if (transitionActive && transitionDelayTemp > 0)
{ {

View File

@ -177,8 +177,4 @@ bool initMqtt()
mqtt->connect(); mqtt->connect();
return true; return true;
} }
#else
bool initMqtt(){return false;}
void publishMqtt(){}
#endif #endif

View File

@ -284,8 +284,10 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
if (t >= 0 && t <= 63999) e131Universe = t; if (t >= 0 && t <= 63999) e131Universe = t;
t = request->arg(F("DA")).toInt(); t = request->arg(F("DA")).toInt();
if (t >= 0 && t <= 510) DMXAddress = t; if (t >= 0 && t <= 510) DMXAddress = t;
t = request->arg(F("XX")).toInt();
if (t >= 0 && t <= 150) DMXSegmentSpacing = t;
t = request->arg(F("DM")).toInt(); t = request->arg(F("DM")).toInt();
if (t >= DMX_MODE_DISABLED && t <= DMX_MODE_MULTIPLE_RGBW) DMXMode = t; if (t >= DMX_MODE_DISABLED && t <= DMX_MODE_PRESET) DMXMode = t;
t = request->arg(F("ET")).toInt(); t = request->arg(F("ET")).toInt();
if (t > 99 && t <= 65000) realtimeTimeoutMs = t; if (t > 99 && t <= 65000) realtimeTimeoutMs = t;
arlsForceMaxBri = request->hasArg(F("FB")); arlsForceMaxBri = request->hasArg(F("FB"));
@ -681,7 +683,9 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
lastEditTime = millis(); lastEditTime = millis();
if (subPage != 2 && !doReboot) doSerializeConfig = true; //serializeConfig(); //do not save if factory reset or LED settings (which are saved after LED re-init) if (subPage != 2 && !doReboot) doSerializeConfig = true; //serializeConfig(); //do not save if factory reset or LED settings (which are saved after LED re-init)
#ifndef WLED_DISABLE_ALEXA
if (subPage == 4) alexaInit(); if (subPage == 4) alexaInit();
#endif
} }

View File

@ -42,7 +42,9 @@ void WLED::loop()
#endif #endif
handleTime(); handleTime();
#ifndef WLED_DISABLE_INFRARED
handleIR(); // 2nd call to function needed for ESP32 to return valid results -- should be good for ESP8266, too handleIR(); // 2nd call to function needed for ESP32 to return valid results -- should be good for ESP8266, too
#endif
handleConnection(); handleConnection();
handleSerial(); handleSerial();
handleNotifications(); handleNotifications();
@ -64,7 +66,9 @@ void WLED::loop()
yield(); yield();
handleIO(); handleIO();
#ifndef WLED_DISABLE_INFRARED
handleIR(); handleIR();
#endif
#ifndef WLED_DISABLE_ALEXA #ifndef WLED_DISABLE_ALEXA
handleAlexa(); handleAlexa();
#endif #endif
@ -135,7 +139,9 @@ void WLED::loop()
} }
if (millis() - lastMqttReconnectAttempt > 30000 || lastMqttReconnectAttempt == 0) { // lastMqttReconnectAttempt==0 forces immediate broadcast if (millis() - lastMqttReconnectAttempt > 30000 || lastMqttReconnectAttempt == 0) { // lastMqttReconnectAttempt==0 forces immediate broadcast
lastMqttReconnectAttempt = millis(); lastMqttReconnectAttempt = millis();
#ifndef WLED_DISABLE_MQTT
initMqtt(); initMqtt();
#endif
yield(); yield();
// refresh WLED nodes list // refresh WLED nodes list
refreshNodeList(); refreshNodeList();
@ -414,8 +420,10 @@ void WLED::setup()
// fill in unique mdns default // fill in unique mdns default
if (strcmp(cmDNS, "x") == 0) sprintf_P(cmDNS, PSTR("wled-%*s"), 6, escapedMac.c_str() + 6); if (strcmp(cmDNS, "x") == 0) sprintf_P(cmDNS, PSTR("wled-%*s"), 6, escapedMac.c_str() + 6);
#ifndef WLED_DISABLE_MQTT
if (mqttDeviceTopic[0] == 0) sprintf_P(mqttDeviceTopic, PSTR("wled/%*s"), 6, escapedMac.c_str() + 6); if (mqttDeviceTopic[0] == 0) sprintf_P(mqttDeviceTopic, PSTR("wled/%*s"), 6, escapedMac.c_str() + 6);
if (mqttClientID[0] == 0) sprintf_P(mqttClientID, PSTR("WLED-%*s"), 6, escapedMac.c_str() + 6); if (mqttClientID[0] == 0) sprintf_P(mqttClientID, PSTR("WLED-%*s"), 6, escapedMac.c_str() + 6);
#endif
#ifdef WLED_ENABLE_ADALIGHT #ifdef WLED_ENABLE_ADALIGHT
if (Serial.available() > 0 && Serial.peek() == 'I') handleImprovPacket(); if (Serial.available() > 0 && Serial.peek() == 'I') handleImprovPacket();
@ -674,9 +682,11 @@ void WLED::initInterfaces()
} }
#endif #endif
#ifndef WLED_DISABLE_ALEXA
// init Alexa hue emulation // init Alexa hue emulation
if (alexaEnabled) if (alexaEnabled)
alexaInit(); alexaInit();
#endif
#ifndef WLED_DISABLE_OTA #ifndef WLED_DISABLE_OTA
if (aOtaEnabled) if (aOtaEnabled)
@ -715,7 +725,9 @@ void WLED::initInterfaces()
e131.begin(e131Multicast, e131Port, e131Universe, E131_MAX_UNIVERSE_COUNT); e131.begin(e131Multicast, e131Port, e131Universe, E131_MAX_UNIVERSE_COUNT);
ddp.begin(false, DDP_DEFAULT_PORT); ddp.begin(false, DDP_DEFAULT_PORT);
reconnectHue(); reconnectHue();
#ifndef WLED_DISABLE_MQTT
initMqtt(); initMqtt();
#endif
interfacesInited = true; interfacesInited = true;
wasConnected = true; wasConnected = true;
} }

View File

@ -8,7 +8,7 @@
*/ */
// version code in format yymmddb (b = daily build) // version code in format yymmddb (b = daily build)
#define VERSION 2301030 #define VERSION 2301170
//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
@ -121,6 +121,7 @@
#define ESPALEXA_MAXDEVICES 10 #define ESPALEXA_MAXDEVICES 10
// #define ESPALEXA_DEBUG // #define ESPALEXA_DEBUG
#include "src/dependencies/espalexa/Espalexa.h" #include "src/dependencies/espalexa/Espalexa.h"
#include "src/dependencies/espalexa/EspalexaDevice.h"
#endif #endif
#ifndef WLED_DISABLE_BLYNK #ifndef WLED_DISABLE_BLYNK
#include "src/dependencies/blynk/BlynkSimpleEsp.h" #include "src/dependencies/blynk/BlynkSimpleEsp.h"
@ -135,7 +136,9 @@
#endif #endif
#include "src/dependencies/e131/ESPAsyncE131.h" #include "src/dependencies/e131/ESPAsyncE131.h"
#ifdef WLED_ENABLE_MQTT
#include "src/dependencies/async-mqtt-client/AsyncMqttClient.h" #include "src/dependencies/async-mqtt-client/AsyncMqttClient.h"
#endif
#define ARDUINOJSON_DECODE_UNICODE 0 #define ARDUINOJSON_DECODE_UNICODE 0
#include "src/dependencies/json/AsyncJson-v6.h" #include "src/dependencies/json/AsyncJson-v6.h"
@ -402,12 +405,18 @@ WLED_GLOBAL uint16_t e131Universe _INIT(1); // settings fo
WLED_GLOBAL uint16_t e131Port _INIT(5568); // DMX in port. E1.31 default is 5568, Art-Net is 6454 WLED_GLOBAL uint16_t e131Port _INIT(5568); // DMX in port. E1.31 default is 5568, Art-Net is 6454
WLED_GLOBAL byte DMXMode _INIT(DMX_MODE_MULTIPLE_RGB); // DMX mode (s.a.) WLED_GLOBAL byte DMXMode _INIT(DMX_MODE_MULTIPLE_RGB); // DMX mode (s.a.)
WLED_GLOBAL uint16_t DMXAddress _INIT(1); // DMX start address of fixture, a.k.a. first Channel [for E1.31 (sACN) protocol] WLED_GLOBAL uint16_t DMXAddress _INIT(1); // DMX start address of fixture, a.k.a. first Channel [for E1.31 (sACN) protocol]
WLED_GLOBAL uint16_t DMXSegmentSpacing _INIT(0); // Number of void/unused channels between each segments DMX channels
WLED_GLOBAL byte e131LastSequenceNumber[E131_MAX_UNIVERSE_COUNT]; // to detect packet loss WLED_GLOBAL byte e131LastSequenceNumber[E131_MAX_UNIVERSE_COUNT]; // to detect packet loss
WLED_GLOBAL bool e131Multicast _INIT(false); // multicast or unicast WLED_GLOBAL bool e131Multicast _INIT(false); // multicast or unicast
WLED_GLOBAL bool e131SkipOutOfSequence _INIT(false); // freeze instead of flickering WLED_GLOBAL bool e131SkipOutOfSequence _INIT(false); // freeze instead of flickering
WLED_GLOBAL uint16_t pollReplyCount _INIT(0); // count number of replies for ArtPoll node report WLED_GLOBAL uint16_t pollReplyCount _INIT(0); // count number of replies for ArtPoll node report
// mqtt
WLED_GLOBAL unsigned long lastMqttReconnectAttempt _INIT(0); // used for other periodic tasks too
#ifndef WLED_DISABLE_MQTT
WLED_GLOBAL AsyncMqttClient *mqtt _INIT(NULL);
WLED_GLOBAL bool mqttEnabled _INIT(false); WLED_GLOBAL bool mqttEnabled _INIT(false);
WLED_GLOBAL char mqttStatusTopic[40] _INIT(""); // this must be global because of async handlers
WLED_GLOBAL char mqttDeviceTopic[33] _INIT(""); // main MQTT topic (individual per device, default is wled/mac) WLED_GLOBAL char mqttDeviceTopic[33] _INIT(""); // main MQTT topic (individual per device, default is wled/mac)
WLED_GLOBAL char mqttGroupTopic[33] _INIT("wled/all"); // second MQTT topic (for example to group devices) WLED_GLOBAL char mqttGroupTopic[33] _INIT("wled/all"); // second MQTT topic (for example to group devices)
WLED_GLOBAL char mqttServer[33] _INIT(""); // both domains and IPs should work (no SSL) WLED_GLOBAL char mqttServer[33] _INIT(""); // both domains and IPs should work (no SSL)
@ -415,6 +424,10 @@ WLED_GLOBAL char mqttUser[41] _INIT(""); // optional: username
WLED_GLOBAL char mqttPass[65] _INIT(""); // optional: password for MQTT auth WLED_GLOBAL char mqttPass[65] _INIT(""); // optional: password for MQTT auth
WLED_GLOBAL char mqttClientID[41] _INIT(""); // override the client ID WLED_GLOBAL char mqttClientID[41] _INIT(""); // override the client ID
WLED_GLOBAL uint16_t mqttPort _INIT(1883); WLED_GLOBAL uint16_t mqttPort _INIT(1883);
#define WLED_MQTT_CONNECTED (mqtt != nullptr && mqtt->connected())
#else
#define WLED_MQTT_CONNECTED false
#endif
#ifndef WLED_DISABLE_HUESYNC #ifndef WLED_DISABLE_HUESYNC
WLED_GLOBAL bool huePollingEnabled _INIT(false); // poll hue bridge for light state WLED_GLOBAL bool huePollingEnabled _INIT(false); // poll hue bridge for light state
@ -590,11 +603,8 @@ WLED_GLOBAL uint8_t tpmPacketCount _INIT(0);
WLED_GLOBAL uint16_t tpmPayloadFrameSize _INIT(0); WLED_GLOBAL uint16_t tpmPayloadFrameSize _INIT(0);
WLED_GLOBAL bool useMainSegmentOnly _INIT(false); WLED_GLOBAL bool useMainSegmentOnly _INIT(false);
// mqtt
WLED_GLOBAL unsigned long lastMqttReconnectAttempt _INIT(0);
WLED_GLOBAL unsigned long lastInterfaceUpdate _INIT(0); WLED_GLOBAL unsigned long lastInterfaceUpdate _INIT(0);
WLED_GLOBAL byte interfaceUpdateCallMode _INIT(CALL_MODE_INIT); WLED_GLOBAL byte interfaceUpdateCallMode _INIT(CALL_MODE_INIT);
WLED_GLOBAL char mqttStatusTopic[40] _INIT(""); // this must be global because of async handlers
// alexa udp // alexa udp
WLED_GLOBAL String escapedMac; WLED_GLOBAL String escapedMac;
@ -655,8 +665,7 @@ WLED_GLOBAL AsyncWebServer server _INIT_N(((80)));
#ifdef WLED_ENABLE_WEBSOCKETS #ifdef WLED_ENABLE_WEBSOCKETS
WLED_GLOBAL AsyncWebSocket ws _INIT_N((("/ws"))); WLED_GLOBAL AsyncWebSocket ws _INIT_N((("/ws")));
#endif #endif
WLED_GLOBAL AsyncClient* hueClient _INIT(NULL); WLED_GLOBAL AsyncClient *hueClient _INIT(NULL);
WLED_GLOBAL AsyncMqttClient* mqtt _INIT(NULL);
WLED_GLOBAL AsyncWebHandler *editHandler _INIT(nullptr); WLED_GLOBAL AsyncWebHandler *editHandler _INIT(nullptr);
// udp interface objects // udp interface objects
@ -766,7 +775,6 @@ WLED_GLOBAL volatile uint8_t jsonBufferLock _INIT(0);
#define WLED_CONNECTED (WiFi.status() == WL_CONNECTED) #define WLED_CONNECTED (WiFi.status() == WL_CONNECTED)
#endif #endif
#define WLED_WIFI_CONFIGURED (strlen(clientSSID) >= 1 && strcmp(clientSSID, DEFAULT_CLIENT_SSID) != 0) #define WLED_WIFI_CONFIGURED (strlen(clientSSID) >= 1 && strcmp(clientSSID, DEFAULT_CLIENT_SSID) != 0)
#define WLED_MQTT_CONNECTED (mqtt != nullptr && mqtt->connected())
#ifndef WLED_AP_SSID_UNIQUE #ifndef WLED_AP_SSID_UNIQUE
#define WLED_SET_AP_SSID() do { \ #define WLED_SET_AP_SSID() do { \

View File

@ -599,10 +599,14 @@ void serveSettings(AsyncWebServerRequest* request, bool post)
case 4: response = request->beginResponse_P(200, "text/html", PAGE_settings_sync, PAGE_settings_sync_length); break; case 4: response = request->beginResponse_P(200, "text/html", PAGE_settings_sync, PAGE_settings_sync_length); break;
case 5: response = request->beginResponse_P(200, "text/html", PAGE_settings_time, PAGE_settings_time_length); break; case 5: response = request->beginResponse_P(200, "text/html", PAGE_settings_time, PAGE_settings_time_length); break;
case 6: response = request->beginResponse_P(200, "text/html", PAGE_settings_sec, PAGE_settings_sec_length); break; case 6: response = request->beginResponse_P(200, "text/html", PAGE_settings_sec, PAGE_settings_sec_length); break;
#ifdef WLED_ENABLE_DMX
case 7: response = request->beginResponse_P(200, "text/html", PAGE_settings_dmx, PAGE_settings_dmx_length); break; case 7: response = request->beginResponse_P(200, "text/html", PAGE_settings_dmx, PAGE_settings_dmx_length); break;
#endif
case 8: response = request->beginResponse_P(200, "text/html", PAGE_settings_um, PAGE_settings_um_length); break; case 8: response = request->beginResponse_P(200, "text/html", PAGE_settings_um, PAGE_settings_um_length); break;
case 9: response = request->beginResponse_P(200, "text/html", PAGE_update, PAGE_update_length); break; case 9: response = request->beginResponse_P(200, "text/html", PAGE_update, PAGE_update_length); break;
#ifndef WLED_DISABLE_2D
case 10: response = request->beginResponse_P(200, "text/html", PAGE_settings_2D, PAGE_settings_2D_length); break; case 10: response = request->beginResponse_P(200, "text/html", PAGE_settings_2D, PAGE_settings_2D_length); break;
#endif
case 251: { case 251: {
correctPIN = !strlen(settingsPIN); // lock if a pin is set correctPIN = !strlen(settingsPIN); // lock if a pin is set
createEditHandler(correctPIN); createEditHandler(correctPIN);

View File

@ -287,6 +287,9 @@ void getSettingsJS(byte subPage, char* dest)
if (subPage == 0) if (subPage == 0)
{ {
#ifndef WLED_DISABLE_2D // include only if 2D is compiled in
oappend(PSTR("gId('2dbtn').style.display='';"));
#endif
#ifdef WLED_ENABLE_DMX // include only if DMX is enabled #ifdef WLED_ENABLE_DMX // include only if DMX is enabled
oappend(PSTR("gId('dmxbtn').style.display='';")); oappend(PSTR("gId('dmxbtn').style.display='';"));
#endif #endif
@ -505,6 +508,7 @@ void getSettingsJS(byte subPage, char* dest)
sappend('c',SET_F("EM"),e131Multicast); sappend('c',SET_F("EM"),e131Multicast);
sappend('v',SET_F("EU"),e131Universe); sappend('v',SET_F("EU"),e131Universe);
sappend('v',SET_F("DA"),DMXAddress); sappend('v',SET_F("DA"),DMXAddress);
sappend('v',SET_F("XX"),DMXSegmentSpacing);
sappend('v',SET_F("DM"),DMXMode); sappend('v',SET_F("DM"),DMXMode);
sappend('v',SET_F("ET"),realtimeTimeoutMs); sappend('v',SET_F("ET"),realtimeTimeoutMs);
sappend('c',SET_F("FB"),arlsForceMaxBri); sappend('c',SET_F("FB"),arlsForceMaxBri);