diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 27beec99c3..6104922bed 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -18,9 +18,17 @@ jobs:
- uses: actions/download-artifact@v4
with:
merge-multiple: true
+ - name: "✏️ Generate release changelog"
+ id: changelog
+ uses: janheinrichmerker/action-github-changelog-generator@v2.3
+ with:
+ token: ${{ secrets.GITHUB_TOKEN }}
+ sinceTag: v0.15.0
+ releaseBranch: 0_15_x
- name: Create draft release
uses: softprops/action-gh-release@v1
with:
+ body: ${{ steps.changelog.outputs.changelog }}
draft: True
files: |
*.bin
diff --git a/.gitignore b/.gitignore
index 8f083e3f6a..6c80b8e8e5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,6 +15,7 @@ wled-update.sh
/build_output/
/node_modules/
+/logs/
/wled00/extLibs
/wled00/LittleFS
@@ -22,3 +23,4 @@ wled-update.sh
/wled00/Release
/wled00/wled00.ino.cpp
/wled00/html_*.h
+_codeql_detected_source_root
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c570ac1f7e..b04ce71f20 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,23 @@
## WLED changelog
+#### Build 2412100
+- WLED 0.15.0 release
+- Usermod BME280: Fix "Unit of Measurement" for temperature
+- WiFi reconnect bugfix (@blazoncek)
+
+#### Build 2411250
+- WLED 0.15.0-rc1 release
+- Add support for esp32S3_wroom2 (#4243 by @softhack007)
+- Fix mixed LED SK6812 and ws2812b booloop (#4301 by @willmmiles)
+- Improved FPS calculation (by DedeHai)
+- Fix crashes when using HTTP API within MQTT (#4269 by @willmmiles)
+- Fix array overflow in exploding_fireworks (#4120 by @willmmiles)
+- Fix MQTT topic buffer length (#4293 by @WouterGritter)
+- Fix SparkFunDMX fix for possible array bounds violation in DMX.write (by @softhack007)
+- Allow TV Simulator on single LED segments (by @softhack007)
+- Fix WLED_RELEASE_NAME (by @netmindz)
+
+
#### Build 2410270
- WLED 0.15.0-b7 release
- Re-license the WLED project from MIT to EUPL (#4194 by @Aircoookie)
diff --git a/HSVTicker_Dokumentation_1.pdf b/HSVTicker_Dokumentation_1.pdf
new file mode 100644
index 0000000000..42e628547b
Binary files /dev/null and b/HSVTicker_Dokumentation_1.pdf differ
diff --git a/lib/NeoESP32RmtHI/include/NeoEsp32RmtHIMethod.h b/lib/NeoESP32RmtHI/include/NeoEsp32RmtHIMethod.h
new file mode 100644
index 0000000000..02e066f741
--- /dev/null
+++ b/lib/NeoESP32RmtHI/include/NeoEsp32RmtHIMethod.h
@@ -0,0 +1,469 @@
+/*-------------------------------------------------------------------------
+NeoPixel driver for ESP32 RMTs using High-priority Interrupt
+
+(NB. This cannot be mixed with the non-HI driver.)
+
+Written by Will M. Miles.
+
+I invest time and resources providing this open source code,
+please support me by donating (see https://github.com/Makuna/NeoPixelBus)
+
+-------------------------------------------------------------------------
+This file is part of the Makuna/NeoPixelBus library.
+
+NeoPixelBus is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as
+published by the Free Software Foundation, either version 3 of
+the License, or (at your option) any later version.
+
+NeoPixelBus is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with NeoPixel. If not, see
+.
+-------------------------------------------------------------------------*/
+
+#pragma once
+
+#if defined(ARDUINO_ARCH_ESP32)
+
+// Use the NeoEspRmtSpeed types from the driver-based implementation
+#include
+
+
+namespace NeoEsp32RmtHiMethodDriver {
+ // Install the driver for a specific channel, specifying timing properties
+ esp_err_t Install(rmt_channel_t channel, uint32_t rmtBit0, uint32_t rmtBit1, uint32_t resetDuration);
+
+ // Remove the driver on a specific channel
+ esp_err_t Uninstall(rmt_channel_t channel);
+
+ // Write a buffer of data to a specific channel.
+ // Buffer reference is held until write completes.
+ esp_err_t Write(rmt_channel_t channel, const uint8_t *src, size_t src_size);
+
+ // Wait until transaction is complete.
+ esp_err_t WaitForTxDone(rmt_channel_t channel, TickType_t wait_time);
+};
+
+template class NeoEsp32RmtHIMethodBase
+{
+public:
+ typedef NeoNoSettings SettingsObject;
+
+ NeoEsp32RmtHIMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
+ _sizeData(pixelCount * elementSize + settingsSize),
+ _pin(pin)
+ {
+ construct();
+ }
+
+ NeoEsp32RmtHIMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize, NeoBusChannel channel) :
+ _sizeData(pixelCount* elementSize + settingsSize),
+ _pin(pin),
+ _channel(channel)
+ {
+ construct();
+ }
+
+ ~NeoEsp32RmtHIMethodBase()
+ {
+ // wait until the last send finishes before destructing everything
+ // arbitrary time out of 10 seconds
+ ESP_ERROR_CHECK_WITHOUT_ABORT(NeoEsp32RmtHiMethodDriver::WaitForTxDone(_channel.RmtChannelNumber, 10000 / portTICK_PERIOD_MS));
+
+ ESP_ERROR_CHECK(NeoEsp32RmtHiMethodDriver::Uninstall(_channel.RmtChannelNumber));
+
+ gpio_matrix_out(_pin, SIG_GPIO_OUT_IDX, false, false);
+ pinMode(_pin, INPUT);
+
+ free(_dataEditing);
+ free(_dataSending);
+ }
+
+ bool IsReadyToUpdate() const
+ {
+ return (ESP_OK == ESP_ERROR_CHECK_WITHOUT_ABORT_SILENT_TIMEOUT(NeoEsp32RmtHiMethodDriver::WaitForTxDone(_channel.RmtChannelNumber, 0)));
+ }
+
+ void Initialize()
+ {
+ rmt_config_t config = {};
+
+ config.rmt_mode = RMT_MODE_TX;
+ config.channel = _channel.RmtChannelNumber;
+ config.gpio_num = static_cast(_pin);
+ config.mem_block_num = 1;
+ config.tx_config.loop_en = false;
+
+ config.tx_config.idle_output_en = true;
+ config.tx_config.idle_level = T_SPEED::IdleLevel;
+
+ config.tx_config.carrier_en = false;
+ config.tx_config.carrier_level = RMT_CARRIER_LEVEL_LOW;
+
+ config.clk_div = T_SPEED::RmtClockDivider;
+
+ ESP_ERROR_CHECK(rmt_config(&config)); // Uses ESP library
+ ESP_ERROR_CHECK(NeoEsp32RmtHiMethodDriver::Install(_channel.RmtChannelNumber, T_SPEED::RmtBit0, T_SPEED::RmtBit1, T_SPEED::RmtDurationReset));
+ }
+
+ void Update(bool maintainBufferConsistency)
+ {
+ // wait for not actively sending data
+ // this will time out at 10 seconds, an arbitrarily long period of time
+ // and do nothing if this happens
+ if (ESP_OK == ESP_ERROR_CHECK_WITHOUT_ABORT(NeoEsp32RmtHiMethodDriver::WaitForTxDone(_channel.RmtChannelNumber, 10000 / portTICK_PERIOD_MS)))
+ {
+ // now start the RMT transmit with the editing buffer before we swap
+ ESP_ERROR_CHECK_WITHOUT_ABORT(NeoEsp32RmtHiMethodDriver::Write(_channel.RmtChannelNumber, _dataEditing, _sizeData));
+
+ if (maintainBufferConsistency)
+ {
+ // copy editing to sending,
+ // this maintains the contract that "colors present before will
+ // be the same after", otherwise GetPixelColor will be inconsistent
+ memcpy(_dataSending, _dataEditing, _sizeData);
+ }
+
+ // swap so the user can modify without affecting the async operation
+ std::swap(_dataSending, _dataEditing);
+ }
+ }
+
+ bool AlwaysUpdate()
+ {
+ // this method requires update to be called only if changes to buffer
+ return false;
+ }
+
+ bool SwapBuffers()
+ {
+ std::swap(_dataSending, _dataEditing);
+ return true;
+ }
+
+ uint8_t* getData() const
+ {
+ return _dataEditing;
+ };
+
+ size_t getDataSize() const
+ {
+ return _sizeData;
+ }
+
+ void applySettings([[maybe_unused]] const SettingsObject& settings)
+ {
+ }
+
+private:
+ const size_t _sizeData; // Size of '_data*' buffers
+ const uint8_t _pin; // output pin number
+ const T_CHANNEL _channel; // holds instance for multi channel support
+
+ // Holds data stream which include LED color values and other settings as needed
+ uint8_t* _dataEditing; // exposed for get and set
+ uint8_t* _dataSending; // used for async send using RMT
+
+
+ void construct()
+ {
+ _dataEditing = static_cast(malloc(_sizeData));
+ // data cleared later in Begin()
+
+ _dataSending = static_cast(malloc(_sizeData));
+ // no need to initialize it, it gets overwritten on every send
+ }
+};
+
+// normal
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINWs2811Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINWs2812xMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINWs2816Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINWs2805Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINSk6812Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINTm1814Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINTm1829Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINTm1914Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINApa106Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINTx1812Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINGs1903Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHIN800KbpsMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHIN400KbpsMethod;
+typedef NeoEsp32RmtHINWs2805Method NeoEsp32RmtHINWs2814Method;
+
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Ws2811Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Ws2812xMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Ws2816Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Ws2805Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Sk6812Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Tm1814Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Tm1829Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Tm1914Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Apa106Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Tx1812Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Gs1903Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0800KbpsMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0400KbpsMethod;
+typedef NeoEsp32RmtHI0Ws2805Method NeoEsp32RmtHI0Ws2814Method;
+
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Ws2811Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Ws2812xMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Ws2816Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Ws2805Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Sk6812Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Tm1814Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Tm1829Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Tm1914Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Apa106Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Tx1812Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Gs1903Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1800KbpsMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1400KbpsMethod;
+typedef NeoEsp32RmtHI1Ws2805Method NeoEsp32RmtHI1Ws2814Method;
+
+#if !defined(CONFIG_IDF_TARGET_ESP32C3)
+
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Ws2811Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Ws2812xMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Ws2816Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Ws2805Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Sk6812Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Tm1814Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Tm1829Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Tm1914Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Apa106Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Tx1812Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Gs1903Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2800KbpsMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2400KbpsMethod;
+typedef NeoEsp32RmtHI2Ws2805Method NeoEsp32RmtHI2Ws2814Method;
+
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Ws2811Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Ws2812xMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Ws2816Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Ws2805Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Sk6812Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Tm1814Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Tm1829Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Tm1914Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Apa106Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Tx1812Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Gs1903Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3800KbpsMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3400KbpsMethod;
+typedef NeoEsp32RmtHI3Ws2805Method NeoEsp32RmtHI3Ws2814Method;
+
+#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32S3)
+
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Ws2811Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Ws2812xMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Ws2816Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Ws2805Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Sk6812Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Tm1814Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Tm1829Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Tm1914Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Apa106Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Tx1812Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Gs1903Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4800KbpsMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4400KbpsMethod;
+typedef NeoEsp32RmtHI4Ws2805Method NeoEsp32RmtHI4Ws2814Method;
+
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Ws2811Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Ws2812xMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Ws2816Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Ws2805Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Sk6812Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Tm1814Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Tm1829Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Tm1914Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Apa106Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Tx1812Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Gs1903Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5800KbpsMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5400KbpsMethod;
+typedef NeoEsp32RmtHI5Ws2805Method NeoEsp32RmtHI5Ws2814Method;
+
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Ws2811Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Ws2812xMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Ws2816Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Ws2805Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Sk6812Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Tm1814Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Tm1829Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Tm1914Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Apa106Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Tx1812Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Gs1903Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6800KbpsMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6400KbpsMethod;
+typedef NeoEsp32RmtHI6Ws2805Method NeoEsp32RmtHI6Ws2814Method;
+
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Ws2811Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Ws2812xMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Ws2816Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Ws2805Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Sk6812Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Tm1814Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Tm1829Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Tm1914Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Apa106Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Tx1812Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Gs1903Method;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7800KbpsMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7400KbpsMethod;
+typedef NeoEsp32RmtHI7Ws2805Method NeoEsp32RmtHI7Ws2814Method;
+
+#endif // !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32S3)
+#endif // !defined(CONFIG_IDF_TARGET_ESP32C3)
+
+// inverted
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINWs2811InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINWs2812xInvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINWs2816InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINWs2805InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINSk6812InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINTm1814InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINTm1829InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINTm1914InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINApa106InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINTx1812InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINGs1903InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHIN800KbpsInvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHIN400KbpsInvertedMethod;
+typedef NeoEsp32RmtHINWs2805InvertedMethod NeoEsp32RmtHINWs2814InvertedMethod;
+
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Ws2811InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Ws2812xInvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Ws2816InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Ws2805InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Sk6812InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Tm1814InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Tm1829InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Tm1914InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Apa106InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Tx1812InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Gs1903InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0800KbpsInvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0400KbpsInvertedMethod;
+typedef NeoEsp32RmtHI0Ws2805InvertedMethod NeoEsp32RmtHI0Ws2814InvertedMethod;
+
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Ws2811InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Ws2812xInvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Ws2816InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Ws2805InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Sk6812InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Tm1814InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Tm1829InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Tm1914InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Apa106InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Tx1812InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Gs1903InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1800KbpsInvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1400KbpsInvertedMethod;
+typedef NeoEsp32RmtHI1Ws2805InvertedMethod NeoEsp32RmtHI1Ws2814InvertedMethod;
+
+#if !defined(CONFIG_IDF_TARGET_ESP32C3)
+
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Ws2811InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Ws2812xInvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Ws2816InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Ws2805InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Sk6812InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Tm1814InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Tm1829InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Tm1914InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Apa106InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Tx1812InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Gs1903InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2800KbpsInvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2400KbpsInvertedMethod;
+typedef NeoEsp32RmtHI2Ws2805InvertedMethod NeoEsp32RmtHI2Ws2814InvertedMethod;
+
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Ws2811InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Ws2812xInvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Ws2805InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Ws2816InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Sk6812InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Tm1814InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Tm1829InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Tm1914InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Apa106InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Tx1812InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Gs1903InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3800KbpsInvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3400KbpsInvertedMethod;
+typedef NeoEsp32RmtHI3Ws2805InvertedMethod NeoEsp32RmtHI3Ws2814InvertedMethod;
+
+#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32S3)
+
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Ws2811InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Ws2812xInvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Ws2816InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Ws2805InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Sk6812InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Tm1814InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Tm1829InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Tm1914InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Apa106InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Tx1812InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Gs1903InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4800KbpsInvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4400KbpsInvertedMethod;
+typedef NeoEsp32RmtHI4Ws2805InvertedMethod NeoEsp32RmtHI4Ws2814InvertedMethod;
+
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Ws2811InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Ws2812xInvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Ws2816InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Ws2805InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Sk6812InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Tm1814InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Tm1829InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Tm1914InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Apa106InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Tx1812InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Gs1903InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5800KbpsInvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5400KbpsInvertedMethod;
+typedef NeoEsp32RmtHI5Ws2805InvertedMethod NeoEsp32RmtHI5Ws2814InvertedMethod;
+
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Ws2811InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Ws2812xInvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Ws2816InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Ws2805InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Sk6812InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Tm1814InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Tm1829InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Tm1914InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Apa106InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Tx1812InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Gs1903InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6800KbpsInvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6400KbpsInvertedMethod;
+typedef NeoEsp32RmtHI6Ws2805InvertedMethod NeoEsp32RmtHI6Ws2814InvertedMethod;
+
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Ws2811InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Ws2812xInvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Ws2816InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Ws2805InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Sk6812InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Tm1814InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Tm1829InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Tm1914InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Apa106InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Tx1812InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Gs1903InvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7800KbpsInvertedMethod;
+typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7400KbpsInvertedMethod;
+typedef NeoEsp32RmtHI7Ws2805InvertedMethod NeoEsp32RmtHI7Ws2814InvertedMethod;
+
+#endif // !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32S3)
+#endif // !defined(CONFIG_IDF_TARGET_ESP32C3)
+
+#endif
diff --git a/lib/NeoESP32RmtHI/library.json b/lib/NeoESP32RmtHI/library.json
new file mode 100644
index 0000000000..0608e59e12
--- /dev/null
+++ b/lib/NeoESP32RmtHI/library.json
@@ -0,0 +1,12 @@
+{
+ "name": "NeoESP32RmtHI",
+ "build": { "libArchive": false },
+ "platforms": ["espressif32"],
+ "dependencies": [
+ {
+ "owner": "makuna",
+ "name": "NeoPixelBus",
+ "version": "^2.8.3"
+ }
+ ]
+}
diff --git a/lib/NeoESP32RmtHI/src/NeoEsp32RmtHI.S b/lib/NeoESP32RmtHI/src/NeoEsp32RmtHI.S
new file mode 100644
index 0000000000..0c60d2ebc9
--- /dev/null
+++ b/lib/NeoESP32RmtHI/src/NeoEsp32RmtHI.S
@@ -0,0 +1,263 @@
+/* RMT ISR shim
+ * Bridges from a high-level interrupt to the C++ code.
+ *
+ * This code is largely derived from Espressif's 'hli_vector.S' Bluetooth ISR.
+ *
+ */
+
+#if defined(__XTENSA__) && defined(ESP32) && !defined(CONFIG_BTDM_CTRL_HLI)
+
+#include
+#include "sdkconfig.h"
+#include "soc/soc.h"
+
+/* If the Bluetooth driver has hooked the high-priority interrupt, we piggyback on it and don't need this. */
+#ifndef CONFIG_BTDM_CTRL_HLI
+
+/*
+ Select interrupt based on system check level
+ - Base ESP32: could be 4 or 5, depends on platform config
+ - S2: 5
+ - S3: 5
+*/
+
+#if CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5
+/* Use level 4 */
+#define RFI_X 4
+#define xt_highintx xt_highint4
+#else /* !CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5 */
+/* Use level 5 */
+#define RFI_X 5
+#define xt_highintx xt_highint5
+#endif /* CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5 */
+
+// Register map, based on interrupt level
+#define EPC_X (EPC + RFI_X)
+#define EXCSAVE_X (EXCSAVE + RFI_X)
+
+// The sp mnemonic is used all over in ESP's assembly, though I'm not sure where it's expected to be defined?
+#define sp a1
+
+/* Interrupt stack size, for C code. */
+#define RMT_INTR_STACK_SIZE 512
+
+/* Save area for the CPU state:
+ * - 64 words for the general purpose registers
+ * - 7 words for some of the special registers:
+ * - WINDOWBASE, WINDOWSTART — only WINDOWSTART is truly needed
+ * - SAR, LBEG, LEND, LCOUNT — since the C code might use these
+ * - EPC1 — since the C code might cause window overflow exceptions
+ * This is not laid out as standard exception frame structure
+ * for simplicity of the save/restore code.
+ */
+#define REG_FILE_SIZE (64 * 4)
+#define SPECREG_OFFSET REG_FILE_SIZE
+#define SPECREG_SIZE (7 * 4)
+#define REG_SAVE_AREA_SIZE (SPECREG_OFFSET + SPECREG_SIZE)
+
+ .data
+_rmt_intr_stack:
+ .space RMT_INTR_STACK_SIZE
+_rmt_save_ctx:
+ .space REG_SAVE_AREA_SIZE
+
+ .section .iram1,"ax"
+ .global xt_highintx
+ .type xt_highintx,@function
+ .align 4
+
+xt_highintx:
+
+ movi a0, _rmt_save_ctx
+ /* save 4 lower registers */
+ s32i a1, a0, 4
+ s32i a2, a0, 8
+ s32i a3, a0, 12
+ rsr a2, EXCSAVE_X /* holds the value of a0 */
+ s32i a2, a0, 0
+
+ /* Save special registers */
+ addi a0, a0, SPECREG_OFFSET
+ rsr a2, WINDOWBASE
+ s32i a2, a0, 0
+ rsr a2, WINDOWSTART
+ s32i a2, a0, 4
+ rsr a2, SAR
+ s32i a2, a0, 8
+ #if XCHAL_HAVE_LOOPS
+ rsr a2, LBEG
+ s32i a2, a0, 12
+ rsr a2, LEND
+ s32i a2, a0, 16
+ rsr a2, LCOUNT
+ s32i a2, a0, 20
+ #endif
+ rsr a2, EPC1
+ s32i a2, a0, 24
+
+ /* disable exception mode, window overflow */
+ movi a0, PS_INTLEVEL(RFI_X+1) | PS_EXCM
+ wsr a0, PS
+ rsync
+
+ /* Save the remaining physical registers.
+ * 4 registers are already saved, which leaves 60 registers to save.
+ * (FIXME: consider the case when the CPU is configured with physical 32 registers)
+ * These 60 registers are saved in 5 iterations, 12 registers at a time.
+ */
+ movi a1, 5
+ movi a3, _rmt_save_ctx + 4 * 4
+
+ /* This is repeated 5 times, each time the window is shifted by 12 registers.
+ * We come here with a1 = downcounter, a3 = save pointer, a2 and a0 unused.
+ */
+1:
+ s32i a4, a3, 0
+ s32i a5, a3, 4
+ s32i a6, a3, 8
+ s32i a7, a3, 12
+ s32i a8, a3, 16
+ s32i a9, a3, 20
+ s32i a10, a3, 24
+ s32i a11, a3, 28
+ s32i a12, a3, 32
+ s32i a13, a3, 36
+ s32i a14, a3, 40
+ s32i a15, a3, 44
+
+ /* We are about to rotate the window, so that a12-a15 will become the new a0-a3.
+ * Copy a0-a3 to a12-15 to still have access to these values.
+ * At the same time we can decrement the counter and adjust the save area pointer
+ */
+
+ /* a0 is constant (_rmt_save_ctx), no need to copy */
+ addi a13, a1, -1 /* copy and decrement the downcounter */
+ /* a2 is scratch so no need to copy */
+ addi a15, a3, 48 /* copy and adjust the save area pointer */
+ beqz a13, 2f /* have saved all registers ? */
+ rotw 3 /* rotate the window and go back */
+ j 1b
+
+ /* the loop is complete */
+2:
+ rotw 4 /* this brings us back to the original window */
+ /* a0 still points to _rmt_save_ctx */
+
+ /* Can clear WINDOWSTART now, all registers are saved */
+ rsr a2, WINDOWBASE
+ /* WINDOWSTART = (1 << WINDOWBASE) */
+ movi a3, 1
+ ssl a2
+ sll a3, a3
+ wsr a3, WINDOWSTART
+
+_highint_stack_switch:
+ movi a0, 0
+ movi sp, _rmt_intr_stack + RMT_INTR_STACK_SIZE - 16
+ s32e a0, sp, -12 /* For GDB: set null SP */
+ s32e a0, sp, -16 /* For GDB: set null PC */
+ movi a0, _highint_stack_switch /* For GDB: cosmetics, for the frame where stack switch happened */
+
+ /* Set up PS for C, disable all interrupts except NMI and debug, and clear EXCM. */
+ movi a6, PS_INTLEVEL(RFI_X) | PS_UM | PS_WOE
+ wsr a6, PS
+ rsync
+
+ /* Call C handler */
+ mov a6, sp
+ call4 NeoEsp32RmtMethodIsr
+
+ l32e sp, sp, -12 /* switch back to the original stack */
+
+ /* Done with C handler; re-enable exception mode, disabling window overflow */
+ movi a2, PS_INTLEVEL(RFI_X+1) | PS_EXCM /* TOCHECK */
+ wsr a2, PS
+ rsync
+
+ /* Restore the special registers.
+ * WINDOWSTART will be restored near the end.
+ */
+ movi a0, _rmt_save_ctx + SPECREG_OFFSET
+ l32i a2, a0, 8
+ wsr a2, SAR
+ #if XCHAL_HAVE_LOOPS
+ l32i a2, a0, 12
+ wsr a2, LBEG
+ l32i a2, a0, 16
+ wsr a2, LEND
+ l32i a2, a0, 20
+ wsr a2, LCOUNT
+ #endif
+ l32i a2, a0, 24
+ wsr a2, EPC1
+
+ /* Restoring the physical registers.
+ * This is the reverse to the saving process above.
+ */
+
+ /* Rotate back to the final window, then start loading 12 registers at a time,
+ * in 5 iterations.
+ * Again, a1 is the downcounter and a3 is the save area pointer.
+ * After each rotation, a1 and a3 are copied from a13 and a15.
+ * To simplify the loop, we put the initial values into a13 and a15.
+ */
+ rotw -4
+ movi a15, _rmt_save_ctx + 64 * 4 /* point to the end of the save area */
+ movi a13, 5
+
+1:
+ /* Copy a1 and a3 from their previous location,
+ * at the same time decrementing and adjusting the save area pointer.
+ */
+ addi a1, a13, -1
+ addi a3, a15, -48
+
+ /* Load 12 registers */
+ l32i a4, a3, 0
+ l32i a5, a3, 4
+ l32i a6, a3, 8
+ l32i a7, a3, 12
+ l32i a8, a3, 16
+ l32i a9, a3, 20
+ l32i a10, a3, 24
+ l32i a11, a3, 28 /* ensure PS and EPC written */
+ l32i a12, a3, 32
+ l32i a13, a3, 36
+ l32i a14, a3, 40
+ l32i a15, a3, 44
+
+ /* Done with the loop? */
+ beqz a1, 2f
+ /* If no, rotate the window and repeat */
+ rotw -3
+ j 1b
+
+2:
+ /* Done with the loop. Only 4 registers (a0-a3 in the original window) remain
+ * to be restored. Also need to restore WINDOWSTART, since all the general
+ * registers are now in place.
+ */
+ movi a0, _rmt_save_ctx
+
+ l32i a2, a0, SPECREG_OFFSET + 4
+ wsr a2, WINDOWSTART
+
+ l32i a1, a0, 4
+ l32i a2, a0, 8
+ l32i a3, a0, 12
+ rsr a0, EXCSAVE_X /* holds the value of a0 before the interrupt handler */
+
+ /* Return from the interrupt, restoring PS from EPS_X */
+ rfi RFI_X
+
+
+/* The linker has no reason to link in this file; all symbols it exports are already defined
+ (weakly!) in the default int handler. Define a symbol here so we can use it to have the
+ linker inspect this anyway. */
+
+ .global ld_include_hli_vectors_rmt
+ld_include_hli_vectors_rmt:
+
+
+#endif // CONFIG_BTDM_CTRL_HLI
+#endif // XTensa
\ No newline at end of file
diff --git a/lib/NeoESP32RmtHI/src/NeoEsp32RmtHIMethod.cpp b/lib/NeoESP32RmtHI/src/NeoEsp32RmtHIMethod.cpp
new file mode 100644
index 0000000000..8353201f08
--- /dev/null
+++ b/lib/NeoESP32RmtHI/src/NeoEsp32RmtHIMethod.cpp
@@ -0,0 +1,507 @@
+/*-------------------------------------------------------------------------
+NeoPixel library helper functions for Esp32.
+
+A BIG thanks to Andreas Merkle for the investigation and implementation of
+a workaround to the GCC bug that drops method attributes from template methods
+
+Written by Michael C. Miller.
+
+I invest time and resources providing this open source code,
+please support me by donating (see https://github.com/Makuna/NeoPixelBus)
+
+-------------------------------------------------------------------------
+This file is part of the Makuna/NeoPixelBus library.
+
+NeoPixelBus is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as
+published by the Free Software Foundation, either version 3 of
+the License, or (at your option) any later version.
+
+NeoPixelBus is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with NeoPixel. If not, see
+.
+-------------------------------------------------------------------------*/
+
+#include
+
+#if defined(ARDUINO_ARCH_ESP32)
+
+#include
+#include "esp_idf_version.h"
+#include "NeoEsp32RmtHIMethod.h"
+#include "soc/soc.h"
+#include "soc/rmt_reg.h"
+
+#ifdef __riscv
+#include "riscv/interrupt.h"
+#endif
+
+
+#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0)
+#include "hal/rmt_ll.h"
+#else
+/* Shims for older ESP-IDF v3; we can safely assume original ESP32 */
+#include "soc/rmt_struct.h"
+
+// Selected RMT API functions borrowed from ESP-IDF v4.4.8
+// components/hal/esp32/include/hal/rmt_ll.h
+// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+__attribute__((always_inline))
+static inline void rmt_ll_tx_reset_pointer(rmt_dev_t *dev, uint32_t channel)
+{
+ dev->conf_ch[channel].conf1.mem_rd_rst = 1;
+ dev->conf_ch[channel].conf1.mem_rd_rst = 0;
+}
+
+__attribute__((always_inline))
+static inline void rmt_ll_tx_start(rmt_dev_t *dev, uint32_t channel)
+{
+ dev->conf_ch[channel].conf1.tx_start = 1;
+}
+
+__attribute__((always_inline))
+static inline void rmt_ll_tx_stop(rmt_dev_t *dev, uint32_t channel)
+{
+ RMTMEM.chan[channel].data32[0].val = 0;
+ dev->conf_ch[channel].conf1.tx_start = 0;
+ dev->conf_ch[channel].conf1.mem_rd_rst = 1;
+ dev->conf_ch[channel].conf1.mem_rd_rst = 0;
+}
+
+__attribute__((always_inline))
+static inline void rmt_ll_tx_enable_pingpong(rmt_dev_t *dev, uint32_t channel, bool enable)
+{
+ dev->apb_conf.mem_tx_wrap_en = enable;
+}
+
+__attribute__((always_inline))
+static inline void rmt_ll_tx_enable_loop(rmt_dev_t *dev, uint32_t channel, bool enable)
+{
+ dev->conf_ch[channel].conf1.tx_conti_mode = enable;
+}
+
+__attribute__((always_inline))
+static inline uint32_t rmt_ll_tx_get_channel_status(rmt_dev_t *dev, uint32_t channel)
+{
+ return dev->status_ch[channel];
+}
+
+__attribute__((always_inline))
+static inline void rmt_ll_tx_set_limit(rmt_dev_t *dev, uint32_t channel, uint32_t limit)
+{
+ dev->tx_lim_ch[channel].limit = limit;
+}
+
+__attribute__((always_inline))
+static inline void rmt_ll_enable_interrupt(rmt_dev_t *dev, uint32_t mask, bool enable)
+{
+ if (enable) {
+ dev->int_ena.val |= mask;
+ } else {
+ dev->int_ena.val &= ~mask;
+ }
+}
+
+__attribute__((always_inline))
+static inline void rmt_ll_enable_tx_end_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable)
+{
+ dev->int_ena.val &= ~(1 << (channel * 3));
+ dev->int_ena.val |= (enable << (channel * 3));
+}
+
+__attribute__((always_inline))
+static inline void rmt_ll_enable_tx_err_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable)
+{
+ dev->int_ena.val &= ~(1 << (channel * 3 + 2));
+ dev->int_ena.val |= (enable << (channel * 3 + 2));
+}
+
+__attribute__((always_inline))
+static inline void rmt_ll_enable_tx_thres_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable)
+{
+ dev->int_ena.val &= ~(1 << (channel + 24));
+ dev->int_ena.val |= (enable << (channel + 24));
+}
+
+__attribute__((always_inline))
+static inline void rmt_ll_clear_tx_end_interrupt(rmt_dev_t *dev, uint32_t channel)
+{
+ dev->int_clr.val = (1 << (channel * 3));
+}
+
+__attribute__((always_inline))
+static inline void rmt_ll_clear_tx_err_interrupt(rmt_dev_t *dev, uint32_t channel)
+{
+ dev->int_clr.val = (1 << (channel * 3 + 2));
+}
+
+__attribute__((always_inline))
+static inline void rmt_ll_clear_tx_thres_interrupt(rmt_dev_t *dev, uint32_t channel)
+{
+ dev->int_clr.val = (1 << (channel + 24));
+}
+
+
+__attribute__((always_inline))
+static inline uint32_t rmt_ll_get_tx_thres_interrupt_status(rmt_dev_t *dev)
+{
+ uint32_t status = dev->int_st.val;
+ return (status & 0xFF000000) >> 24;
+}
+#endif
+
+
+// *********************************
+// Select method for binding interrupt
+//
+// - If the Bluetooth driver has registered a high-level interrupt, piggyback on that API
+// - If we're on a modern core, allocate the interrupt with the API (old cores are bugged)
+// - Otherwise use the low-level hardware API to manually bind the interrupt
+
+
+#if defined(CONFIG_BTDM_CTRL_HLI)
+// Espressif's bluetooth driver offers a helpful sharing layer; bring in the interrupt management calls
+#include "hal/interrupt_controller_hal.h"
+extern "C" esp_err_t hli_intr_register(intr_handler_t handler, void* arg, uint32_t intr_reg, uint32_t intr_mask);
+
+#else /* !CONFIG_BTDM_CTRL_HLI*/
+
+// Declare the our high-priority ISR handler
+extern "C" void ld_include_hli_vectors_rmt(); // an object with an address, but no space
+
+#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C3)
+#include "soc/periph_defs.h"
+#endif
+
+// Select level flag
+#if defined(__riscv)
+// RISCV chips don't block interrupts while scheduling; all we need to do is be higher than the WiFi ISR
+#define INT_LEVEL_FLAG ESP_INTR_FLAG_LEVEL3
+#elif defined(CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5)
+#define INT_LEVEL_FLAG ESP_INTR_FLAG_LEVEL4
+#else
+#define INT_LEVEL_FLAG ESP_INTR_FLAG_LEVEL5
+#endif
+
+// ESP-IDF v3 cannot enable high priority interrupts through the API at all;
+// and ESP-IDF v4 on XTensa cannot enable Level 5 due to incorrect interrupt descriptor tables
+#if !defined(__XTENSA__) || (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)) || ((ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0) && CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5))
+#define NEOESP32_RMT_CAN_USE_INTR_ALLOC
+
+// XTensa cores require the assembly bridge
+#ifdef __XTENSA__
+#define HI_IRQ_HANDLER nullptr
+#define HI_IRQ_HANDLER_ARG ld_include_hli_vectors_rmt
+#else
+#define HI_IRQ_HANDLER NeoEsp32RmtMethodIsr
+#define HI_IRQ_HANDLER_ARG nullptr
+#endif
+
+#else
+/* !CONFIG_BTDM_CTRL_HLI && !NEOESP32_RMT_CAN_USE_INTR_ALLOC */
+// This is the index of the LV5 interrupt vector - see interrupt descriptor table in idf components/hal/esp32/interrupt_descriptor_table.c
+#define ESP32_LV5_IRQ_INDEX 26
+
+#endif /* NEOESP32_RMT_CAN_USE_INTR_ALLOC */
+#endif /* CONFIG_BTDM_CTRL_HLI */
+
+
+// RMT driver implementation
+struct NeoEsp32RmtHIChannelState {
+ uint32_t rmtBit0, rmtBit1;
+ uint32_t resetDuration;
+
+ const byte* txDataStart; // data array
+ const byte* txDataEnd; // one past end
+ const byte* txDataCurrent; // current location
+ size_t rmtOffset;
+};
+
+// Global variables
+#if defined(NEOESP32_RMT_CAN_USE_INTR_ALLOC)
+static intr_handle_t isrHandle = nullptr;
+#endif
+
+static NeoEsp32RmtHIChannelState** driverState = nullptr;
+constexpr size_t rmtBatchSize = RMT_MEM_ITEM_NUM / 2;
+
+// Fill the RMT buffer memory
+// This is implemented using many arguments instead of passing the structure object to ensure we do only one lookup
+// All the arguments are passed in registers, so they don't need to be looked up again
+static void IRAM_ATTR RmtFillBuffer(uint8_t channel, const byte** src_ptr, const byte* end, uint32_t bit0, uint32_t bit1, size_t* offset_ptr, size_t reserve) {
+ // We assume that (rmtToWrite % 8) == 0
+ size_t rmtToWrite = rmtBatchSize - reserve;
+ rmt_item32_t* dest =(rmt_item32_t*) &RMTMEM.chan[channel].data32[*offset_ptr + reserve]; // write directly in to RMT memory
+ const byte* psrc = *src_ptr;
+
+ *offset_ptr ^= rmtBatchSize;
+
+ if (psrc != end) {
+ while (rmtToWrite > 0) {
+ uint8_t data = *psrc;
+ for (uint8_t bit = 0; bit < 8; bit++)
+ {
+ dest->val = (data & 0x80) ? bit1 : bit0;
+ dest++;
+ data <<= 1;
+ }
+ rmtToWrite -= 8;
+ psrc++;
+
+ if (psrc == end) {
+ break;
+ }
+ }
+
+ *src_ptr = psrc;
+ }
+
+ if (rmtToWrite > 0) {
+ // Add end event
+ rmt_item32_t bit0_val = {{.val = bit0 }};
+ *dest = rmt_item32_t {{{ .duration0 = 0, .level0 = bit0_val.level1, .duration1 = 0, .level1 = bit0_val.level1 }}};
+ }
+}
+
+static void IRAM_ATTR RmtStartWrite(uint8_t channel, NeoEsp32RmtHIChannelState& state) {
+ // Reset context state
+ state.rmtOffset = 0;
+
+ // Fill the first part of the buffer with a reset event
+ // FUTURE: we could do timing analysis with the last interrupt on this channel
+ // Use 8 words to stay aligned with the buffer fill logic
+ rmt_item32_t bit0_val = {{.val = state.rmtBit0 }};
+ rmt_item32_t fill = {{{ .duration0 = 100, .level0 = bit0_val.level1, .duration1 = 100, .level1 = bit0_val.level1 }}};
+ rmt_item32_t* dest = (rmt_item32_t*) &RMTMEM.chan[channel].data32[0];
+ for (auto i = 0; i < 7; ++i) dest[i] = fill;
+ fill.duration1 = state.resetDuration > 1400 ? (state.resetDuration - 1400) : 100;
+ dest[7] = fill;
+
+ // Fill the remaining buffer with real data
+ RmtFillBuffer(channel, &state.txDataCurrent, state.txDataEnd, state.rmtBit0, state.rmtBit1, &state.rmtOffset, 8);
+ RmtFillBuffer(channel, &state.txDataCurrent, state.txDataEnd, state.rmtBit0, state.rmtBit1, &state.rmtOffset, 0);
+
+ // Start operation
+ rmt_ll_clear_tx_thres_interrupt(&RMT, channel);
+ rmt_ll_tx_reset_pointer(&RMT, channel);
+ rmt_ll_tx_start(&RMT, channel);
+}
+
+extern "C" void IRAM_ATTR NeoEsp32RmtMethodIsr(void *arg) {
+ // Tx threshold interrupt
+ uint32_t status = rmt_ll_get_tx_thres_interrupt_status(&RMT);
+ while (status) {
+ uint8_t channel = __builtin_ffs(status) - 1;
+ if (driverState[channel]) {
+ // Normal case
+ NeoEsp32RmtHIChannelState& state = *driverState[channel];
+ RmtFillBuffer(channel, &state.txDataCurrent, state.txDataEnd, state.rmtBit0, state.rmtBit1, &state.rmtOffset, 0);
+ } else {
+ // Danger - another driver got invoked?
+ rmt_ll_tx_stop(&RMT, channel);
+ }
+ rmt_ll_clear_tx_thres_interrupt(&RMT, channel);
+ status = rmt_ll_get_tx_thres_interrupt_status(&RMT);
+ }
+};
+
+// Wrapper around the register analysis defines
+// For all currently supported chips, this is constant for all channels; but this is not true of *all* ESP32
+static inline bool _RmtStatusIsTransmitting(rmt_channel_t channel, uint32_t status) {
+ uint32_t v;
+ switch(channel) {
+#ifdef RMT_STATE_CH0
+ case 0: v = (status >> RMT_STATE_CH0_S) & RMT_STATE_CH0_V; break;
+#endif
+#ifdef RMT_STATE_CH1
+ case 1: v = (status >> RMT_STATE_CH1_S) & RMT_STATE_CH1_V; break;
+#endif
+#ifdef RMT_STATE_CH2
+ case 2: v = (status >> RMT_STATE_CH2_S) & RMT_STATE_CH2_V; break;
+#endif
+#ifdef RMT_STATE_CH3
+ case 3: v = (status >> RMT_STATE_CH3_S) & RMT_STATE_CH3_V; break;
+#endif
+#ifdef RMT_STATE_CH4
+ case 4: v = (status >> RMT_STATE_CH4_S) & RMT_STATE_CH4_V; break;
+#endif
+#ifdef RMT_STATE_CH5
+ case 5: v = (status >> RMT_STATE_CH5_S) & RMT_STATE_CH5_V; break;
+#endif
+#ifdef RMT_STATE_CH6
+ case 6: v = (status >> RMT_STATE_CH6_S) & RMT_STATE_CH6_V; break;
+#endif
+#ifdef RMT_STATE_CH7
+ case 7: v = (status >> RMT_STATE_CH7_S) & RMT_STATE_CH7_V; break;
+#endif
+ default: v = 0;
+ }
+
+ return v != 0;
+}
+
+
+esp_err_t NeoEsp32RmtHiMethodDriver::Install(rmt_channel_t channel, uint32_t rmtBit0, uint32_t rmtBit1, uint32_t reset) {
+ // Validate channel number
+ if (channel >= RMT_CHANNEL_MAX) {
+ return ESP_ERR_INVALID_ARG;
+ }
+
+ esp_err_t err = ESP_OK;
+ if (!driverState) {
+ // First time init
+ driverState = reinterpret_cast(heap_caps_calloc(RMT_CHANNEL_MAX, sizeof(NeoEsp32RmtHIChannelState*), MALLOC_CAP_INTERNAL));
+ if (!driverState) return ESP_ERR_NO_MEM;
+
+ // Ensure all interrupts are cleared before binding
+ RMT.int_ena.val = 0;
+ RMT.int_clr.val = 0xFFFFFFFF;
+
+ // Bind interrupt handler
+#if defined(CONFIG_BTDM_CTRL_HLI)
+ // Bluetooth driver has taken the empty high-priority interrupt. Fortunately, it allows us to
+ // hook up another handler.
+ err = hli_intr_register(NeoEsp32RmtMethodIsr, nullptr, (uintptr_t) &RMT.int_st, 0xFF000000);
+ // 25 is the magic number of the bluetooth ISR on ESP32 - see soc/soc.h.
+ intr_matrix_set(cpu_hal_get_core_id(), ETS_RMT_INTR_SOURCE, 25);
+ intr_cntrl_ll_enable_interrupts(1<<25);
+#elif defined(NEOESP32_RMT_CAN_USE_INTR_ALLOC)
+ // Use the platform code to allocate the interrupt
+ // If we need the additional assembly bridge, we pass it as the "arg" to the IDF so it gets linked in
+ err = esp_intr_alloc(ETS_RMT_INTR_SOURCE, INT_LEVEL_FLAG | ESP_INTR_FLAG_IRAM, HI_IRQ_HANDLER, (void*) HI_IRQ_HANDLER_ARG, &isrHandle);
+ //err = ESP_ERR_NOT_FINISHED;
+#else
+ // Broken IDF API does not allow us to reserve the interrupt; do it manually
+ static volatile const void* __attribute__((used)) pleaseLinkAssembly = (void*) ld_include_hli_vectors_rmt;
+ intr_matrix_set(xPortGetCoreID(), ETS_RMT_INTR_SOURCE, ESP32_LV5_IRQ_INDEX);
+ ESP_INTR_ENABLE(ESP32_LV5_IRQ_INDEX);
+#endif
+
+ if (err != ESP_OK) {
+ heap_caps_free(driverState);
+ driverState = nullptr;
+ return err;
+ }
+ }
+
+ if (driverState[channel] != nullptr) {
+ return ESP_ERR_INVALID_STATE; // already in use
+ }
+
+ NeoEsp32RmtHIChannelState* state = reinterpret_cast(heap_caps_calloc(1, sizeof(NeoEsp32RmtHIChannelState), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT));
+ if (state == nullptr) {
+ return ESP_ERR_NO_MEM;
+ }
+
+ // Store timing information
+ state->rmtBit0 = rmtBit0;
+ state->rmtBit1 = rmtBit1;
+ state->resetDuration = reset;
+
+ // Initialize hardware
+ rmt_ll_tx_stop(&RMT, channel);
+ rmt_ll_tx_reset_pointer(&RMT, channel);
+ rmt_ll_enable_tx_err_interrupt(&RMT, channel, false);
+ rmt_ll_enable_tx_end_interrupt(&RMT, channel, false);
+ rmt_ll_enable_tx_thres_interrupt(&RMT, channel, false);
+ rmt_ll_clear_tx_err_interrupt(&RMT, channel);
+ rmt_ll_clear_tx_end_interrupt(&RMT, channel);
+ rmt_ll_clear_tx_thres_interrupt(&RMT, channel);
+
+ rmt_ll_tx_enable_loop(&RMT, channel, false);
+ rmt_ll_tx_enable_pingpong(&RMT, channel, true);
+ rmt_ll_tx_set_limit(&RMT, channel, rmtBatchSize);
+
+ driverState[channel] = state;
+
+ rmt_ll_enable_tx_thres_interrupt(&RMT, channel, true);
+
+ return err;
+}
+
+esp_err_t NeoEsp32RmtHiMethodDriver::Uninstall(rmt_channel_t channel) {
+ if ((channel >= RMT_CHANNEL_MAX) || !driverState || !driverState[channel]) return ESP_ERR_INVALID_ARG;
+
+ NeoEsp32RmtHIChannelState* state = driverState[channel];
+
+ WaitForTxDone(channel, 10000 / portTICK_PERIOD_MS);
+
+ // Done or not, we're out of here
+ rmt_ll_tx_stop(&RMT, channel);
+ rmt_ll_enable_tx_thres_interrupt(&RMT, channel, false);
+ driverState[channel] = nullptr;
+ heap_caps_free(state);
+
+#if !defined(CONFIG_BTDM_CTRL_HLI) /* Cannot unbind from bluetooth ISR */
+ // Turn off the driver ISR and release global state if none are left
+ for (uint8_t channelIndex = 0; channelIndex < RMT_CHANNEL_MAX; ++channelIndex) {
+ if (driverState[channelIndex]) return ESP_OK; // done
+ }
+
+#if defined(NEOESP32_RMT_CAN_USE_INTR_ALLOC)
+ esp_intr_free(isrHandle);
+#else
+ ESP_INTR_DISABLE(ESP32_LV5_IRQ_INDEX);
+#endif
+
+ heap_caps_free(driverState);
+ driverState = nullptr;
+#endif /* !defined(CONFIG_BTDM_CTRL_HLI) */
+
+ return ESP_OK;
+}
+
+esp_err_t NeoEsp32RmtHiMethodDriver::Write(rmt_channel_t channel, const uint8_t *src, size_t src_size) {
+ if ((channel >= RMT_CHANNEL_MAX) || !driverState || !driverState[channel]) return ESP_ERR_INVALID_ARG;
+
+ NeoEsp32RmtHIChannelState& state = *driverState[channel];
+ esp_err_t result = WaitForTxDone(channel, 10000 / portTICK_PERIOD_MS);
+
+ if (result == ESP_OK) {
+ state.txDataStart = src;
+ state.txDataCurrent = src;
+ state.txDataEnd = src + src_size;
+ RmtStartWrite(channel, state);
+ }
+ return result;
+}
+
+esp_err_t NeoEsp32RmtHiMethodDriver::WaitForTxDone(rmt_channel_t channel, TickType_t wait_time) {
+ if ((channel >= RMT_CHANNEL_MAX) || !driverState || !driverState[channel]) return ESP_ERR_INVALID_ARG;
+
+ NeoEsp32RmtHIChannelState& state = *driverState[channel];
+ // yield-wait until wait_time
+ esp_err_t rv = ESP_OK;
+ uint32_t status;
+ while(1) {
+ status = rmt_ll_tx_get_channel_status(&RMT, channel);
+ if (!_RmtStatusIsTransmitting(channel, status)) break;
+ if (wait_time == 0) { rv = ESP_ERR_TIMEOUT; break; };
+
+ TickType_t sleep = std::min(wait_time, (TickType_t) 5);
+ vTaskDelay(sleep);
+ wait_time -= sleep;
+ };
+
+ return rv;
+}
+
+#endif
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 0f73bff0c4..2b8eb0a2f5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,18 +1,21 @@
{
"name": "wled",
- "version": "0.15.0-b7",
+ "version": "0.15.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "wled",
- "version": "0.15.0-b7",
+ "version": "0.15.3",
"license": "ISC",
"dependencies": {
"clean-css": "^5.3.3",
"html-minifier-terser": "^7.2.0",
"inliner": "^1.13.1",
- "nodemon": "^3.0.2"
+ "nodemon": "^3.1.7"
+ },
+ "engines": {
+ "node": ">=20.0.0"
}
},
"node_modules/@jridgewell/gen-mapping": {
diff --git a/package.json b/package.json
index a11a135539..68369b8f8a 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "wled",
- "version": "0.15.0-b7",
+ "version": "0.15.3",
"description": "Tools for WLED project",
"main": "tools/cdata.js",
"directories": {
diff --git a/pio-scripts/build_ui.py b/pio-scripts/build_ui.py
index f3688a5d4a..047fac442c 100644
--- a/pio-scripts/build_ui.py
+++ b/pio-scripts/build_ui.py
@@ -1,3 +1,21 @@
-Import('env')
+Import("env")
+import shutil
-env.Execute("npm run build")
\ No newline at end of file
+node_ex = shutil.which("node")
+# Check if Node.js is installed and present in PATH if it failed, abort the build
+if node_ex is None:
+ print('\x1b[0;31;43m' + 'Node.js is not installed or missing from PATH html css js will not be processed check https://kno.wled.ge/advanced/compiling-wled/' + '\x1b[0m')
+ exitCode = env.Execute("null")
+ exit(exitCode)
+else:
+ # Install the necessary node packages for the pre-build asset bundling script
+ print('\x1b[6;33;42m' + 'Installing node packages' + '\x1b[0m')
+ env.Execute("npm install")
+
+ # Call the bundling script
+ exitCode = env.Execute("npm run build")
+
+ # If it failed, abort the build
+ if (exitCode):
+ print('\x1b[0;31;43m' + 'npm run build fails check https://kno.wled.ge/advanced/compiling-wled/' + '\x1b[0m')
+ exit(exitCode)
\ No newline at end of file
diff --git a/pio-scripts/output_bins.py b/pio-scripts/output_bins.py
index 4d1594d843..d369ed7927 100644
--- a/pio-scripts/output_bins.py
+++ b/pio-scripts/output_bins.py
@@ -2,6 +2,7 @@
import os
import shutil
import gzip
+import json
OUTPUT_DIR = "build_output{}".format(os.path.sep)
#OUTPUT_DIR = os.path.join("build_output")
@@ -22,7 +23,8 @@ def create_release(source):
release_name_def = _get_cpp_define_value(env, "WLED_RELEASE_NAME")
if release_name_def:
release_name = release_name_def.replace("\\\"", "")
- version = _get_cpp_define_value(env, "WLED_VERSION")
+ with open("package.json", "r") as package:
+ version = json.load(package)["version"]
release_file = os.path.join(OUTPUT_DIR, "release", f"WLED_{version}_{release_name}.bin")
release_gz_file = release_file + ".gz"
print(f"Copying {source} to {release_file}")
diff --git a/pio-scripts/set_metadata.py b/pio-scripts/set_metadata.py
new file mode 100644
index 0000000000..7c8c223038
--- /dev/null
+++ b/pio-scripts/set_metadata.py
@@ -0,0 +1,116 @@
+Import('env')
+import subprocess
+import json
+import re
+
+def get_github_repo():
+ """Extract GitHub repository name from git remote URL.
+
+ Uses the remote that the current branch tracks, falling back to 'origin'.
+ This handles cases where repositories have multiple remotes or where the
+ main remote is not named 'origin'.
+
+ Returns:
+ str: Repository name in 'owner/repo' format for GitHub repos,
+ 'unknown' for non-GitHub repos, missing git CLI, or any errors.
+ """
+ try:
+ remote_name = 'origin' # Default fallback
+
+ # Try to get the remote for the current branch
+ try:
+ # Get current branch name
+ branch_result = subprocess.run(['git', 'rev-parse', '--abbrev-ref', 'HEAD'],
+ capture_output=True, text=True, check=True)
+ current_branch = branch_result.stdout.strip()
+
+ # Get the remote for the current branch
+ remote_result = subprocess.run(['git', 'config', f'branch.{current_branch}.remote'],
+ capture_output=True, text=True, check=True)
+ tracked_remote = remote_result.stdout.strip()
+
+ # Use the tracked remote if we found one
+ if tracked_remote:
+ remote_name = tracked_remote
+ except subprocess.CalledProcessError:
+ # If branch config lookup fails, continue with 'origin' as fallback
+ pass
+
+ # Get the remote URL for the determined remote
+ result = subprocess.run(['git', 'remote', 'get-url', remote_name],
+ capture_output=True, text=True, check=True)
+ remote_url = result.stdout.strip()
+
+ # Check if it's a GitHub URL
+ if 'github.com' not in remote_url.lower():
+ return None
+
+ # Parse GitHub URL patterns:
+ # https://github.com/owner/repo.git
+ # git@github.com:owner/repo.git
+ # https://github.com/owner/repo
+
+ # Remove .git suffix if present
+ if remote_url.endswith('.git'):
+ remote_url = remote_url[:-4]
+
+ # Handle HTTPS URLs
+ https_match = re.search(r'github\.com/([^/]+/[^/]+)', remote_url, re.IGNORECASE)
+ if https_match:
+ return https_match.group(1)
+
+ # Handle SSH URLs
+ ssh_match = re.search(r'github\.com:([^/]+/[^/]+)', remote_url, re.IGNORECASE)
+ if ssh_match:
+ return ssh_match.group(1)
+
+ return None
+
+ except FileNotFoundError:
+ # Git CLI is not installed or not in PATH
+ return None
+ except subprocess.CalledProcessError:
+ # Git command failed (e.g., not a git repo, no remote, etc.)
+ return None
+ except Exception:
+ # Any other unexpected error
+ return None
+
+# WLED version is managed by package.json; this is picked up in several places
+# - It's integrated in to the UI code
+# - Here, for wled_metadata.cpp
+# - The output_bins script
+# We always take it from package.json to ensure consistency
+with open("package.json", "r") as package:
+ WLED_VERSION = json.load(package)["version"]
+
+def has_def(cppdefs, name):
+ """ Returns true if a given name is set in a CPPDEFINES collection """
+ for f in cppdefs:
+ if isinstance(f, tuple):
+ f = f[0]
+ if f == name:
+ return True
+ return False
+
+
+def add_wled_metadata_flags(env, node):
+ cdefs = env["CPPDEFINES"].copy()
+
+ if not has_def(cdefs, "WLED_REPO"):
+ repo = get_github_repo()
+ if repo:
+ cdefs.append(("WLED_REPO", f"\\\"{repo}\\\""))
+
+ cdefs.append(("WLED_VERSION", WLED_VERSION))
+
+ # This transforms the node in to a Builder; it cannot be modified again
+ return env.Object(
+ node,
+ CPPDEFINES=cdefs
+ )
+
+env.AddBuildMiddleware(
+ add_wled_metadata_flags,
+ "*/wled_metadata.cpp"
+)
diff --git a/pio-scripts/set_version.py b/pio-scripts/set_version.py
deleted file mode 100644
index 1d8e076ea8..0000000000
--- a/pio-scripts/set_version.py
+++ /dev/null
@@ -1,8 +0,0 @@
-Import('env')
-import json
-
-PACKAGE_FILE = "package.json"
-
-with open(PACKAGE_FILE, "r") as package:
- version = json.load(package)["version"]
- env.Append(BUILD_FLAGS=[f"-DWLED_VERSION={version}"])
diff --git a/platformio.ini b/platformio.ini
index fe02213ff2..4164a4c186 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -1,343 +1,212 @@
; PlatformIO Project Configuration File
-; Please visit documentation: https://docs.platformio.org/page/projectconf.html
+;
+; Build options: build flags, source filter
+; Upload options: custom upload port, speed and extra flags
+; Library options: dependencies, extra library storages
+; Advanced options: extra scripting
+;
+; Please visit documentation for the other options and examples
+; https://docs.platformio.org/page/projectconf.html
[platformio]
-# ------------------------------------------------------------------------------
-# ENVIRONMENTS
-#
-# Please uncomment one of the lines below to select your board(s)
-# (use `platformio_override.ini` when building for your own board; see `platformio_override.ini.sample` for an example)
-# ------------------------------------------------------------------------------
-
-# CI/release binaries
-default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, nodemcuv2_160, esp8266_2m_160, esp01_1m_full_160, nodemcuv2_compat, esp8266_2m_compat, esp01_1m_full_compat, esp32dev, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_16MB_opi, esp32s3dev_8MB_opi, esp32s3_4M_qspi, esp32_wrover
-
-src_dir = ./wled00
+default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, nodemcuv2_160, esp8266_2m_160, esp01_1m_full_160, nodemcuv2_compat, esp8266_2m_compat, esp01_1m_full_compat, esp32dev, esp32dev_V4, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_16MB_opi, esp32s3dev_8MB_opi, esp32s3_4M_qspi, esp32_wrover
+src_dir = ./wled00
data_dir = ./wled00/data
build_cache_dir = ~/.buildcache
-extra_configs =
- platformio_override.ini
+extra_configs =
+ platformio_override.ini
[common]
-# ------------------------------------------------------------------------------
-# PLATFORM:
-# !! DO NOT confuse platformio's ESP8266 development platform with Arduino core for ESP8266
-#
-# arduino core 2.6.3 = platformIO 2.3.2
-# arduino core 2.7.0 = platformIO 2.5.0
-# ------------------------------------------------------------------------------
arduino_core_2_6_3 = espressif8266@2.3.3
arduino_core_2_7_4 = espressif8266@2.6.2
arduino_core_3_0_0 = espressif8266@3.0.0
arduino_core_3_0_2 = espressif8266@3.2.0
arduino_core_3_1_0 = espressif8266@4.1.0
arduino_core_3_1_2 = espressif8266@4.2.1
-
-# Development platforms
arduino_core_develop = https://github.com/platformio/platform-espressif8266#develop
arduino_core_git = https://github.com/platformio/platform-espressif8266#feature/stage
-
-# Platform to use for ESP8266
platform_wled_default = ${common.arduino_core_3_1_2}
-# We use 2.7.4.7 for all, includes PWM flicker fix and Wstring optimization
-#platform_packages = tasmota/framework-arduinoespressif8266 @ 3.20704.7
-platform_packages = platformio/toolchain-xtensa @ ~2.100300.220621 #2.40802.200502
- platformio/tool-esptool #@ ~1.413.0
- platformio/tool-esptoolpy #@ ~1.30000.0
-
-## previous platform for 8266, in case of problems with the new one
-## you'll need makuna/NeoPixelBus@ 2.6.9 for arduino_core_3_0_2, which does not support Ucs890x
-;; platform_wled_default = ${common.arduino_core_3_0_2}
-;; platform_packages = tasmota/framework-arduinoespressif8266 @ 3.20704.7
-;; platformio/toolchain-xtensa @ ~2.40802.200502
-;; platformio/tool-esptool @ ~1.413.0
-;; platformio/tool-esptoolpy @ ~1.30000.0
-
-# ------------------------------------------------------------------------------
-# FLAGS: DEBUG
-# esp8266 : see https://docs.platformio.org/en/latest/platforms/espressif8266.html#debug-level
-# esp32 : see https://docs.platformio.org/en/latest/platforms/espressif32.html#debug-level
-# ------------------------------------------------------------------------------
+platform_packages = platformio/toolchain-xtensa @ ~2.100300.220621
+ platformio/tool-esptool
+ platformio/tool-esptoolpy
debug_flags = -D DEBUG=1 -D WLED_DEBUG
- -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_UPDATE -DDEBUG_ESP_HTTP_SERVER -DDEBUG_ESP_UPDATER -DDEBUG_ESP_OTA -DDEBUG_TLS_MEM ;; for esp8266
- # if needed (for memleaks etc) also add; -DDEBUG_ESP_OOM -include "umm_malloc/umm_malloc_cfg.h"
- # -DDEBUG_ESP_CORE is not working right now
-
-# ------------------------------------------------------------------------------
-# FLAGS: ldscript (available ldscripts at https://github.com/esp8266/Arduino/tree/master/tools/sdk/ld)
-# ldscript_2m1m (2048 KB) = 1019 KB sketch, 4 KB eeprom, 1004 KB spiffs, 16 KB reserved
-# ldscript_4m1m (4096 KB) = 1019 KB sketch, 4 KB eeprom, 1002 KB spiffs, 16 KB reserved, 2048 KB empty/ota?
-#
-# Available lwIP variants (macros):
-# -DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH = v1.4 Higher Bandwidth (default)
-# -DPIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY = v2 Lower Memory
-# -DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH = v2 Higher Bandwidth
-# -DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH_LOW_FLASH
-#
-# BearSSL performance:
-# When building with -DSECURE_CLIENT=SECURE_CLIENT_BEARSSL, please add `board_build.f_cpu = 160000000` to the environment configuration
-#
-# BearSSL ciphers:
-# When building on core >= 2.5, you can add the build flag -DBEARSSL_SSL_BASIC in order to build BearSSL with a limited set of ciphers:
-# TLS_RSA_WITH_AES_128_CBC_SHA256 / AES128-SHA256
-# TLS_RSA_WITH_AES_256_CBC_SHA256 / AES256-SHA256
-# TLS_RSA_WITH_AES_128_CBC_SHA / AES128-SHA
-# TLS_RSA_WITH_AES_256_CBC_SHA / AES256-SHA
-# This reduces the OTA size with ~45KB, so it's especially useful on low memory boards (512k/1m).
-# ------------------------------------------------------------------------------
-build_flags =
- -DMQTT_MAX_PACKET_SIZE=1024
- -DSECURE_CLIENT=SECURE_CLIENT_BEARSSL
- -DBEARSSL_SSL_BASIC
- -D CORE_DEBUG_LEVEL=0
- -D NDEBUG
- -Wno-attributes ;; silence warnings about unknown attribute 'maybe_unused' in NeoPixelBus
- #build_flags for the IRremoteESP8266 library (enabled decoders have to appear here)
- -D _IR_ENABLE_DEFAULT_=false
- -D DECODE_HASH=true
- -D DECODE_NEC=true
- -D DECODE_SONY=true
- -D DECODE_SAMSUNG=true
- -D DECODE_LG=true
- -DWLED_USE_MY_CONFIG
-
-build_unflags =
-
+ -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_UPDATE -DDEBUG_ESP_HTTP_SERVER -DDEBUG_ESP_UPDATER -DDEBUG_ESP_OTA -DDEBUG_TLS_MEM
+build_flags =
+ -DMQTT_MAX_PACKET_SIZE=1024
+ -DSECURE_CLIENT=SECURE_CLIENT_BEARSSL
+ -DBEARSSL_SSL_BASIC
+ -D CORE_DEBUG_LEVEL=0
+ -D NDEBUG
+ -Wno-attributes
+ -D _IR_ENABLE_DEFAULT_=false
+ -D DECODE_HASH=true
+ -D DECODE_NEC=true
+ -D DECODE_SONY=true
+ -D DECODE_SAMSUNG=true
+ -D DECODE_LG=true
+ -DWLED_USE_MY_CONFIG
+build_unflags =
ldscript_1m128k = eagle.flash.1m128.ld
ldscript_2m512k = eagle.flash.2m512.ld
ldscript_2m1m = eagle.flash.2m1m.ld
ldscript_4m1m = eagle.flash.4m1m.ld
[scripts_defaults]
-extra_scripts =
- pre:pio-scripts/set_version.py
- post:pio-scripts/output_bins.py
- post:pio-scripts/strip-floats.py
- pre:pio-scripts/user_config_copy.py
- pre:pio-scripts/build_ui.py
- ; post:pio-scripts/obj-dump.py ;; convenience script to create a disassembly dump of the firmware (hardcore debugging)
+extra_scripts =
+ pre:pio-scripts/set_metadata.py
+ post:pio-scripts/output_bins.py
+ post:pio-scripts/strip-floats.py
+ pre:pio-scripts/user_config_copy.py
+ pre:pio-scripts/build_ui.py
-# ------------------------------------------------------------------------------
-# COMMON SETTINGS:
-# ------------------------------------------------------------------------------
[env]
framework = arduino
board_build.flash_mode = dout
monitor_speed = 115200
-# slow upload speed but most compatible (use platformio_override.ini to use faster speed)
upload_speed = 115200
-
-# ------------------------------------------------------------------------------
-# LIBRARIES: required dependencies
-# Please note that we don't always use the latest version of a library.
-#
-# The following libraries have been included (and some of them changed) in the source:
-# ArduinoJson@5.13.5, E131@1.0.0(changed), Time@1.5, Timezone@1.2.1
-# ------------------------------------------------------------------------------
lib_compat_mode = strict
-lib_deps =
- fastled/FastLED @ 3.6.0
- IRremoteESP8266 @ 2.8.2
- makuna/NeoPixelBus @ 2.8.0
- #https://github.com/makuna/NeoPixelBus.git#CoreShaderBeta
- https://github.com/Aircoookie/ESPAsyncWebServer.git#v2.2.1
- # for I2C interface
- ;Wire
- # ESP-NOW library
- ;gmag11/QuickESPNow @ ~0.7.0
- https://github.com/blazoncek/QuickESPNow.git#optional-debug
- #For use of the TTGO T-Display ESP32 Module with integrated TFT display uncomment the following line
- #TFT_eSPI
- #For compatible OLED display uncomment following
- #olikraus/U8g2 #@ ~2.33.15
- #For Dallas sensor uncomment following
- #paulstoffregen/OneWire @ ~2.3.8
- #For BME280 sensor uncomment following
- #BME280 @ ~3.0.0
- ;adafruit/Adafruit BMP280 Library @ 2.1.0
- ;adafruit/Adafruit CCS811 Library @ 1.0.4
- ;adafruit/Adafruit Si7021 Library @ 1.4.0
- #For ADS1115 sensor uncomment following
- ;adafruit/Adafruit BusIO @ 1.13.2
- ;adafruit/Adafruit ADS1X15 @ 2.4.0
- #For MAX1704x Lipo Monitor / Fuel Gauge uncomment following
- ; https://github.com/adafruit/Adafruit_BusIO @ 1.14.5
- ; https://github.com/adafruit/Adafruit_MAX1704X @ 1.0.2
- #For MPU6050 IMU uncomment follwoing
- ;electroniccats/MPU6050 @1.0.1
- # For -D USERMOD_ANIMARTRIX
- # CC BY-NC 3.0 licensed effects by Stefan Petrick, include this usermod only if you accept the terms!
- ;https://github.com/netmindz/animartrix.git#18bf17389e57c69f11bc8d04ebe1d215422c7fb7
- # SHT85
- ;robtillaart/SHT85@~0.3.3
- # Audioreactive usermod
- ;kosme/arduinoFFT @ 2.0.1
-
+lib_deps =
+ fastled/FastLED @ 3.6.0
+ IRremoteESP8266 @ 2.8.2
+ https://github.com/Makuna/NeoPixelBus.git#a0919d1c10696614625978dd6fb750a1317a14ce
+ https://github.com/Aircoookie/ESPAsyncWebServer.git#v2.4.2
+ https://github.com/blazoncek/QuickESPNow.git#optional-debug
extra_scripts = ${scripts_defaults.extra_scripts}
[esp8266]
-build_flags =
- -DESP8266
- -DFP_IN_IROM
- ;-Wno-deprecated-declarations
- ;-Wno-register ;; leaves some warnings when compiling C files: command-line option '-Wno-register' is valid for C++/ObjC++ but not for C
- ;-Dregister= # remove warnings in C++17 due to use of deprecated register keyword by the FastLED library ;; warning: this can be dangerous
- -Wno-misleading-indentation
- ; NONOSDK22x_190703 = 2.2.2-dev(38a443e)
- -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_190703
- ; lwIP 2 - Higher Bandwidth no Features
- ; -DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH_LOW_FLASH
- ; lwIP 1.4 - Higher Bandwidth (Aircoookie has)
- -DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH
- ; VTABLES in Flash
- -DVTABLES_IN_FLASH
- ; restrict to minimal mime-types
- -DMIMETYPE_MINIMAL
- ; other special-purpose framework flags (see https://docs.platformio.org/en/latest/platforms/espressif8266.html)
- ; decrease code cache size and increase IRAM to fit all pixel functions
- -D PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48 ;; in case of linker errors like "section `.text1' will not fit in region `iram1_0_seg'"
- ; -D PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48_SECHEAP_SHARED ;; (experimental) adds some extra heap, but may cause slowdown
- -D NON32XFER_HANDLER ;; ask forgiveness for PROGMEM misuse
-
-lib_deps =
- #https://github.com/lorol/LITTLEFS.git
- ESPAsyncTCP @ 1.2.2
- ESPAsyncUDP
- ESP8266PWM
- ${env.lib_deps}
-
-;; compatibilty flags - same as 0.14.0 which seems to work better on some 8266 boards. Not using PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48
-build_flags_compat =
- -DESP8266
- -DFP_IN_IROM
- ;;-Wno-deprecated-declarations
- -Wno-misleading-indentation
- ;;-Wno-attributes ;; silence warnings about unknown attribute 'maybe_unused' in NeoPixelBus
- -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_190703
- -DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH
- -DVTABLES_IN_FLASH
- -DMIMETYPE_MINIMAL
- -DWLED_SAVE_IRAM ;; needed to prevent linker error
-
-;; this platform version was used for WLED 0.14.0
+build_unflags = ${common.build_unflags}
+build_flags =
+ -DESP8266
+ -DFP_IN_IROM
+ -Wno-misleading-indentation
+ -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_190703
+ -DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH
+ -DVTABLES_IN_FLASH
+ -DMIMETYPE_MINIMAL
+ -D PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48
+ -D NON32XFER_HANDLER
+lib_deps =
+ ESPAsyncTCP @ 1.2.2
+ ESPAsyncUDP
+ ESP8266PWM
+ ${env.lib_deps}
+build_flags_compat =
+ -DESP8266
+ -DFP_IN_IROM
+ -Wno-misleading-indentation
+ -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_190703
+ -DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH
+ -DVTABLES_IN_FLASH
+ -DMIMETYPE_MINIMAL
+ -DWLED_SAVE_IRAM
platform_compat = espressif8266@4.2.0
-platform_packages_compat =
- platformio/toolchain-xtensa @ ~2.100300.220621 #2.40802.200502
- platformio/tool-esptool #@ ~1.413.0
- platformio/tool-esptoolpy #@ ~1.30000.0
-
-;; experimental - for using older NeoPixelBus 2.7.9
-lib_deps_compat =
- ESPAsyncTCP @ 1.2.2
- ESPAsyncUDP
- ESP8266PWM
- fastled/FastLED @ 3.6.0
- IRremoteESP8266 @ 2.8.2
- makuna/NeoPixelBus @ 2.7.9
- https://github.com/blazoncek/QuickESPNow.git#optional-debug
- https://github.com/Aircoookie/ESPAsyncWebServer.git#v2.2.1
-
+platform_packages_compat =
+ platformio/toolchain-xtensa @ ~2.100300.220621
+ platformio/tool-esptool
+ platformio/tool-esptoolpy
+lib_deps_compat =
+ ESPAsyncTCP @ 1.2.2
+ ESPAsyncUDP
+ ESP8266PWM
+ fastled/FastLED @ 3.6.0
+ IRremoteESP8266 @ 2.8.2
+ makuna/NeoPixelBus @ 2.7.9
+ https://github.com/blazoncek/QuickESPNow.git#optional-debug
+ https://github.com/Aircoookie/ESPAsyncWebServer.git#v2.2.1
[esp32]
-#platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.2.3/platform-espressif32-2.0.2.3.zip
platform = espressif32@3.5.0
platform_packages = framework-arduinoespressif32 @ https://github.com/Aircoookie/arduino-esp32.git#1.0.6.4
+build_unflags = ${common.build_unflags}
build_flags = -g
- -DARDUINO_ARCH_ESP32
- #-DCONFIG_LITTLEFS_FOR_IDF_3_2
- -D CONFIG_ASYNC_TCP_USE_WDT=0
- #use LITTLEFS library by lorol in ESP32 core 1.x.x instead of built-in in 2.x.x
- -D LOROL_LITTLEFS
- ; -DARDUINO_USB_CDC_ON_BOOT=0 ;; this flag is mandatory for "classic ESP32" when building with arduino-esp32 >=2.0.3
+ -DARDUINO_ARCH_ESP32
+ -D CONFIG_ASYNC_TCP_USE_WDT=0
+ -D CONFIG_ASYNC_TCP_STACK_SIZE=8192
+ -D LOROL_LITTLEFS
tiny_partitions = tools/WLED_ESP32_2MB_noOTA.csv
default_partitions = tools/WLED_ESP32_4MB_1MB_FS.csv
extended_partitions = tools/WLED_ESP32_4MB_700k_FS.csv
-big_partitions = tools/WLED_ESP32_4MB_256KB_FS.csv ;; 1.8MB firmware, 256KB filesystem, coredump support
+big_partitions = tools/WLED_ESP32_4MB_256KB_FS.csv
large_partitions = tools/WLED_ESP32_8MB.csv
extreme_partitions = tools/WLED_ESP32_16MB_9MB_FS.csv
-lib_deps =
- https://github.com/lorol/LITTLEFS.git
- https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
- ${env.lib_deps}
-# additional build flags for audioreactive
-AR_build_flags = -D USERMOD_AUDIOREACTIVE
- -D sqrt_internal=sqrtf ;; -fsingle-precision-constant ;; forces ArduinoFFT to use float math (2x faster)
-AR_lib_deps = kosme/arduinoFFT @ 2.0.1
+lib_deps =
+ https://github.com/lorol/LITTLEFS.git
+ esp32async/AsyncTCP @ 3.4.7
+ ${env.lib_deps}
+ar_build_flags = -D USERMOD_AUDIOREACTIVE
+ -D sqrt_internal=sqrtf
+ar_lib_deps = kosme/arduinoFFT @ 2.0.1
+board_build.partitions = ${esp32.default_partitions}
[esp32_idf_V4]
-;; experimental build environment for ESP32 using ESP-IDF 4.4.x / arduino-esp32 v2.0.5
-;; very similar to the normal ESP32 flags, but omitting Lorol LittleFS, as littlefs is included in the new framework already.
-;;
-;; please note that you can NOT update existing ESP32 installs with a "V4" build. Also updating by OTA will not work properly.
-;; You need to completely erase your device (esptool erase_flash) first, then install the "V4" build from VSCode+platformio.
platform = espressif32@ ~6.3.2
-platform_packages = platformio/framework-arduinoespressif32 @ 3.20009.0 ;; select arduino-esp32 v2.0.9 (arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them)
+platform_packages = platformio/framework-arduinoespressif32 @ 3.20009.0
+build_unflags = ${common.build_unflags}
build_flags = -g
- -Wshadow=compatible-local ;; emit warning in case a local variable "shadows" another local one
- -DARDUINO_ARCH_ESP32 -DESP32
- -D CONFIG_ASYNC_TCP_USE_WDT=0
- -DARDUINO_USB_CDC_ON_BOOT=0 ;; this flag is mandatory for "classic ESP32" when building with arduino-esp32 >=2.0.3
-lib_deps =
- https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
- ${env.lib_deps}
+ -Wshadow=compatible-local
+ -DARDUINO_ARCH_ESP32 -DESP32
+ -D CONFIG_ASYNC_TCP_USE_WDT=0
+ -D CONFIG_ASYNC_TCP_STACK_SIZE=8192
+ -DARDUINO_USB_CDC_ON_BOOT=0
+ -D WLED_ENABLE_DMX_INPUT
+lib_deps =
+ esp32async/AsyncTCP @ 3.4.7
+ https://github.com/someweisguy/esp_dmx.git#47db25d
+ ${env.lib_deps}
+board_build.partitions = ${esp32.default_partitions}
[esp32s2]
-;; generic definitions for all ESP32-S2 boards
platform = espressif32@ ~6.3.2
-platform_packages = platformio/framework-arduinoespressif32 @ 3.20009.0 ;; select arduino-esp32 v2.0.9 (arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them)
+platform_packages = platformio/framework-arduinoespressif32 @ 3.20009.0
+build_unflags = ${common.build_unflags}
build_flags = -g
- -DARDUINO_ARCH_ESP32
- -DARDUINO_ARCH_ESP32S2
- -DCONFIG_IDF_TARGET_ESP32S2=1
- -D CONFIG_ASYNC_TCP_USE_WDT=0
- -DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_USB_DFU_ON_BOOT=0
- -DCO
- -DARDUINO_USB_MODE=0 ;; this flag is mandatory for ESP32-S2 !
- ;; please make sure that the following flags are properly set (to 0 or 1) by your board.json, or included in your custom platformio_override.ini entry:
- ;; ARDUINO_USB_CDC_ON_BOOT
-lib_deps =
- https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
- ${env.lib_deps}
+ -DARDUINO_ARCH_ESP32
+ -DARDUINO_ARCH_ESP32S2
+ -DCONFIG_IDF_TARGET_ESP32S2=1
+ -D CONFIG_ASYNC_TCP_USE_WDT=0
+ -D CONFIG_ASYNC_TCP_STACK_SIZE=8192
+ -DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_USB_DFU_ON_BOOT=0
+ -DCO
+ -DARDUINO_USB_MODE=0
+lib_deps =
+ esp32async/AsyncTCP @ 3.4.7
+ ${env.lib_deps}
+board_build.partitions = ${esp32.default_partitions}
[esp32c3]
-;; generic definitions for all ESP32-C3 boards
platform = espressif32@ ~6.3.2
-platform_packages = platformio/framework-arduinoespressif32 @ 3.20009.0 ;; select arduino-esp32 v2.0.9 (arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them)
+platform_packages = platformio/framework-arduinoespressif32 @ 3.20009.0
+build_unflags = ${common.build_unflags}
build_flags = -g
- -DARDUINO_ARCH_ESP32
- -DARDUINO_ARCH_ESP32C3
- -DCONFIG_IDF_TARGET_ESP32C3=1
- -D CONFIG_ASYNC_TCP_USE_WDT=0
- -DCO
- -DARDUINO_USB_MODE=1 ;; this flag is mandatory for ESP32-C3
- ;; please make sure that the following flags are properly set (to 0 or 1) by your board.json, or included in your custom platformio_override.ini entry:
- ;; ARDUINO_USB_CDC_ON_BOOT
-lib_deps =
- https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
- ${env.lib_deps}
+ -DARDUINO_ARCH_ESP32
+ -DARDUINO_ARCH_ESP32C3
+ -DCONFIG_IDF_TARGET_ESP32C3=1
+ -D CONFIG_ASYNC_TCP_USE_WDT=0
+ -D CONFIG_ASYNC_TCP_STACK_SIZE=8192
+ -DCO
+ -DARDUINO_USB_MODE=1
+lib_deps =
+ esp32async/AsyncTCP @ 3.4.7
+ ${env.lib_deps}
+board_build.partitions = ${esp32.default_partitions}
[esp32s3]
-;; generic definitions for all ESP32-S3 boards
platform = espressif32@ ~6.3.2
-platform_packages = platformio/framework-arduinoespressif32 @ 3.20009.0 ;; select arduino-esp32 v2.0.9 (arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them)
+platform_packages = platformio/framework-arduinoespressif32 @ 3.20009.0
+build_unflags = ${common.build_unflags}
build_flags = -g
- -DESP32
- -DARDUINO_ARCH_ESP32
- -DARDUINO_ARCH_ESP32S3
- -DCONFIG_IDF_TARGET_ESP32S3=1
- -D CONFIG_ASYNC_TCP_USE_WDT=0
- -DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_DFU_ON_BOOT=0
- -DCO
- ;; please make sure that the following flags are properly set (to 0 or 1) by your board.json, or included in your custom platformio_override.ini entry:
- ;; ARDUINO_USB_MODE, ARDUINO_USB_CDC_ON_BOOT
-lib_deps =
- https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
- ${env.lib_deps}
-
-
-# ------------------------------------------------------------------------------
-# WLED BUILDS
-# ------------------------------------------------------------------------------
+ -DESP32
+ -DARDUINO_ARCH_ESP32
+ -DARDUINO_ARCH_ESP32S3
+ -DCONFIG_IDF_TARGET_ESP32S3=1
+ -D CONFIG_ASYNC_TCP_USE_WDT=0
+ -D CONFIG_ASYNC_TCP_STACK_SIZE=8192
+ -DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_DFU_ON_BOOT=0
+ -DCO
+lib_deps =
+ esp32async/AsyncTCP @ 3.4.7
+ ${env.lib_deps}
+board_build.partitions = ${esp32.large_partitions}
[env:nodemcuv2]
board = nodemcuv2
@@ -345,23 +214,21 @@ platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_4m1m}
build_unflags = ${common.build_unflags}
-build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP8266\" #-DWLED_DISABLE_2D
+build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP8266\"
lib_deps = ${esp8266.lib_deps}
monitor_filters = esp8266_exception_decoder
[env:nodemcuv2_compat]
extends = env:nodemcuv2
-;; using platform version and build options from WLED 0.14.0
platform = ${esp8266.platform_compat}
platform_packages = ${esp8266.platform_packages_compat}
-build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=\"ESP8266_compat\" #-DWLED_DISABLE_2D
-;; lib_deps = ${esp8266.lib_deps_compat} ;; experimental - use older NeoPixelBus 2.7.9
+build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=\"ESP8266_compat\"
[env:nodemcuv2_160]
extends = env:nodemcuv2
board_build.f_cpu = 160000000L
-build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP8266_160\" #-DWLED_DISABLE_2D
- -D USERMOD_AUDIOREACTIVE
+build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP8266_160\"
+ -D USERMOD_AUDIOREACTIVE
[env:esp8266_2m]
board = esp_wroom_02
@@ -374,16 +241,15 @@ lib_deps = ${esp8266.lib_deps}
[env:esp8266_2m_compat]
extends = env:esp8266_2m
-;; using platform version and build options from WLED 0.14.0
platform = ${esp8266.platform_compat}
platform_packages = ${esp8266.platform_packages_compat}
-build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=\"ESP02_compat\" #-DWLED_DISABLE_2D
+build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=\"ESP02_compat\"
[env:esp8266_2m_160]
extends = env:esp8266_2m
board_build.f_cpu = 160000000L
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP02_160\"
- -D USERMOD_AUDIOREACTIVE
+ -D USERMOD_AUDIOREACTIVE
[env:esp01_1m_full]
board = esp01_1m
@@ -392,32 +258,43 @@ platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_1m128k}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP01\" -D WLED_DISABLE_OTA
- ; -D WLED_USE_REAL_MATH ;; may fix wrong sunset/sunrise times, at the cost of 7064 bytes FLASH and 975 bytes RAM
lib_deps = ${esp8266.lib_deps}
[env:esp01_1m_full_compat]
extends = env:esp01_1m_full
-;; using platform version and build options from WLED 0.14.0
platform = ${esp8266.platform_compat}
platform_packages = ${esp8266.platform_packages_compat}
-build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=\"ESP01_compat\" -D WLED_DISABLE_OTA #-DWLED_DISABLE_2D
+build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=\"ESP01_compat\" -D WLED_DISABLE_OTA
[env:esp01_1m_full_160]
extends = env:esp01_1m_full
board_build.f_cpu = 160000000L
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP01_160\" -D WLED_DISABLE_OTA
- -D USERMOD_AUDIOREACTIVE
- ; -D WLED_USE_REAL_MATH ;; may fix wrong sunset/sunrise times, at the cost of 7064 bytes FLASH and 975 bytes RAM
+ -D USERMOD_AUDIOREACTIVE
[env:esp32dev]
board = esp32dev
platform = ${esp32.platform}
platform_packages = ${esp32.platform_packages}
build_unflags = ${common.build_unflags}
-build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"ESP32\" #-D WLED_DISABLE_BROWNOUT_DET
- ${esp32.AR_build_flags}
-lib_deps = ${esp32.lib_deps}
- ${esp32.AR_lib_deps}
+build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"ESP32\"
+ ${esp32.AR_build_flags}
+lib_deps =
+ ${esp32.lib_deps}
+ ${esp32.AR_lib_deps}
+monitor_filters = esp32_exception_decoder
+board_build.partitions = ${esp32.default_partitions}
+
+[env:esp32dev_V4]
+board = esp32dev
+platform = ${esp32_idf_V4.platform}
+platform_packages = ${esp32_idf_V4.platform_packages}
+build_unflags = ${common.build_unflags}
+build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_V4\"
+ ${esp32.AR_build_flags}
+lib_deps =
+ ${esp32_idf_V4.lib_deps}
+ ${esp32.AR_lib_deps}
monitor_filters = esp32_exception_decoder
board_build.partitions = ${esp32.default_partitions}
@@ -426,26 +303,26 @@ board = esp32dev
platform = ${esp32_idf_V4.platform}
platform_packages = ${esp32_idf_V4.platform_packages}
build_unflags = ${common.build_unflags}
-build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_8M\" #-D WLED_DISABLE_BROWNOUT_DET
- ${esp32.AR_build_flags}
-lib_deps = ${esp32_idf_V4.lib_deps}
- ${esp32.AR_lib_deps}
+build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_8M\"
+ ${esp32.AR_build_flags}
+lib_deps =
+ ${esp32_idf_V4.lib_deps}
+ ${esp32.AR_lib_deps}
monitor_filters = esp32_exception_decoder
board_build.partitions = ${esp32.large_partitions}
board_upload.flash_size = 8MB
board_upload.maximum_size = 8388608
-; board_build.f_flash = 80000000L
-; board_build.flash_mode = qio
[env:esp32dev_16M]
board = esp32dev
platform = ${esp32_idf_V4.platform}
platform_packages = ${esp32_idf_V4.platform_packages}
build_unflags = ${common.build_unflags}
-build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_16M\" #-D WLED_DISABLE_BROWNOUT_DET
- ${esp32.AR_build_flags}
-lib_deps = ${esp32_idf_V4.lib_deps}
- ${esp32.AR_lib_deps}
+build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_16M\"
+ ${esp32.AR_build_flags}
+lib_deps =
+ ${esp32_idf_V4.lib_deps}
+ ${esp32.AR_lib_deps}
monitor_filters = esp32_exception_decoder
board_build.partitions = ${esp32.extreme_partitions}
board_upload.flash_size = 16MB
@@ -453,20 +330,6 @@ board_upload.maximum_size = 16777216
board_build.f_flash = 80000000L
board_build.flash_mode = dio
-;[env:esp32dev_audioreactive]
-;board = esp32dev
-;platform = ${esp32.platform}
-;platform_packages = ${esp32.platform_packages}
-;build_unflags = ${common.build_unflags}
-;build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"ESP32_audioreactive\" #-D WLED_DISABLE_BROWNOUT_DET
-; ${esp32.AR_build_flags}
-;lib_deps = ${esp32.lib_deps}
-; ${esp32.AR_lib_deps}
-;monitor_filters = esp32_exception_decoder
-;board_build.partitions = ${esp32.default_partitions}
-;; board_build.f_flash = 80000000L
-;; board_build.flash_mode = dio
-
[env:esp32_eth]
board = esp32-poe
platform = ${esp32.platform}
@@ -474,10 +337,10 @@ platform_packages = ${esp32.platform_packages}
upload_speed = 921600
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"ESP32_Ethernet\" -D RLYPIN=-1 -D WLED_USE_ETHERNET -D BTNPIN=-1
-; -D WLED_DISABLE_ESPNOW ;; ESP-NOW requires wifi, may crash with ethernet only
- ${esp32.AR_build_flags}
-lib_deps = ${esp32.lib_deps}
- ${esp32.AR_lib_deps}
+ ${esp32.AR_build_flags}
+lib_deps =
+ ${esp32.lib_deps}
+ ${esp32.AR_lib_deps}
board_build.partitions = ${esp32.default_partitions}
[env:esp32_wrover]
@@ -490,11 +353,12 @@ board_build.flash_mode = qio
board_build.partitions = ${esp32.extended_partitions}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_WROVER\"
- -DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue ;; Older ESP32 (rev.<3) need a PSRAM fix (increases static RAM used) https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/external-ram.html
- -D DATA_PINS=25
- ${esp32.AR_build_flags}
-lib_deps = ${esp32_idf_V4.lib_deps}
- ${esp32.AR_lib_deps}
+ -DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue
+ -D DATA_PINS=25
+ ${esp32.AR_build_flags}
+lib_deps =
+ ${esp32_idf_V4.lib_deps}
+ ${esp32.AR_lib_deps}
[env:esp32c3dev]
extends = esp32c3
@@ -504,30 +368,28 @@ framework = arduino
board = esp32-c3-devkitm-1
board_build.partitions = ${esp32.default_partitions}
build_flags = ${common.build_flags} ${esp32c3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-C3\"
- -D WLED_WATCHDOG_TIMEOUT=0
- -DLOLIN_WIFI_FIX ; seems to work much better with this
- -DARDUINO_USB_CDC_ON_BOOT=1 ;; for virtual CDC USB
- ;-DARDUINO_USB_CDC_ON_BOOT=0 ;; for serial-to-USB chip
+ -D WLED_WATCHDOG_TIMEOUT=0
+ -DLOLIN_WIFI_FIX
+ -DARDUINO_USB_CDC_ON_BOOT=1
upload_speed = 460800
build_unflags = ${common.build_unflags}
lib_deps = ${esp32c3.lib_deps}
[env:esp32s3dev_16MB_opi]
-;; ESP32-S3 development board, with 16MB FLASH and >= 8MB PSRAM (memory_type: qio_opi)
-board = esp32-s3-devkitc-1 ;; generic dev board; the next line adds PSRAM support
-board_build.arduino.memory_type = qio_opi ;; use with PSRAM: 8MB or 16MB
+board = esp32-s3-devkitc-1
+board_build.arduino.memory_type = qio_opi
platform = ${esp32s3.platform}
platform_packages = ${esp32s3.platform_packages}
upload_speed = 921600
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_16MB_opi\"
- -D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0
- ;-D ARDUINO_USB_CDC_ON_BOOT=0 ;; -D ARDUINO_USB_MODE=1 ;; for boards with serial-to-USB chip
- -D ARDUINO_USB_CDC_ON_BOOT=1 -D ARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB")
- -DBOARD_HAS_PSRAM
- ${esp32.AR_build_flags}
-lib_deps = ${esp32s3.lib_deps}
- ${esp32.AR_lib_deps}
+ -D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0
+ -D ARDUINO_USB_CDC_ON_BOOT=1 -D ARDUINO_USB_MODE=1
+ -DBOARD_HAS_PSRAM
+ ${esp32.AR_build_flags}
+lib_deps =
+ ${esp32s3.lib_deps}
+ ${esp32.AR_lib_deps}
board_build.partitions = ${esp32.extreme_partitions}
board_upload.flash_size = 16MB
board_upload.maximum_size = 16777216
@@ -536,68 +398,64 @@ board_build.flash_mode = qio
monitor_filters = esp32_exception_decoder
[env:esp32s3dev_8MB_opi]
-;; ESP32-S3 development board, with 8MB FLASH and >= 8MB PSRAM (memory_type: qio_opi)
-board = esp32-s3-devkitc-1 ;; generic dev board; the next line adds PSRAM support
-board_build.arduino.memory_type = qio_opi ;; use with PSRAM: 8MB or 16MB
+board = esp32-s3-devkitc-1
+board_build.arduino.memory_type = qio_opi
platform = ${esp32s3.platform}
platform_packages = ${esp32s3.platform_packages}
upload_speed = 921600
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_8MB_opi\"
- -D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0
- ;-D ARDUINO_USB_CDC_ON_BOOT=0 ;; -D ARDUINO_USB_MODE=1 ;; for boards with serial-to-USB chip
- -D ARDUINO_USB_CDC_ON_BOOT=1 -D ARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB")
- -DBOARD_HAS_PSRAM
- ${esp32.AR_build_flags}
-lib_deps = ${esp32s3.lib_deps}
- ${esp32.AR_lib_deps}
+ -D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0
+ -D ARDUINO_USB_CDC_ON_BOOT=1 -D ARDUINO_USB_MODE=1
+ -DBOARD_HAS_PSRAM
+ ${esp32.AR_build_flags}
+lib_deps =
+ ${esp32s3.lib_deps}
+ ${esp32.AR_lib_deps}
board_build.partitions = ${esp32.large_partitions}
board_build.f_flash = 80000000L
board_build.flash_mode = qio
monitor_filters = esp32_exception_decoder
[env:esp32S3_wroom2]
-;; For ESP32-S3 WROOM-2, a.k.a. ESP32-S3 DevKitC-1 v1.1
-;; with >= 16MB FLASH and >= 8MB PSRAM (memory_type: opi_opi)
platform = ${esp32s3.platform}
platform_packages = ${esp32s3.platform_packages}
-board = esp32s3camlcd ;; this is the only standard board with "opi_opi"
+board = esp32s3camlcd
board_build.arduino.memory_type = opi_opi
upload_speed = 921600
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_WROOM-2\"
- -D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0
- -D ARDUINO_USB_CDC_ON_BOOT=0 ;; -D ARDUINO_USB_MODE=1 ;; for boards with serial-to-USB chip
- ;; -D ARDUINO_USB_CDC_ON_BOOT=1 -D ARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB")
- -DBOARD_HAS_PSRAM
- -D LEDPIN=38 -D DATA_PINS=38 ;; buildin WS2812b LED
- -D BTNPIN=0 -D RLYPIN=16 -D IRPIN=17 -D AUDIOPIN=-1
- -D WLED_DEBUG
- ${esp32.AR_build_flags}
- -D SR_DMTYPE=1 -D I2S_SDPIN=13 -D I2S_CKPIN=14 -D I2S_WSPIN=15 -D MCLK_PIN=4 ;; I2S mic
-lib_deps = ${esp32s3.lib_deps}
- ${esp32.AR_lib_deps}
-
+ -D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0
+ -D ARDUINO_USB_CDC_ON_BOOT=0
+ -DBOARD_HAS_PSRAM
+ -D LEDPIN=38 -D DATA_PINS=38
+ -D BTNPIN=0 -D RLYPIN=16 -D IRPIN=17 -D AUDIOPIN=-1
+ -D WLED_DEBUG
+ ${esp32.AR_build_flags}
+ -D SR_DMTYPE=1 -D I2S_SDPIN=13 -D I2S_CKPIN=14 -D I2S_WSPIN=15 -D MCLK_PIN=4
+lib_deps =
+ ${esp32s3.lib_deps}
+ ${esp32.AR_lib_deps}
board_build.partitions = ${esp32.extreme_partitions}
board_upload.flash_size = 16MB
board_upload.maximum_size = 16777216
monitor_filters = esp32_exception_decoder
[env:esp32s3_4M_qspi]
-;; ESP32-S3, with 4MB FLASH and <= 4MB PSRAM (memory_type: qio_qspi)
-board = lolin_s3_mini ;; -S3 mini, 4MB flash 2MB PSRAM
+board = lolin_s3_mini
platform = ${esp32s3.platform}
platform_packages = ${esp32s3.platform_packages}
upload_speed = 921600
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_4M_qspi\"
- -DARDUINO_USB_CDC_ON_BOOT=1 -DARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB")
- -DBOARD_HAS_PSRAM
- -DLOLIN_WIFI_FIX ; seems to work much better with this
- -D WLED_WATCHDOG_TIMEOUT=0
- ${esp32.AR_build_flags}
-lib_deps = ${esp32s3.lib_deps}
- ${esp32.AR_lib_deps}
+ -DARDUINO_USB_CDC_ON_BOOT=1 -DARDUINO_USB_MODE=1
+ -DBOARD_HAS_PSRAM
+ -DLOLIN_WIFI_FIX
+ -D WLED_WATCHDOG_TIMEOUT=0
+ ${esp32.AR_build_flags}
+lib_deps =
+ ${esp32s3.lib_deps}
+ ${esp32.AR_lib_deps}
board_build.partitions = ${esp32.default_partitions}
board_build.f_flash = 80000000L
board_build.flash_mode = qio
@@ -612,20 +470,21 @@ board_build.flash_mode = qio
board_build.f_flash = 80000000L
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp32s2.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S2\"
- -DARDUINO_USB_CDC_ON_BOOT=1
- -DARDUINO_USB_MSC_ON_BOOT=0
- -DARDUINO_USB_DFU_ON_BOOT=0
- -DBOARD_HAS_PSRAM
- -DLOLIN_WIFI_FIX ; seems to work much better with this
- -D WLED_WATCHDOG_TIMEOUT=0
- -D CONFIG_ASYNC_TCP_USE_WDT=0
- -D DATA_PINS=16
- -D HW_PIN_SCL=35
- -D HW_PIN_SDA=33
- -D HW_PIN_CLOCKSPI=7
- -D HW_PIN_DATASPI=11
- -D HW_PIN_MISOSPI=9
-; -D STATUSLED=15
- ${esp32.AR_build_flags}
-lib_deps = ${esp32s2.lib_deps}
- ${esp32.AR_lib_deps}
+ -DARDUINO_USB_CDC_ON_BOOT=1
+ -DARDUINO_USB_MSC_ON_BOOT=0
+ -DARDUINO_USB_DFU_ON_BOOT=0
+ -DBOARD_HAS_PSRAM
+ -DLOLIN_WIFI_FIX
+ -D WLED_WATCHDOG_TIMEOUT=0
+ -D CONFIG_ASYNC_TCP_USE_WDT=0
+ -D CONFIG_ASYNC_TCP_STACK_SIZE=8192
+ -D DATA_PINS=16
+ -D HW_PIN_SCL=35
+ -D HW_PIN_SDA=33
+ -D HW_PIN_CLOCKSPI=7
+ -D HW_PIN_DATASPI=11
+ -D HW_PIN_MISOSPI=9
+ ${esp32.AR_build_flags}
+lib_deps =
+ ${esp32s2.lib_deps}
+ ${esp32.AR_lib_deps}
diff --git a/platformio_override.sample.ini b/platformio_override.sample.ini
index dd3630d82c..7bfeae5e41 100644
--- a/platformio_override.sample.ini
+++ b/platformio_override.sample.ini
@@ -1,519 +1,6 @@
-# Example PlatformIO Project Configuration Override
-# ------------------------------------------------------------------------------
-# Copy to platformio_override.ini to activate overrides
-# ------------------------------------------------------------------------------
-# Please visit documentation: https://docs.platformio.org/page/projectconf.html
-
-[platformio]
-default_envs = WLED_tasmota_1M # define as many as you need
-
-#----------
-# SAMPLE
-#----------
-[env:WLED_generic8266_1M]
-extends = env:esp01_1m_full # when you want to extend the existing environment (define only updated options)
-; board = esp01_1m # uncomment when ou need different board
-; platform = ${common.platform_wled_default} # uncomment and change when you want particular platform
-; platform_packages = ${common.platform_packages}
-; board_build.ldscript = ${common.ldscript_1m128k}
-; upload_speed = 921600 # fast upload speed (remove ';' if your board supports fast upload speed)
-# Sample libraries used for various usermods. Uncomment when using particular usermod.
-lib_deps = ${esp8266.lib_deps}
-; olikraus/U8g2 # @~2.33.15
-; paulstoffregen/OneWire@~2.3.8
-; adafruit/Adafruit Unified Sensor@^1.1.4
-; adafruit/DHT sensor library@^1.4.1
-; adafruit/Adafruit BME280 Library@^2.2.2
-; Wire
-; robtillaart/SHT85@~0.3.3
-; ;gmag11/QuickESPNow @ ~0.7.0 # will also load QuickDebug
-; https://github.com/blazoncek/QuickESPNow.git#optional-debug ;; exludes debug library
-; ${esp32.AR_lib_deps} ;; used for USERMOD_AUDIOREACTIVE
-; bitbank2/PNGdec@^1.0.1 ;; used for POV display uncomment following
-
-build_unflags = ${common.build_unflags}
-build_flags = ${common.build_flags} ${esp8266.build_flags}
-;
-; *** To use the below defines/overrides, copy and paste each onto it's own line just below build_flags in the section above.
-;
-; Set a release name that may be used to distinguish required binary for flashing
-; -D WLED_RELEASE_NAME=\"ESP32_MULTI_USREMODS\"
-;
-; disable specific features
-; -D WLED_DISABLE_OTA
-; -D WLED_DISABLE_ALEXA
-; -D WLED_DISABLE_HUESYNC
-; -D WLED_DISABLE_LOXONE
-; -D WLED_DISABLE_INFRARED
-; -D WLED_DISABLE_WEBSOCKETS
-; -D WLED_DISABLE_MQTT
-; -D WLED_DISABLE_ADALIGHT
-; -D WLED_DISABLE_2D
-; -D WLED_DISABLE_PXMAGIC
-; -D WLED_DISABLE_ESPNOW
-; -D WLED_DISABLE_BROWNOUT_DET
-;
-; enable optional built-in features
-; -D WLED_ENABLE_PIXART
-; -D WLED_ENABLE_USERMOD_PAGE # if created
-; -D WLED_ENABLE_DMX
-;
-; PIN defines - uncomment and change, if needed:
-; -D DATA_PINS=2
-; or use this for multiple outputs
-; -D DATA_PINS=1,3
-; -D BTNPIN=0
-; -D IRPIN=4
-; -D RLYPIN=12
-; -D RLYMDE=1
-; -D RLYODRAIN=0
-; -D LED_BUILTIN=2 # GPIO of built-in LED
-;
-; Limit max buses
-; -D WLED_MAX_BUSSES=2
-; -D WLED_MAX_ANALOG_CHANNELS=3 # only 3 PWM HW pins available
-; -D WLED_MAX_DIGITAL_CHANNELS=2 # only 2 HW accelerated pins available
-;
-; Configure default WiFi
-; -D CLIENT_SSID='"MyNetwork"'
-; -D CLIENT_PASS='"Netw0rkPassw0rd"'
-;
-; Configure and use Ethernet
-; -D WLED_USE_ETHERNET
-; -D WLED_ETH_DEFAULT=5
-; do not use pins 5, (16,) 17, 18, 19, 21, 22, 23, 25, 26, 27 for anything but ethernet
-; -D PHY_ADDR=0 -D ETH_PHY_POWER=5 -D ETH_PHY_MDC=23 -D ETH_PHY_MDIO=18
-; -D ETH_CLK_MODE=ETH_CLOCK_GPIO17_OUT
-;
-; NTP time configuration
-; -D WLED_NTP_ENABLED=true
-; -D WLED_TIMEZONE=2
-; -D WLED_LAT=48.86
-; -D WLED_LON=2.33
-;
-; Use Watchdog timer with 10s guard
-; -D WLED_WATCHDOG_TIMEOUT=10
-;
-; Create debug build (with remote debug)
-; -D WLED_DEBUG
-; -D WLED_DEBUG_HOST='"192.168.0.100"'
-; -D WLED_DEBUG_PORT=7868
-;
-; Use Autosave usermod and set it to do save after 90s
-; -D USERMOD_AUTO_SAVE
-; -D AUTOSAVE_AFTER_SEC=90
-;
-; Use AHT10/AHT15/AHT20 usermod
-; -D USERMOD_AHT10
-;
-; Use INA226 usermod
-; -D USERMOD_INA226
-;
-; Use 4 Line Display usermod with SPI display
-; -D USERMOD_FOUR_LINE_DISPLAY
-; -DFLD_SPI_DEFAULT
-; -D FLD_TYPE=SSD1306_SPI64
-; -D FLD_PIN_CLOCKSPI=14
-; -D FLD_PIN_DATASPI=13
-; -D FLD_PIN_DC=26
-; -D FLD_PIN_CS=15
-; -D FLD_PIN_RESET=27
-;
-; Use Rotary encoder usermod (in conjunction with 4LD)
-; -D USERMOD_ROTARY_ENCODER_UI
-; -D ENCODER_DT_PIN=5
-; -D ENCODER_CLK_PIN=18
-; -D ENCODER_SW_PIN=19
-;
-; Use Dallas DS18B20 temperature sensor usermod and configure it to use GPIO13
-; -D USERMOD_DALLASTEMPERATURE
-; -D TEMPERATURE_PIN=13
-;
-; Use Multi Relay usermod and configure it to use 6 relays and appropriate GPIO
-; -D USERMOD_MULTI_RELAY
-; -D MULTI_RELAY_MAX_RELAYS=6
-; -D MULTI_RELAY_PINS=12,23,22,21,24,25
-;
-; Use PIR sensor usermod and configure it to use GPIO4 and timer of 60s
-; -D USERMOD_PIRSWITCH
-; -D PIR_SENSOR_PIN=4 # use -1 to disable usermod
-; -D PIR_SENSOR_OFF_SEC=60
-; -D PIR_SENSOR_MAX_SENSORS=2 # max allowable sensors (uses OR logic for triggering)
-;
-; Use Audioreactive usermod and configure I2S microphone
-; -D USERMOD_AUDIOREACTIVE
-; -D AUDIOPIN=-1
-; -D DMTYPE=1 # 0-analog/disabled, 1-I2S generic, 2-ES7243, 3-SPH0645, 4-I2S+mclk, 5-I2S PDM
-; -D I2S_SDPIN=36
-; -D I2S_WSPIN=23
-; -D I2S_CKPIN=19
-;
-; Use PWM fan usermod
-; -D USERMOD_PWM_FAN
-; -D TACHO_PIN=33
-; -D PWM_PIN=32
-;
-; Use POV Display usermod
-; -D USERMOD_POV_DISPLAY
-; Use built-in or custom LED as a status indicator (assumes LED is connected to GPIO16)
-; -D STATUSLED=16
-;
-; set the name of the module - make sure there is a quote-backslash-quote before the name and a backslash-quote-quote after the name
-; -D SERVERNAME="\"WLED\""
-;
-; set the number of LEDs
-; -D DEFAULT_LED_COUNT=30
-; or this for multiple outputs
-; -D PIXEL_COUNTS=30,30
-;
-; set the default LED type
-; -D DEFAULT_LED_TYPE=22 # see const.h (TYPE_xxxx)
-;
-; set milliampere limit when using ESP power pin (or inadequate PSU) to power LEDs
-; -D ABL_MILLIAMPS_DEFAULT=850
-; -D LED_MILLIAMPS_DEFAULT=55
-;
-; enable IR by setting remote type
-; -D IRTYPE=0 # 0 Remote disabled | 1 24-key RGB | 2 24-key with CT | 3 40-key blue | 4 40-key RGB | 5 21-key RGB | 6 6-key black | 7 9-key red | 8 JSON remote
-;
-; set default color order of your led strip
-; -D DEFAULT_LED_COLOR_ORDER=COL_ORDER_GRB
-;
-; use PSRAM on classic ESP32 rev.1 (rev.3 or above has no issues)
-; -DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue # needed only for classic ESP32 rev.1
-;
-; configure I2C and SPI interface (for various hardware)
-; -D I2CSDAPIN=33 # initialise interface
-; -D I2CSCLPIN=35 # initialise interface
-; -D HW_PIN_SCL=35
-; -D HW_PIN_SDA=33
-; -D HW_PIN_CLOCKSPI=7
-; -D HW_PIN_DATASPI=11
-; -D HW_PIN_MISOSPI=9
-
-
-
-# ------------------------------------------------------------------------------
-# PRE-CONFIGURED DEVELOPMENT BOARDS AND CONTROLLERS
-# ------------------------------------------------------------------------------
-
-[env:esp07]
-board = esp07
-platform = ${common.platform_wled_default}
-platform_packages = ${common.platform_packages}
-board_build.ldscript = ${common.ldscript_4m1m}
-build_unflags = ${common.build_unflags}
-build_flags = ${common.build_flags} ${esp8266.build_flags}
-lib_deps = ${esp8266.lib_deps}
-
-[env:d1_mini]
-board = d1_mini
-platform = ${common.platform_wled_default}
-platform_packages = ${common.platform_packages}
-upload_speed = 921600
-board_build.ldscript = ${common.ldscript_4m1m}
-build_unflags = ${common.build_unflags}
-build_flags = ${common.build_flags} ${esp8266.build_flags}
-lib_deps = ${esp8266.lib_deps}
-monitor_filters = esp8266_exception_decoder
-
-[env:heltec_wifi_kit_8]
-board = d1_mini
-platform = ${common.platform_wled_default}
-platform_packages = ${common.platform_packages}
-board_build.ldscript = ${common.ldscript_4m1m}
-build_unflags = ${common.build_unflags}
-build_flags = ${common.build_flags} ${esp8266.build_flags}
-lib_deps = ${esp8266.lib_deps}
-
-[env:h803wf]
-board = d1_mini
-platform = ${common.platform_wled_default}
-platform_packages = ${common.platform_packages}
-board_build.ldscript = ${common.ldscript_4m1m}
-build_unflags = ${common.build_unflags}
-build_flags = ${common.build_flags} ${esp8266.build_flags} -D DATA_PINS=1 -D WLED_DISABLE_INFRARED
-lib_deps = ${esp8266.lib_deps}
-
-[env:esp32dev_qio80]
-board = esp32dev
-platform = ${esp32.platform}
-platform_packages = ${esp32.platform_packages}
-build_unflags = ${common.build_unflags}
-build_flags = ${common.build_flags} ${esp32.build_flags} #-D WLED_DISABLE_BROWNOUT_DET
-lib_deps = ${esp32.lib_deps}
-monitor_filters = esp32_exception_decoder
-board_build.partitions = ${esp32.default_partitions}
-board_build.f_flash = 80000000L
-board_build.flash_mode = qio
-
-[env:esp32dev_V4_dio80]
-;; experimental ESP32 env using ESP-IDF V4.4.x
-;; Warning: this build environment is not stable!!
-;; please erase your device before installing.
-board = esp32dev
-platform = ${esp32_idf_V4.platform}
-platform_packages = ${esp32_idf_V4.platform_packages}
-build_unflags = ${common.build_unflags}
-build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} #-D WLED_DISABLE_BROWNOUT_DET
-lib_deps = ${esp32_idf_V4.lib_deps}
-monitor_filters = esp32_exception_decoder
-board_build.partitions = ${esp32_idf_V4.default_partitions}
-board_build.f_flash = 80000000L
-board_build.flash_mode = dio
-
-[env:esp32s2_saola]
-board = esp32-s2-saola-1
-platform = ${esp32s2.platform}
-platform_packages = ${esp32s2.platform_packages}
-framework = arduino
-board_build.partitions = tools/WLED_ESP32_4MB_1MB_FS.csv
-board_build.flash_mode = qio
-upload_speed = 460800
-build_unflags = ${common.build_unflags}
-build_flags = ${common.build_flags} ${esp32s2.build_flags}
- ;-DLOLIN_WIFI_FIX ;; try this in case Wifi does not work
- -DARDUINO_USB_CDC_ON_BOOT=1
-lib_deps = ${esp32s2.lib_deps}
-
-[env:esp32s3dev_8MB_PSRAM_qspi]
-;; ESP32-TinyS3 development board, with 8MB FLASH and PSRAM (memory_type: qio_qspi)
-extends = env:esp32s3dev_8MB_PSRAM_opi
-;board = um_tinys3 ; -> needs workaround from https://github.com/Aircoookie/WLED/pull/2905#issuecomment-1328049860
-board = esp32-s3-devkitc-1 ;; generic dev board; the next line adds PSRAM support
-board_build.arduino.memory_type = qio_qspi ;; use with PSRAM: 2MB or 4MB
-
-[env:esp8285_4CH_MagicHome]
-board = esp8285
-platform = ${common.platform_wled_default}
-platform_packages = ${common.platform_packages}
-board_build.ldscript = ${common.ldscript_1m128k}
-build_unflags = ${common.build_unflags}
-build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_DISABLE_OTA
-lib_deps = ${esp8266.lib_deps}
-
-[env:esp8285_H801]
-board = esp8285
-platform = ${common.platform_wled_default}
-platform_packages = ${common.platform_packages}
-board_build.ldscript = ${common.ldscript_1m128k}
-build_unflags = ${common.build_unflags}
-build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_DISABLE_OTA
-lib_deps = ${esp8266.lib_deps}
-
-[env:d1_mini_5CH_Shojo_PCB]
-board = d1_mini
-platform = ${common.platform_wled_default}
-platform_packages = ${common.platform_packages}
-board_build.ldscript = ${common.ldscript_4m1m}
-build_unflags = ${common.build_unflags}
-build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_USE_SHOJO_PCB
-lib_deps = ${esp8266.lib_deps}
-
-[env:d1_mini_debug]
-board = d1_mini
-build_type = debug
-platform = ${common.platform_wled_default}
-platform_packages = ${common.platform_packages}
-board_build.ldscript = ${common.ldscript_4m1m}
-build_unflags = ${common.build_unflags}
-build_flags = ${common.build_flags} ${esp8266.build_flags} ${common.debug_flags}
-lib_deps = ${esp8266.lib_deps}
-
-[env:d1_mini_ota]
-board = d1_mini
-upload_protocol = espota
-# exchange for your WLED IP
-upload_port = "10.10.1.27"
-platform = ${common.platform_wled_default}
-platform_packages = ${common.platform_packages}
-board_build.ldscript = ${common.ldscript_4m1m}
-build_unflags = ${common.build_unflags}
-build_flags = ${common.build_flags} ${esp8266.build_flags}
-lib_deps = ${esp8266.lib_deps}
-
-[env:anavi_miracle_controller]
-board = d1_mini
-platform = ${common.platform_wled_default}
-platform_packages = ${common.platform_packages}
-board_build.ldscript = ${common.ldscript_4m1m}
-build_unflags = ${common.build_unflags}
-build_flags = ${common.build_flags} ${esp8266.build_flags} -D DATA_PINS=12 -D IRPIN=-1 -D RLYPIN=2
-lib_deps = ${esp8266.lib_deps}
-
-[env:esp32c3dev_2MB]
-;; for ESP32-C3 boards with 2MB flash (instead of 4MB).
-;; this board need a specific partition file. OTA not possible.
-extends = esp32c3
-platform = ${esp32c3.platform}
-platform_packages = ${esp32c3.platform_packages}
-board = esp32-c3-devkitm-1
-build_flags = ${common.build_flags} ${esp32c3.build_flags}
- -D WLED_WATCHDOG_TIMEOUT=0
- -D WLED_DISABLE_OTA
- ; -DARDUINO_USB_CDC_ON_BOOT=1 ;; for virtual CDC USB
- -DARDUINO_USB_CDC_ON_BOOT=0 ;; for serial-to-USB chip
-build_unflags = ${common.build_unflags}
-upload_speed = 115200
-lib_deps = ${esp32c3.lib_deps}
-board_build.partitions = tools/WLED_ESP32_2MB_noOTA.csv
-board_build.flash_mode = dio
-board_upload.flash_size = 2MB
-board_upload.maximum_size = 2097152
-
-[env:wemos_shield_esp32]
-board = esp32dev
-platform = ${esp32.platform}
-platform_packages = ${esp32.platform_packages}
-upload_speed = 460800
-build_unflags = ${common.build_unflags}
-build_flags = ${common.build_flags} ${esp32.build_flags}
- -D DATA_PINS=16
- -D RLYPIN=19
- -D BTNPIN=17
- -D IRPIN=18
- -D UWLED_USE_MY_CONFIG
- -D USERMOD_DALLASTEMPERATURE
- -D USERMOD_FOUR_LINE_DISPLAY
- -D TEMPERATURE_PIN=23
- -D USERMOD_AUDIOREACTIVE
-lib_deps = ${esp32.lib_deps}
- OneWire@~2.3.5
- olikraus/U8g2 @ ^2.28.8
- https://github.com/blazoncek/arduinoFFT.git
-board_build.partitions = ${esp32.default_partitions}
-
-[env:m5atom]
-board = esp32dev
-build_unflags = ${common.build_unflags}
-build_flags = ${common.build_flags} ${esp32.build_flags} -D DATA_PINS=27 -D BTNPIN=39
-lib_deps = ${esp32.lib_deps}
-platform = ${esp32.platform}
-platform_packages = ${esp32.platform_packages}
-board_build.partitions = ${esp32.default_partitions}
-
-[env:sp501e]
-board = esp_wroom_02
-platform = ${common.platform_wled_default}
-board_build.ldscript = ${common.ldscript_2m512k}
-build_flags = ${common.build_flags} ${esp8266.build_flags} -D DATA_PINS=3 -D BTNPIN=1
-lib_deps = ${esp8266.lib_deps}
-
-[env:sp511e]
-board = esp_wroom_02
-platform = ${common.platform_wled_default}
-board_build.ldscript = ${common.ldscript_2m512k}
-build_flags = ${common.build_flags} ${esp8266.build_flags} -D DATA_PINS=3 -D BTNPIN=2 -D IRPIN=5 -D WLED_MAX_BUTTONS=3
-lib_deps = ${esp8266.lib_deps}
-
-[env:Athom_RGBCW] ;7w and 5w(GU10) bulbs
-board = esp8285
-platform = ${common.platform_wled_default}
-platform_packages = ${common.platform_packages}
-board_build.ldscript = ${common.ldscript_2m512k}
-build_unflags = ${common.build_unflags}
-build_flags = ${common.build_flags} ${esp8266.build_flags} -D BTNPIN=-1 -D RLYPIN=-1 -D DATA_PINS=4,12,14,13,5
- -D DEFAULT_LED_TYPE=TYPE_ANALOG_5CH -D WLED_DISABLE_INFRARED -D WLED_MAX_CCT_BLEND=0
-lib_deps = ${esp8266.lib_deps}
-
-[env:Athom_15w_RGBCW] ;15w bulb
-board = esp8285
-platform = ${common.platform_wled_default}
-platform_packages = ${common.platform_packages}
-board_build.ldscript = ${common.ldscript_2m512k}
-build_unflags = ${common.build_unflags}
-build_flags = ${common.build_flags} ${esp8266.build_flags} -D BTNPIN=-1 -D RLYPIN=-1 -D DATA_PINS=4,12,14,5,13
- -D DEFAULT_LED_TYPE=TYPE_ANALOG_5CH -D WLED_DISABLE_INFRARED -D WLED_MAX_CCT_BLEND=0 -D WLED_USE_IC_CCT
-lib_deps = ${esp8266.lib_deps}
-
-[env:Athom_3Pin_Controller] ;small controller with only data
-board = esp8285
-platform = ${common.platform_wled_default}
-platform_packages = ${common.platform_packages}
-board_build.ldscript = ${common.ldscript_2m512k}
-build_unflags = ${common.build_unflags}
-build_flags = ${common.build_flags} ${esp8266.build_flags} -D BTNPIN=0 -D RLYPIN=-1 -D DATA_PINS=1 -D WLED_DISABLE_INFRARED
-lib_deps = ${esp8266.lib_deps}
-
-[env:Athom_4Pin_Controller] ; With clock and data interface
-board = esp8285
-platform = ${common.platform_wled_default}
-platform_packages = ${common.platform_packages}
-board_build.ldscript = ${common.ldscript_2m512k}
-build_unflags = ${common.build_unflags}
-build_flags = ${common.build_flags} ${esp8266.build_flags} -D BTNPIN=0 -D RLYPIN=12 -D DATA_PINS=1 -D WLED_DISABLE_INFRARED
-lib_deps = ${esp8266.lib_deps}
-
-[env:Athom_5Pin_Controller] ;Analog light strip controller
-board = esp8285
-platform = ${common.platform_wled_default}
-platform_packages = ${common.platform_packages}
-board_build.ldscript = ${common.ldscript_2m512k}
-build_unflags = ${common.build_unflags}
-build_flags = ${common.build_flags} ${esp8266.build_flags} -D BTNPIN=0 -D RLYPIN=-1 DATA_PINS=4,12,14,13 -D WLED_DISABLE_INFRARED
-lib_deps = ${esp8266.lib_deps}
-
-[env:MY9291]
-board = esp01_1m
-platform = ${common.platform_wled_default}
-platform_packages = ${common.platform_packages}
-board_build.ldscript = ${common.ldscript_1m128k}
-build_unflags = ${common.build_unflags}
-build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_DISABLE_OTA -D USERMOD_MY9291
-lib_deps = ${esp8266.lib_deps}
-
-# ------------------------------------------------------------------------------
-# codm pixel controller board configurations
-# codm-controller-0_6 can also be used for the TYWE3S controller
-# ------------------------------------------------------------------------------
-
-[env:codm-controller-0_6]
-board = esp_wroom_02
-platform = ${common.platform_wled_default}
-platform_packages = ${common.platform_packages}
-board_build.ldscript = ${common.ldscript_2m512k}
-build_unflags = ${common.build_unflags}
-build_flags = ${common.build_flags} ${esp8266.build_flags}
-lib_deps = ${esp8266.lib_deps}
-
-[env:codm-controller-0_6-rev2]
-board = esp_wroom_02
-platform = ${common.platform_wled_default}
-platform_packages = ${common.platform_packages}
-board_build.ldscript = ${common.ldscript_4m1m}
-build_unflags = ${common.build_unflags}
-build_flags = ${common.build_flags} ${esp8266.build_flags}
-lib_deps = ${esp8266.lib_deps}
-
-# ------------------------------------------------------------------------------
-# EleksTube-IPS
-# ------------------------------------------------------------------------------
-[env:elekstube_ips]
-board = esp32dev
-platform = ${esp32.platform}
-platform_packages = ${esp32.platform_packages}
-upload_speed = 921600
-build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_DISABLE_BROWNOUT_DET -D WLED_DISABLE_INFRARED
- -D USERMOD_RTC
- -D USERMOD_ELEKSTUBE_IPS
- -D DATA_PINS=12
- -D RLYPIN=27
- -D BTNPIN=34
- -D DEFAULT_LED_COUNT=6
- # Display config
- -D ST7789_DRIVER
- -D TFT_WIDTH=135
- -D TFT_HEIGHT=240
- -D CGRAM_OFFSET
- -D TFT_SDA_READ
- -D TFT_MOSI=23
- -D TFT_SCLK=18
- -D TFT_DC=25
- -D TFT_RST=26
- -D SPI_FREQUENCY=40000000
- -D USER_SETUP_LOADED
-monitor_filters = esp32_exception_decoder
-lib_deps =
- ${esp32.lib_deps}
- TFT_eSPI @ ^2.3.70
-board_build.partitions = ${esp32.default_partitions}
+[env:esp32dev]
+build_flags =
+ ${env.build_flags}
+ -D DEFAULT_LED_COUNT=1
+ -D DEFAULT_LED_TYPE=TYPE_AN1615
+ -D DEFAULT_LED_PIN=32
diff --git a/tools/AutoCubeMap.xlsx b/tools/AutoCubeMap.xlsx
new file mode 100644
index 0000000000..b3f5cee2ad
Binary files /dev/null and b/tools/AutoCubeMap.xlsx differ
diff --git a/tools/cdata.js b/tools/cdata.js
index c5d3c6aa52..1381cd240f 100644
--- a/tools/cdata.js
+++ b/tools/cdata.js
@@ -370,12 +370,6 @@ const char PAGE_dmxmap[] PROGMEM = R"=====()=====";
name: "PAGE_update",
method: "gzip",
filter: "html-minify",
- mangle: (str) =>
- str
- .replace(
- /function GetV().*\<\/script\>/gms,
- ""
- )
},
{
file: "welcome.htm",
diff --git a/usermods/BME280_v2/usermod_bme280.h b/usermods/BME280_v2/usermod_bme280.h
index 9168f42291..aa6d003f3d 100644
--- a/usermods/BME280_v2/usermod_bme280.h
+++ b/usermods/BME280_v2/usermod_bme280.h
@@ -444,6 +444,7 @@ class UsermodBME280 : public Usermod
configComplete &= getJsonValue(top[F("PublishAlways")], PublishAlways, false);
configComplete &= getJsonValue(top[F("UseCelsius")], UseCelsius, true);
configComplete &= getJsonValue(top[F("HomeAssistantDiscovery")], HomeAssistantDiscovery, false);
+ tempScale = UseCelsius ? "°C" : "°F";
DEBUG_PRINT(FPSTR(_name));
if (!initDone) {
diff --git a/usermods/audioreactive/audio_reactive.h b/usermods/audioreactive/audio_reactive.h
index ad449fc83a..ea8d214455 100644
--- a/usermods/audioreactive/audio_reactive.h
+++ b/usermods/audioreactive/audio_reactive.h
@@ -7,10 +7,6 @@
#include
#include
-#ifdef WLED_ENABLE_DMX
- #error This audio reactive usermod is not compatible with DMX Out.
-#endif
-
#endif
#if defined(ARDUINO_ARCH_ESP32) && (defined(WLED_DEBUG) || defined(SR_DEBUG))
@@ -75,7 +71,7 @@ static uint8_t soundAgc = 0; // Automagic gain control: 0 - n
//static float volumeSmth = 0.0f; // either sampleAvg or sampleAgc depending on soundAgc; smoothed sample
static float FFT_MajorPeak = 1.0f; // FFT: strongest (peak) frequency
static float FFT_Magnitude = 0.0f; // FFT: volume (magnitude) of peak frequency
-static bool samplePeak = false; // Boolean flag for peak - used in effects. Responding routine may reset this flag. Auto-reset after strip.getMinShowDelay()
+static bool samplePeak = false; // Boolean flag for peak - used in effects. Responding routine may reset this flag. Auto-reset after strip.getFrameTime()
static bool udpSamplePeak = false; // Boolean flag for peak. Set at the same time as samplePeak, but reset by transmitAudioData
static unsigned long timeOfPeak = 0; // time of last sample peak detection.
static uint8_t fftResult[NUM_GEQ_CHANNELS]= {0};// Our calculated freq. channel result table to be used by effects
@@ -536,8 +532,8 @@ static void detectSamplePeak(void) {
#endif
static void autoResetPeak(void) {
- uint16_t MinShowDelay = MAX(50, strip.getMinShowDelay()); // Fixes private class variable compiler error. Unsure if this is the correct way of fixing the root problem. -THATDONFC
- if (millis() - timeOfPeak > MinShowDelay) { // Auto-reset of samplePeak after a complete frame has passed.
+ uint16_t peakDelay = max(uint16_t(50), strip.getFrameTime());
+ if (millis() - timeOfPeak > peakDelay) { // Auto-reset of samplePeak after at least one complete frame has passed.
samplePeak = false;
if (audioSyncEnabled == 0) udpSamplePeak = false; // this is normally reset by transmitAudioData
}
@@ -1225,7 +1221,6 @@ class AudioReactive : public Usermod {
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3)
// ADC over I2S is only possible on "classic" ESP32
case 0:
- default:
DEBUGSR_PRINTLN(F("AR: Analog Microphone (left channel only)."));
audioSource = new I2SAdcSource(SAMPLE_RATE, BLOCK_SIZE);
delay(100);
@@ -1233,6 +1228,13 @@ class AudioReactive : public Usermod {
if (audioSource) audioSource->initialize(audioPin);
break;
#endif
+
+ case 255: // 255 = -1 = no audio source
+ // falls through to default
+ default:
+ if (audioSource) delete audioSource; audioSource = nullptr;
+ enabled = false;
+ break;
}
delay(250); // give microphone enough time to initialise
@@ -1319,7 +1321,7 @@ class AudioReactive : public Usermod {
disableSoundProcessing = true;
} else {
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_DEBUG)
- if ((disableSoundProcessing == true) && (audioSyncEnabled == 0) && audioSource->isInitialized()) { // we just switched to "enabled"
+ if ((disableSoundProcessing == true) && (audioSyncEnabled == 0) && audioSource && audioSource->isInitialized()) { // we just switched to "enabled"
DEBUG_PRINTLN(F("[AR userLoop] realtime mode ended - audio processing resumed."));
DEBUG_PRINTF_P(PSTR(" RealtimeMode = %d; RealtimeOverride = %d\n"), int(realtimeMode), int(realtimeOverride));
}
@@ -1331,7 +1333,7 @@ class AudioReactive : public Usermod {
if (audioSyncEnabled & 0x02) disableSoundProcessing = true; // make sure everything is disabled IF in audio Receive mode
if (audioSyncEnabled & 0x01) disableSoundProcessing = false; // keep running audio IF we're in audio Transmit mode
#ifdef ARDUINO_ARCH_ESP32
- if (!audioSource->isInitialized()) disableSoundProcessing = true; // no audio source
+ if (!audioSource || !audioSource->isInitialized()) disableSoundProcessing = true; // no audio source
// Only run the sampling code IF we're not in Receive mode or realtime mode
diff --git a/usermods/rgb-rotary-encoder/readme.md b/usermods/rgb-rotary-encoder/readme.md
index ba5aad4df7..6531791799 100644
--- a/usermods/rgb-rotary-encoder/readme.md
+++ b/usermods/rgb-rotary-encoder/readme.md
@@ -9,7 +9,7 @@ The actual / original code that controls the LED modes is from Adam Zeloof. I ta
It was quite a bit more work than I hoped, but I got there eventually :)
## Requirements
-* "ESP Rotary" by Lennart Hennigs, v1.5.0 or higher: https://github.com/LennartHennigs/ESPRotary
+* "ESP Rotary" by Lennart Hennigs, v2.1.1 or higher: https://github.com/LennartHennigs/ESPRotary
## Usermod installation
Simply copy the below block (build task) to your `platformio_override.ini` and compile WLED using this new build task. Or use an existing one and add the buildflag `-D RGB_ROTARY_ENCODER`.
@@ -20,7 +20,7 @@ ESP32:
extends = env:esp32dev
build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32 -D RGB_ROTARY_ENCODER
lib_deps = ${esp32.lib_deps}
- lennarthennigs/ESP Rotary@^1.5.0
+ lennarthennigs/ESP Rotary@^2.1.1
```
ESP8266 / D1 Mini:
@@ -29,7 +29,7 @@ ESP8266 / D1 Mini:
extends = env:d1_mini
build_flags = ${common.build_flags_esp8266} -D RGB_ROTARY_ENCODER
lib_deps = ${esp8266.lib_deps}
- lennarthennigs/ESP Rotary@^1.5.0
+ lennarthennigs/ESP Rotary@^2.1.1
```
## How to connect the board to your ESP
diff --git a/usermods/usermod_rotary_brightness_color/usermod_rotary_brightness_color.h b/usermods/usermod_rotary_brightness_color/usermod_rotary_brightness_color.h
index 85a9a16054..c3e1ce17b2 100644
--- a/usermods/usermod_rotary_brightness_color/usermod_rotary_brightness_color.h
+++ b/usermods/usermod_rotary_brightness_color/usermod_rotary_brightness_color.h
@@ -95,9 +95,9 @@ class RotaryEncoderBrightnessColor : public Usermod
}
else
{
- fastled_col.red = col[0];
- fastled_col.green = col[1];
- fastled_col.blue = col[2];
+ fastled_col.red = colPri[0];
+ fastled_col.green = colPri[1];
+ fastled_col.blue = colPri[2];
prim_hsv = rgb2hsv_approximate(fastled_col);
new_val = (int16_t)prim_hsv.h + fadeAmount;
if (new_val > 255)
@@ -106,9 +106,9 @@ class RotaryEncoderBrightnessColor : public Usermod
new_val += 255; // roll-over if smaller than 0
prim_hsv.h = (byte)new_val;
hsv2rgb_rainbow(prim_hsv, fastled_col);
- col[0] = fastled_col.red;
- col[1] = fastled_col.green;
- col[2] = fastled_col.blue;
+ colPri[0] = fastled_col.red;
+ colPri[1] = fastled_col.green;
+ colPri[2] = fastled_col.blue;
}
}
else if (Enc_B == LOW)
@@ -120,9 +120,9 @@ class RotaryEncoderBrightnessColor : public Usermod
}
else
{
- fastled_col.red = col[0];
- fastled_col.green = col[1];
- fastled_col.blue = col[2];
+ fastled_col.red = colPri[0];
+ fastled_col.green = colPri[1];
+ fastled_col.blue = colPri[2];
prim_hsv = rgb2hsv_approximate(fastled_col);
new_val = (int16_t)prim_hsv.h - fadeAmount;
if (new_val > 255)
@@ -131,9 +131,9 @@ class RotaryEncoderBrightnessColor : public Usermod
new_val += 255; // roll-over if smaller than 0
prim_hsv.h = (byte)new_val;
hsv2rgb_rainbow(prim_hsv, fastled_col);
- col[0] = fastled_col.red;
- col[1] = fastled_col.green;
- col[2] = fastled_col.blue;
+ colPri[0] = fastled_col.red;
+ colPri[1] = fastled_col.green;
+ colPri[2] = fastled_col.blue;
}
}
//call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification)
diff --git a/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h b/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h
index 383c1193eb..9533fa21bf 100644
--- a/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h
+++ b/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h
@@ -518,7 +518,7 @@ void RotaryEncoderUIUsermod::setup()
loopTime = millis();
- currentCCT = (approximateKelvinFromRGB(RGBW32(col[0], col[1], col[2], col[3])) - 1900) >> 5;
+ currentCCT = (approximateKelvinFromRGB(RGBW32(colPri[0], colPri[1], colPri[2], colPri[3])) - 1900) >> 5;
if (!initDone) sortModesAndPalettes();
@@ -920,17 +920,17 @@ void RotaryEncoderUIUsermod::changeHue(bool increase){
display->updateRedrawTime();
#endif
currentHue1 = max(min((increase ? currentHue1+fadeAmount : currentHue1-fadeAmount), 255), 0);
- colorHStoRGB(currentHue1*256, currentSat1, col);
+ colorHStoRGB(currentHue1*256, currentSat1, colPri);
stateChanged = true;
if (applyToAll) {
for (unsigned i=0; iupdateRedrawTime();
#endif
currentSat1 = max(min((increase ? currentSat1+fadeAmount : currentSat1-fadeAmount), 255), 0);
- colorHStoRGB(currentHue1*256, currentSat1, col);
+ colorHStoRGB(currentHue1*256, currentSat1, colPri);
if (applyToAll) {
for (unsigned i=0; i> 15;
- unsigned rem = 0;
- rem = (prog * SEGLEN) * 2; //mod 0xFFFF
+ uint16_t rem = (prog * SEGLEN) * 2; //mod 0xFFFF by truncating
rem /= (SEGMENT.intensity +1);
if (rem > 255) rem = 255;
@@ -581,7 +580,7 @@ uint16_t mode_twinkle(void) {
SEGENV.step = it;
}
- unsigned PRNG16 = SEGENV.aux1;
+ uint16_t PRNG16 = SEGENV.aux1;
for (unsigned i = 0; i < SEGENV.aux0; i++)
{
@@ -600,11 +599,12 @@ static const char _data_FX_MODE_TWINKLE[] PROGMEM = "Twinkle@!,!;!,!;!;;m12=0";
* Dissolve function
*/
uint16_t dissolve(uint32_t color) {
- unsigned dataSize = (SEGLEN+7) >> 3; //1 bit per LED
+ unsigned dataSize = sizeof(uint32_t) * SEGLEN;
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
+ uint32_t* pixels = reinterpret_cast(SEGENV.data);
if (SEGENV.call == 0) {
- memset(SEGMENT.data, 0xFF, dataSize); // start by fading pixels up
+ for (unsigned i = 0; i < SEGLEN; i++) pixels[i] = SEGCOLOR(1);
SEGENV.aux0 = 1;
}
@@ -612,33 +612,26 @@ uint16_t dissolve(uint32_t color) {
if (random8() <= SEGMENT.intensity) {
for (size_t times = 0; times < 10; times++) { //attempt to spawn a new pixel 10 times
unsigned i = random16(SEGLEN);
- unsigned index = i >> 3;
- unsigned bitNum = i & 0x07;
- bool fadeUp = bitRead(SEGENV.data[index], bitNum);
if (SEGENV.aux0) { //dissolve to primary/palette
- if (fadeUp) {
- if (color == SEGCOLOR(0)) {
- SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
- } else {
- SEGMENT.setPixelColor(i, color);
- }
- bitWrite(SEGENV.data[index], bitNum, false);
+ if (pixels[i] == SEGCOLOR(1)) {
+ pixels[i] = color == SEGCOLOR(0) ? SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0) : color;
break; //only spawn 1 new pixel per frame per 50 LEDs
}
} else { //dissolve to secondary
- if (!fadeUp) {
- SEGMENT.setPixelColor(i, SEGCOLOR(1)); break;
- bitWrite(SEGENV.data[index], bitNum, true);
+ if (pixels[i] != SEGCOLOR(1)) {
+ pixels[i] = SEGCOLOR(1);
+ break;
}
}
}
}
}
+ // fix for #4401
+ for (unsigned i = 0; i < SEGLEN; i++) SEGMENT.setPixelColor(i, pixels[i]);
if (SEGENV.step > (255 - SEGMENT.speed) + 15U) {
SEGENV.aux0 = !SEGENV.aux0;
SEGENV.step = 0;
- memset(SEGMENT.data, (SEGENV.aux0 ? 0xFF : 0), dataSize); // switch fading
} else {
SEGENV.step++;
}
@@ -1097,7 +1090,7 @@ uint16_t mode_running_random(void) {
unsigned z = it % zoneSize;
bool nzone = (!z && it != SEGENV.aux1);
- for (unsigned i=SEGLEN-1; i > 0; i--) {
+ for (int i=SEGLEN-1; i >= 0; i--) {
if (nzone || z >= zoneSize) {
unsigned lastrand = PRNG16 >> 8;
int16_t diff = 0;
@@ -1441,7 +1434,7 @@ uint16_t mode_fairy() {
if (z == zones-1) flashersInZone = numFlashers-(flashersInZone*(zones-1));
for (unsigned f = firstFlasher; f < firstFlasher + flashersInZone; f++) {
- unsigned stateTime = now16 - flashers[f].stateStart;
+ unsigned stateTime = uint16_t(now16 - flashers[f].stateStart);
//random on/off time reached, switch state
if (stateTime > flashers[f].stateDur * 10) {
flashers[f].stateOn = !flashers[f].stateOn;
@@ -1500,7 +1493,7 @@ uint16_t mode_fairytwinkle() {
unsigned maxDur = riseFallTime/100 + ((255 - SEGMENT.intensity) >> 2) + 13 + ((255 - SEGMENT.intensity) >> 1);
for (int f = 0; f < SEGLEN; f++) {
- unsigned stateTime = now16 - flashers[f].stateStart;
+ uint16_t stateTime = now16 - flashers[f].stateStart;
//random on/off time reached, switch state
if (stateTime > flashers[f].stateDur * 100) {
flashers[f].stateOn = !flashers[f].stateOn;
@@ -1653,8 +1646,8 @@ static const char _data_FX_MODE_TRICOLOR_WIPE[] PROGMEM = "Tri Wipe@!;1,2,3;!";
* Modified by Aircoookie
*/
uint16_t mode_tricolor_fade(void) {
- unsigned counter = strip.now * ((SEGMENT.speed >> 3) +1);
- uint16_t prog = (counter * 768) >> 16;
+ uint16_t counter = strip.now * ((SEGMENT.speed >> 3) +1);
+ uint32_t prog = (counter * 768) >> 16;
uint32_t color1 = 0, color2 = 0;
unsigned stage = 0;
@@ -1745,7 +1738,7 @@ uint16_t mode_random_chase(void) {
uint32_t color = SEGENV.step;
random16_set_seed(SEGENV.aux0);
- for (unsigned i = SEGLEN -1; i > 0; i--) {
+ for (int i = SEGLEN -1; i >= 0; i--) {
uint8_t r = random8(6) != 0 ? (color >> 16 & 0xFF) : random8();
uint8_t g = random8(6) != 0 ? (color >> 8 & 0xFF) : random8();
uint8_t b = random8(6) != 0 ? (color & 0xFF) : random8();
@@ -1798,7 +1791,7 @@ uint16_t mode_oscillate(void) {
// if the counter has increased, move the oscillator by the random step
if (it != SEGENV.step) oscillators[i].pos += oscillators[i].dir * oscillators[i].speed;
oscillators[i].size = SEGLEN/(3+SEGMENT.intensity/8);
- if((oscillators[i].dir == -1) && (oscillators[i].pos <= 0)) {
+ if((oscillators[i].dir == -1) && (oscillators[i].pos > SEGLEN << 1)) { // use integer overflow
oscillators[i].pos = 0;
oscillators[i].dir = 1;
// make bigger steps for faster speeds
@@ -1814,8 +1807,8 @@ uint16_t mode_oscillate(void) {
for (unsigned i = 0; i < SEGLEN; i++) {
uint32_t color = BLACK;
for (unsigned j = 0; j < numOscillators; j++) {
- if(i >= (unsigned)oscillators[j].pos - oscillators[j].size && i <= oscillators[j].pos + oscillators[j].size) {
- color = (color == BLACK) ? SEGCOLOR(j) : color_blend(color, SEGCOLOR(j), 128);
+ if((int)i >= (int)oscillators[j].pos - oscillators[j].size && i <= oscillators[j].pos + oscillators[j].size) {
+ color = (color == BLACK) ? SEGCOLOR(j) : color_blend(color, SEGCOLOR(j), uint8_t(128));
}
}
SEGMENT.setPixelColor(i, color);
@@ -2003,7 +1996,7 @@ uint16_t mode_palette() {
const mathType sourceX = xtSinTheta + ytCosTheta + centerX;
// The computation was scaled just right so that the result should always be in range [0, maxXOut], but enforce this anyway
// to account for imprecision. Then scale it so that the range is [0, 255], which we can use with the palette.
- int colorIndex = (std::min(std::max(sourceX, mathType(0)), maxXOut * sInt16Scale) * 255) / (sInt16Scale * maxXOut);
+ int colorIndex = (std::min(std::max(sourceX, mathType(0)), maxXOut * sInt16Scale) * wideMathType(255)) / (sInt16Scale * maxXOut);
// inputSize determines by how much we want to scale the palette:
// values < 128 display a fraction of a palette,
// values > 128 display multiple palettes.
@@ -2565,11 +2558,11 @@ static CRGB twinklefox_one_twinkle(uint32_t ms, uint8_t salt, bool cat)
{
// Overall twinkle speed (changed)
unsigned ticks = ms / SEGENV.aux0;
- unsigned fastcycle8 = ticks;
- unsigned slowcycle16 = (ticks >> 8) + salt;
+ unsigned fastcycle8 = uint8_t(ticks);
+ uint16_t slowcycle16 = (ticks >> 8) + salt;
slowcycle16 += sin8_t(slowcycle16);
slowcycle16 = (slowcycle16 * 2053) + 1384;
- unsigned slowcycle8 = (slowcycle16 & 0xFF) + (slowcycle16 >> 8);
+ uint8_t slowcycle8 = (slowcycle16 & 0xFF) + (slowcycle16 >> 8);
// Overall twinkle density.
// 0 (NONE lit) to 8 (ALL lit at once).
@@ -3920,7 +3913,7 @@ uint16_t mode_percent(void) {
return FRAMETIME;
}
-static const char _data_FX_MODE_PERCENT[] PROGMEM = "Percent@,% of fill,,,,One color;!,!;!";
+static const char _data_FX_MODE_PERCENT[] PROGMEM = "Percent@!,% of fill,,,,One color;!,!;!";
/*
@@ -5170,7 +5163,7 @@ uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https:
neighbors++;
bool colorFound = false;
int k;
- for (k=0; k<9 && colorsCount[i].count != 0; k++)
+ for (k=0; k<9 && colorsCount[k].count != 0; k++)
if (colorsCount[k].color == prevLeds[xy]) {
colorsCount[k].count++;
colorFound = true;
@@ -6639,14 +6632,16 @@ static const char _data_FX_MODE_JUGGLES[] PROGMEM = "Juggles@!,# of balls;!,!;!;
// * MATRIPIX //
//////////////////////
uint16_t mode_matripix(void) { // Matripix. By Andrew Tuline.
- if (SEGLEN == 1) return mode_static();
- // even with 1D effect we have to take logic for 2D segments for allocation as fill_solid() fills whole segment
+ // effect can work on single pixels, we just lose the shifting effect
+ unsigned dataSize = sizeof(uint32_t) * SEGLEN;
+ if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
+ uint32_t* pixels = reinterpret_cast(SEGENV.data);
um_data_t *um_data = getAudioData();
int volumeRaw = *(int16_t*)um_data->u_data[1];
if (SEGENV.call == 0) {
- SEGMENT.fill(BLACK);
+ for (unsigned i = 0; i < SEGLEN; i++) pixels[i] = BLACK; // may not be needed as resetIfRequired() clears buffer
}
uint8_t secondHand = micros()/(256-SEGMENT.speed)/500 % 16;
@@ -6654,8 +6649,14 @@ uint16_t mode_matripix(void) { // Matripix. By Andrew Tuline.
SEGENV.aux0 = secondHand;
int pixBri = volumeRaw * SEGMENT.intensity / 64;
- for (int i = 0; i < SEGLEN-1; i++) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); // shift left
- SEGMENT.setPixelColor(SEGLEN-1, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(strip.now, false, PALETTE_SOLID_WRAP, 0), pixBri));
+ unsigned k = SEGLEN-1;
+ // loop will not execute if SEGLEN equals 1
+ for (unsigned i = 0; i < k; i++) {
+ pixels[i] = pixels[i+1]; // shift left
+ SEGMENT.setPixelColor(i, pixels[i]);
+ }
+ pixels[k] = color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(strip.now, false, PALETTE_SOLID_WRAP, 0), pixBri);
+ SEGMENT.setPixelColor(k, pixels[k]);
}
return FRAMETIME;
@@ -7283,8 +7284,11 @@ static const char _data_FX_MODE_ROCKTAVES[] PROGMEM = "Rocktaves@;!,!;!;01f;m12=
// Combines peak detection with FFT_MajorPeak and FFT_Magnitude.
uint16_t mode_waterfall(void) { // Waterfall. By: Andrew Tuline
// effect can work on single pixels, we just lose the shifting effect
-
- um_data_t *um_data = getAudioData();
+ unsigned dataSize = sizeof(uint32_t) * SEGLEN;
+ if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
+ uint32_t* pixels = reinterpret_cast(SEGENV.data);
+
+ um_data_t *um_data = getAudioData();
uint8_t samplePeak = *(uint8_t*)um_data->u_data[3];
float FFT_MajorPeak = *(float*) um_data->u_data[4];
uint8_t *maxVol = (uint8_t*)um_data->u_data[6];
@@ -7294,7 +7298,7 @@ uint16_t mode_waterfall(void) { // Waterfall. By: Andrew Tulin
if (FFT_MajorPeak < 1) FFT_MajorPeak = 1; // log10(0) is "forbidden" (throws exception)
if (SEGENV.call == 0) {
- SEGMENT.fill(BLACK);
+ for (unsigned i = 0; i < SEGLEN; i++) pixels[i] = BLACK; // may not be needed as resetIfRequired() clears buffer
SEGENV.aux0 = 255;
SEGMENT.custom1 = *binNum;
SEGMENT.custom2 = *maxVol * 2;
@@ -7311,13 +7315,18 @@ uint16_t mode_waterfall(void) { // Waterfall. By: Andrew Tulin
uint8_t pixCol = (log10f(FFT_MajorPeak) - 2.26f) * 150; // 22Khz sampling - log10 frequency range is from 2.26 (182hz) to 3.967 (9260hz). Let's scale accordingly.
if (FFT_MajorPeak < 182.0f) pixCol = 0; // handle underflow
+ unsigned k = SEGLEN-1;
if (samplePeak) {
- SEGMENT.setPixelColor(SEGLEN-1, CHSV(92,92,92));
+ pixels[k] = (uint32_t)CRGB(CHSV(92,92,92));
} else {
- SEGMENT.setPixelColor(SEGLEN-1, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(pixCol+SEGMENT.intensity, false, PALETTE_SOLID_WRAP, 0), (int)my_magnitude));
+ pixels[k] = color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(pixCol+SEGMENT.intensity, false, PALETTE_SOLID_WRAP, 0), (uint8_t)my_magnitude);
}
+ SEGMENT.setPixelColor(k, pixels[k]);
// loop will not execute if SEGLEN equals 1
- for (int i = 0; i < SEGLEN-1; i++) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); // shift left
+ for (unsigned i = 0; i < k; i++) {
+ pixels[i] = pixels[i+1]; // shift left
+ SEGMENT.setPixelColor(i, pixels[i]);
+ }
}
return FRAMETIME;
diff --git a/wled00/FX.h b/wled00/FX.h
index 5451615464..e9d447e6ff 100644
--- a/wled00/FX.h
+++ b/wled00/FX.h
@@ -1,3 +1,4 @@
+#pragma once
/*
WS2812FX.h - Library for WS2812 LED effects.
Harm Aldick - 2016
@@ -8,12 +9,15 @@
Adapted from code originally licensed under the MIT license
Modified for WLED
+
+ Segment class/struct (c) 2022 Blaz Kristan (@blazoncek)
*/
#ifndef WS2812FX_h
#define WS2812FX_h
#include
+#include "wled.h"
#include "const.h"
@@ -46,6 +50,14 @@
#define WLED_FPS 42
#define FRAMETIME_FIXED (1000/WLED_FPS)
#define FRAMETIME strip.getFrameTime()
+#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S2)
+ #define MIN_FRAME_DELAY 2 // minimum wait between repaints, to keep other functions like WiFi alive
+#elif defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3)
+ #define MIN_FRAME_DELAY 3 // S2/C3 are slower than normal esp32, and only have one core
+#else
+ #define MIN_FRAME_DELAY 8 // 8266 legacy MIN_SHOW_DELAY
+#endif
+#define FPS_UNLIMITED 0
// FPS calculation (can be defined as compile flag for debugging)
#ifndef FPS_CALC_AVG
@@ -59,26 +71,21 @@
/* each segment uses 82 bytes of SRAM memory, so if you're application fails because of
insufficient memory, decreasing MAX_NUM_SEGMENTS may help */
#ifdef ESP8266
- #define MAX_NUM_SEGMENTS 16
+ #define MAX_NUM_SEGMENTS 16
/* How much data bytes all segments combined may allocate */
#define MAX_SEGMENT_DATA 5120
+#elif defined(CONFIG_IDF_TARGET_ESP32S2)
+ #define MAX_NUM_SEGMENTS 20
+ #define MAX_SEGMENT_DATA (MAX_NUM_SEGMENTS*512) // 10k by default (S2 is short on free RAM)
#else
- #ifndef MAX_NUM_SEGMENTS
- #define MAX_NUM_SEGMENTS 32
- #endif
- #if defined(ARDUINO_ARCH_ESP32S2)
- #define MAX_SEGMENT_DATA MAX_NUM_SEGMENTS*768 // 24k by default (S2 is short on free RAM)
- #else
- #define MAX_SEGMENT_DATA MAX_NUM_SEGMENTS*1280 // 40k by default
- #endif
+ #define MAX_NUM_SEGMENTS 32 // warning: going beyond 32 may consume too much RAM for stable operation
+ #define MAX_SEGMENT_DATA (MAX_NUM_SEGMENTS*1280) // 40k by default
#endif
/* How much data bytes each segment should max allocate to leave enough space for other segments,
assuming each segment uses the same amount of data. 256 for ESP8266, 640 for ESP32. */
#define FAIR_DATA_PER_SEG (MAX_SEGMENT_DATA / strip.getMaxSegments())
-#define MIN_SHOW_DELAY (_frametime < 16 ? 8 : 15)
-
#define NUM_COLORS 3 /* number of colors per segment */
#define SEGMENT strip._segments[strip.getCurrSegmentId()]
#define SEGENV strip._segments[strip.getCurrSegmentId()]
@@ -524,6 +531,9 @@ typedef struct Segment {
inline uint16_t length() const { return width() * height(); } // segment length (count) in physical pixels
inline uint16_t groupLength() const { return grouping + spacing; }
inline uint8_t getLightCapabilities() const { return _capabilities; }
+ inline void deactivate() { setGeometry(0,0); }
+ inline Segment &clearName() { if (name) free(name); name = nullptr; return *this; }
+ inline Segment &setName(const String &name) { return setName(name.c_str()); }
inline static uint16_t getUsedSegmentData() { return _usedSegmentData; }
inline static void addUsedSegmentData(int len) { _usedSegmentData += len; }
@@ -533,14 +543,15 @@ typedef struct Segment {
static void handleRandomPalette();
inline static const CRGBPalette16 &getCurrentPalette() { return Segment::_currentPalette; }
- void setUp(uint16_t i1, uint16_t i2, uint8_t grp=1, uint8_t spc=0, uint16_t ofs=UINT16_MAX, uint16_t i1Y=0, uint16_t i2Y=1);
+ void setGeometry(uint16_t i1, uint16_t i2, uint8_t grp=1, uint8_t spc=0, uint16_t ofs=UINT16_MAX, uint16_t i1Y=0, uint16_t i2Y=1, uint8_t m12 = 0);
Segment &setColor(uint8_t slot, uint32_t c);
Segment &setCCT(uint16_t k);
Segment &setOpacity(uint8_t o);
Segment &setOption(uint8_t n, bool val);
Segment &setMode(uint8_t fx, bool loadDefaults = false);
Segment &setPalette(uint8_t pal);
- uint8_t differs(Segment& b) const;
+ Segment &setName(const char* name);
+ uint8_t differs(const Segment& b) const;
void refreshLightCapabilities();
// runtime data functions
@@ -748,6 +759,7 @@ class WS2812FX { // 96 bytes
customMappingTable(nullptr),
customMappingSize(0),
_lastShow(0),
+ _lastServiceShow(0),
_segment_index(0),
_mainSegment(0)
{
@@ -846,7 +858,7 @@ class WS2812FX { // 96 bytes
getMappedPixelIndex(uint16_t index) const;
inline uint16_t getFrameTime() const { return _frametime; } // returns amount of time a frame should take (in ms)
- inline uint16_t getMinShowDelay() const { return MIN_SHOW_DELAY; } // returns minimum amount of time strip.service() can be delayed (constant)
+ inline uint16_t getMinShowDelay() const { return MIN_FRAME_DELAY; } // returns minimum amount of time strip.service() can be delayed (constant)
inline uint16_t getLength() const { return _length; } // returns actual amount of LEDs on a strip (2D matrix may have less LEDs than W*H)
inline uint16_t getTransition() const { return _transitionDur; } // returns currently set transition time (in ms)
@@ -958,6 +970,7 @@ class WS2812FX { // 96 bytes
uint16_t customMappingSize;
unsigned long _lastShow;
+ unsigned long _lastServiceShow;
uint8_t _segment_index;
uint8_t _mainSegment;
diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp
index 7177ca89e8..ce6f53a2cd 100644
--- a/wled00/FX_fcn.cpp
+++ b/wled00/FX_fcn.cpp
@@ -438,37 +438,44 @@ void Segment::setCurrentPalette() {
// relies on WS2812FX::service() to call it for each frame
void Segment::handleRandomPalette() {
+ uint16_t time_ms = millis();
+ uint16_t time_s = millis()/1000U;
// is it time to generate a new palette?
- if ((uint16_t)((uint16_t)(millis() / 1000U) - _lastPaletteChange) > randomPaletteChangeTime){
- _newRandomPalette = useHarmonicRandomPalette ? generateHarmonicRandomPalette(_randomPalette) : generateRandomPalette();
- _lastPaletteChange = (uint16_t)(millis() / 1000U);
- _lastPaletteBlend = (uint16_t)((uint16_t)millis() - 512); // starts blending immediately
+ if ((uint16_t)(time_s - _lastPaletteChange) > randomPaletteChangeTime) {
+ _newRandomPalette = useHarmonicRandomPalette ? generateHarmonicRandomPalette(_randomPalette) : generateRandomPalette();
+ _lastPaletteChange = time_s;
+ _lastPaletteBlend = time_ms - 512; // starts blending immediately
}
// if palette transitions is enabled, blend it according to Transition Time (if longer than minimum given by service calls)
if (strip.paletteFade) {
// assumes that 128 updates are sufficient to blend a palette, so shift by 7 (can be more, can be less)
// in reality there need to be 255 blends to fully blend two entirely different palettes
- if ((uint16_t)((uint16_t)millis() - _lastPaletteBlend) < strip.getTransition() >> 7) return; // not yet time to fade, delay the update
+ if ((uint16_t)(time_ms - _lastPaletteBlend) < strip.getTransition() >> 7) return; // not yet time to fade, delay the update
_lastPaletteBlend = (uint16_t)millis();
}
nblendPaletteTowardPalette(_randomPalette, _newRandomPalette, 48);
}
// segId is given when called from network callback, changes are queued if that segment is currently in its effect function
-void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t ofs, uint16_t i1Y, uint16_t i2Y) {
+void Segment::setGeometry(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t ofs, uint16_t i1Y, uint16_t i2Y, uint8_t m12) {
// return if neither bounds nor grouping have changed
bool boundsUnchanged = (start == i1 && stop == i2);
#ifndef WLED_DISABLE_2D
if (Segment::maxHeight>1) boundsUnchanged &= (startY == i1Y && stopY == i2Y); // 2D
#endif
+
+ m12 = constrain(m12, 0, 7);
+ if (stop && (spc > 0 || m12 != map1D2D)) fill(BLACK);
+ if (m12 != map1D2D) map1D2D = m12;
+/*
if (boundsUnchanged
&& (!grp || (grouping == grp && spacing == spc))
- && (ofs == UINT16_MAX || ofs == offset)) return;
-
+ && (m12 == map1D2D)
+ ) return;
+*/
stateChanged = true; // send UDP/WS broadcast
- if (stop) fill(BLACK); // turn old segment range off (clears pixels if changing spacing)
if (grp) { // prevent assignment of 0
grouping = grp;
spacing = spc;
@@ -478,12 +485,9 @@ void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t
}
if (ofs < UINT16_MAX) offset = ofs;
- DEBUG_PRINT(F("setUp segment: ")); DEBUG_PRINT(i1);
- DEBUG_PRINT(','); DEBUG_PRINT(i2);
- DEBUG_PRINT(F(" -> ")); DEBUG_PRINT(i1Y);
- DEBUG_PRINT(','); DEBUG_PRINTLN(i2Y);
- markForReset();
+ DEBUG_PRINTF_P(PSTR("Segment geometry: %d,%d -> %d,%d\n"), (int)i1, (int)i2, (int)i1Y, (int)i2Y);
if (boundsUnchanged) return;
+ markForReset();
// apply change immediately
if (i2 <= i1) { //disable segment
@@ -601,6 +605,20 @@ Segment &Segment::setPalette(uint8_t pal) {
return *this;
}
+Segment &Segment::setName(const char *newName) {
+ if (newName) {
+ const int newLen = min(strlen(newName), (size_t)WLED_MAX_SEGNAME_LEN);
+ if (newLen) {
+ if (name) name = static_cast(realloc(name, newLen+1));
+ else name = static_cast(malloc(newLen+1));
+ if (name) strlcpy(name, newName, newLen+1);
+ name[newLen] = 0;
+ return *this;
+ }
+ }
+ return clearName();
+}
+
// 2D matrix
unsigned IRAM_ATTR Segment::virtualWidth() const {
unsigned groupLen = groupLength();
@@ -951,7 +969,7 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColor(int i) const
return strip.getPixelColor(i);
}
-uint8_t Segment::differs(Segment& b) const {
+uint8_t Segment::differs(const Segment& b) const {
uint8_t d = 0;
if (start != b.start) d |= SEG_DIFFERS_BOUNDS;
if (stop != b.stop) d |= SEG_DIFFERS_BOUNDS;
@@ -1047,36 +1065,25 @@ void Segment::fade_out(uint8_t rate) {
const int cols = is2D() ? virtualWidth() : virtualLength();
const int rows = virtualHeight(); // will be 1 for 1D
- rate = (255-rate) >> 1;
- float mappedRate = 1.0f / (float(rate) + 1.1f);
-
- uint32_t color = colors[1]; // SEGCOLOR(1); // target color
- int w2 = W(color);
- int r2 = R(color);
- int g2 = G(color);
- int b2 = B(color);
+ rate = (256-rate) >> 1;
+ const int mappedRate = 256 / (rate + 1);
for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) {
- color = is2D() ? getPixelColorXY(x, y) : getPixelColor(x);
+ uint32_t color = is2D() ? getPixelColorXY(x, y) : getPixelColor(x);
if (color == colors[1]) continue; // already at target color
- int w1 = W(color);
- int r1 = R(color);
- int g1 = G(color);
- int b1 = B(color);
-
- int wdelta = (w2 - w1) * mappedRate;
- int rdelta = (r2 - r1) * mappedRate;
- int gdelta = (g2 - g1) * mappedRate;
- int bdelta = (b2 - b1) * mappedRate;
-
- // if fade isn't complete, make sure delta is at least 1 (fixes rounding issues)
- wdelta += (w2 == w1) ? 0 : (w2 > w1) ? 1 : -1;
- rdelta += (r2 == r1) ? 0 : (r2 > r1) ? 1 : -1;
- gdelta += (g2 == g1) ? 0 : (g2 > g1) ? 1 : -1;
- bdelta += (b2 == b1) ? 0 : (b2 > b1) ? 1 : -1;
-
- if (is2D()) setPixelColorXY(x, y, r1 + rdelta, g1 + gdelta, b1 + bdelta, w1 + wdelta);
- else setPixelColor(x, r1 + rdelta, g1 + gdelta, b1 + bdelta, w1 + wdelta);
+ for (int i = 0; i < 32; i += 8) {
+ uint8_t c2 = (colors[1]>>i); // get background channel
+ uint8_t c1 = (color>>i); // get foreground channel
+ // we can't use bitshift since we are using int
+ int delta = (c2 - c1) * mappedRate / 256;
+ // if fade isn't complete, make sure delta is at least 1 (fixes rounding issues)
+ if (delta == 0) delta += (c2 == c1) ? 0 : (c2 > c1) ? 1 : -1;
+ // stuff new value back into color
+ color &= ~(0xFF<