diff --git a/.github/workflows/wled-ci.yml b/.github/workflows/wled-ci.yml
index 1655f7ec..59661ff8 100644
--- a/.github/workflows/wled-ci.yml
+++ b/.github/workflows/wled-ci.yml
@@ -8,21 +8,23 @@ jobs:
name: Gather Environments
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Cache pip
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
- - uses: actions/setup-python@v2
+ - uses: actions/setup-python@v4
+ with:
+ python-version: '3.9'
- name: Install PlatformIO
run: pip install -r requirements.txt
- name: Get default environments
id: envs
run: |
- echo "::set-output name=environments::$(pio project config --json-output | jq -cr '.[0][1][0][1]')"
+ echo "environments=$(pio project config --json-output | jq -cr '.[0][1][0][1]')" >> $GITHUB_OUTPUT
outputs:
environments: ${{ steps.envs.outputs.environments }}
@@ -32,24 +34,27 @@ jobs:
runs-on: ubuntu-latest
needs: get_default_envs
strategy:
+ fail-fast: false
matrix:
environment: ${{ fromJSON(needs.get_default_envs.outputs.environments) }}
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Cache pip
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Cache PlatformIO
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
path: ~/.platformio
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
- name: Set up Python
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.9'
- name: Install PlatformIO
run: pip install -r requirements.txt
- name: Build firmware
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 69129061..641568de 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
## WLED changelog
+#### Build 2304090
+- updated Arduino ESP8266 core to 4.1.0 (newer compiler)
+- updated NeoPixelBus to 2.7.3 (with support for UCS890x chipset)
+- better support for ESP32-C3, ESP32-S2 and ESP32-S3 (Arduino ESP32 core 5.2.0)
+- iPad/tablet with 1024 pixels width in landscape orientation PC mode support (#3153)
+- fix for Pixel Art Converter (#3155)
+
#### Build 2303240
- Peek scaling of large 2D matrices
- Added 0D (1 pixel) metadata for effects & enhance 0D (analog strip) UI handling
diff --git a/package-lock.json b/package-lock.json
index 9a2d44e6..df1fb2de 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "wled",
- "version": "0.14.0-b15.23",
+ "version": "0.14.0-b15.24",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "wled",
- "version": "0.14.0-b15.23",
+ "version": "0.14.0-b15.24",
"license": "ISC",
"dependencies": {
"clean-css": "^4.2.3",
diff --git a/package.json b/package.json
index 87922f0b..bf855c85 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "wled",
- "version": "0.14.0-b15.23",
+ "version": "0.14.0-b15.24",
"description": "Tools for WLED project",
"main": "tools/cdata.js",
"directories": {
diff --git a/platformio.ini b/platformio.ini
index fa239a70..ac273f8b 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -12,6 +12,9 @@
# Release / CI binaries
; default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth, esp32s2_saola, esp32c3, esp32s3dev_8MB
+# Release binaries
+; default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_8MB
+
# Build everything
; default_envs = esp32dev, esp8285_4CH_MagicHome, codm-controller-0_6-rev2, codm-controller-0_6, esp32s2_saola, d1_mini_5CH_Shojo_PCB, d1_mini, sp501e, nodemcuv2, esp32_eth, anavi_miracle_controller, esp07, esp01_1m_full, m5atom, h803wf, d1_mini_ota, heltec_wifi_kit_8, esp8285_H801, d1_mini_debug, wemos_shield_esp32, elekstube_ips
@@ -40,24 +43,24 @@
; ===================
default_envs =
- esp32_4MB_S
+ ; esp32_4MB_S
esp32_4MB_M ; recommended default
esp32_4MB_M_debug
esp32_4MB_XL
esp32_16MB_M
- esp32_16MB_M_debug
- esp32_16MB_XL
+ ; esp32_16MB_M_debug
+ ; esp32_16MB_XL
esp8266_4MB_S
- esp8266_4MB_M
+ ; esp8266_4MB_M
wemos_shield_esp32_4MB_M
- wemos_shield_esp32_4MB_ICS4343x_M
- wemos_shield_esp32_4MB_SPM1423_M
- wemos_shield_esp32_4MB_LineIn_M
- wemos_shield_esp32_16MB_M
- wemos_shield_esp32_16MB_ICS4343x_M
- wemos_shield_esp32_16MB_SPM1423_M
- wemos_shield_esp32_16MB_SPM1423_XL
- wemos_shield_esp32_16MB_LineIn_M
+ ; wemos_shield_esp32_4MB_ICS4343x_M
+ ; wemos_shield_esp32_4MB_SPM1423_M
+ ; wemos_shield_esp32_4MB_LineIn_M
+ ; wemos_shield_esp32_16MB_M
+ ; wemos_shield_esp32_16MB_ICS4343x_M
+ ; wemos_shield_esp32_16MB_SPM1423_M
+ ; wemos_shield_esp32_16MB_SPM1423_XL
+ ; wemos_shield_esp32_16MB_LineIn_M
esp32_pico_4MB_M
esp32_4MB_PSRAM_S
esp32S3_8MB_M
@@ -138,6 +141,7 @@ debug_flags = -D DEBUG=1 -D WLED_DEBUG -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_CLIENT
# This reduces the OTA size with ~45KB, so it's especially useful on low memory boards (512k/1m).
# ------------------------------------------------------------------------------
build_flags =
+ -Wno-attributes
-DMQTT_MAX_PACKET_SIZE=1024
-DSECURE_CLIENT=SECURE_CLIENT_BEARSSL
-DBEARSSL_SSL_BASIC
@@ -839,7 +843,7 @@ build_flags_M =
-D USERMOD_GAMES ; WLEDMM usermod
-D USERMOD_BATTERY ;; enable Battery usermod
-D USERMOD_BATTERY_USE_LIPO ;; use new "decharging curve" for LiPo cells
- ; -D USERMOD_FASTLED ; WLEDMM usermod: CC BY-NC 3.0 licensed effects by Stefan Petrick, include this usermod only if you accept the terms!
+ -D USERMOD_ANIMARTRIX ; WLEDMM usermod: CC BY-NC 3.0 licensed effects by Stefan Petrick
;WLEDMM: only setting WLED_DEBUG_HOST is enough, ip and port can be defined in sync settings as well
-D WLED_DEBUG_HOST='"192.168.x.x"' ;; to send debug messages over network to host 192.168.x.y - FQDN is also possible
-D WLED_DEBUG_PORT=1768 ;; port for network debugging. default = 7868
@@ -1099,7 +1103,7 @@ build_flags = ${common.build_flags_esp8266}
-D USERMOD_FOUR_LINE_DISPLAY
-D USERMOD_MPU6050_IMU ; gyro/accelero for USERMOD_GAMES (ONLY WORKS IF USERMOD_FOUR_LINE_DISPLAY NOT INCLUDED - I2C SHARING BUG)
-D USERMOD_GAMES ; WLEDMM usermod
- -D USERMOD_ARTIFX
+ ; -D USERMOD_ARTIFX ; this is compiling but not working due to low memory on 8266
-D USERMOD_BATTERY ;; enable Battery usermod
-D USERMOD_BATTERY_USE_LIPO ;; use new "decharging curve" for LiPo cells
-D WLED_DEBUG_HOST='"192.168.x.x"' ;; to send debug messages over network to host 192.168.x.y - FQDN is also possible
diff --git a/requirements.txt b/requirements.txt
index e484d7bc..da65486c 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -4,63 +4,59 @@
#
# pip-compile
#
-aiofiles==0.8.0
+aiofiles==22.1.0
# via platformio
ajsonrpc==1.2.0
# via platformio
-anyio==3.6.1
+anyio==3.6.2
# via starlette
-async-timeout==4.0.2
- # via zeroconf
-bottle==0.12.23
+bottle==0.12.25
# via platformio
certifi==2022.12.7
# via requests
-charset-normalizer==2.1.1
+charset-normalizer==3.1.0
# via requests
click==8.1.3
# via
# platformio
# uvicorn
-colorama==0.4.5
- # via platformio
-h11==0.13.0
+colorama==0.4.6
+ # via
+ # click
+ # platformio
+h11==0.14.0
# via
# uvicorn
# wsproto
-idna==3.3
+idna==3.4
# via
# anyio
# requests
-ifaddr==0.2.0
- # via zeroconf
-marshmallow==3.17.0
+marshmallow==3.19.0
# via platformio
-packaging==21.3
+packaging==23.1
# via marshmallow
-platformio==6.1.4
+platformio==6.1.6
# via -r requirements.in
pyelftools==0.29
# via platformio
-pyparsing==3.0.9
- # via packaging
pyserial==3.5
# via platformio
-requests==2.28.1
+requests==2.28.2
# via platformio
semantic-version==2.10.0
# via platformio
-sniffio==1.2.0
+sniffio==1.3.0
# via anyio
-starlette==0.20.4
+starlette==0.23.1
# via platformio
-tabulate==0.8.10
+tabulate==0.9.0
# via platformio
-urllib3==1.26.11
+typing-extensions==4.5.0
+ # via starlette
+urllib3==1.26.15
# via requests
-uvicorn==0.18.2
+uvicorn==0.20.0
# via platformio
-wsproto==1.1.0
- # via platformio
-zeroconf==0.39.0
+wsproto==1.2.0
# via platformio
diff --git a/tools/cdata.js b/tools/cdata.js
index 55b04e13..707360d6 100644
--- a/tools/cdata.js
+++ b/tools/cdata.js
@@ -221,6 +221,7 @@ function writeChunks(srcDir, specs, resultFile) {
writeHtmlGzipped("wled00/data/index.htm", "wled00/html_ui.h", 'index');
writeHtmlGzipped("wled00/data/simple.htm", "wled00/html_simple.h", 'simple');
writeHtmlGzipped("wled00/data/pixart/pixart.htm", "wled00/html_pixart.h", 'pixart');
+writeHtmlGzipped("wled00/data/cpal/cpal.htm", "wled00/html_cpal.h", 'cpal');
/*
writeChunks(
"wled00/data",
diff --git a/usermods/Battery/battery_defaults.h b/usermods/Battery/battery_defaults.h
index 71c73b3b..c1e3c6bb 100644
--- a/usermods/Battery/battery_defaults.h
+++ b/usermods/Battery/battery_defaults.h
@@ -26,6 +26,15 @@
#endif
#endif
+//the default ratio for the voltage divider
+#ifndef USERMOD_BATTERY_VOLTAGE_MULTIPLIER
+ #ifdef ARDUINO_ARCH_ESP32
+ #define USERMOD_BATTERY_VOLTAGE_MULTIPLIER 2.0f
+ #else //ESP8266 boards
+ #define USERMOD_BATTERY_VOLTAGE_MULTIPLIER 4.2f
+ #endif
+#endif
+
#ifndef USERMOD_BATTERY_MAX_VOLTAGE
#define USERMOD_BATTERY_MAX_VOLTAGE 4.2f
#endif
diff --git a/usermods/Battery/usermod_v2_Battery.h b/usermods/Battery/usermod_v2_Battery.h
index 98aeda43..3d519724 100644
--- a/usermods/Battery/usermod_v2_Battery.h
+++ b/usermods/Battery/usermod_v2_Battery.h
@@ -29,6 +29,10 @@ class UsermodBattery : public Usermod
float rawValue = 0.0f;
// calculated voltage
float voltage = maxBatteryVoltage;
+ // between 0 and 1, to control strength of voltage smoothing filter
+ float alpha = 0.05f;
+ // multiplier for the voltage divider that is in place between ADC pin and battery, default will be 2 but might be adapted to readout voltages over ~5v ESP32 or ~6.6v ESP8266
+ float voltageMultiplier = USERMOD_BATTERY_VOLTAGE_MULTIPLIER;
// mapped battery level based on voltage
int8_t batteryLevel = 100;
// offset or calibration value to fine tune the calculated voltage
@@ -110,6 +114,17 @@ class UsermodBattery : public Usermod
}
}
+ float readVoltage()
+ {
+ #ifdef ARDUINO_ARCH_ESP32
+ // use calibrated millivolts analogread on esp32 (150 mV ~ 2450 mV default attentuation) and divide by 1000 to get from milivolts to volts and multiply by voltage multiplier and apply calibration value
+ return (analogReadMilliVolts(batteryPin) / 1000.0f) * voltageMultiplier + calibration;
+ #else
+ // use analog read on esp8266 ( 0V ~ 1V no attenuation options) and divide by ADC precision 1023 and multiply by voltage multiplier and apply calibration value
+ return (analogRead(batteryPin) / 1023.0f) * voltageMultiplier + calibration;
+ #endif
+ }
+
public:
//Functions called by WLED
@@ -126,6 +141,7 @@ class UsermodBattery : public Usermod
if (pinManager.allocatePin(batteryPin, false, PinOwner::UM_Battery)) {
DEBUG_PRINTLN(F("Battery pin allocation succeeded."));
success = true;
+ voltage = readVoltage();
}
if (!success) {
@@ -135,8 +151,8 @@ class UsermodBattery : public Usermod
pinMode(batteryPin, INPUT);
}
#else //ESP8266 boards have only one analog input pin A0
-
pinMode(batteryPin, INPUT);
+ voltage = readVoltage();
#endif
nextReadTime = millis() + readingInterval;
@@ -176,22 +192,12 @@ class UsermodBattery : public Usermod
initializing = false;
-#ifdef ARDUINO_ARCH_ESP32
- // use calibrated millivolts analogread on esp32 (150 mV ~ 2450 mV)
- rawValue = analogReadMilliVolts(batteryPin);
- // calculate the voltage
- voltage = (rawValue / 1000.0f) + calibration;
- // usually a voltage divider (50%) is used on ESP32, so we need to multiply by 2
- voltage *= 2.0f;
-#else
- // read battery raw input
- rawValue = analogRead(batteryPin);
+ rawValue = readVoltage();
+ // filter with exponential smoothing because ADC in esp32 is fluctuating too much for a good single readout
+ voltage = voltage + alpha * (rawValue - voltage);
- // calculate the voltage
- voltage = ((rawValue / getAdcPrecision()) * maxBatteryVoltage) + calibration;
-#endif
- // check if voltage is within specified voltage range, allow 10% over/under voltage
- voltage = ((voltage < minBatteryVoltage * 0.85f) || (voltage > maxBatteryVoltage * 1.1f)) ? -1.0f : voltage;
+ // check if voltage is within specified voltage range, allow 10% over/under voltage - removed cause this just makes it hard for people to troubleshoot as the voltage in the web gui will say invalid instead of displaying a voltage
+ //voltage = ((voltage < minBatteryVoltage * 0.85f) || (voltage > maxBatteryVoltage * 1.1f)) ? -1.0f : voltage;
// translate battery voltage into percentage
/*
@@ -363,6 +369,7 @@ class UsermodBattery : public Usermod
battery[F("max-voltage")] = maxBatteryVoltage;
battery[F("capacity")] = totalBatteryCapacity;
battery[F("calibration")] = calibration;
+ battery[F("voltage-multiplier")] = voltageMultiplier;
battery[FPSTR(_readInterval)] = readingInterval;
JsonObject ao = battery.createNestedObject(F("auto-off")); // auto off section
@@ -375,6 +382,9 @@ class UsermodBattery : public Usermod
lp[FPSTR(_threshold)] = lowPowerIndicatorThreshold;
lp[FPSTR(_duration)] = lowPowerIndicatorDuration;
+ // read voltage in case calibration or voltage multiplier changed to see immediate effect
+ voltage = readVoltage();
+
DEBUG_PRINTLN(F("Battery config saved."));
}
@@ -441,6 +451,7 @@ class UsermodBattery : public Usermod
setMaxBatteryVoltage(battery[F("max-voltage")] | maxBatteryVoltage);
setTotalBatteryCapacity(battery[F("capacity")] | totalBatteryCapacity);
setCalibration(battery[F("calibration")] | calibration);
+ setVoltageMultiplier(battery[F("voltage-multiplier")] | voltageMultiplier);
setReadingInterval(battery[FPSTR(_readInterval)] | readingInterval);
JsonObject ao = battery[F("auto-off")];
@@ -597,21 +608,7 @@ class UsermodBattery : public Usermod
totalBatteryCapacity = capacity;
}
- /*
- * Get the choosen adc precision
- * esp8266 = 10bit resolution = 1024.0f
- * esp32 = 12bit resolution = 4095.0f
- */
- float getAdcPrecision()
- {
- #ifdef ARDUINO_ARCH_ESP32
- // esp32
- return 4096.0f;
- #else
- // esp8266
- return 1024.0f;
- #endif
- }
+
/*
* Get the calculated voltage
@@ -649,6 +646,23 @@ class UsermodBattery : public Usermod
calibration = offset;
}
+ /*
+ * Set the voltage multiplier value
+ * A multiplier that may need adjusting for different voltage divider setups
+ */
+ void setVoltageMultiplier(float multiplier)
+ {
+ voltageMultiplier = multiplier;
+ }
+
+ /*
+ * Get the voltage multiplier value
+ * A multiplier that may need adjusting for different voltage divider setups
+ */
+ float getVoltageMultiplier()
+ {
+ return voltageMultiplier;
+ }
/*
* Get auto-off feature enabled status
diff --git a/usermods/artifx/artifx.js b/usermods/artifx/artifx.js
index 892afb5c..d1658077 100644
--- a/usermods/artifx/artifx.js
+++ b/usermods/artifx/artifx.js
@@ -9,33 +9,9 @@ function toggleCEEditor(name, segID) {
d.getElementById('ceEditor').style.transform = (isCEEditor) ? "translateY(0px)":"translateY(100%)";
}
-function fetchAndExecute(url, name, callback, callError)
-{
- fetch
- (url+name, {
- method: 'get'
- })
- .then(res => {
- if (!res.ok) {
- callError("File " + name + " not found");
- return "";
- }
- return res.text();
- })
- .then(text => {
- callback(text);
- })
- .catch(function (error) {
- callError("Error getting " + name);
- })
- .finally(() => {
- // if (callback) setTimeout(callback,99);
- });
-}
-
function loadLogFile(name, attempt) {
var ceLogArea = d.getElementById("ceLogArea");
- fetchAndExecute((loc?`http://${locip}`:'.') + "/", name , function(logtext)
+ fetchAndExecute((loc?`http://${locip}`:'.') + "/", name, null, function(parms,logtext)
{
if (logtext == "") {
if (attempt < 10) {
@@ -50,7 +26,7 @@ function loadLogFile(name, attempt) {
}
else
ceLogArea.value = logtext;
- }, function(error){
+ }, function(parms,error){
showToast(error);
console.log(error);
});
@@ -91,7 +67,7 @@ function saveCE(name, segID) {
function populateCEEditor(name, segID)
{
- fetchAndExecute((loc?`http://${locip}`:'.') + "/", name + ".wled", function(text)
+ fetchAndExecute((loc?`http://${locip}`:'.') + "/", name + ".wled", null, function(parms,text)
{
var cn=`ARTI-FX Editor
${name}.wled
@@ -117,7 +93,7 @@ function populateCEEditor(name, segID)
ceLogArea.value = ".";
loadLogFile(name + ".log", 1);
- }, function(error){
+ }, function(parms,error){
showToast(error);
console.log(error);
});
@@ -129,7 +105,7 @@ function downloadGHFile(url, name, save=false, warn=false) { //Githubfile
if (url == "HBE") url = "https://raw.githubusercontent.com/MoonModules/WLED-Effects/master/Presets/HB_PresetPack210808_32x32_16seg/Effects%20pack/";
if (url == "LM") url = "https://raw.githubusercontent.com/MoonModules/WLED-Effects/master/Ledmaps/";
- fetchAndExecute(url, name, function(text) {
+ fetchAndExecute(url, name, null, function(parms,text) {
if (save) {
if (warn && !confirm('Are you sure to download/overwrite ' + name + '?'))
return;
@@ -140,7 +116,7 @@ function downloadGHFile(url, name, save=false, warn=false) { //Githubfile
var ceProgramArea = d.getElementById("ceProgramArea");
ceProgramArea.value = text;
}
- }, function(error){
+ }, function(parms,error){
showToast(error);
console.log(url + name,error);
});
diff --git a/usermods/usermod_v2_fastled/readme.md b/usermods/usermod_v2_animartrix/readme.md
similarity index 84%
rename from usermods/usermod_v2_fastled/readme.md
rename to usermods/usermod_v2_animartrix/readme.md
index 93707655..d12dd1b0 100644
--- a/usermods/usermod_v2_fastled/readme.md
+++ b/usermods/usermod_v2_animartrix/readme.md
@@ -4,7 +4,7 @@ In this usermod file you can find the documentation on how to take advantage of
## Installation
-Copy `usermod_v2_fastled.h` to the wled00 directory.
+Copy `usermod_v2_animartrix.h` to the wled00 directory.
Uncomment the corresponding lines in `usermods_list.cpp` and compile!
_(You shouldn't need to actually install this, it does nothing useful)_
diff --git a/usermods/usermod_v2_fastled/usermod_v2_fastled.h b/usermods/usermod_v2_animartrix/usermod_v2_animartrix.h
similarity index 97%
rename from usermods/usermod_v2_fastled/usermod_v2_fastled.h
rename to usermods/usermod_v2_animartrix/usermod_v2_animartrix.h
index c105396b..ad21ae63 100644
--- a/usermods/usermod_v2_fastled/usermod_v2_fastled.h
+++ b/usermods/usermod_v2_animartrix/usermod_v2_animartrix.h
@@ -20,7 +20,7 @@
//based on: https://gist.github.com/StefanPetrick/9c091d9a28a902af5a7b540e40442c64
-class StefanPetrickCore {
+class AnimartrixCore {
private:
public:
@@ -60,11 +60,11 @@ class StefanPetrickCore {
float noise_angle_c, noise_angle_d, noise_angle_e, noise_angle_f; // angles based on linear noise travel
float dir_c, dir_d, dir_e, dir_f; // direction multiplicators
- StefanPetrickCore() {
- USER_PRINTLN("StefanPetrickCore constructor");
+ AnimartrixCore() {
+ USER_PRINTLN("AnimartrixCore constructor");
}
- ~StefanPetrickCore() {
- USER_PRINTLN("StefanPetrickCore destructor");
+ ~AnimartrixCore() {
+ USER_PRINTLN("AnimartrixCore destructor");
}
void init() {
@@ -177,7 +177,7 @@ class StefanPetrickCore {
}
};
-class PolarBasics:public StefanPetrickCore {
+class PolarBasics:public AnimartrixCore {
private:
public:
@@ -262,7 +262,7 @@ class PolarBasics:public StefanPetrickCore {
void calculate_oscillators() {
- StefanPetrickCore::calculate_oscillators();
+ AnimartrixCore::calculate_oscillators();
uint16_t noi;
noi = inoise16(10000 + linear_c * 100000); // some noise controlled angular offsets
@@ -369,7 +369,7 @@ class PolarBasics:public StefanPetrickCore {
//based on https://gist.github.com/StefanPetrick/35ffd8467df22a77067545cfb889aa4f
//and Fastled podcast nr 3: https://www.youtube.com/watch?v=3tfjP7GJnZo
-class CircularBlobs:public StefanPetrickCore {
+class CircularBlobs:public AnimartrixCore {
private:
float fade(float t){ return t * t * t * (t * (t * 6 - 15) + 10); }
@@ -498,7 +498,7 @@ class CircularBlobs:public StefanPetrickCore {
void calculate_oscillators() {
- StefanPetrickCore::calculate_oscillators();
+ AnimartrixCore::calculate_oscillators();
float n;
@@ -615,11 +615,11 @@ uint16_t mode_CircularBlobs(void) {
static const char _data_FX_mode_CircularBlobs[] PROGMEM = "💡CircularBlobs ☾@AngleDist,AngleMult;;!;2;sx=51,ix=51,c1=0,c2=0,c3=0";
-class FastledUsermod : public Usermod {
+class AnimartrixUsermod : public Usermod {
public:
- FastledUsermod(const char *name, bool enabled):Usermod(name, enabled) {} //WLEDMM
+ AnimartrixUsermod(const char *name, bool enabled):Usermod(name, enabled) {} //WLEDMM
void setup() {
strip.addEffect(255, &mode_PolarBasics, _data_FX_mode_PolarBasics);
@@ -640,7 +640,7 @@ class FastledUsermod : public Usermod {
uint16_t getId()
{
- return USERMOD_ID_FASTLED;
+ return USERMOD_ID_ANIMARTRIX;
}
};
diff --git a/usermods/usermod_v2_word_clock/usermod_v2_word_clock.h b/usermods/usermod_v2_word_clock/usermod_v2_word_clock.h
index c825a7af..058b8318 100644
--- a/usermods/usermod_v2_word_clock/usermod_v2_word_clock.h
+++ b/usermods/usermod_v2_word_clock/usermod_v2_word_clock.h
@@ -40,39 +40,39 @@ class WordClockUsermod : public Usermod
// Normal wiring
const int maskMinutes[14][maskSizeMinutes] =
{
- {107, 108, 109, -1, -1, -1, -1, -1, -1, -1, -1, -1}, // :00
- { 7, 8, 9, 10, 40, 41, 42, 43, -1, -1, -1, -1}, // :05 fünf nach
- { 11, 12, 13, 14, 40, 41, 42, 43, -1, -1, -1, -1}, // :10 zehn nach
- { 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, -1, -1}, // :15 viertel
- { 15, 16, 17, 18, 19, 20, 21, 40, 41, 42, 43, -1}, // :20 zwanzig nach
- { 7, 8, 9, 10, 33, 34, 35, 44, 45, 46, 47, -1}, // :25 fünf vor halb
- { 44, 45, 46, 47, -1, -1, -1, -1, -1, -1, -1, -1}, // :30 halb
- { 7, 8, 9, 10, 40, 41, 42, 43, 44, 45, 46, 47}, // :35 fünf nach halb
- { 15, 16, 17, 18, 19, 20, 21, 33, 34, 35, -1, -1}, // :40 zwanzig vor
- { 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, -1}, // :45 dreiviertel
- { 11, 12, 13, 14, 33, 34, 35, -1, -1, -1, -1, -1}, // :50 zehn vor
- { 7, 8, 9, 10, 33, 34, 35, -1, -1, -1, -1, -1}, // :55 fünf vor
- { 26, 27, 28, 29, 30, 31, 32, 40, 41, 42, 43, -1}, // :15 alternative viertel nach
- { 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1} // :45 alternative viertel vor
+ {107, 108, 109, -1, -1, -1, -1, -1, -1, -1, -1, -1}, // 0 - 00
+ { 7, 8, 9, 10, 40, 41, 42, 43, -1, -1, -1, -1}, // 1 - 05 fünf nach
+ { 11, 12, 13, 14, 40, 41, 42, 43, -1, -1, -1, -1}, // 2 - 10 zehn nach
+ { 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, -1, -1}, // 3 - 15 viertel
+ { 15, 16, 17, 18, 19, 20, 21, 40, 41, 42, 43, -1}, // 4 - 20 zwanzig nach
+ { 7, 8, 9, 10, 33, 34, 35, 44, 45, 46, 47, -1}, // 5 - 25 fünf vor halb
+ { 44, 45, 46, 47, -1, -1, -1, -1, -1, -1, -1, -1}, // 6 - 30 halb
+ { 7, 8, 9, 10, 40, 41, 42, 43, 44, 45, 46, 47}, // 7 - 35 fünf nach halb
+ { 15, 16, 17, 18, 19, 20, 21, 33, 34, 35, -1, -1}, // 8 - 40 zwanzig vor
+ { 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, -1}, // 9 - 45 dreiviertel
+ { 11, 12, 13, 14, 33, 34, 35, -1, -1, -1, -1, -1}, // 10 - 50 zehn vor
+ { 7, 8, 9, 10, 33, 34, 35, -1, -1, -1, -1, -1}, // 11 - 55 fünf vor
+ { 26, 27, 28, 29, 30, 31, 32, 40, 41, 42, 43, -1}, // 12 - 15 alternative viertel nach
+ { 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1} // 13 - 45 alternative viertel vor
};
// Meander wiring
const int maskMinutesMea[14][maskSizeMinutesMea] =
{
- { 99, 100, 101, -1, -1, -1, -1, -1, -1, -1, -1, -1}, // :00
- { 7, 8, 9, 10, 33, 34, 35, 36, -1, -1, -1, -1}, // :05 fünf nach
- { 18, 19, 20, 21, 33, 34, 35, 36, -1, -1, -1, -1}, // :10 zehn nach
- { 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, -1, -1}, // :15 viertel
- { 11, 12, 13, 14, 15, 16, 17, 33, 34, 35, 36, -1}, // :20 zwanzig nach
- { 7, 8, 9, 10, 41, 42, 43, 44, 45, 46, 47, -1}, // :25 fünf vor halb
- { 44, 45, 46, 47, -1, -1, -1, -1, -1, -1, -1, -1}, // :30 halb
- { 7, 8, 9, 10, 33, 34, 35, 36, 44, 45, 46, 47}, // :35 fünf nach halb
- { 11, 12, 13, 14, 15, 16, 17, 41, 42, 43, -1, -1}, // :40 zwanzig vor
- { 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, -1}, // :45 dreiviertel
- { 18, 19, 20, 21, 41, 42, 43, -1, -1, -1, -1, -1}, // :50 zehn vor
- { 7, 8, 9, 10, 41, 42, 43, -1, -1, -1, -1, -1}, // :55 fünf vor
- { 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, -1}, // :15 alternative viertel nach
- { 26, 27, 28, 29, 30, 31, 32, 41, 42, 43, -1, -1} // :45 alternative viertel vor
+ { 99, 100, 101, -1, -1, -1, -1, -1, -1, -1, -1, -1}, // 0 - 00
+ { 7, 8, 9, 10, 33, 34, 35, 36, -1, -1, -1, -1}, // 1 - 05 fünf nach
+ { 18, 19, 20, 21, 33, 34, 35, 36, -1, -1, -1, -1}, // 2 - 10 zehn nach
+ { 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, -1, -1}, // 3 - 15 viertel
+ { 11, 12, 13, 14, 15, 16, 17, 33, 34, 35, 36, -1}, // 4 - 20 zwanzig nach
+ { 7, 8, 9, 10, 41, 42, 43, 44, 45, 46, 47, -1}, // 5 - 25 fünf vor halb
+ { 44, 45, 46, 47, -1, -1, -1, -1, -1, -1, -1, -1}, // 6 - 30 halb
+ { 7, 8, 9, 10, 33, 34, 35, 36, 44, 45, 46, 47}, // 7 - 35 fünf nach halb
+ { 11, 12, 13, 14, 15, 16, 17, 41, 42, 43, -1, -1}, // 8 - 40 zwanzig vor
+ { 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, -1}, // 9 - 45 dreiviertel
+ { 18, 19, 20, 21, 41, 42, 43, -1, -1, -1, -1, -1}, // 10 - 50 zehn vor
+ { 7, 8, 9, 10, 41, 42, 43, -1, -1, -1, -1, -1}, // 11 - 55 fünf vor
+ { 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, -1}, // 12 - 15 alternative viertel nach
+ { 26, 27, 28, 29, 30, 31, 32, 41, 42, 43, -1, -1} // 13 - 45 alternative viertel vor
};
@@ -284,12 +284,13 @@ class WordClockUsermod : public Usermod
setHours(hours + 1, false);
break;
case 9:
- // viertel vor bzw dreiviertel
+ // viertel vor
if (nord) {
- setMinutes(9);
+ setMinutes(13);
}
+ // dreiviertel
else {
- setMinutes(12);
+ setMinutes(9);
}
setHours(hours + 1, false);
break;
@@ -422,12 +423,18 @@ class WordClockUsermod : public Usermod
*/
void addToConfig(JsonObject& root)
{
- JsonObject top = root.createNestedObject("WordClockUsermod");
- top["active"] = usermodActive;
- top["displayItIs"] = displayItIs;
- top["ledOffset"] = ledOffset;
- top["Meander wiring?"] = meander;
- top["Norddeutsch"] = nord;
+ JsonObject top = root.createNestedObject(F("WordClockUsermod"));
+ top[F("active")] = usermodActive;
+ top[F("displayItIs")] = displayItIs;
+ top[F("ledOffset")] = ledOffset;
+ top[F("Meander wiring?")] = meander;
+ top[F("Norddeutsch")] = nord;
+ }
+
+ void appendConfigData()
+ {
+ oappend(SET_F("addInfo('WordClockUsermod:ledOffset', 1, 'Number of LEDs before the letters');"));
+ oappend(SET_F("addInfo('WordClockUsermod:Norddeutsch', 1, 'Viertel vor instead of Dreiviertel');"));
}
/*
@@ -450,15 +457,15 @@ class WordClockUsermod : public Usermod
// default settings values could be set here (or below using the 3-argument getJsonValue()) instead of in the class definition or constructor
// setting them inside readFromConfig() is slightly more robust, handling the rare but plausible use case of single value being missing after boot (e.g. if the cfg.json was manually edited and a value was removed)
- JsonObject top = root["WordClockUsermod"];
+ JsonObject top = root[F("WordClockUsermod")];
bool configComplete = !top.isNull();
- configComplete &= getJsonValue(top["active"], usermodActive);
- configComplete &= getJsonValue(top["displayItIs"], displayItIs);
- configComplete &= getJsonValue(top["ledOffset"], ledOffset);
- configComplete &= getJsonValue(top["Meander wiring?"], meander);
- configComplete &= getJsonValue(top["Norddeutsch"], nord);
+ configComplete &= getJsonValue(top[F("active")], usermodActive);
+ configComplete &= getJsonValue(top[F("displayItIs")], displayItIs);
+ configComplete &= getJsonValue(top[F("ledOffset")], ledOffset);
+ configComplete &= getJsonValue(top[F("Meander wiring?")], meander);
+ configComplete &= getJsonValue(top[F("Norddeutsch")], nord);
return configComplete;
}
diff --git a/wled00/FX.cpp b/wled00/FX.cpp
index 586db297..dab70a6b 100644
--- a/wled00/FX.cpp
+++ b/wled00/FX.cpp
@@ -1247,10 +1247,10 @@ uint16_t mode_rain() {
if (SEGENV.call && SEGENV.step > SPEED_FORMULA_L) {
SEGENV.step = 1;
if (strip.isMatrix) {
- uint32_t ctemp[width];
- for (int i = 0; i> 6; //div 64
+ const uint32_t it = strip.now >> 5; //div 32
struct virtualStrip {
static void runStrip(uint16_t stripNr, byte* heat, uint32_t it) {
@@ -1987,28 +1987,24 @@ uint16_t mode_fire_2012() {
// Step 1. Cool down every cell a little
for (int i = 0; i < SEGLEN; i++) {
- uint8_t cool = (it != SEGENV.step) ? random8((((20 + SEGMENT.speed/3) * 16) / SEGLEN)+2) : random(8);
- uint8_t minTemp = 0;
- if (i 1; k--) {
heat[k] = (heat[k - 1] + (heat[k - 2]<<1) ) / 3; // heat[k-2] multiplied by 2
}
- }
- // Step 3. Randomly ignite new 'sparks' of heat near the bottom
- if (random8() <= SEGMENT.intensity) {
- uint8_t y = random8(ignition);
- uint8_t boost = (32+SEGMENT.custom3*2) * (2*ignition-y) / (2*ignition);
- heat[y] = qadd8(heat[y], random8(64+boost,128+boost));
+ // Step 3. Randomly ignite new 'sparks' of heat near the bottom
+ if (random8() <= SEGMENT.intensity) {
+ uint8_t y = random8(ignition);
+ uint8_t boost = (17+SEGMENT.custom3) * (ignition - y/2) / ignition; // integer math!
+ heat[y] = qadd8(heat[y], random8(96+2*boost,207+boost));
+ }
}
// Step 4. Map from heat cells to LED colors
@@ -2028,7 +2024,7 @@ uint16_t mode_fire_2012() {
return FRAMETIME;
}
-static const char _data_FX_MODE_FIRE_2012[] PROGMEM = "Fire 2012@Cooling,Spark rate,,,Boost;;!;1.5d;pal=0,sx=120,ix=64,m12=1"; // bars WLEDMM 1.5d, pal = 0
+static const char _data_FX_MODE_FIRE_2012[] PROGMEM = "Fire 2012@Cooling,Spark rate,,,Boost;;!;1.5d;sx=64,ix=160,m12=1"; // bars WLEDMM 1.5d,
// ColorWavesWithPalettes by Mark Kriegsman: https://gist.github.com/kriegsman/8281905786e8b2632aeb
@@ -2765,7 +2761,7 @@ uint16_t mode_spots()
{
return spots_base((255 - SEGMENT.speed) << 8);
}
-static const char _data_FX_MODE_SPOTS[] PROGMEM = "Spots@,Width,,,,,Overlay;!,!;!";
+static const char _data_FX_MODE_SPOTS[] PROGMEM = "Spots@Spread,Width,,,,,Overlay;!,!;!";
//Intensity slider sets number of "lights", LEDs per light fade in and out
@@ -4111,7 +4107,7 @@ uint16_t mode_dancing_shadows(void)
spotlights[i].type = random8(SPOT_TYPES_COUNT);
}
- uint32_t color = SEGMENT.color_from_palette(spotlights[i].colorIdx, false, false, 0);
+ uint32_t color = SEGMENT.color_from_palette(spotlights[i].colorIdx, false, false, 255);
int start = spotlights[i].position;
if (spotlights[i].width <= 1) {
@@ -5530,22 +5526,30 @@ uint16_t mode_2Dtartan(void) { // By: Elliott Kember https://editor.so
SEGMENT.fill(BLACK);
}
- uint8_t hue;
+ uint8_t hue, bri;
+ size_t intensity;
int offsetX = beatsin16(3, -360, 360);
int offsetY = beatsin16(2, -360, 360);
+ int sharpness = SEGMENT.custom3 / 8; // 0-3
for (int x = 0; x < cols; x++) {
for (int y = 0; y < rows; y++) {
hue = x * beatsin16(10, 1, 10) + offsetY;
- SEGMENT.setPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, hue, sin8(x * SEGMENT.speed + offsetX) * sin8(x * SEGMENT.speed + offsetX) / 255, LINEARBLEND));
+ intensity = bri = sin8(x * SEGMENT.speed/2 + offsetX);
+ for (int i=0; i>= 8*sharpness;
+ SEGMENT.setPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, hue, intensity, LINEARBLEND));
hue = y * 3 + offsetX;
- SEGMENT.addPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, hue, sin8(y * SEGMENT.intensity + offsetY) * sin8(y * SEGMENT.intensity + offsetY) / 255, LINEARBLEND));
+ intensity = bri = sin8(y * SEGMENT.intensity/2 + offsetY);
+ for (int i=0; i>= 8*sharpness;
+ SEGMENT.addPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, hue, intensity, LINEARBLEND));
}
}
return FRAMETIME;
} // mode_2DTartan()
-static const char _data_FX_MODE_2DTARTAN[] PROGMEM = "Tartan@X scale,Y scale;;!;2";
+static const char _data_FX_MODE_2DTARTAN[] PROGMEM = "Tartan@X scale,Y scale,,,Sharpness;;!;2";
/////////////////////////
@@ -7576,7 +7580,7 @@ static const char _data_FX_MODE_2DAKEMI[] PROGMEM = "Akemi@Color speed,Dance;Hea
// Distortion waves - ldirko
// https://editor.soulmatelights.com/gallery/1089-distorsion-waves
-// apated for WLD by @blazoncek
+// adapted for WLED by @blazoncek
uint16_t mode_2Ddistortionwaves() {
if (!strip.isMatrix) return mode_static(); // not a 2D set-up
@@ -7625,7 +7629,116 @@ uint16_t mode_2Ddistortionwaves() {
return FRAMETIME;
}
-static const char _data_FX_MODE_2DDISTORTIONWAVES[] PROGMEM = "Distortion Waves@!,Scale;;;2;";
+static const char _data_FX_MODE_2DDISTORTIONWAVES[] PROGMEM = "Distortion Waves@!,Scale;;;2";
+
+//Soap
+//@Stepko
+//Idea from https://www.youtube.com/watch?v=DiHBgITrZck&ab_channel=StefanPetrick
+// adapted for WLED by @blazoncek
+uint16_t mode_2Dsoap() {
+ if (!strip.isMatrix) return mode_static(); // not a 2D set-up
+
+ const uint16_t cols = SEGMENT.virtualWidth();
+ const uint16_t rows = SEGMENT.virtualHeight();
+
+ const size_t dataSize = SEGMENT.width() * SEGMENT.height() * sizeof(uint8_t); // prevent reallocation if mirrored or grouped
+ if (!SEGENV.allocateData(dataSize + sizeof(uint32_t)*3)) return mode_static(); //allocation failed
+
+ uint8_t *noise3d = reinterpret_cast(SEGENV.data);
+ uint32_t *noise32_x = reinterpret_cast(SEGENV.data + dataSize);
+ uint32_t *noise32_y = reinterpret_cast(SEGENV.data + dataSize + sizeof(uint32_t));
+ uint32_t *noise32_z = reinterpret_cast(SEGENV.data + dataSize + sizeof(uint32_t)*2);
+ uint32_t scale32_x = 160000U/cols;
+ uint32_t scale32_y = 160000U/rows;
+
+ // init
+ if (SEGENV.call == 0) {
+ SEGMENT.setUpLeds();
+ *noise32_x = random16();
+ *noise32_y = random16();
+ *noise32_z = random16();
+ for (int i = 0; i < cols; i++) {
+ int32_t ioffset = scale32_x * (i - cols / 2);
+ for (int j = 0; j < rows; j++) {
+ int32_t joffset = scale32_y * (j - rows / 2);
+ uint8_t data = inoise16(*noise32_x + ioffset, *noise32_y + joffset, *noise32_z) >> 8;
+ noise3d[XY(i,j)] = scale8(noise3d[XY(i,j)], SEGMENT.intensity) + scale8(data, 255 - SEGMENT.intensity);
+ SEGMENT.setPixelColorXY(i, j, ColorFromPalette(SEGPALETTE,~noise3d[XY(i,j)]*3));
+ }
+ }
+ }
+
+ uint32_t mov = MAX(cols,rows)*(SEGMENT.speed+1)/2;
+ *noise32_x += mov;
+ *noise32_y += mov;
+ *noise32_z += mov;
+
+ for (int i = 0; i < cols; i++) {
+ int32_t ioffset = scale32_x * (i - cols / 2);
+ for (int j = 0; j < rows; j++) {
+ int32_t joffset = scale32_y * (j - rows / 2);
+ uint8_t data = inoise16(*noise32_x + ioffset, *noise32_y + joffset, *noise32_z) >> 8;
+ noise3d[XY(i,j)] = scale8(noise3d[XY(i,j)], SEGMENT.intensity) + scale8(data, 256 - SEGMENT.intensity);
+ }
+ }
+
+ int zD;
+ int zF;
+ int amplitude;
+ int8_t shiftX = 0; //(SEGMENT.custom1 - 128) / 4;
+ int8_t shiftY = 0; //(SEGMENT.custom2 - 128) / 4;
+
+ amplitude = (cols >= 16) ? (cols-8)/8 : 1;
+ for (int y = 0; y < rows; y++) {
+ int amount = ((int)noise3d[XY(0,y)] - 128) * 2 * amplitude + 256*shiftX;
+ int delta = abs(amount) >> 8;
+ int fraction = abs(amount) & 255;
+ for (int x = 0; x < cols; x++) {
+ if (amount < 0) {
+ zD = x - delta;
+ zF = zD - 1;
+ } else {
+ zD = x + delta;
+ zF = zD + 1;
+ }
+ CRGB PixelA = CRGB::Black;
+ if ((zD >= 0) && (zD < cols)) PixelA = SEGMENT.getPixelColorXY(zD, y);
+ else PixelA = ColorFromPalette(SEGPALETTE, ~noise3d[XY(abs(zD),y)]*3);
+ CRGB PixelB = CRGB::Black;
+ if ((zF >= 0) && (zF < cols)) PixelB = SEGMENT.getPixelColorXY(zF, y);
+ else PixelB = ColorFromPalette(SEGPALETTE, ~noise3d[XY(abs(zF),y)]*3);
+ CRGB pix = (PixelA.nscale8(ease8InOutApprox(255 - fraction))) + (PixelB.nscale8(ease8InOutApprox(fraction)));
+ SEGMENT.setPixelColorXY(x, y, pix);
+ }
+ }
+
+ amplitude = (rows >= 16) ? (rows-8)/8 : 1;
+ for (int x = 0; x < cols; x++) {
+ int amount = ((int)noise3d[XY(x,0)] - 128) * 2 * amplitude + 256*shiftY;
+ int delta = abs(amount) >> 8;
+ int fraction = abs(amount) & 255;
+ for (int y = 0; y < rows; y++) {
+ if (amount < 0) {
+ zD = y - delta;
+ zF = zD - 1;
+ } else {
+ zD = y + delta;
+ zF = zD + 1;
+ }
+ CRGB PixelA = CRGB::Black;
+ if ((zD >= 0) && (zD < rows)) PixelA = SEGMENT.getPixelColorXY(x, zD);
+ else PixelA = ColorFromPalette(SEGPALETTE, ~noise3d[XY(x,abs(zD))]*3);
+ CRGB PixelB = CRGB::Black;
+ if ((zF >= 0) && (zF < rows)) PixelB = SEGMENT.getPixelColorXY(x, zF);
+ else PixelB = ColorFromPalette(SEGPALETTE, ~noise3d[XY(x,abs(zF))]*3);
+ CRGB pix = (PixelA.nscale8(ease8InOutApprox(255 - fraction))) + (PixelB.nscale8(ease8InOutApprox(fraction)));
+ SEGMENT.setPixelColorXY(x, y, pix);
+ }
+ }
+
+ return FRAMETIME;
+}
+static const char _data_FX_MODE_2DSOAP[] PROGMEM = "Soap@!,Smoothness;;!;2";
#endif // WLED_DISABLE_2D
@@ -7860,6 +7973,7 @@ void WS2812FX::setupEffectData() {
addEffect(FX_MODE_2DSINDOTS, &mode_2DSindots, _data_FX_MODE_2DSINDOTS);
addEffect(FX_MODE_2DDNASPIRAL, &mode_2DDNASpiral, _data_FX_MODE_2DDNASPIRAL);
addEffect(FX_MODE_2DBLACKHOLE, &mode_2DBlackHole, _data_FX_MODE_2DBLACKHOLE);
+ addEffect(FX_MODE_2DSOAP, &mode_2Dsoap, _data_FX_MODE_2DSOAP);
addEffect(FX_MODE_2DAKEMI, &mode_2DAkemi, _data_FX_MODE_2DAKEMI); // audio
#endif // WLED_DISABLE_2D
diff --git a/wled00/FX.h b/wled00/FX.h
index 6fec67c8..08ac0797 100644
--- a/wled00/FX.h
+++ b/wled00/FX.h
@@ -266,7 +266,8 @@
#define FX_MODE_2DBLOBS 121 //gap fill
#define FX_MODE_2DSCROLLTEXT 122 //gap fill
#define FX_MODE_2DDRIFTROSE 123 //gap fill
-#define FX_MODE_2DDISTORTIONWAVES 124
+#define FX_MODE_2DDISTORTIONWAVES 124 //gap fill
+#define FX_MODE_2DSOAP 125 //gap fill
// WLED-SR effects (SR compatible IDs !!!)
#define FX_MODE_PIXELS 128
@@ -579,9 +580,9 @@ typedef struct Segment {
void fadeToBlackBy(uint8_t fadeBy);
void blendPixelColor(int n, uint32_t color, uint8_t blend);
void blendPixelColor(int n, CRGB c, uint8_t blend) { blendPixelColor(n, RGBW32(c.r,c.g,c.b,0), blend); }
- void addPixelColor(int n, uint32_t color);
- void addPixelColor(int n, byte r, byte g, byte b, byte w = 0) { addPixelColor(n, RGBW32(r,g,b,w)); } // automatically inline
- void addPixelColor(int n, CRGB c) { addPixelColor(n, RGBW32(c.r,c.g,c.b,0)); } // automatically inline
+ void addPixelColor(int n, uint32_t color, bool fast = false);
+ void addPixelColor(int n, byte r, byte g, byte b, byte w = 0, bool fast = false) { addPixelColor(n, RGBW32(r,g,b,w), fast); } // automatically inline
+ void addPixelColor(int n, CRGB c, bool fast = false) { addPixelColor(n, RGBW32(c.r,c.g,c.b,0), fast); } // automatically inline
void fadePixelColor(uint16_t n, uint8_t fade);
uint8_t get_random_wheel_index(uint8_t pos);
uint32_t __attribute__((pure)) color_from_palette(uint_fast16_t, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri = 255);
@@ -605,16 +606,16 @@ typedef struct Segment {
// 2D support functions
void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t blend);
void blendPixelColorXY(uint16_t x, uint16_t y, CRGB c, uint8_t blend) { blendPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), blend); }
- void addPixelColorXY(int x, int y, uint32_t color);
- void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { addPixelColorXY(x, y, RGBW32(r,g,b,w)); } // automatically inline
- void addPixelColorXY(int x, int y, CRGB c) { addPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); }
+ void addPixelColorXY(int x, int y, uint32_t color, bool fast = false);
+ void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0, bool fast = false) { addPixelColorXY(x, y, RGBW32(r,g,b,w), fast); } // automatically inline
+ void addPixelColorXY(int x, int y, CRGB c, bool fast = false) { addPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), fast); }
void fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade);
void box_blur(uint16_t i, bool vertical, fract8 blur_amount); // 1D box blur (with weight)
void blurRow(uint16_t row, fract8 blur_amount);
void blurCol(uint16_t col, fract8 blur_amount);
- void moveX(int8_t delta);
- void moveY(int8_t delta);
- void move(uint8_t dir, uint8_t delta);
+ void moveX(int8_t delta, bool wrap = false);
+ void moveY(int8_t delta, bool wrap = false);
+ void move(uint8_t dir, uint8_t delta, bool wrap = false);
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 drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c);
@@ -628,7 +629,7 @@ typedef struct Segment {
void blur2d(fract8 blur_amount) { blur(blur_amount); }
void fill_solid(CRGB c) { fill(RGBW32(c.r,c.g,c.b,0)); }
void nscale8(uint8_t scale);
- bool jsonToPixels(char *name, uint8_t fileNr);
+ bool jsonToPixels(char *name, uint8_t fileNr); //WLEDMM for artifx
#else
uint16_t XY(uint16_t x, uint16_t y) { return x; }
void setPixelColorXY(int x, int y, uint32_t c) { setPixelColor(x, c); }
@@ -640,16 +641,16 @@ typedef struct Segment {
uint32_t getPixelColorXY(uint16_t x, uint16_t y) { return getPixelColor(x); }
void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t c, uint8_t blend) { blendPixelColor(x, c, blend); }
void blendPixelColorXY(uint16_t x, uint16_t y, CRGB c, uint8_t blend) { blendPixelColor(x, RGBW32(c.r,c.g,c.b,0), blend); }
- void addPixelColorXY(int x, int y, uint32_t color) { addPixelColor(x, color); }
- void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { addPixelColor(x, RGBW32(r,g,b,w)); }
- void addPixelColorXY(int x, int y, CRGB c) { addPixelColor(x, RGBW32(c.r,c.g,c.b,0)); }
+ void addPixelColorXY(int x, int y, uint32_t color, bool fast = false) { addPixelColor(x, color, fast); }
+ void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0, bool fast = false) { addPixelColor(x, RGBW32(r,g,b,w), fast); }
+ void addPixelColorXY(int x, int y, CRGB c, bool fast = false) { addPixelColor(x, RGBW32(c.r,c.g,c.b,0), fast); }
void fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { fadePixelColor(x, fade); }
void box_blur(uint16_t i, bool vertical, fract8 blur_amount) {}
void blurRow(uint16_t row, fract8 blur_amount) {}
void blurCol(uint16_t col, fract8 blur_amount) {}
- void moveX(int8_t delta) {}
- void moveY(int8_t delta) {}
- void move(uint8_t dir, uint8_t delta) {}
+ void moveX(int8_t delta, bool wrap = false) {}
+ void moveY(int8_t delta, bool wrap = false) {}
+ void move(uint8_t dir, uint8_t delta, bool wrap = false) {}
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, CRGB c) {}
@@ -711,6 +712,7 @@ class WS2812FX { // 96 bytes
_modeCount(MODE_COUNT),
_callback(nullptr),
customMappingTable(nullptr),
+ customMappingTableSize(0), //WLEDMM
customMappingSize(0),
_lastShow(0),
_segment_index(0),
@@ -941,8 +943,9 @@ class WS2812FX { // 96 bytes
show_callback _callback;
- uint16_t* customMappingTable = nullptr;
- uint16_t customMappingSize = 0;
+ uint16_t* customMappingTable;
+ uint16_t customMappingTableSize; //WLEDMM
+ uint16_t customMappingSize;
/*uint32_t*/ unsigned long _lastShow; // WLEDMM avoid losing precision
diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp
index 910405bf..1db4f50a 100644
--- a/wled00/FX_2Dfcn.cpp
+++ b/wled00/FX_2Dfcn.cpp
@@ -36,12 +36,6 @@
// so matrix should disable regular ledmap processing
void WS2812FX::setUpMatrix() {
#ifndef WLED_DISABLE_2D
- // erase old ledmap, just in case.
- //if (customMappingTable != nullptr) delete[] customMappingTable;
- if (customMappingTable != nullptr) free(customMappingTable);
- customMappingTable = nullptr;
- customMappingSize = 0;
-
// isMatrix is set in cfg.cpp or set.cpp
if (isMatrix) {
// calculate width dynamically because it will have gaps
@@ -69,15 +63,19 @@ void WS2812FX::setUpMatrix() {
return;
}
- //customMappingTable = new uint16_t[Segment::maxWidth * Segment::maxHeight];
- if (nullptr != customMappingTable) free(customMappingTable);
- customMappingTable = (uint16_t *) calloc(Segment::maxWidth * Segment::maxHeight, sizeof(uint16_t));
+ //WLEDMM recreate customMappingTable if more space needed
+ if (Segment::maxWidth * Segment::maxHeight > customMappingTableSize) {
+ USER_PRINTF("setupmatrix customMappingTable alloc %d from %d\n", Segment::maxWidth * Segment::maxHeight, customMappingTableSize);
+ if (customMappingTable != nullptr) delete[] customMappingTable;
+ customMappingTable = new uint16_t[Segment::maxWidth * Segment::maxHeight];
+ if (customMappingTable != nullptr) customMappingTableSize = Segment::maxWidth * Segment::maxHeight;
+ }
if (customMappingTable != nullptr) {
customMappingSize = Segment::maxWidth * Segment::maxHeight;
// fill with empty in case we don't fill the entire matrix
- for (size_t i = 0; i< customMappingSize; i++) {
+ for (size_t i = 0; i< customMappingTableSize; i++) { //WLEDMM use customMappingTableSize
customMappingTable[i] = (uint16_t)-1;
}
@@ -314,8 +312,22 @@ void Segment::blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t
}
// Adds the specified color with the existing pixel color perserving color balance.
-void Segment::addPixelColorXY(int x, int y, uint32_t color) {
- setPixelColorXY(x, y, color_add(getPixelColorXY(x,y), color));
+void Segment::addPixelColorXY(int x, int y, uint32_t color, bool fast) {
+ uint32_t col = getPixelColorXY(x,y);
+ uint8_t r = R(col);
+ uint8_t g = G(col);
+ uint8_t b = B(col);
+ uint8_t w = W(col);
+ if (fast) {
+ r = qadd8(r, R(color));
+ g = qadd8(g, G(color));
+ b = qadd8(b, B(color));
+ w = qadd8(w, W(color));
+ col = RGBW32(r,g,b,w);
+ } else {
+ col = color_add(col, color);
+ }
+ setPixelColorXY(x, y, col);
}
void Segment::fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) {
@@ -426,54 +438,55 @@ void Segment::blur1d(fract8 blur_amount) { //WLEDMM: use fast types
for (uint_fast16_t y = 0; y < rows; y++) blurRow(y, blur_amount);
}
-void Segment::moveX(int8_t delta) {
+void Segment::moveX(int8_t delta, bool wrap) {
const uint16_t cols = virtualWidth();
const uint16_t rows = virtualHeight();
- if (!delta) return;
- if (delta > 0) {
- for (uint8_t y = 0; y < rows; y++) for (uint8_t x = 0; x < cols-1; x++) {
- if (x + delta >= cols) break;
- setPixelColorXY(x, y, getPixelColorXY((x + delta)%cols, y));
- }
- } else {
- for (uint8_t y = 0; y < rows; y++) for (int16_t x = cols-1; x >= 0; x--) {
- if (x + delta < 0) break;
- setPixelColorXY(x, y, getPixelColorXY(x + delta, y));
+ if (!delta || abs(delta) >= cols) return;
+ uint32_t newPxCol[cols];
+ for (int y = 0; y < rows; y++) {
+ if (delta > 0) {
+ for (int x = 0; x < cols-delta; x++) newPxCol[x] = getPixelColorXY((x + delta), y);
+ for (int x = cols-delta; x < cols; x++) newPxCol[x] = getPixelColorXY(wrap ? (x + delta) - cols : x, y);
+ } else {
+ for (int x = cols-1; x >= -delta; x--) newPxCol[x] = getPixelColorXY((x + delta), y);
+ for (int x = -delta-1; x >= 0; x--) newPxCol[x] = getPixelColorXY(wrap ? (x + delta) + cols : x, y);
}
+ for (int x = 0; x < cols; x++) setPixelColorXY(x, y, newPxCol[x]);
}
}
-void Segment::moveY(int8_t delta) {
+void Segment::moveY(int8_t delta, bool wrap) {
const uint16_t cols = virtualWidth();
const uint16_t rows = virtualHeight();
- if (!delta) return;
- if (delta > 0) {
- for (uint8_t x = 0; x < cols; x++) for (uint8_t y = 0; y < rows-1; y++) {
- if (y + delta >= rows) break;
- setPixelColorXY(x, y, getPixelColorXY(x, (y + delta)));
- }
- } else {
- for (uint8_t x = 0; x < cols; x++) for (int16_t y = rows-1; y >= 0; y--) {
- if (y + delta < 0) break;
- setPixelColorXY(x, y, getPixelColorXY(x, y + delta));
+ if (!delta || abs(delta) >= rows) return;
+ uint32_t newPxCol[rows];
+ for (int x = 0; x < cols; x++) {
+ if (delta > 0) {
+ for (int y = 0; y < rows-delta; y++) newPxCol[y] = getPixelColorXY(x, (y + delta));
+ for (int y = rows-delta; y < rows; y++) newPxCol[y] = getPixelColorXY(x, wrap ? (y + delta) - rows : y);
+ } else {
+ for (int y = rows-1; y >= -delta; y--) newPxCol[y] = getPixelColorXY(x, (y + delta));
+ for (int y = -delta-1; y >= 0; y--) newPxCol[y] = getPixelColorXY(x, wrap ? (y + delta) + rows : y);
}
+ for (int y = 0; y < rows; y++) setPixelColorXY(x, y, newPxCol[y]);
}
}
// move() - move all pixels in desired direction delta number of pixels
// @param dir direction: 0=left, 1=left-up, 2=up, 3=right-up, 4=right, 5=right-down, 6=down, 7=left-down
// @param delta number of pixels to move
-void Segment::move(uint8_t dir, uint8_t delta) {
+// @param wrap around
+void Segment::move(uint8_t dir, uint8_t delta, bool wrap) {
if (delta==0) return;
switch (dir) {
- case 0: moveX( delta); break;
- case 1: moveX( delta); moveY( delta); break;
- case 2: moveY( delta); break;
- case 3: moveX(-delta); moveY( delta); break;
- case 4: moveX(-delta); break;
- case 5: moveX(-delta); moveY(-delta); break;
- case 6: moveY(-delta); break;
- case 7: moveX( delta); moveY(-delta); break;
+ case 0: moveX( delta, wrap); break;
+ case 1: moveX( delta, wrap); moveY( delta, wrap); break;
+ case 2: moveY( delta, wrap); break;
+ case 3: moveX(-delta, wrap); moveY( delta, wrap); break;
+ case 4: moveX(-delta, wrap); break;
+ case 5: moveX(-delta, wrap); moveY(-delta, wrap); break;
+ case 6: moveY(-delta, wrap); break;
+ case 7: moveX( delta, wrap); moveY(-delta, wrap); break;
}
}
@@ -562,6 +575,7 @@ void Segment::drawArc(uint16_t x0, uint16_t y0, uint16_t radius, uint32_t color,
}
}
+//WLEDMM for artifx
bool Segment::jsonToPixels(char * name, uint8_t fileNr) {
char fileName[32];
//WLEDMM: als support segment name ledmaps
diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp
index ccd7656e..275f91f2 100644
--- a/wled00/FX_fcn.cpp
+++ b/wled00/FX_fcn.cpp
@@ -235,6 +235,7 @@ CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) {
case FX_MODE_GLITTER : pal = 11; break; // rainbow colors
case FX_MODE_SUNRISE : pal = 35; break; // heat palette
case FX_MODE_RAILWAY : pal = 3; break; // prim + sec
+ case FX_MODE_2DSOAP : pal = 11; break; // rainbow colors
}
switch (pal) {
case 0: //default palette. Exceptions for specific effects above
@@ -591,7 +592,6 @@ class JMapC {
if (jVectorMap.size() > 0) {
USER_PRINTLN("delete jVectorMap");
for (size_t i=0; i();
- if (name != nullptr) len = strlen(name);
+ if (name != nullptr) {
+ len = strlen(name);
if (len > 0 && len < 33) {
ledmapNames[i-1] = new char[len+1];
if (ledmapNames[i-1]) strlcpy(ledmapNames[i-1], name, 33);
@@ -1371,6 +1392,7 @@ void WS2812FX::enumerateLedmaps() {
if (ledmapNames[i-1]) strlcpy(ledmapNames[i-1], tmp, 33);
}
}
+ f.close();
releaseJSONBufferLock();
}
#endif
@@ -2090,12 +2112,9 @@ bool WS2812FX::deserializeMap(uint8_t n) {
if (!isFile) {
// erase custom mapping if selecting nonexistent ledmap.json (n==0)
- //WLEDM: doubt this is necessary as return false causes setupMatrix to deal with this
- if (!isMatrix && !n && customMappingTable != nullptr) {
+ //WLEDM: doubt this is necessary as return false causes setupMatrix to deal with this !!!!
+ if (!isMatrix && !n) {
customMappingSize = 0;
- //delete[] customMappingTable;
- free(customMappingTable);
- customMappingTable = nullptr;
loadedLedmap = 0; //WLEDMM
}
return false;
@@ -2103,7 +2122,11 @@ bool WS2812FX::deserializeMap(uint8_t n) {
if (!requestJSONBufferLock(7)) return false;
- if (!readObjectFromFile(fileName, nullptr, &doc)) {
+ //WLEDMM: change upstream code: do not load complete ledmaps in json as this blows up memory, use file read instead
+ //read the file
+ File f;
+ f = WLED_FS.open(fileName, "r");
+ if (!f) {
releaseJSONBufferLock();
return false; //if file does not exist just exit
}
@@ -2111,41 +2134,46 @@ bool WS2812FX::deserializeMap(uint8_t n) {
USER_PRINT(F("Reading LED map from ")); //WLEDMM use USER_PRINT
USER_PRINTLN(fileName);
- // erase old custom ledmap
- if (customMappingTable != nullptr) {
- customMappingSize = 0;
- //delete[] customMappingTable;
- free(customMappingTable); // softhack007 use calloc / free, as they behave better when heap is low
- customMappingTable = nullptr;
- loadedLedmap = 0;
+ //WLEDMM: read width and height (mandatory in file!!)
+ f.find("\"width\":");
+ uint16_t maxWidth = f.readStringUntil('\n').toInt();
+
+ f.find("\"height\":");
+ uint16_t maxHeight = f.readStringUntil('\n').toInt();
+
+ USER_PRINTF("deserializeMap %d x %d\n", maxWidth, maxHeight);
+ if (maxWidth * maxHeight <= 0) {
+ releaseJSONBufferLock();
+ return false;
}
- JsonArray map = doc[F("map")];
- if (!map.isNull() && map.size()) { // not an empty map
+ //WLEDMM: support ledmap file properties width and height
+ Segment::maxWidth = maxWidth;
+ Segment::maxHeight = maxHeight;
+ resetSegments(true); //WLEDMM not makeAutoSegments() as we only want to change bounds
- //WLEDMM: support ledmap file properties width and height
- if (doc[F("width")]>0 && doc[F("height")]>0) {
- Segment::maxWidth = doc[F("width")];
- Segment::maxHeight = doc[F("height")];
- resetSegments(true); //WLEDMM not makeAutoSegments() as we only want to change bounds
- }
+ //WLEDMM recreate customMappingTable if more space needed
+ if (Segment::maxWidth * Segment::maxHeight > customMappingTableSize) {
+ USER_PRINTF("deserializemap customMappingTable alloc %d from %d\n", Segment::maxWidth * Segment::maxHeight, customMappingTableSize);
+ if (customMappingTable != nullptr) delete[] customMappingTable;
+ customMappingTable = new uint16_t[Segment::maxWidth * Segment::maxHeight];
+ if (customMappingTable != nullptr) customMappingTableSize = Segment::maxWidth * Segment::maxHeight;
+ }
- customMappingSize = map.size();
- if (nullptr != customMappingTable) free(customMappingTable);
- //customMappingTable = new uint16_t[customMappingSize];
- customMappingTable = (uint16_t *) calloc(customMappingSize+1, sizeof(uint16_t)); // softhack007 use calloc / free, as they behave better when heap is low
- if (nullptr == customMappingTable) { // WLEDMM handle out-of-memory
- USER_PRINTF("deserializeMap(): cannot alloate %d bytes for customMappingTable[]\n", sizeof(uint16_t) * (customMappingSize+1));
- customMappingSize = 0;
- loadedLedmap = 0;
- releaseJSONBufferLock();
- return false; //if not enough memory - just exit
- }
+ if (customMappingTable != nullptr) {
+ customMappingSize = maxWidth * maxHeight;
- for (uint16_t i=0; i ANALOG_BTN_READ_CYCLE) { // button is not a button but a potentiometer
- analog = true;
- handleAnalog(b); continue;
+ if (buttonType[b] == BTN_TYPE_ANALOG || buttonType[b] == BTN_TYPE_ANALOG_INVERTED) { // button is not a button but a potentiometer
+ if (now - lastRead > ANALOG_BTN_READ_CYCLE) {
+ handleAnalog(b);
+ lastRead = now;
+ }
+ continue;
}
//button is not momentary, but switch. This is only suitable on pins whose on-boot state does not matter (NOT gpio0)
if (buttonType[b] == BTN_TYPE_SWITCH || buttonType[b] == BTN_TYPE_PIR_SENSOR) {
- handleSwitch(b); continue;
+ handleSwitch(b);
+ continue;
}
//momentary button logic
@@ -305,7 +308,6 @@ void handleButton()
shortPressAction(b);
}
}
- if (analog) lastRead = now;
}
// If enabled, RMT idle level is set to HIGH when off
diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp
index d0a731b0..32712fb5 100644
--- a/wled00/cfg.cpp
+++ b/wled00/cfg.cpp
@@ -19,6 +19,8 @@ void getStringFromJson(char* dest, const char* src, size_t len) {
bool deserializeConfig(JsonObject doc, bool fromFS) {
//WLEDMM add USER_PRINT
+ // String temp;
+ // serializeJson(doc, temp);
USER_PRINTF("deserializeConfig\n");
bool needsSave = false;
@@ -177,10 +179,11 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
uint8_t ledType = elm["type"] | TYPE_WS2812_RGB;
bool reversed = elm["rev"];
bool refresh = elm["ref"] | false;
+ uint16_t freqkHz = elm[F("freq")] | 0; // will be in kHz for DotStar and Hz for PWM (not yet implemented fully)
ledType |= refresh << 7; // hack bit 7 to indicate strip requires off refresh
uint8_t AWmode = elm[F("rgbwm")] | autoWhiteMode;
if (fromFS) {
- BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode);
+ BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode); //WLEDMM to do bus , freqkHz
mem += BusManager::memUsage(bc);
if (mem <= MAX_LED_MEMORY) if (busses.add(bc) == -1) break; // finalization will be done in WLED::beginStrip()
} else {
@@ -784,6 +787,7 @@ void serializeConfig() {
ins["type"] = bus->getType() & 0x7F;
ins["ref"] = bus->isOffRefreshRequired();
ins[F("rgbwm")] = bus->getAutoWhiteMode();
+ // ins[F("freq")] = bus->getFrequency(); WLEDMM to do bus
}
JsonArray hw_com = hw.createNestedArray(F("com"));
diff --git a/wled00/const.h b/wled00/const.h
index 449eeba0..a35da318 100644
--- a/wled00/const.h
+++ b/wled00/const.h
@@ -141,7 +141,7 @@
#define USERMOD_ID_ARTIFX 90 //Usermod "usermod_v2_artifx.h"
#define USERMOD_ID_WEATHER 91 //Usermod "usermod_v2_weather.h"
#define USERMOD_ID_GAMES 92 //Usermod "usermod_v2_games.h"
-#define USERMOD_ID_FASTLED 93 //Usermod "usermod_v2_fastled.h"
+#define USERMOD_ID_ANIMARTRIX 93 //Usermod "usermod_v2_animartrix.h"
//Access point behavior
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot
@@ -226,6 +226,8 @@
#define TYPE_GS8608 23 //same driver as WS2812, but will require signal 2x per second (else displays test pattern)
#define TYPE_WS2811_400KHZ 24 //half-speed WS2812 protocol, used by very old WS2811 units
#define TYPE_TM1829 25
+#define TYPE_UCS8903 26
+#define TYPE_UCS8904 29
#define TYPE_SK6812_RGBW 30
#define TYPE_TM1814 31
//"Analog" types (PWM) (32-47)
@@ -274,7 +276,7 @@
#define BTN_TYPE_ANALOG_INVERTED 8
//Ethernet board types
-#define WLED_NUM_ETH_TYPES 9
+#define WLED_NUM_ETH_TYPES 10
#define WLED_ETH_NONE 0
#define WLED_ETH_WT32_ETH01 1
@@ -283,6 +285,7 @@
#define WLED_ETH_QUINLED 4
#define WLED_ETH_TWILIGHTLORD 5
#define WLED_ETH_ESP32DEUX 6
+#define WLED_ETH_ABCWLEDV43ETH 9
//Hue error codes
#define HUE_ERROR_INACTIVE 0
diff --git a/wled00/data/404.htm b/wled00/data/404.htm
index 87244a94..260253a3 100644
--- a/wled00/data/404.htm
+++ b/wled00/data/404.htm
@@ -1,47 +1,47 @@
-
-
-
-
- Not found
-
-
-
-
-404 Not Found
-Akemi does not know where you are headed...
-
-
+ img {
+ width: 400px;
+ max-width: 50%;
+ image-rendering: pixelated;
+ image-rendering: crisp-edges;
+ margin: 25px 0 -10px 0;
+ }
+
+ button {
+ outline: none;
+ cursor: pointer;
+ padding: 8px;
+ margin: 10px;
+ width: 230px;
+ text-transform: uppercase;
+ font-family: helvetica;
+ font-size: 19px;
+ background-color: #333;
+ color: white;
+ border: 0px solid white;
+ border-radius: 25px;
+ }
+
+
+
+
+ 404 Not Found
+ Akemi does not know where you are headed...
+
+