Porównaj commity

...

42 Commity

Autor SHA1 Wiadomość Data
gaaat98 37ef568b60
Merge 74bc159a52 into a6e536189c 2024-05-06 00:02:53 +02:00
Frank a6e536189c output_bin.py : fix for mapfile copy
The build script was not looking into the right place, so there was never a .map file dropped into build_output/map/

Builds with the newer arduino-esp32 v2.0.x framework actually generate a .map file that is placed directly next to firmware.bin
2024-05-05 21:56:01 +02:00
Frank 3f9a6cae53 AR: fix for arduinoFFT 2.x API
in contrast to previous 'dev' versions, the storage for windowWeighingFactors is now managed internally by the arduinoFFT object.
2024-05-04 14:34:23 +02:00
Frank cd5494fdd2 AR pin config: SCK == 1 --> PDM microphone 2024-05-04 14:12:44 +02:00
Blaž Kristan 5ab1b14d6b
Merge pull request #3946 from freakintoddles2/0_15
Adds an API parameter to allow the user to skip to the next preset in a playlist at any time
2024-05-03 23:25:36 +02:00
Todd Meyer 379f181362 Further simplification 2024-05-03 11:51:47 -07:00
Todd Meyer dd19aa63d0 Forgot F[], added it 2024-05-03 08:47:14 -07:00
Todd Meyer 6df3b417a9 Updated based on more feedback 2024-05-03 08:30:37 -07:00
Blaz Kristan fa76431dd6 Changelog update 2024-05-03 16:08:20 +02:00
Blaz Kristan 6504fb68b6 Minor MQTT optimisation. 2024-05-03 15:46:16 +02:00
Blaz Kristan 2ff49cf657 Fix for #3952
- included IR optimisations & code rearrangement
2024-05-03 15:45:15 +02:00
Blaž Kristan fa1aa1fe80
Merge pull request #3944 from paspiz85/pas4
Using brightness in analog clock overlay
2024-05-03 09:56:14 +02:00
Blaž Kristan 85b95a2940
Merge pull request #3945 from w00000dy/Webpage-shortcuts
Add Webpage shortcuts and Fix resizing bug
2024-05-03 09:53:00 +02:00
Todd Meyer 5e38039c4d Updated based on more feedback 2024-05-02 14:36:18 -07:00
Blaz Kristan 4df936a437 Fix for unfortunate prior CRLF coversion. 2024-05-02 10:33:10 +02:00
Blaz Kristan 736a8b1b80 Fix for rotating tablet into PC mode. 2024-05-02 10:31:50 +02:00
Pasquale Pizzuti 22f6128bc4 using global brightness 2024-05-02 09:05:37 +02:00
freakintoddles2 db475b6998
Update playlist.cpp 2024-05-01 10:09:17 -07:00
freakintoddles2 6daf7f6322
Update wled.cpp
reworked based on PR feedback
2024-05-01 10:07:52 -07:00
freakintoddles2 16086c0961
Update wled.h
reworked based on feedback from original PR
2024-05-01 10:05:26 -07:00
freakintoddles2 e88c81ad0d
Update set.cpp
reworked based on feedback
2024-05-01 10:04:02 -07:00
freakintoddles2 a2b9aed40d
Update playlist.cpp
reworked approach based on feedback
2024-05-01 10:03:16 -07:00
freakintoddles2 caa4fe1ec4
Update json.cpp
reworked approach based on feedback
2024-05-01 10:02:27 -07:00
freakintoddles2 25fb878e54
Update fcn_declare.h
reworked approach based on feedback
2024-05-01 10:01:30 -07:00
freakintoddles2 a1d6ffadad
Update json.cpp
adds support for np boolean parameter to skip to next preset
2024-04-30 16:49:52 -07:00
freakintoddles2 3b89814b69
Update set.cpp
added new NP command to API to allow user to skip to next preset in a playlist. Example use is win&NP in a preset.
2024-04-30 16:33:30 -07:00
freakintoddles2 071e0be445
Update fcn_declare.h
Updated to add the optional skipNext bool to handlePlaylist() which allows people to skip to the next preset when desired
2024-04-30 16:23:43 -07:00
freakintoddles2 bed364d75e
Update playlist.cpp
Updated to allow a user to optionally skip to the next preset in the playlist anytime they desire.
2024-04-30 16:21:40 -07:00
Woody d2984e9e16
add Webpage shortcuts, resolves #2362 2024-04-30 18:57:53 +02:00
Pasquale Pizzuti fd9570e782 using color_fade 2024-04-30 17:52:35 +02:00
Woody ff10130176
Fix resizing bug
The bug was that when resizing the window, it always jumped to the Colors tab instead of staying on the currently selected tab.
2024-04-30 16:53:47 +02:00
Pasquale Pizzuti c7d292a716 using brightness in analog clock overlay 2024-04-30 14:09:12 +02:00
Frank 9f99a1896d presets.json PSRAM caching: consider cacheInvalidate
* trying to make the caching mechanism bulletproof.
`cacheInvalidate` is changed when
- autosave usermod updates presets
- a file was upload
* (coding style) fixed some unitialized variables
2024-04-29 16:51:27 +02:00
Blaž Kristan 8110259d1c
Merge pull request #3892 from askask/pollreply 2024-04-28 09:32:04 +02:00
Frank 1048bf993a
use lolin_s3_mini for esp32-S3 4MB buildenv 2024-04-27 23:34:35 +02:00
Blaž Kristan 3eba0f4e0d
Merge pull request #3933 from gaaat98/0_15
Improved brightness change via long button presses
2024-04-27 12:53:56 +02:00
gaaat98 d7e0b364d1
fixed wrong comment 2024-04-27 12:25:34 +02:00
Blaz Kristan 25dd43b949 Bugfix for bugfix
- thanks @softhack007
2024-04-26 23:49:34 +02:00
Blaz Kristan d48bab02a1 Speed & size optimisations using native sized variables 2024-04-26 20:11:46 +02:00
Blaz Kristan 886120fe9f Bugfix
- getPixelColor() for analog
- RMT channel (#3922)
2024-04-26 20:07:27 +02:00
gaaat98 bdd4d9f3ff
set buttonBriDirection as local static 2024-04-26 18:23:34 +02:00
Andreas Kling c3787af29d Send ArtnetPollReply for Art-Net proxy universe 2024-04-09 20:00:00 +02:00
21 zmienionych plików z 526 dodań i 475 usunięć

Wyświetl plik

@ -1,5 +1,15 @@
## WLED changelog
#### Build 240503
- Using brightness in analog clock overlay (#3944 by @paspiz85)
- Add Webpage shortcuts (#3945 by @w00000dy)
- ArtNet Poll reply (#3892 by @askask)
- Improved brightness change via long button presses (#3933 by @gaaat98)
- Relay open drain output (#3920 by @Suxsem)
- NEW JSON API: release info (update page, `info.release`)
- update esp32 platform to arduino-esp32 v2.0.9 (#3902)
- various optimisations and bugfixes (#3952, #3922, #3878, #3926, #3919, #3904 @DedeHai)
#### Build 2404120
- v0.15.0-b3
- fix for #3896 & WS2815 current saving

Wyświetl plik

@ -36,6 +36,8 @@ def create_release(source):
def bin_rename_copy(source, target, env):
_create_dirs()
variant = env["PIOENV"]
builddir = os.path.join(env["PROJECT_BUILD_DIR"], variant)
source_map = os.path.join(builddir, env["PROGNAME"] + ".map")
# create string with location and file names based on variant
map_file = "{}map{}{}.map".format(OUTPUT_DIR, os.path.sep, variant)
@ -44,7 +46,11 @@ def bin_rename_copy(source, target, env):
# copy firmware.map to map/<variant>.map
if os.path.isfile("firmware.map"):
shutil.move("firmware.map", map_file)
print("Found linker mapfile firmware.map")
shutil.copy("firmware.map", map_file)
if os.path.isfile(source_map):
print(f"Found linker mapfile {source_map}")
shutil.copy(source_map, map_file)
def bin_gzip(source, target):
# only create gzip for esp8266

Wyświetl plik

@ -471,8 +471,7 @@ monitor_filters = esp32_exception_decoder
[env:esp32s3_4M_qspi]
;; ESP32-S3, with 4MB FLASH and <= 4MB PSRAM (memory_type: qio_qspi)
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
board = lolin_s3_mini ;; -S3 mini, 4MB flash 2MB PSRAM
platform = ${esp32s3.platform}
platform_packages = ${esp32s3.platform_packages}
upload_speed = 921600

Wyświetl plik

@ -183,7 +183,6 @@ constexpr uint16_t samplesFFT_2 = 256; // meaningfull part of FFT resul
// These are the input and output vectors. Input vectors receive computed results from FFT.
static float vReal[samplesFFT] = {0.0f}; // FFT sample inputs / freq output - these are our raw result bins
static float vImag[samplesFFT] = {0.0f}; // imaginary parts
static float windowWeighingFactors[samplesFFT] = {0.0f};
// Create FFT object
// lib_deps += https://github.com/kosme/arduinoFFT#develop @ 1.9.2
@ -196,7 +195,8 @@ static float windowWeighingFactors[samplesFFT] = {0.0f};
#include <arduinoFFT.h>
static ArduinoFFT<float> FFT = ArduinoFFT<float>( vReal, vImag, samplesFFT, SAMPLE_RATE, windowWeighingFactors);
/* Create FFT object with weighing factor storage */
static ArduinoFFT<float> FFT = ArduinoFFT<float>( vReal, vImag, samplesFFT, SAMPLE_RATE, true);
// Helper functions
@ -1121,6 +1121,11 @@ class AudioReactive : public Usermod {
delay(100); // Give that poor microphone some time to setup.
useBandPassFilter = false;
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
if ((i2sckPin == I2S_PIN_NO_CHANGE) && (i2ssdPin >= 0) && (i2swsPin >= 0) && ((dmType == 1) || (dmType == 4)) ) dmType = 5; // dummy user support: SCK == -1 --means--> PDM microphone
#endif
switch (dmType) {
#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S3)
// stub cases for not-yet-supported I2S modes on other ESP32 chips

Wyświetl plik

@ -110,11 +110,11 @@ void WS2812FX::setUpMatrix() {
releaseJSONBufferLock();
}
uint16_t x, y, pix=0; //pixel
unsigned x, y, pix=0; //pixel
for (size_t pan = 0; pan < panel.size(); pan++) {
Panel &p = panel[pan];
uint16_t h = p.vertical ? p.height : p.width;
uint16_t v = p.vertical ? p.width : p.height;
unsigned h = p.vertical ? p.height : p.width;
unsigned v = p.vertical ? p.width : p.height;
for (size_t j = 0; j < v; j++){
for(size_t i = 0; i < h; i++) {
y = (p.vertical?p.rightStart:p.bottomStart) ? v-j-1 : j;
@ -163,8 +163,8 @@ void WS2812FX::setUpMatrix() {
// XY(x,y) - gets pixel index within current segment (often used to reference leds[] array element)
uint16_t IRAM_ATTR Segment::XY(uint16_t x, uint16_t y)
{
uint16_t width = virtualWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
uint16_t height = virtualHeight(); // segment height in logical pixels (is always >= 1)
unsigned width = virtualWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
unsigned height = virtualHeight(); // segment height in logical pixels (is always >= 1)
return isActive() ? (x%width) + (y%height) * width : 0;
}
@ -180,7 +180,7 @@ void IRAM_ATTR Segment::setPixelColorXY(int x, int y, uint32_t col)
if (reverse ) x = virtualWidth() - x - 1;
if (reverse_y) y = virtualHeight() - y - 1;
if (transpose) { uint16_t t = x; x = y; y = t; } // swap X & Y if segment transposed
if (transpose) { unsigned t = x; x = y; y = t; } // swap X & Y if segment transposed
x *= groupLength(); // expand to physical pixels
y *= groupLength(); // expand to physical pixels
@ -189,7 +189,7 @@ void IRAM_ATTR Segment::setPixelColorXY(int x, int y, uint32_t col)
uint32_t tmpCol = col;
for (int j = 0; j < grouping; j++) { // groupping vertically
for (int g = 0; g < grouping; g++) { // groupping horizontally
uint16_t xX = (x+g), yY = (y+j);
unsigned xX = (x+g), yY = (y+j);
if (xX >= width() || yY >= height()) continue; // we have reached one dimension's end
#ifndef WLED_DISABLE_MODE_BLEND
@ -221,16 +221,16 @@ void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa)
if (!isActive()) return; // not active
if (x<0.0f || x>1.0f || y<0.0f || y>1.0f) return; // not normalized
const uint16_t cols = virtualWidth();
const uint16_t rows = virtualHeight();
const unsigned cols = virtualWidth();
const unsigned rows = virtualHeight();
float fX = x * (cols-1);
float fY = y * (rows-1);
if (aa) {
uint16_t xL = roundf(fX-0.49f);
uint16_t xR = roundf(fX+0.49f);
uint16_t yT = roundf(fY-0.49f);
uint16_t yB = roundf(fY+0.49f);
unsigned xL = roundf(fX-0.49f);
unsigned xR = roundf(fX+0.49f);
unsigned yT = roundf(fY-0.49f);
unsigned yB = roundf(fY+0.49f);
float dL = (fX - xL)*(fX - xL);
float dR = (xR - fX)*(xR - fX);
float dT = (fY - yT)*(fY - yT);
@ -266,7 +266,7 @@ uint32_t IRAM_ATTR Segment::getPixelColorXY(int x, int y) {
if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return 0; // if pixel would fall out of virtual segment just exit
if (reverse ) x = virtualWidth() - x - 1;
if (reverse_y) y = virtualHeight() - y - 1;
if (transpose) { uint16_t t = x; x = y; y = t; } // swap X & Y if segment transposed
if (transpose) { unsigned t = x; x = y; y = t; } // swap X & Y if segment transposed
x *= groupLength(); // expand to physical pixels
y *= groupLength(); // expand to physical pixels
if (x >= width() || y >= height()) return 0;
@ -276,8 +276,8 @@ uint32_t IRAM_ATTR Segment::getPixelColorXY(int x, int y) {
// blurRow: perform a blur on a row of a rectangular matrix
void Segment::blurRow(uint32_t row, fract8 blur_amount, bool smear){
if (!isActive() || blur_amount == 0) return; // not active
const uint_fast16_t cols = virtualWidth();
const uint_fast16_t rows = virtualHeight();
const unsigned cols = virtualWidth();
const unsigned rows = virtualHeight();
if (row >= rows) return;
// blur one row
@ -309,8 +309,8 @@ void Segment::blurRow(uint32_t row, fract8 blur_amount, bool smear){
// blurCol: perform a blur on a column of a rectangular matrix
void Segment::blurCol(uint32_t col, fract8 blur_amount, bool smear) {
if (!isActive() || blur_amount == 0) return; // not active
const uint_fast16_t cols = virtualWidth();
const uint_fast16_t rows = virtualHeight();
const unsigned cols = virtualWidth();
const unsigned rows = virtualHeight();
if (col >= cols) return;
// blur one column
@ -342,34 +342,34 @@ void Segment::blurCol(uint32_t col, fract8 blur_amount, bool smear) {
// 1D Box blur (with added weight - blur_amount: [0=no blur, 255=max blur])
void Segment::box_blur(uint16_t i, bool vertical, fract8 blur_amount) {
if (!isActive() || blur_amount == 0) return; // not active
const uint16_t cols = virtualWidth();
const uint16_t rows = virtualHeight();
const uint16_t dim1 = vertical ? rows : cols;
const uint16_t dim2 = vertical ? cols : rows;
const unsigned cols = virtualWidth();
const unsigned rows = virtualHeight();
const unsigned dim1 = vertical ? rows : cols;
const unsigned dim2 = vertical ? cols : rows;
if (i >= dim2) return;
const float seep = blur_amount/255.f;
const float keep = 3.f - 2.f*seep;
// 1D box blur
CRGB tmp[dim1];
for (int j = 0; j < dim1; j++) {
uint16_t x = vertical ? i : j;
uint16_t y = vertical ? j : i;
int16_t xp = vertical ? x : x-1; // "signed" to prevent underflow
int16_t yp = vertical ? y-1 : y; // "signed" to prevent underflow
uint16_t xn = vertical ? x : x+1;
uint16_t yn = vertical ? y+1 : y;
for (unsigned j = 0; j < dim1; j++) {
unsigned x = vertical ? i : j;
unsigned y = vertical ? j : i;
int xp = vertical ? x : x-1; // "signed" to prevent underflow
int yp = vertical ? y-1 : y; // "signed" to prevent underflow
unsigned xn = vertical ? x : x+1;
unsigned yn = vertical ? y+1 : y;
CRGB curr = getPixelColorXY(x,y);
CRGB prev = (xp<0 || yp<0) ? CRGB::Black : getPixelColorXY(xp,yp);
CRGB next = ((vertical && yn>=dim1) || (!vertical && xn>=dim1)) ? CRGB::Black : getPixelColorXY(xn,yn);
uint16_t r, g, b;
unsigned r, g, b;
r = (curr.r*keep + (prev.r + next.r)*seep) / 3;
g = (curr.g*keep + (prev.g + next.g)*seep) / 3;
b = (curr.b*keep + (prev.b + next.b)*seep) / 3;
tmp[j] = CRGB(r,g,b);
}
for (int j = 0; j < dim1; j++) {
uint16_t x = vertical ? i : j;
uint16_t y = vertical ? j : i;
for (unsigned j = 0; j < dim1; j++) {
unsigned x = vertical ? i : j;
unsigned y = vertical ? j : i;
setPixelColorXY(x, y, tmp[j]);
}
}
@ -389,14 +389,14 @@ void Segment::box_blur(uint16_t i, bool vertical, fract8 blur_amount) {
// it can be used to (slowly) clear the LEDs to black.
void Segment::blur1d(fract8 blur_amount) {
const uint16_t rows = virtualHeight();
const unsigned rows = virtualHeight();
for (unsigned y = 0; y < rows; y++) blurRow(y, blur_amount);
}
void Segment::moveX(int8_t delta, bool wrap) {
if (!isActive()) return; // not active
const uint16_t cols = virtualWidth();
const uint16_t rows = virtualHeight();
const int cols = virtualWidth();
const int rows = virtualHeight();
if (!delta || abs(delta) >= cols) return;
uint32_t newPxCol[cols];
for (int y = 0; y < rows; y++) {
@ -413,8 +413,8 @@ void Segment::moveX(int8_t delta, bool wrap) {
void Segment::moveY(int8_t delta, bool wrap) {
if (!isActive()) return; // not active
const uint16_t cols = virtualWidth();
const uint16_t rows = virtualHeight();
const int cols = virtualWidth();
const int rows = virtualHeight();
if (!delta || abs(delta) >= rows) return;
uint32_t newPxCol[rows];
for (int x = 0; x < cols; x++) {
@ -474,13 +474,13 @@ void Segment::draw_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) {
// by stepko, taken from https://editor.soulmatelights.com/gallery/573-blobs
void Segment::fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) {
if (!isActive() || radius == 0) return; // not active
const uint16_t cols = virtualWidth();
const uint16_t rows = virtualHeight();
for (int16_t y = -radius; y <= radius; y++) {
for (int16_t x = -radius; x <= radius; x++) {
const int cols = virtualWidth();
const int rows = virtualHeight();
for (int y = -radius; y <= radius; y++) {
for (int x = -radius; x <= radius; x++) {
if (x * x + y * y <= radius * radius &&
int16_t(cx)+x>=0 && int16_t(cy)+y>=0 &&
int16_t(cx)+x<cols && int16_t(cy)+y<rows)
int(cx)+x>=0 && int(cy)+y>=0 &&
int(cx)+x<cols && int(cy)+y<rows)
setPixelColorXY(cx + x, cy + y, col);
}
}
@ -488,9 +488,9 @@ void Segment::fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) {
void Segment::nscale8(uint8_t scale) {
if (!isActive()) return; // not active
const uint16_t cols = virtualWidth();
const uint16_t rows = virtualHeight();
for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) {
const unsigned cols = virtualWidth();
const unsigned rows = virtualHeight();
for (unsigned y = 0; y < rows; y++) for (unsigned x = 0; x < cols; x++) {
setPixelColorXY(x, y, CRGB(getPixelColorXY(x, y)).nscale8(scale));
}
}
@ -498,12 +498,12 @@ void Segment::nscale8(uint8_t scale) {
//line function
void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c) {
if (!isActive()) return; // not active
const uint16_t cols = virtualWidth();
const uint16_t rows = virtualHeight();
const unsigned cols = virtualWidth();
const unsigned rows = virtualHeight();
if (x0 >= cols || x1 >= cols || y0 >= rows || y1 >= rows) return;
const int16_t dx = abs(x1-x0), sx = x0<x1 ? 1 : -1;
const int16_t dy = abs(y1-y0), sy = y0<y1 ? 1 : -1;
int16_t err = (dx>dy ? dx : -dy)/2, e2;
const int dx = abs(x1-x0), sx = x0<x1 ? 1 : -1;
const int dy = abs(y1-y0), sy = y0<y1 ? 1 : -1;
int err = (dx>dy ? dx : -dy)/2, e2;
for (;;) {
setPixelColorXY(x0,y0,c);
if (x0==x1 && y0==y1) break;
@ -525,8 +525,8 @@ void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w,
if (!isActive()) return; // not active
if (chr < 32 || chr > 126) return; // only ASCII 32-126 supported
chr -= 32; // align with font table entries
const uint16_t cols = virtualWidth();
const uint16_t rows = virtualHeight();
const int cols = virtualWidth();
const int rows = virtualHeight();
const int font = w*h;
CRGB col = CRGB(color);
@ -565,7 +565,7 @@ void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w,
void Segment::wu_pixel(uint32_t x, uint32_t y, CRGB c) { //awesome wu_pixel procedure by reddit u/sutaburosu
if (!isActive()) return; // not active
// extract the fractional parts and derive their inverses
uint8_t xx = x & 0xff, yy = y & 0xff, ix = 255 - xx, iy = 255 - yy;
unsigned xx = x & 0xff, yy = y & 0xff, ix = 255 - xx, iy = 255 - yy;
// calculate the intensities for each affected pixel
uint8_t wu[4] = {WU_WEIGHT(ix, iy), WU_WEIGHT(xx, iy),
WU_WEIGHT(ix, yy), WU_WEIGHT(xx, yy)};

Wyświetl plik

@ -327,7 +327,7 @@ void Segment::stopTransition() {
}
void Segment::handleTransition() {
uint16_t _progress = progress();
unsigned _progress = progress();
if (_progress == 0xFFFFU) stopTransition();
}
@ -412,9 +412,9 @@ void Segment::restoreSegenv(tmpsegd_t &tmpSeg) {
#endif
uint8_t IRAM_ATTR Segment::currentBri(bool useCct) {
uint32_t prog = progress();
unsigned prog = progress();
if (prog < 0xFFFFU) {
uint32_t curBri = (useCct ? cct : (on ? opacity : 0)) * prog;
unsigned curBri = (useCct ? cct : (on ? opacity : 0)) * prog;
curBri += (useCct ? _t->_cctT : _t->_briT) * (0xFFFFU - prog);
return curBri / 0xFFFFU;
}
@ -423,7 +423,7 @@ uint8_t IRAM_ATTR Segment::currentBri(bool useCct) {
uint8_t IRAM_ATTR Segment::currentMode() {
#ifndef WLED_DISABLE_MODE_BLEND
uint16_t prog = progress();
unsigned prog = progress();
if (modeBlending && prog < 0xFFFFU) return _t->_modeT;
#endif
return mode;
@ -440,13 +440,13 @@ uint32_t IRAM_ATTR Segment::currentColor(uint8_t slot) {
CRGBPalette16 IRAM_ATTR &Segment::currentPalette(CRGBPalette16 &targetPalette, uint8_t pal) {
loadPalette(targetPalette, pal);
uint16_t prog = progress();
unsigned prog = progress();
if (strip.paletteFade && prog < 0xFFFFU) {
// blend palettes
// there are about 255 blend passes of 48 "blends" to completely blend two palettes (in _dur time)
// minimum blend time is 100ms maximum is 65535ms
uint16_t noOfBlends = ((255U * prog) / 0xFFFFU) - _t->_prevPaletteBlends;
for (int i=0; i<noOfBlends; i++, _t->_prevPaletteBlends++) nblendPaletteTowardPalette(_t->_palT, targetPalette, 48);
unsigned noOfBlends = ((255U * prog) / 0xFFFFU) - _t->_prevPaletteBlends;
for (unsigned i=0; i<noOfBlends; i++, _t->_prevPaletteBlends++) nblendPaletteTowardPalette(_t->_palT, targetPalette, 48);
targetPalette = _t->_palT; // copy transitioning/temporary palette
}
return targetPalette;
@ -576,7 +576,7 @@ void Segment::setMode(uint8_t fx, bool loadDefaults) {
mode = fx;
// load default values from effect string
if (loadDefaults) {
int16_t sOpt;
int sOpt;
sOpt = extractModeDefaults(fx, "sx"); speed = (sOpt >= 0) ? sOpt : DEFAULT_SPEED;
sOpt = extractModeDefaults(fx, "ix"); intensity = (sOpt >= 0) ? sOpt : DEFAULT_INTENSITY;
sOpt = extractModeDefaults(fx, "c1"); custom1 = (sOpt >= 0) ? sOpt : DEFAULT_C1;
@ -610,21 +610,21 @@ void Segment::setPalette(uint8_t pal) {
// 2D matrix
uint16_t IRAM_ATTR Segment::virtualWidth() const {
uint16_t groupLen = groupLength();
uint16_t vWidth = ((transpose ? height() : width()) + groupLen - 1) / groupLen;
unsigned groupLen = groupLength();
unsigned vWidth = ((transpose ? height() : width()) + groupLen - 1) / groupLen;
if (mirror) vWidth = (vWidth + 1) /2; // divide by 2 if mirror, leave at least a single LED
return vWidth;
}
uint16_t IRAM_ATTR Segment::virtualHeight() const {
uint16_t groupLen = groupLength();
uint16_t vHeight = ((transpose ? width() : height()) + groupLen - 1) / groupLen;
unsigned groupLen = groupLength();
unsigned vHeight = ((transpose ? width() : height()) + groupLen - 1) / groupLen;
if (mirror_y) vHeight = (vHeight + 1) /2; // divide by 2 if mirror, leave at least a single LED
return vHeight;
}
uint16_t IRAM_ATTR Segment::nrOfVStrips() const {
uint16_t vLen = 1;
unsigned vLen = 1;
#ifndef WLED_DISABLE_2D
if (is2D()) {
switch (map1D2D) {
@ -641,9 +641,9 @@ uint16_t IRAM_ATTR Segment::nrOfVStrips() const {
uint16_t IRAM_ATTR Segment::virtualLength() const {
#ifndef WLED_DISABLE_2D
if (is2D()) {
uint16_t vW = virtualWidth();
uint16_t vH = virtualHeight();
uint16_t vLen = vW * vH; // use all pixels from segment
unsigned vW = virtualWidth();
unsigned vH = virtualHeight();
unsigned vLen = vW * vH; // use all pixels from segment
switch (map1D2D) {
case M12_pBar:
vLen = vH;
@ -656,8 +656,8 @@ uint16_t IRAM_ATTR Segment::virtualLength() const {
return vLen;
}
#endif
uint16_t groupLen = groupLength(); // is always >= 1
uint16_t vLength = (length() + groupLen - 1) / groupLen;
unsigned groupLen = groupLength(); // is always >= 1
unsigned vLength = (length() + groupLen - 1) / groupLen;
if (mirror) vLength = (vLength + 1) /2; // divide by 2 if mirror, leave at least a single LED
return vLength;
}
@ -674,8 +674,8 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col)
#ifndef WLED_DISABLE_2D
if (is2D()) {
uint16_t vH = virtualHeight(); // segment height in logical pixels
uint16_t vW = virtualWidth();
int vH = virtualHeight(); // segment height in logical pixels
int vW = virtualWidth();
switch (map1D2D) {
case M12_Pixels:
// use all available pixels as a long strip
@ -732,7 +732,7 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col)
}
#endif
uint16_t len = length();
unsigned len = length();
uint8_t _bri_t = currentBri();
if (_bri_t < 255) {
col = color_fade(col, _bri_t);
@ -785,8 +785,8 @@ void Segment::setPixelColor(float i, uint32_t col, bool aa)
float fC = i * (virtualLength()-1);
if (aa) {
uint16_t iL = roundf(fC-0.49f);
uint16_t iR = roundf(fC+0.49f);
unsigned iL = roundf(fC-0.49f);
unsigned iR = roundf(fC+0.49f);
float dL = (fC - iL)*(fC - iL);
float dR = (iR - fC)*(iR - fC);
uint32_t cIL = getPixelColor(iL | (vStrip<<16));
@ -803,7 +803,7 @@ void Segment::setPixelColor(float i, uint32_t col, bool aa)
setPixelColor(iL | (vStrip<<16), col);
}
} else {
setPixelColor(uint16_t(roundf(fC)) | (vStrip<<16), col);
setPixelColor(int(roundf(fC)) | (vStrip<<16), col);
}
}
#endif
@ -818,8 +818,8 @@ uint32_t IRAM_ATTR Segment::getPixelColor(int i)
#ifndef WLED_DISABLE_2D
if (is2D()) {
uint16_t vH = virtualHeight(); // segment height in logical pixels
uint16_t vW = virtualWidth();
unsigned vH = virtualHeight(); // segment height in logical pixels
unsigned vW = virtualWidth();
switch (map1D2D) {
case M12_Pixels:
return getPixelColorXY(i % vW, i / vW);
@ -875,9 +875,9 @@ uint8_t Segment::differs(Segment& b) const {
}
void Segment::refreshLightCapabilities() {
uint8_t capabilities = 0;
uint16_t segStartIdx = 0xFFFFU;
uint16_t segStopIdx = 0;
unsigned capabilities = 0;
unsigned segStartIdx = 0xFFFFU;
unsigned segStopIdx = 0;
if (!isActive()) {
_capabilities = 0;
@ -887,7 +887,7 @@ void Segment::refreshLightCapabilities() {
if (start < Segment::maxWidth * Segment::maxHeight) {
// we are withing 2D matrix (includes 1D segments)
for (int y = startY; y < stopY; y++) for (int x = start; x < stop; x++) {
uint16_t index = strip.getMappedPixelIndex(x + Segment::maxWidth * y); // convert logical address to physical
unsigned index = strip.getMappedPixelIndex(x + Segment::maxWidth * y); // convert logical address to physical
if (index < 0xFFFFU) {
if (segStartIdx > index) segStartIdx = index;
if (segStopIdx < index) segStopIdx = index;
@ -912,7 +912,7 @@ void Segment::refreshLightCapabilities() {
if (!cctFromRgb && bus->hasCCT()) capabilities |= SEG_CAPABILITY_CCT;
if (correctWB && (bus->hasRGB() || bus->hasCCT())) capabilities |= SEG_CAPABILITY_CCT; //white balance correction (CCT slider)
if (bus->hasWhite()) {
uint8_t aWM = Bus::getGlobalAWMode() == AW_GLOBAL_DISABLED ? bus->getAutoWhiteMode() : Bus::getGlobalAWMode();
unsigned aWM = Bus::getGlobalAWMode() == AW_GLOBAL_DISABLED ? bus->getAutoWhiteMode() : Bus::getGlobalAWMode();
bool whiteSlider = (aWM == RGBW_MODE_DUAL || aWM == RGBW_MODE_MANUAL_ONLY); // white slider allowed
// if auto white calculation from RGB is active (Accurate/Brighter), force RGB controls even if there are no RGB busses
if (!whiteSlider) capabilities |= SEG_CAPABILITY_RGB;
@ -928,8 +928,8 @@ void Segment::refreshLightCapabilities() {
*/
void Segment::fill(uint32_t c) {
if (!isActive()) return; // not active
const uint16_t cols = is2D() ? virtualWidth() : virtualLength();
const uint16_t rows = virtualHeight(); // will be 1 for 1D
const int cols = is2D() ? virtualWidth() : virtualLength();
const int rows = virtualHeight(); // will be 1 for 1D
for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) {
if (is2D()) setPixelColorXY(x, y, c);
else setPixelColor(x, c);
@ -941,8 +941,8 @@ void Segment::fill(uint32_t c) {
*/
void Segment::fade_out(uint8_t rate) {
if (!isActive()) return; // not active
const uint16_t cols = is2D() ? virtualWidth() : virtualLength();
const uint16_t rows = virtualHeight(); // will be 1 for 1D
const int cols = is2D() ? virtualWidth() : virtualLength();
const int rows = virtualHeight(); // will be 1 for 1D
rate = (255-rate) >> 1;
float mappedRate = float(rate) +1.1f;
@ -979,8 +979,8 @@ void Segment::fade_out(uint8_t rate) {
// fades all pixels to black using nscale8()
void Segment::fadeToBlackBy(uint8_t fadeBy) {
if (!isActive() || fadeBy == 0) return; // optimization - no scaling to apply
const uint16_t cols = is2D() ? virtualWidth() : virtualLength();
const uint16_t rows = virtualHeight(); // will be 1 for 1D
const int cols = is2D() ? virtualWidth() : virtualLength();
const int rows = virtualHeight(); // will be 1 for 1D
for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) {
if (is2D()) setPixelColorXY(x, y, color_fade(getPixelColorXY(x,y), 255-fadeBy));
@ -1065,7 +1065,7 @@ uint32_t Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_
// default palette or no RGB support on segment
if ((palette == 0 && mcol < NUM_COLORS) || !_isRGB) return (pbri == 255) ? color : color_fade(color, pbri, true);
uint8_t paletteIndex = i;
unsigned paletteIndex = i;
if (mapping && virtualLength() > 1) paletteIndex = (i*255)/(virtualLength() -1);
// paletteBlend: 0 - wrap when moving, 1 - always wrap, 2 - never wrap, 3 - none (undefined)
if (!wrap && strip.paletteBlend != 3) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end"
@ -1132,7 +1132,7 @@ void WS2812FX::finalizeInit(void) {
_hasWhiteChannel |= bus->hasWhite();
//refresh is required to remain off if at least one of the strips requires the refresh.
_isOffRefreshRequired |= bus->isOffRefreshRequired();
uint16_t busEnd = bus->getStart() + bus->getLength();
unsigned busEnd = bus->getStart() + bus->getLength();
if (busEnd > _length) _length = busEnd;
#ifdef ESP8266
if ((!IS_DIGITAL(bus->getType()) || IS_2PIN(bus->getType()))) continue;
@ -1176,10 +1176,10 @@ void WS2812FX::service() {
if (nowUp > seg.next_time || _triggered || (doShow && seg.mode == FX_MODE_STATIC))
{
doShow = true;
uint16_t delay = FRAMETIME;
unsigned delay = FRAMETIME;
if (!seg.freeze) { //only run effect function if not frozen
int16_t oldCCT = BusManager::getSegmentCCT(); // store original CCT value (actually it is not Segment based)
int oldCCT = BusManager::getSegmentCCT(); // store original CCT value (actually it is not Segment based)
_virtualSegmentLength = seg.virtualLength(); //SEGLEN
_colors_t[0] = gamma32(seg.currentColor(0));
_colors_t[1] = gamma32(seg.currentColor(1));
@ -1203,7 +1203,7 @@ void WS2812FX::service() {
Segment::modeBlend(true); // set semaphore
seg.swapSegenv(_tmpSegData); // temporarily store new mode state (and swap it with transitional state)
_virtualSegmentLength = seg.virtualLength(); // update SEGLEN (mapping may have changed)
uint16_t d2 = (*_mode[tmpMode])(); // run old mode
unsigned d2 = (*_mode[tmpMode])(); // run old mode
seg.restoreSegenv(_tmpSegData); // restore mode state (will also update transitional state)
delay = MIN(delay,d2); // use shortest delay
Segment::modeBlend(false); // unset semaphore
@ -1378,13 +1378,13 @@ uint8_t WS2812FX::getActiveSegmentsNum(void) {
}
uint16_t WS2812FX::getLengthTotal(void) {
uint16_t len = Segment::maxWidth * Segment::maxHeight; // will be _length for 1D (see finalizeInit()) but should cover whole matrix for 2D
unsigned len = Segment::maxWidth * Segment::maxHeight; // will be _length for 1D (see finalizeInit()) but should cover whole matrix for 2D
if (isMatrix && _length > len) len = _length; // for 2D with trailing strip
return len;
}
uint16_t WS2812FX::getLengthPhysical(void) {
uint16_t len = 0;
unsigned len = 0;
for (size_t b = 0; b < BusManager::getNumBusses(); b++) {
Bus *bus = BusManager::getBus(b);
if (bus->getType() >= TYPE_NET_DDP_RGB) continue; //exclude non-physical network busses
@ -1461,8 +1461,8 @@ void WS2812FX::resetSegments() {
void WS2812FX::makeAutoSegments(bool forceReset) {
if (autoSegments) { //make one segment per bus
uint16_t segStarts[MAX_NUM_SEGMENTS] = {0};
uint16_t segStops [MAX_NUM_SEGMENTS] = {0};
unsigned segStarts[MAX_NUM_SEGMENTS] = {0};
unsigned segStops [MAX_NUM_SEGMENTS] = {0};
size_t s = 0;
#ifndef WLED_DISABLE_2D

Wyświetl plik

@ -466,7 +466,22 @@ void BusPwm::setPixelColor(uint16_t pix, uint32_t c) {
//does no index check
uint32_t BusPwm::getPixelColor(uint16_t pix) {
if (!_valid) return 0;
return RGBW32(_data[0], _data[1], _data[2], _data[3]);
// TODO getting the reverse from CCT is involved (a quick approximation when CCT blending is ste to 0 implemented)
switch (_type) {
case TYPE_ANALOG_1CH: //one channel (white), relies on auto white calculation
return RGBW32(0, 0, 0, _data[0]);
case TYPE_ANALOG_2CH: //warm white + cold white
if (cctICused) return RGBW32(0, 0, 0, _data[0]);
else return RGBW32(0, 0, 0, _data[0] + _data[1]);
case TYPE_ANALOG_5CH: //RGB + warm white + cold white
if (cctICused) return RGBW32(_data[0], _data[1], _data[2], _data[3]);
else return RGBW32(_data[0], _data[1], _data[2], _data[3] + _data[4]);
case TYPE_ANALOG_4CH: //RGBW
return RGBW32(_data[0], _data[1], _data[2], _data[3]);
case TYPE_ANALOG_3CH: //standard dumb RGB
return RGBW32(_data[0], _data[1], _data[2], 0);
}
return RGBW32(_data[0], _data[0], _data[0], _data[0]);
}
#ifndef ESP8266

Wyświetl plik

@ -496,6 +496,11 @@ class PolyBus {
}
static void* create(uint8_t busType, uint8_t* pins, uint16_t len, uint8_t channel, uint16_t clock_kHz = 0U) {
#if defined(ARDUINO_ARCH_ESP32) && !(defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C3))
// NOTE: "channel" is only used on ESP32 (and its variants) for RMT channel allocation
// since 0.15.0-b3 I2S1 is favoured for classic ESP32 and moved to position 0 (channel 0) so we need to subtract 1 for correct RMT allocation
if (channel > 0) channel--; // accommodate I2S1 which is used as 1st bus on classic ESP32
#endif
void* busPtr = nullptr;
switch (busType) {
case I_NONE: break;

Wyświetl plik

@ -10,9 +10,10 @@
#define WLED_LONG_REPEATED_ACTION 400 // how often a repeated action (e.g. dimming) is fired on long press on button IDs >0
#define WLED_LONG_AP 5000 // how long button 0 needs to be held to activate WLED-AP
#define WLED_LONG_FACTORY_RESET 10000 // how long button 0 needs to be held to trigger a factory reset
#define WLED_LONG_BRI_STEPS 16 // how long to wait before increasing/decreasing brightness on long press
#define WLED_LONG_BRI_STEPS 16 // how much to increase/decrease the brightness with each long press repetition
static const char _mqtt_topic_button[] PROGMEM = "%s/button/%d"; // optimize flash usage
static bool buttonBriDirection = false; // true: increase brightness, false: decrease brightness
void shortPressAction(uint8_t b)
{
@ -41,7 +42,6 @@ void longPressAction(uint8_t b)
switch (b) {
case 0: setRandomColor(col); colorUpdated(CALL_MODE_BUTTON); break;
case 1:
// increase bri on true, decrease on false
if(buttonBriDirection) {
if (bri == 255) break; // avoid unnecessary updates to brightness
if (bri >= 255 - WLED_LONG_BRI_STEPS) bri = 255;

Wyświetl plik

@ -272,6 +272,7 @@ function onLoad()
selectSlot(0);
updateTablinks(0);
handleLocationHash();
cpick.on("input:end", () => {setColor(1);});
cpick.on("color:change", () => {updatePSliders()});
pmtLS = localStorage.getItem('wledPmt');
@ -304,7 +305,6 @@ function updateTablinks(tabI)
{
var tablinks = gEBCN("tablinks");
for (var i of tablinks) i.classList.remove('active');
if (pcMode) return;
tablinks[tabI].classList.add('active');
}
@ -315,6 +315,21 @@ function openTab(tabI, force = false)
_C.classList.toggle('smooth', false);
_C.style.setProperty('--i', iSlide);
updateTablinks(tabI);
switch (tabI) {
case 0: window.location.hash = "Colors"; break;
case 1: window.location.hash = "Effects"; break;
case 2: window.location.hash = "Segments"; break;
case 3: window.location.hash = "Presets"; break;
}
}
function handleLocationHash() {
switch (window.location.hash) {
case "#Colors": openTab(0); break;
case "#Effects": openTab(1); break;
case "#Segments": openTab(2); break;
case "#Presets": openTab(3); break;
}
}
var timeout;
@ -3051,8 +3066,7 @@ function togglePcMode(fromB = false)
pcMode = (wW >= 1024) && pcModeA;
if (cpick) cpick.resize(pcMode && wW>1023 && wW<1250 ? 230 : 260); // for tablet in landscape
if (!fromB && ((wW < 1024 && lastw < 1024) || (wW >= 1024 && lastw >= 1024))) return; // no change in size and called from size()
openTab(0, true);
updateTablinks(0);
if (pcMode) openTab(0, true);
gId('buttonPcm').className = (pcMode) ? "active":"";
gId('bot').style.height = (pcMode && !cfg.comp.pcmbot) ? "0":"auto";
sCol('--bh', gId('bot').clientHeight + "px");
@ -3214,6 +3228,7 @@ size();
_C.style.setProperty('--n', N);
window.addEventListener('resize', size, true);
window.addEventListener('hashchange', handleLocationHash);
_C.addEventListener('mousedown', lock, false);
_C.addEventListener('touchstart', lock, false);

Wyświetl plik

@ -346,7 +346,6 @@ void handleArtnetPollReply(IPAddress ipAddress) {
switch (DMXMode) {
case DMX_MODE_DISABLED:
return; // nothing to do
break;
case DMX_MODE_SINGLE_RGB:
@ -391,9 +390,17 @@ void handleArtnetPollReply(IPAddress ipAddress) {
break;
}
for (uint16_t i = startUniverse; i <= endUniverse; ++i) {
sendArtnetPollReply(&artnetPollReply, ipAddress, i);
if (DMXMode != DMX_MODE_DISABLED) {
for (uint16_t i = startUniverse; i <= endUniverse; ++i) {
sendArtnetPollReply(&artnetPollReply, ipAddress, i);
}
}
#ifdef WLED_ENABLE_DMX
if (e131ProxyUniverse > 0 && (DMXMode == DMX_MODE_DISABLED || (e131ProxyUniverse < startUniverse || e131ProxyUniverse > endUniverse))) {
sendArtnetPollReply(&artnetPollReply, ipAddress, e131ProxyUniverse);
}
#endif
}
void prepareArtnetPollReply(ArtPollReply *reply) {

Wyświetl plik

@ -143,20 +143,8 @@ void handleImprovWifiScan();
void sendImprovIPRPCResult(ImprovRPCType type);
//ir.cpp
void applyRepeatActions();
byte relativeChange(byte property, int8_t amount, byte lowerBoundary = 0, byte higherBoundary = 0xFF);
void decodeIR(uint32_t code);
void decodeIR24(uint32_t code);
void decodeIR24OLD(uint32_t code);
void decodeIR24CT(uint32_t code);
void decodeIR40(uint32_t code);
void decodeIR44(uint32_t code);
void decodeIR21(uint32_t code);
void decodeIR6(uint32_t code);
void decodeIR9(uint32_t code);
void decodeIRJson(uint32_t code);
void initIR();
void deInitIR();
void handleIR();
//json.cpp

Wyświetl plik

@ -381,11 +381,15 @@ void updateFSInfo() {
// original idea by @akaricchi (https://github.com/Akaricchi)
// returns a pointer to the PSRAM buffer, updates size parameter
static const uint8_t *getPresetCache(size_t &size) {
static unsigned long presetsCachedTime;
static uint8_t *presetsCached;
static size_t presetsCachedSize;
static unsigned long presetsCachedTime = 0;
static uint8_t *presetsCached = nullptr;
static size_t presetsCachedSize = 0;
static byte presetsCachedValidate = 0;
if (presetsModifiedTime != presetsCachedTime) {
//if (presetsModifiedTime != presetsCachedTime) DEBUG_PRINTLN(F("getPresetCache(): presetsModifiedTime changed."));
//if (presetsCachedValidate != cacheInvalidate) DEBUG_PRINTLN(F("getPresetCache(): cacheInvalidate changed."));
if ((presetsModifiedTime != presetsCachedTime) || (presetsCachedValidate != cacheInvalidate)) {
if (presetsCached) {
free(presetsCached);
presetsCached = nullptr;
@ -396,6 +400,7 @@ static const uint8_t *getPresetCache(size_t &size) {
File file = WLED_FS.open(FPSTR(getPresetsFileName()), "r");
if (file) {
presetsCachedTime = presetsModifiedTime;
presetsCachedValidate = cacheInvalidate;
presetsCachedSize = 0;
presetsCached = (uint8_t*)ps_malloc(file.size() + 1);
if (presetsCached) {

Wyświetl plik

@ -1,20 +1,14 @@
#include "wled.h"
#ifndef WLED_DISABLE_INFRARED
#include "ir_codes.h"
/*
* Infrared sensor support for generic 24/40/44 key RGB remotes
* Infrared sensor support for several generic RGB remotes and custom JSON remote
*/
#if defined(WLED_DISABLE_INFRARED)
void handleIR(){}
#else
IRrecv* irrecv;
//change pin in NpbWrapper.h
decode_results results;
unsigned long irCheckedTime = 0;
uint32_t lastValidCode = 0;
byte lastRepeatableAction = ACTION_NONE;
@ -35,16 +29,16 @@ uint8_t lastIR6ColourIdx = 0;
// print("%d values: %s" % (len(result), result))
//
// It would be hard to maintain repeatable steps if calculating this on the fly.
const byte brightnessSteps[] = {
const uint8_t brightnessSteps[] = {
5, 7, 9, 12, 16, 20, 26, 34, 43, 56, 72, 93, 119, 154, 198, 255
};
const size_t numBrightnessSteps = sizeof(brightnessSteps) / sizeof(uint8_t);
// increment `bri` to the next `brightnessSteps` value
void incBrightness()
static void incBrightness()
{
// dumb incremental search is efficient enough for so few items
for (uint8_t index = 0; index < numBrightnessSteps; ++index)
for (unsigned index = 0; index < numBrightnessSteps; ++index)
{
if (brightnessSteps[index] > bri)
{
@ -56,7 +50,7 @@ void incBrightness()
}
// decrement `bri` to the next `brightnessSteps` value
void decBrightness()
static void decBrightness()
{
// dumb incremental search is efficient enough for so few items
for (int index = numBrightnessSteps - 1; index >= 0; --index)
@ -70,12 +64,12 @@ void decBrightness()
}
}
void presetFallback(uint8_t presetID, uint8_t effectID, uint8_t paletteID)
static void presetFallback(uint8_t presetID, uint8_t effectID, uint8_t paletteID)
{
applyPresetWithFallback(presetID, CALL_MODE_BUTTON_PRESET, effectID, paletteID);
}
byte relativeChange(byte property, int8_t amount, byte lowerBoundary, byte higherBoundary)
static byte relativeChange(byte property, int8_t amount, byte lowerBoundary = 0, byte higherBoundary = 0xFF)
{
int16_t new_val = (int16_t) property + amount;
if (lowerBoundary >= higherBoundary) return property;
@ -84,10 +78,10 @@ byte relativeChange(byte property, int8_t amount, byte lowerBoundary, byte highe
return (byte)constrain(new_val, 0, 255);
}
void changeEffect(uint8_t fx)
static void changeEffect(uint8_t fx)
{
if (irApplyToAllSelected) {
for (uint8_t i = 0; i < strip.getSegmentsNum(); i++) {
for (unsigned i = 0; i < strip.getSegmentsNum(); i++) {
Segment& seg = strip.getSegment(i);
if (!seg.isActive() || !seg.isSelected()) continue;
strip.setMode(i, fx);
@ -100,10 +94,10 @@ void changeEffect(uint8_t fx)
stateChanged = true;
}
void changePalette(uint8_t pal)
static void changePalette(uint8_t pal)
{
if (irApplyToAllSelected) {
for (uint8_t i = 0; i < strip.getSegmentsNum(); i++) {
for (unsigned i = 0; i < strip.getSegmentsNum(); i++) {
Segment& seg = strip.getSegment(i);
if (!seg.isActive() || !seg.isSelected()) continue;
seg.setPalette(pal);
@ -116,13 +110,13 @@ void changePalette(uint8_t pal)
stateChanged = true;
}
void changeEffectSpeed(int8_t amount)
static void changeEffectSpeed(int8_t amount)
{
if (effectCurrent != 0) {
int16_t new_val = (int16_t) effectSpeed + amount;
effectSpeed = (byte)constrain(new_val,0,255);
if (irApplyToAllSelected) {
for (uint8_t i = 0; i < strip.getSegmentsNum(); i++) {
for (unsigned i = 0; i < strip.getSegmentsNum(); i++) {
Segment& seg = strip.getSegment(i);
if (!seg.isActive() || !seg.isSelected()) continue;
seg.speed = effectSpeed;
@ -134,10 +128,7 @@ void changeEffectSpeed(int8_t amount)
}
} else { // if Effect == "solid Color", change the hue of the primary color
Segment& sseg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment();
CRGB fastled_col;
fastled_col.red = R(sseg.colors[0]);
fastled_col.green = G(sseg.colors[0]);
fastled_col.blue = B(sseg.colors[0]);
CRGB fastled_col = CRGB(sseg.colors[0]);
CHSV prim_hsv = rgb2hsv_approximate(fastled_col);
int16_t new_val = (int16_t)prim_hsv.h + amount;
if (new_val > 255) new_val -= 255; // roll-over if bigger than 255
@ -145,7 +136,7 @@ void changeEffectSpeed(int8_t amount)
prim_hsv.h = (byte)new_val;
hsv2rgb_rainbow(prim_hsv, fastled_col);
if (irApplyToAllSelected) {
for (uint8_t i = 0; i < strip.getSegmentsNum(); i++) {
for (unsigned i = 0; i < strip.getSegmentsNum(); i++) {
Segment& seg = strip.getSegment(i);
if (!seg.isActive() || !seg.isSelected()) continue;
seg.colors[0] = RGBW32(fastled_col.red, fastled_col.green, fastled_col.blue, W(sseg.colors[0]));
@ -163,13 +154,13 @@ void changeEffectSpeed(int8_t amount)
lastRepeatableValue = amount;
}
void changeEffectIntensity(int8_t amount)
static void changeEffectIntensity(int8_t amount)
{
if (effectCurrent != 0) {
int16_t new_val = (int16_t) effectIntensity + amount;
effectIntensity = (byte)constrain(new_val,0,255);
if (irApplyToAllSelected) {
for (uint8_t i = 0; i < strip.getSegmentsNum(); i++) {
for (unsigned i = 0; i < strip.getSegmentsNum(); i++) {
Segment& seg = strip.getSegment(i);
if (!seg.isActive() || !seg.isSelected()) continue;
seg.intensity = effectIntensity;
@ -181,16 +172,13 @@ void changeEffectIntensity(int8_t amount)
}
} else { // if Effect == "solid Color", change the saturation of the primary color
Segment& sseg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment();
CRGB fastled_col;
fastled_col.red = R(sseg.colors[0]);
fastled_col.green = G(sseg.colors[0]);
fastled_col.blue = B(sseg.colors[0]);
CRGB fastled_col = CRGB(sseg.colors[0]);
CHSV prim_hsv = rgb2hsv_approximate(fastled_col);
int16_t new_val = (int16_t) prim_hsv.s + amount;
prim_hsv.s = (byte)constrain(new_val,0,255); // constrain to 0-255
hsv2rgb_rainbow(prim_hsv, fastled_col);
if (irApplyToAllSelected) {
for (uint8_t i = 0; i < strip.getSegmentsNum(); i++) {
for (unsigned i = 0; i < strip.getSegmentsNum(); i++) {
Segment& seg = strip.getSegment(i);
if (!seg.isActive() || !seg.isSelected()) continue;
seg.colors[0] = RGBW32(fastled_col.red, fastled_col.green, fastled_col.blue, W(sseg.colors[0]));
@ -208,11 +196,11 @@ void changeEffectIntensity(int8_t amount)
lastRepeatableValue = amount;
}
void changeColor(uint32_t c, int16_t cct=-1)
static void changeColor(uint32_t c, int16_t cct=-1)
{
if (irApplyToAllSelected) {
// main segment may not be selected!
for (uint8_t i = 0; i < strip.getSegmentsNum(); i++) {
for (unsigned i = 0; i < strip.getSegmentsNum(); i++) {
Segment& seg = strip.getSegment(i);
if (!seg.isActive() || !seg.isSelected()) continue;
byte capabilities = seg.getLightCapabilities();
@ -249,7 +237,7 @@ void changeColor(uint32_t c, int16_t cct=-1)
stateChanged = true;
}
void changeWhite(int8_t amount, int16_t cct=-1)
static void changeWhite(int8_t amount, int16_t cct=-1)
{
Segment& seg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment();
byte r = R(seg.colors[0]);
@ -259,72 +247,7 @@ void changeWhite(int8_t amount, int16_t cct=-1)
changeColor(RGBW32(r, g, b, w), cct);
}
void decodeIR(uint32_t code)
{
if (code == 0xFFFFFFFF) {
//repeated code, continue brightness up/down
irTimesRepeated++;
applyRepeatActions();
return;
}
lastValidCode = 0; irTimesRepeated = 0;
lastRepeatableAction = ACTION_NONE;
if (irEnabled == 8) { // any remote configurable with ir.json file
decodeIRJson(code);
stateUpdated(CALL_MODE_BUTTON);
return;
}
if (code > 0xFFFFFF) return; //invalid code
switch (irEnabled) {
case 1:
if (code > 0xF80000) decodeIR24OLD(code); // white 24-key remote (old) - it sends 0xFF0000 values
else decodeIR24(code); // 24-key remote - 0xF70000 to 0xF80000
break;
case 2: decodeIR24CT(code); break; // white 24-key remote with CW, WW, CT+ and CT- keys
case 3: decodeIR40(code); break; // blue 40-key remote with 25%, 50%, 75% and 100% keys
case 4: decodeIR44(code); break; // white 44-key remote with color-up/down keys and DIY1 to 6 keys
case 5: decodeIR21(code); break; // white 21-key remote
case 6: decodeIR6(code); break; // black 6-key learning remote defaults: "CH" controls brightness,
// "VOL +" controls effect, "VOL -" controls colour/palette, "MUTE"
// sets bright plain white
case 7: decodeIR9(code); break;
//case 8: return; // ir.json file, handled above switch statement
}
if (nightlightActive && bri == 0) nightlightActive = false;
stateUpdated(CALL_MODE_BUTTON); //for notifier, IR is considered a button input
}
void applyRepeatActions()
{
if (irEnabled == 8) {
decodeIRJson(lastValidCode);
return;
} else switch (lastRepeatableAction) {
case ACTION_BRIGHT_UP : incBrightness(); stateUpdated(CALL_MODE_BUTTON); return;
case ACTION_BRIGHT_DOWN : decBrightness(); stateUpdated(CALL_MODE_BUTTON); return;
case ACTION_SPEED_UP : changeEffectSpeed(lastRepeatableValue); stateUpdated(CALL_MODE_BUTTON); return;
case ACTION_SPEED_DOWN : changeEffectSpeed(lastRepeatableValue); stateUpdated(CALL_MODE_BUTTON); return;
case ACTION_INTENSITY_UP : changeEffectIntensity(lastRepeatableValue); stateUpdated(CALL_MODE_BUTTON); return;
case ACTION_INTENSITY_DOWN : changeEffectIntensity(lastRepeatableValue); stateUpdated(CALL_MODE_BUTTON); return;
default: break;
}
if (lastValidCode == IR40_WPLUS) {
changeWhite(10);
stateUpdated(CALL_MODE_BUTTON);
} else if (lastValidCode == IR40_WMINUS) {
changeWhite(-10);
stateUpdated(CALL_MODE_BUTTON);
} else if ((lastValidCode == IR24_ON || lastValidCode == IR40_ON) && irTimesRepeated > 7 ) {
nightlightActive = true;
nightlightStartTime = millis();
stateUpdated(CALL_MODE_BUTTON);
}
}
void decodeIR24(uint32_t code)
static void decodeIR24(uint32_t code)
{
switch (code) {
case IR24_BRIGHTER : incBrightness(); break;
@ -356,7 +279,7 @@ void decodeIR24(uint32_t code)
lastValidCode = code;
}
void decodeIR24OLD(uint32_t code)
static void decodeIR24OLD(uint32_t code)
{
switch (code) {
case IR24_OLD_BRIGHTER : incBrightness(); break;
@ -388,7 +311,7 @@ void decodeIR24OLD(uint32_t code)
lastValidCode = code;
}
void decodeIR24CT(uint32_t code)
static void decodeIR24CT(uint32_t code)
{
switch (code) {
case IR24_CT_BRIGHTER : incBrightness(); break;
@ -420,7 +343,7 @@ void decodeIR24CT(uint32_t code)
lastValidCode = code;
}
void decodeIR40(uint32_t code)
static void decodeIR40(uint32_t code)
{
Segment& seg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment();
byte r = R(seg.colors[0]);
@ -473,7 +396,7 @@ void decodeIR40(uint32_t code)
lastValidCode = code;
}
void decodeIR44(uint32_t code)
static void decodeIR44(uint32_t code)
{
switch (code) {
case IR44_BPLUS : incBrightness(); break;
@ -525,7 +448,7 @@ void decodeIR44(uint32_t code)
lastValidCode = code;
}
void decodeIR21(uint32_t code)
static void decodeIR21(uint32_t code)
{
switch (code) {
case IR21_BRIGHTER: incBrightness(); break;
@ -554,7 +477,7 @@ void decodeIR21(uint32_t code)
lastValidCode = code;
}
void decodeIR6(uint32_t code)
static void decodeIR6(uint32_t code)
{
switch (code) {
case IR6_POWER: toggleOnOff(); break;
@ -587,7 +510,7 @@ void decodeIR6(uint32_t code)
lastValidCode = code;
}
void decodeIR9(uint32_t code)
static void decodeIR9(uint32_t code)
{
switch (code) {
case IR9_POWER : toggleOnOff(); break;
@ -628,7 +551,7 @@ Sample:
"label": "Preset 1, fallback to Saw - Party if not found"},
}
*/
void decodeIRJson(uint32_t code)
static void decodeIRJson(uint32_t code)
{
char objKey[10];
char fileName[16];
@ -701,41 +624,102 @@ void decodeIRJson(uint32_t code)
releaseJSONBufferLock();
}
static void applyRepeatActions()
{
if (irEnabled == 8) {
decodeIRJson(lastValidCode);
return;
} else switch (lastRepeatableAction) {
case ACTION_BRIGHT_UP : incBrightness(); stateUpdated(CALL_MODE_BUTTON); return;
case ACTION_BRIGHT_DOWN : decBrightness(); stateUpdated(CALL_MODE_BUTTON); return;
case ACTION_SPEED_UP : changeEffectSpeed(lastRepeatableValue); stateUpdated(CALL_MODE_BUTTON); return;
case ACTION_SPEED_DOWN : changeEffectSpeed(lastRepeatableValue); stateUpdated(CALL_MODE_BUTTON); return;
case ACTION_INTENSITY_UP : changeEffectIntensity(lastRepeatableValue); stateUpdated(CALL_MODE_BUTTON); return;
case ACTION_INTENSITY_DOWN : changeEffectIntensity(lastRepeatableValue); stateUpdated(CALL_MODE_BUTTON); return;
default: break;
}
if (lastValidCode == IR40_WPLUS) {
changeWhite(10);
stateUpdated(CALL_MODE_BUTTON);
} else if (lastValidCode == IR40_WMINUS) {
changeWhite(-10);
stateUpdated(CALL_MODE_BUTTON);
} else if ((lastValidCode == IR24_ON || lastValidCode == IR40_ON) && irTimesRepeated > 7 ) {
nightlightActive = true;
nightlightStartTime = millis();
stateUpdated(CALL_MODE_BUTTON);
}
}
static void decodeIR(uint32_t code)
{
if (code == 0xFFFFFFFF) {
//repeated code, continue brightness up/down
irTimesRepeated++;
applyRepeatActions();
return;
}
lastValidCode = 0; irTimesRepeated = 0;
lastRepeatableAction = ACTION_NONE;
if (irEnabled == 8) { // any remote configurable with ir.json file
decodeIRJson(code);
stateUpdated(CALL_MODE_BUTTON);
return;
}
if (code > 0xFFFFFF) return; //invalid code
switch (irEnabled) {
case 1:
if (code > 0xF80000) decodeIR24OLD(code); // white 24-key remote (old) - it sends 0xFF0000 values
else decodeIR24(code); // 24-key remote - 0xF70000 to 0xF80000
break;
case 2: decodeIR24CT(code); break; // white 24-key remote with CW, WW, CT+ and CT- keys
case 3: decodeIR40(code); break; // blue 40-key remote with 25%, 50%, 75% and 100% keys
case 4: decodeIR44(code); break; // white 44-key remote with color-up/down keys and DIY1 to 6 keys
case 5: decodeIR21(code); break; // white 21-key remote
case 6: decodeIR6(code); break; // black 6-key learning remote defaults: "CH" controls brightness,
// "VOL +" controls effect, "VOL -" controls colour/palette, "MUTE"
// sets bright plain white
case 7: decodeIR9(code); break;
//case 8: return; // ir.json file, handled above switch statement
}
if (nightlightActive && bri == 0) nightlightActive = false;
stateUpdated(CALL_MODE_BUTTON); //for notifier, IR is considered a button input
}
void initIR()
{
if (irEnabled > 0)
{
if (irEnabled > 0) {
irrecv = new IRrecv(irPin);
irrecv->enableIRIn();
if (irrecv) irrecv->enableIRIn();
} else irrecv = nullptr;
}
void deInitIR()
{
if (irrecv) {
irrecv->disableIRIn();
delete irrecv;
}
irrecv = nullptr;
}
void handleIR()
{
if (irEnabled > 0 && millis() - irCheckedTime > 120 && !strip.isUpdating())
{
irCheckedTime = millis();
if (irEnabled > 0)
{
if (irrecv == NULL)
{
initIR(); return;
unsigned long currentTime = millis();
unsigned timeDiff = currentTime - irCheckedTime;
if (timeDiff > 120 && irEnabled > 0 && irrecv) {
if (strip.isUpdating() && timeDiff < 240) return; // be nice, but not too nice
irCheckedTime = currentTime;
if (irrecv->decode(&results)) {
if (results.value != 0) { // only print results if anything is received ( != 0 )
if (!pinManager.isPinAllocated(hardwareTX) || pinManager.getPinOwner(hardwareTX) == PinOwner::DebugOut) // Serial TX pin (GPIO 1 on ESP32 and ESP8266)
Serial.printf_P(PSTR("IR recv: 0x%lX\n"), (unsigned long)results.value);
}
if (irrecv->decode(&results))
{
if (results.value != 0) // only print results if anything is received ( != 0 )
{
if (!pinManager.isPinAllocated(hardwareTX) || pinManager.getPinOwner(hardwareTX) == PinOwner::DebugOut) // Serial TX pin (GPIO 1 on ESP32 and ESP8266)
Serial.printf_P(PSTR("IR recv: 0x%lX\n"), (unsigned long)results.value);
}
decodeIR(results.value);
irrecv->resume();
}
} else if (irrecv != NULL)
{
irrecv->disableIRIn();
delete irrecv; irrecv = NULL;
decodeIR(results.value);
irrecv->resume();
}
}
}

Wyświetl plik

@ -487,6 +487,8 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
}
}
doAdvancePlaylist = root[F("np")] | doAdvancePlaylist; //advances to next preset in playlist when true
JsonObject wifi = root[F("wifi")];
if (!wifi.isNull()) {
bool apMode = getBoolVal(wifi[F("ap")], apActive);

Wyświetl plik

@ -1,197 +1,194 @@
#include "wled.h"
/*
* MQTT communication protocol for home automation
*/
#ifdef WLED_ENABLE_MQTT
#define MQTT_KEEP_ALIVE_TIME 60 // contact the MQTT broker every 60 seconds
void parseMQTTBriPayload(char* payload)
{
if (strstr(payload, "ON") || strstr(payload, "on") || strstr(payload, "true")) {bri = briLast; stateUpdated(CALL_MODE_DIRECT_CHANGE);}
else if (strstr(payload, "T" ) || strstr(payload, "t" )) {toggleOnOff(); stateUpdated(CALL_MODE_DIRECT_CHANGE);}
else {
uint8_t in = strtoul(payload, NULL, 10);
if (in == 0 && bri > 0) briLast = bri;
bri = in;
stateUpdated(CALL_MODE_DIRECT_CHANGE);
}
}
void onMqttConnect(bool sessionPresent)
{
//(re)subscribe to required topics
char subuf[38];
if (mqttDeviceTopic[0] != 0) {
strlcpy(subuf, mqttDeviceTopic, 33);
mqtt->subscribe(subuf, 0);
strcat_P(subuf, PSTR("/col"));
mqtt->subscribe(subuf, 0);
strlcpy(subuf, mqttDeviceTopic, 33);
strcat_P(subuf, PSTR("/api"));
mqtt->subscribe(subuf, 0);
}
if (mqttGroupTopic[0] != 0) {
strlcpy(subuf, mqttGroupTopic, 33);
mqtt->subscribe(subuf, 0);
strcat_P(subuf, PSTR("/col"));
mqtt->subscribe(subuf, 0);
strlcpy(subuf, mqttGroupTopic, 33);
strcat_P(subuf, PSTR("/api"));
mqtt->subscribe(subuf, 0);
}
usermods.onMqttConnect(sessionPresent);
DEBUG_PRINTLN(F("MQTT ready"));
publishMqtt();
}
void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
static char *payloadStr;
DEBUG_PRINT(F("MQTT msg: "));
DEBUG_PRINTLN(topic);
// paranoia check to avoid npe if no payload
if (payload==nullptr) {
DEBUG_PRINTLN(F("no payload -> leave"));
return;
}
if (index == 0) { // start (1st partial packet or the only packet)
if (payloadStr) delete[] payloadStr; // fail-safe: release buffer
payloadStr = new char[total+1]; // allocate new buffer
}
if (payloadStr == nullptr) return; // buffer not allocated
// copy (partial) packet to buffer and 0-terminate it if it is last packet
char* buff = payloadStr + index;
memcpy(buff, payload, len);
if (index + len >= total) { // at end
payloadStr[total] = '\0'; // terminate c style string
} else {
DEBUG_PRINTLN(F("MQTT partial packet received."));
return; // process next packet
}
DEBUG_PRINTLN(payloadStr);
size_t topicPrefixLen = strlen(mqttDeviceTopic);
if (strncmp(topic, mqttDeviceTopic, topicPrefixLen) == 0) {
topic += topicPrefixLen;
} else {
topicPrefixLen = strlen(mqttGroupTopic);
if (strncmp(topic, mqttGroupTopic, topicPrefixLen) == 0) {
topic += topicPrefixLen;
} else {
// Non-Wled Topic used here. Probably a usermod subscribed to this topic.
usermods.onMqttMessage(topic, payloadStr);
delete[] payloadStr;
payloadStr = nullptr;
return;
}
}
//Prefix is stripped from the topic at this point
if (strcmp_P(topic, PSTR("/col")) == 0) {
colorFromDecOrHexString(col, payloadStr);
colorUpdated(CALL_MODE_DIRECT_CHANGE);
} else if (strcmp_P(topic, PSTR("/api")) == 0) {
if (!requestJSONBufferLock(15)) {
delete[] payloadStr;
payloadStr = nullptr;
return;
}
if (payloadStr[0] == '{') { //JSON API
deserializeJson(*pDoc, payloadStr);
deserializeState(pDoc->as<JsonObject>());
} else { //HTTP API
String apireq = "win"; apireq += '&'; // reduce flash string usage
apireq += payloadStr;
handleSet(nullptr, apireq);
}
releaseJSONBufferLock();
} else if (strlen(topic) != 0) {
// non standard topic, check with usermods
usermods.onMqttMessage(topic, payloadStr);
} else {
// topmost topic (just wled/MAC)
parseMQTTBriPayload(payloadStr);
}
delete[] payloadStr;
payloadStr = nullptr;
}
void publishMqtt()
{
if (!WLED_MQTT_CONNECTED) return;
DEBUG_PRINTLN(F("Publish MQTT"));
#ifndef USERMOD_SMARTNEST
char s[10];
char subuf[48];
sprintf_P(s, PSTR("%u"), bri);
strlcpy(subuf, mqttDeviceTopic, 33);
strcat_P(subuf, PSTR("/g"));
mqtt->publish(subuf, 0, retainMqttMsg, s); // optionally retain message (#2263)
sprintf_P(s, PSTR("#%06X"), (col[3] << 24) | (col[0] << 16) | (col[1] << 8) | (col[2]));
strlcpy(subuf, mqttDeviceTopic, 33);
strcat_P(subuf, PSTR("/c"));
mqtt->publish(subuf, 0, retainMqttMsg, s); // optionally retain message (#2263)
strlcpy(subuf, mqttDeviceTopic, 33);
strcat_P(subuf, PSTR("/status"));
mqtt->publish(subuf, 0, true, "online"); // retain message for a LWT
char apires[1024]; // allocating 1024 bytes from stack can be risky
XML_response(nullptr, apires);
strlcpy(subuf, mqttDeviceTopic, 33);
strcat_P(subuf, PSTR("/v"));
mqtt->publish(subuf, 0, retainMqttMsg, apires); // optionally retain message (#2263)
#endif
}
//HA autodiscovery was removed in favor of the native integration in HA v0.102.0
bool initMqtt()
{
if (!mqttEnabled || mqttServer[0] == 0 || !WLED_CONNECTED) return false;
if (mqtt == nullptr) {
mqtt = new AsyncMqttClient();
mqtt->onMessage(onMqttMessage);
mqtt->onConnect(onMqttConnect);
}
if (mqtt->connected()) return true;
DEBUG_PRINTLN(F("Reconnecting MQTT"));
IPAddress mqttIP;
if (mqttIP.fromString(mqttServer)) //see if server is IP or domain
{
mqtt->setServer(mqttIP, mqttPort);
} else {
mqtt->setServer(mqttServer, mqttPort);
}
mqtt->setClientId(mqttClientID);
if (mqttUser[0] && mqttPass[0]) mqtt->setCredentials(mqttUser, mqttPass);
#ifndef USERMOD_SMARTNEST
strlcpy(mqttStatusTopic, mqttDeviceTopic, 33);
strcat_P(mqttStatusTopic, PSTR("/status"));
mqtt->setWill(mqttStatusTopic, 0, true, "offline"); // LWT message
#endif
mqtt->setKeepAlive(MQTT_KEEP_ALIVE_TIME);
mqtt->connect();
return true;
}
#endif
#include "wled.h"
/*
* MQTT communication protocol for home automation
*/
#ifdef WLED_ENABLE_MQTT
#define MQTT_KEEP_ALIVE_TIME 60 // contact the MQTT broker every 60 seconds
void parseMQTTBriPayload(char* payload)
{
if (strstr(payload, "ON") || strstr(payload, "on") || strstr(payload, "true")) {bri = briLast; stateUpdated(CALL_MODE_DIRECT_CHANGE);}
else if (strstr(payload, "T" ) || strstr(payload, "t" )) {toggleOnOff(); stateUpdated(CALL_MODE_DIRECT_CHANGE);}
else {
uint8_t in = strtoul(payload, NULL, 10);
if (in == 0 && bri > 0) briLast = bri;
bri = in;
stateUpdated(CALL_MODE_DIRECT_CHANGE);
}
}
void onMqttConnect(bool sessionPresent)
{
//(re)subscribe to required topics
char subuf[38];
if (mqttDeviceTopic[0] != 0) {
strlcpy(subuf, mqttDeviceTopic, 33);
mqtt->subscribe(subuf, 0);
strcat_P(subuf, PSTR("/col"));
mqtt->subscribe(subuf, 0);
strlcpy(subuf, mqttDeviceTopic, 33);
strcat_P(subuf, PSTR("/api"));
mqtt->subscribe(subuf, 0);
}
if (mqttGroupTopic[0] != 0) {
strlcpy(subuf, mqttGroupTopic, 33);
mqtt->subscribe(subuf, 0);
strcat_P(subuf, PSTR("/col"));
mqtt->subscribe(subuf, 0);
strlcpy(subuf, mqttGroupTopic, 33);
strcat_P(subuf, PSTR("/api"));
mqtt->subscribe(subuf, 0);
}
usermods.onMqttConnect(sessionPresent);
DEBUG_PRINTLN(F("MQTT ready"));
publishMqtt();
}
void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
static char *payloadStr;
DEBUG_PRINT(F("MQTT msg: "));
DEBUG_PRINTLN(topic);
// paranoia check to avoid npe if no payload
if (payload==nullptr) {
DEBUG_PRINTLN(F("no payload -> leave"));
return;
}
if (index == 0) { // start (1st partial packet or the only packet)
if (payloadStr) delete[] payloadStr; // fail-safe: release buffer
payloadStr = new char[total+1]; // allocate new buffer
}
if (payloadStr == nullptr) return; // buffer not allocated
// copy (partial) packet to buffer and 0-terminate it if it is last packet
char* buff = payloadStr + index;
memcpy(buff, payload, len);
if (index + len >= total) { // at end
payloadStr[total] = '\0'; // terminate c style string
} else {
DEBUG_PRINTLN(F("MQTT partial packet received."));
return; // process next packet
}
DEBUG_PRINTLN(payloadStr);
size_t topicPrefixLen = strlen(mqttDeviceTopic);
if (strncmp(topic, mqttDeviceTopic, topicPrefixLen) == 0) {
topic += topicPrefixLen;
} else {
topicPrefixLen = strlen(mqttGroupTopic);
if (strncmp(topic, mqttGroupTopic, topicPrefixLen) == 0) {
topic += topicPrefixLen;
} else {
// Non-Wled Topic used here. Probably a usermod subscribed to this topic.
usermods.onMqttMessage(topic, payloadStr);
delete[] payloadStr;
payloadStr = nullptr;
return;
}
}
//Prefix is stripped from the topic at this point
if (strcmp_P(topic, PSTR("/col")) == 0) {
colorFromDecOrHexString(col, payloadStr);
colorUpdated(CALL_MODE_DIRECT_CHANGE);
} else if (strcmp_P(topic, PSTR("/api")) == 0) {
if (requestJSONBufferLock(15)) {
if (payloadStr[0] == '{') { //JSON API
deserializeJson(*pDoc, payloadStr);
deserializeState(pDoc->as<JsonObject>());
} else { //HTTP API
String apireq = "win"; apireq += '&'; // reduce flash string usage
apireq += payloadStr;
handleSet(nullptr, apireq);
}
releaseJSONBufferLock();
}
} else if (strlen(topic) != 0) {
// non standard topic, check with usermods
usermods.onMqttMessage(topic, payloadStr);
} else {
// topmost topic (just wled/MAC)
parseMQTTBriPayload(payloadStr);
}
delete[] payloadStr;
payloadStr = nullptr;
}
void publishMqtt()
{
if (!WLED_MQTT_CONNECTED) return;
DEBUG_PRINTLN(F("Publish MQTT"));
#ifndef USERMOD_SMARTNEST
char s[10];
char subuf[48];
sprintf_P(s, PSTR("%u"), bri);
strlcpy(subuf, mqttDeviceTopic, 33);
strcat_P(subuf, PSTR("/g"));
mqtt->publish(subuf, 0, retainMqttMsg, s); // optionally retain message (#2263)
sprintf_P(s, PSTR("#%06X"), (col[3] << 24) | (col[0] << 16) | (col[1] << 8) | (col[2]));
strlcpy(subuf, mqttDeviceTopic, 33);
strcat_P(subuf, PSTR("/c"));
mqtt->publish(subuf, 0, retainMqttMsg, s); // optionally retain message (#2263)
strlcpy(subuf, mqttDeviceTopic, 33);
strcat_P(subuf, PSTR("/status"));
mqtt->publish(subuf, 0, true, "online"); // retain message for a LWT
char apires[1024]; // allocating 1024 bytes from stack can be risky
XML_response(nullptr, apires);
strlcpy(subuf, mqttDeviceTopic, 33);
strcat_P(subuf, PSTR("/v"));
mqtt->publish(subuf, 0, retainMqttMsg, apires); // optionally retain message (#2263)
#endif
}
//HA autodiscovery was removed in favor of the native integration in HA v0.102.0
bool initMqtt()
{
if (!mqttEnabled || mqttServer[0] == 0 || !WLED_CONNECTED) return false;
if (mqtt == nullptr) {
mqtt = new AsyncMqttClient();
mqtt->onMessage(onMqttMessage);
mqtt->onConnect(onMqttConnect);
}
if (mqtt->connected()) return true;
DEBUG_PRINTLN(F("Reconnecting MQTT"));
IPAddress mqttIP;
if (mqttIP.fromString(mqttServer)) //see if server is IP or domain
{
mqtt->setServer(mqttIP, mqttPort);
} else {
mqtt->setServer(mqttServer, mqttPort);
}
mqtt->setClientId(mqttClientID);
if (mqttUser[0] && mqttPass[0]) mqtt->setCredentials(mqttUser, mqttPass);
#ifndef USERMOD_SMARTNEST
strlcpy(mqttStatusTopic, mqttDeviceTopic, 33);
strcat_P(mqttStatusTopic, PSTR("/status"));
mqtt->setWill(mqttStatusTopic, 0, true, "offline"); // LWT message
#endif
mqtt->setKeepAlive(MQTT_KEEP_ALIVE_TIME);
mqtt->connect();
return true;
}
#endif

Wyświetl plik

@ -25,11 +25,11 @@ void _overlayAnalogClock()
{
if (secondPixel < analogClock12pixel)
{
strip.setRange(analogClock12pixel, overlayMax, 0xFF0000);
strip.setRange(overlayMin, secondPixel, 0xFF0000);
strip.setRange(analogClock12pixel, overlayMax, color_fade(0xFF0000, bri));
strip.setRange(overlayMin, secondPixel, color_fade(0xFF0000, bri));
} else
{
strip.setRange(analogClock12pixel, secondPixel, 0xFF0000);
strip.setRange(analogClock12pixel, secondPixel, color_fade(0xFF0000, bri));
}
}
if (analogClock5MinuteMarks)
@ -38,12 +38,12 @@ void _overlayAnalogClock()
{
unsigned pix = analogClock12pixel + roundf((overlaySize / 12.0f) *i);
if (pix > overlayMax) pix -= overlaySize;
strip.setPixelColor(pix, 0x00FFAA);
strip.setPixelColor(pix, color_fade(0x00FFAA, bri));
}
}
if (!analogClockSecondsTrail) strip.setPixelColor(secondPixel, 0xFF0000);
strip.setPixelColor(minutePixel, 0x00FF00);
strip.setPixelColor(hourPixel, 0x0000FF);
if (!analogClockSecondsTrail) strip.setPixelColor(secondPixel, color_fade(0xFF0000, bri));
strip.setPixelColor(minutePixel, color_fade(0x00FF00, bri));
strip.setPixelColor(hourPixel, color_fade(0x0000FF, bri));
}

Wyświetl plik

@ -127,7 +127,7 @@ void handlePlaylist() {
static unsigned long presetCycledTime = 0;
if (currentPlaylist < 0 || playlistEntries == nullptr) return;
if (millis() - presetCycledTime > (100*playlistEntryDur)) {
if (millis() - presetCycledTime > (100 * playlistEntryDur) || doAdvancePlaylist) {
presetCycledTime = millis();
if (bri == 0 || nightlightActive) return;
@ -149,6 +149,7 @@ void handlePlaylist() {
strip.setTransition(fadeTransition ? playlistEntries[playlistIndex].tr * 100 : 0);
playlistEntryDur = playlistEntries[playlistIndex].dur;
applyPresetFromPlaylist(playlistEntries[playlistIndex].preset);
doAdvancePlaylist = false;
}
}

Wyświetl plik

@ -104,7 +104,8 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
}
#ifndef WLED_DISABLE_INFRARED
if (irPin>=0 && pinManager.isPinAllocated(irPin, PinOwner::IR)) {
pinManager.deallocatePin(irPin, PinOwner::IR);
deInitIR();
pinManager.deallocatePin(irPin, PinOwner::IR);
}
#endif
for (uint8_t s=0; s<WLED_MAX_BUTTONS; s++) {
@ -233,6 +234,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
irPin = -1;
}
irEnabled = request->arg(F("IT")).toInt();
initIR();
#endif
irApplyToAllSelected = !request->hasArg(F("MSO"));
@ -901,6 +903,9 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
applyPreset(presetCycCurr);
}
pos = req.indexOf(F("NP")); //advances to next preset in a playlist
if (pos > 0) doAdvancePlaylist = true;
//set brightness
updateVal(req.c_str(), "&A=", &bri);

Wyświetl plik

@ -505,6 +505,13 @@ void WLED::setup()
initServer();
DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap());
#ifndef WLED_DISABLE_INFRARED
// init IR
DEBUG_PRINTLN(F("initIR"));
initIR();
DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap());
#endif
// Seed FastLED random functions with an esp random value, which already works properly at this point.
#if defined(ARDUINO_ARCH_ESP32)
const uint32_t seed32 = esp_random();

Wyświetl plik

@ -8,7 +8,7 @@
*/
// version code in format yymmddb (b = daily build)
#define VERSION 2404120
#define VERSION 2405030
//uncomment this if you have a "my_config.h" file you'd like to use
//#define WLED_USE_MY_CONFIG
@ -594,7 +594,6 @@ WLED_GLOBAL bool buttonPressedBefore[WLED_MAX_BUTTONS] _INIT({false});
WLED_GLOBAL bool buttonLongPressed[WLED_MAX_BUTTONS] _INIT({false});
WLED_GLOBAL unsigned long buttonPressedTime[WLED_MAX_BUTTONS] _INIT({0});
WLED_GLOBAL unsigned long buttonWaitTime[WLED_MAX_BUTTONS] _INIT({0});
WLED_GLOBAL bool buttonBriDirection _INIT(false);
WLED_GLOBAL bool disablePullUp _INIT(false);
WLED_GLOBAL byte touchThreshold _INIT(TOUCH_THRESHOLD);
@ -646,6 +645,7 @@ WLED_GLOBAL byte timerWeekday[] _INIT_N(({ 255, 255, 255, 255, 255, 255, 255,
WLED_GLOBAL byte timerMonth[] _INIT_N(({28,28,28,28,28,28,28,28}));
WLED_GLOBAL byte timerDay[] _INIT_N(({1,1,1,1,1,1,1,1}));
WLED_GLOBAL byte timerDayEnd[] _INIT_N(({31,31,31,31,31,31,31,31}));
WLED_GLOBAL bool doAdvancePlaylist _INIT(false);
//improv
WLED_GLOBAL byte improvActive _INIT(0); //0: no improv packet received, 1: improv active, 2: provisioning