1st attempt at 'blazoncek' 0.12
This commit is contained in:
parent
5c6cb41124
commit
77dee439e6
@ -395,41 +395,12 @@ uint16_t WS2812FX::mode_rainbow_cycle(void) {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* theater chase function
|
||||
*/
|
||||
uint16_t WS2812FX::theater_chase(uint32_t color1, uint32_t color2, bool do_palette) {
|
||||
byte gap = 2 + ((255 - SEGMENT.intensity) >> 5);
|
||||
uint32_t cycleTime = 50 + (255 - SEGMENT.speed)*2;
|
||||
uint32_t it = now / cycleTime;
|
||||
if (it != SEGENV.step) //new color
|
||||
{
|
||||
SEGENV.aux0 = (SEGENV.aux0 +1) % gap;
|
||||
SEGENV.step = it;
|
||||
}
|
||||
|
||||
for(uint16_t i = 0; i < SEGLEN; i++) {
|
||||
if((i % gap) == SEGENV.aux0) {
|
||||
if (do_palette)
|
||||
{
|
||||
setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
|
||||
} else {
|
||||
setPixelColor(i, color1);
|
||||
}
|
||||
} else {
|
||||
setPixelColor(i, color2);
|
||||
}
|
||||
}
|
||||
return FRAMETIME;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Theatre-style crawling lights.
|
||||
* Inspired by the Adafruit examples.
|
||||
*/
|
||||
uint16_t WS2812FX::mode_theater_chase(void) {
|
||||
return theater_chase(SEGCOLOR(0), SEGCOLOR(1), true);
|
||||
return running(SEGCOLOR(0), SEGCOLOR(1), true);
|
||||
}
|
||||
|
||||
|
||||
@ -438,7 +409,7 @@ uint16_t WS2812FX::mode_theater_chase(void) {
|
||||
* Inspired by the Adafruit examples.
|
||||
*/
|
||||
uint16_t WS2812FX::mode_theater_chase_rainbow(void) {
|
||||
return theater_chase(color_wheel(SEGENV.step), SEGCOLOR(1), false);
|
||||
return running(color_wheel(SEGENV.step), SEGCOLOR(1), true);
|
||||
}
|
||||
|
||||
|
||||
@ -966,29 +937,27 @@ uint16_t WS2812FX::mode_chase_flash_random(void) {
|
||||
/*
|
||||
* Alternating pixels running function.
|
||||
*/
|
||||
uint16_t WS2812FX::running(uint32_t color1, uint32_t color2) {
|
||||
uint8_t pxw = 1 + (SEGMENT.intensity >> 5);
|
||||
uint32_t cycleTime = 35 + (255 - SEGMENT.speed);
|
||||
uint16_t WS2812FX::running(uint32_t color1, uint32_t color2, bool theatre) {
|
||||
uint8_t width = (theatre ? 3 : 1) + (SEGMENT.intensity >> 4); // window
|
||||
uint32_t cycleTime = 50 + (255 - SEGMENT.speed);
|
||||
uint32_t it = now / cycleTime;
|
||||
if (SEGMENT.speed == 0) it = 0;
|
||||
bool usePalette = color1 == SEGCOLOR(0);
|
||||
|
||||
for(uint16_t i = 0; i < SEGLEN; i++) {
|
||||
if((i + SEGENV.aux0) % (pxw*2) < pxw) {
|
||||
if (color1 == SEGCOLOR(0))
|
||||
{
|
||||
setPixelColor(SEGLEN -i -1, color_from_palette(SEGLEN -i -1, true, PALETTE_SOLID_WRAP, 0));
|
||||
} else
|
||||
{
|
||||
setPixelColor(SEGLEN -i -1, color1);
|
||||
}
|
||||
uint32_t col = color2;
|
||||
if (usePalette) color1 = color_from_palette(i, true, PALETTE_SOLID_WRAP, 0);
|
||||
if (theatre) {
|
||||
if ((i % width) == SEGENV.aux0) col = color1;
|
||||
} else {
|
||||
setPixelColor(SEGLEN -i -1, color2);
|
||||
int8_t pos = (i % (width<<1));
|
||||
if ((pos < SEGENV.aux0-width) || ((pos >= SEGENV.aux0) && (pos < SEGENV.aux0+width))) col = color1;
|
||||
}
|
||||
setPixelColor(i,col);
|
||||
}
|
||||
|
||||
if (it != SEGENV.step )
|
||||
{
|
||||
SEGENV.aux0 = (SEGENV.aux0 +1) % (pxw*2);
|
||||
SEGENV.aux0 = (SEGENV.aux0 +1) % (theatre ? width : (width<<1));
|
||||
SEGENV.step = it;
|
||||
}
|
||||
return FRAMETIME;
|
||||
@ -1778,7 +1747,7 @@ uint16_t WS2812FX::mode_fire_2012()
|
||||
// Step 1. Cool down every cell a little
|
||||
for (uint16_t i = 0; i < SEGLEN; i++) {
|
||||
uint8_t temp = qsub8(heat[i], random8(0, (((20 + SEGMENT.speed /3) * 10) / SEGLEN) + 2));
|
||||
heat[i] = (temp==0 && i<ignition) ? 2 : temp; // prevent ignition area from becoming black
|
||||
heat[i] = (temp==0 && i<ignition) ? 16 : temp; // prevent ignition area from becoming black
|
||||
}
|
||||
|
||||
// Step 2. Heat from each cell drifts 'up' and diffuses a little
|
||||
@ -1993,7 +1962,7 @@ uint16_t WS2812FX::mode_colortwinkle()
|
||||
|
||||
if (fadeUp) {
|
||||
CRGB incrementalColor = fastled_col;
|
||||
incrementalColor.nscale8_video( fadeUpAmount);
|
||||
incrementalColor.nscale8_video(fadeUpAmount);
|
||||
fastled_col += incrementalColor;
|
||||
|
||||
if (fastled_col.red == 255 || fastled_col.green == 255 || fastled_col.blue == 255) {
|
||||
@ -2001,24 +1970,21 @@ uint16_t WS2812FX::mode_colortwinkle()
|
||||
}
|
||||
setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
|
||||
|
||||
if (col_to_crgb(getPixelColor(i)) == prev) //fix "stuck" pixels
|
||||
{
|
||||
if (col_to_crgb(getPixelColor(i)) == prev) { //fix "stuck" pixels
|
||||
fastled_col += fastled_col;
|
||||
setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
|
||||
}
|
||||
} else {
|
||||
fastled_col.nscale8( 255 - fadeDownAmount);
|
||||
fastled_col.nscale8(255 - fadeDownAmount);
|
||||
setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue);
|
||||
}
|
||||
}
|
||||
|
||||
for (uint16_t j = 0; j <= SEGLEN / 50; j++)
|
||||
{
|
||||
for (uint16_t j = 0; j <= SEGLEN / 50; j++) {
|
||||
if (random8() <= SEGMENT.intensity) {
|
||||
for (uint8_t times = 0; times < 5; times++) //attempt to spawn a new pixel 5 times
|
||||
{
|
||||
for (uint8_t times = 0; times < 5; times++) { //attempt to spawn a new pixel 5 times
|
||||
int i = random16(SEGLEN);
|
||||
if(getPixelColor(i) == 0) {
|
||||
if (getPixelColor(i) == 0) {
|
||||
fastled_col = ColorFromPalette(currentPalette, random8(), 64, NOBLEND);
|
||||
uint16_t index = i >> 3;
|
||||
uint8_t bitNum = i & 0x07;
|
||||
@ -2650,7 +2616,7 @@ uint16_t WS2812FX::mode_sinelon_dual(void) {
|
||||
}
|
||||
|
||||
uint16_t WS2812FX::mode_sinelon_rainbow(void) {
|
||||
return sinelon_base(true, true);
|
||||
return sinelon_base(false, true);
|
||||
}
|
||||
|
||||
|
||||
@ -2955,7 +2921,7 @@ uint16_t WS2812FX::mode_starburst(void) {
|
||||
uint16_t WS2812FX::mode_exploding_fireworks(void)
|
||||
{
|
||||
//allocate segment data
|
||||
uint16_t numSparks = 2 + (SEGLEN >> 1);
|
||||
uint16_t numSparks = 2 + (SEGLEN >> 2);
|
||||
if (numSparks > 80) numSparks = 80;
|
||||
uint16_t dataSize = sizeof(spark) * numSparks;
|
||||
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
||||
@ -3051,7 +3017,7 @@ uint16_t WS2812FX::mode_exploding_fireworks(void)
|
||||
SEGENV.aux0--;
|
||||
if (SEGENV.aux0 < 4) {
|
||||
SEGENV.aux0 = 0; //back to flare
|
||||
SEGENV.step = (SEGMENT.intensity > random8()); //decide firing side
|
||||
SEGENV.step = actuallyReverse ^ (SEGMENT.intensity > random8()); //decide firing side
|
||||
}
|
||||
}
|
||||
|
||||
@ -3162,7 +3128,7 @@ uint16_t WS2812FX::mode_tetrix(void) {
|
||||
|
||||
if (SEGENV.step == 0) { //init
|
||||
drop->speed = 0.0238 * (SEGMENT.speed ? (SEGMENT.speed>>3)+1 : random8(6,40)); // set speed
|
||||
drop->pos = SEGLEN-1; // start at end of segment
|
||||
drop->pos = SEGLEN; // start at end of segment (no need to subtract 1)
|
||||
drop->col = color_from_palette(random8(0,15)<<4,false,false,0); // limit color choices so there is enough HUE gap
|
||||
SEGENV.step = 1; // drop state (0 init, 1 forming, 2 falling)
|
||||
SEGENV.aux0 = (SEGMENT.intensity ? (SEGMENT.intensity>>5)+1 : random8(1,5)) * (1+(SEGLEN>>6)); // size of brick
|
||||
@ -3194,8 +3160,8 @@ uint16_t WS2812FX::mode_tetrix(void) {
|
||||
/ adapted from https://github.com/atuline/FastLED-Demos/blob/master/plasma/plasma.ino
|
||||
*/
|
||||
uint16_t WS2812FX::mode_plasma(void) {
|
||||
uint8_t thisPhase = beatsin8(6,-64,64); // Setting phase change for a couple of waves.
|
||||
uint8_t thatPhase = beatsin8(7,-64,64);
|
||||
uint8_t thisPhase = beatsin8(6+_segment_index%3,-64,64); // Setting phase change for a couple of waves.
|
||||
uint8_t thatPhase = beatsin8(7+_segment_index%3,-64,64);
|
||||
|
||||
for (int i = 0; i < SEGLEN; i++) { // For each of the LED's in the strand, set color & brightness based on a wave as follows:
|
||||
uint8_t colorIndex = cubicwave8((i*(1+ 3*(SEGMENT.speed >> 5)))+(thisPhase) & 0xFF)/2 // factor=23 // Create a wave and add a phase change and add another wave with its own phase change.
|
||||
@ -3634,7 +3600,7 @@ uint16_t WS2812FX::mode_chunchun(void)
|
||||
for (uint16_t i = 0; i < numBirds; i++)
|
||||
{
|
||||
counter -= span/numBirds;
|
||||
int megumin = sin16(counter) + 0x8000;
|
||||
uint16_t megumin = sin16(counter) + 0x8000;
|
||||
uint32_t bird = (megumin * SEGLEN) >> 16;
|
||||
uint32_t c = color_from_palette((i * 255)/ numBirds, false, true, 0);
|
||||
setPixelColor(bird, c);
|
||||
|
23
wled00/FX.h
23
wled00/FX.h
@ -24,8 +24,6 @@
|
||||
Modified for WLED
|
||||
*/
|
||||
|
||||
#include "wled.h"
|
||||
|
||||
#ifndef WS2812FX_h
|
||||
#define WS2812FX_h
|
||||
|
||||
@ -58,11 +56,11 @@
|
||||
/* each segment uses 52 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 12
|
||||
#define MAX_NUM_SEGMENTS 13
|
||||
/* How many color transitions can run at once */
|
||||
#define MAX_NUM_TRANSITIONS 8
|
||||
/* How much data bytes all segments combined may allocate */
|
||||
#define MAX_SEGMENT_DATA 2048
|
||||
#define MAX_SEGMENT_DATA 2560
|
||||
#else
|
||||
#define MAX_NUM_SEGMENTS 16
|
||||
#define MAX_NUM_TRANSITIONS 16
|
||||
@ -584,7 +582,7 @@ class WS2812FX {
|
||||
}
|
||||
|
||||
void
|
||||
finalizeInit(bool supportWhite, uint16_t countPixels, bool skipFirst),
|
||||
finalizeInit(void),
|
||||
service(void),
|
||||
blur(uint8_t),
|
||||
fill(uint32_t),
|
||||
@ -609,7 +607,6 @@ class WS2812FX {
|
||||
setPixelSegment(uint8_t n);
|
||||
|
||||
bool
|
||||
reverseMode = false, //is the entire LED strip reversed?
|
||||
gammaCorrectBri = false,
|
||||
gammaCorrectCol = true,
|
||||
applyToAllSelected = true,
|
||||
@ -624,8 +621,6 @@ class WS2812FX {
|
||||
paletteFade = 0,
|
||||
paletteBlend = 0,
|
||||
milliampsPerLed = 55,
|
||||
// getStripType(uint8_t strip=0),
|
||||
// setStripType(uint8_t type, uint8_t strip=0),
|
||||
getBrightness(void),
|
||||
getMode(void),
|
||||
getSpeed(void),
|
||||
@ -640,17 +635,11 @@ class WS2812FX {
|
||||
get_random_wheel_index(uint8_t);
|
||||
|
||||
int8_t
|
||||
// setStripPin(uint8_t strip, int8_t pin),
|
||||
// getStripPin(uint8_t strip=0),
|
||||
// setStripPinClk(uint8_t strip, int8_t pin),
|
||||
// getStripPinClk(uint8_t strip=0),
|
||||
tristate_square8(uint8_t x, uint8_t pulsewidth, uint8_t attdec);
|
||||
|
||||
uint16_t
|
||||
ablMilliampsMax,
|
||||
currentMilliamps,
|
||||
// setStripLen(uint8_t strip, uint16_t len),
|
||||
// getStripLen(uint8_t strip=0),
|
||||
triwave16(uint16_t),
|
||||
getFps();
|
||||
|
||||
@ -803,7 +792,7 @@ class WS2812FX {
|
||||
CRGBPalette16 currentPalette;
|
||||
CRGBPalette16 targetPalette;
|
||||
|
||||
uint16_t _length, _lengthRaw, _virtualSegmentLength;
|
||||
uint16_t _length, _virtualSegmentLength;
|
||||
uint16_t _rand16seed;
|
||||
uint8_t _brightness;
|
||||
uint16_t _usedSegmentData = 0;
|
||||
@ -816,7 +805,6 @@ class WS2812FX {
|
||||
|
||||
bool
|
||||
_useRgbw = false,
|
||||
_skipFirstMode,
|
||||
_triggered;
|
||||
|
||||
mode_ptr _mode[MODE_COUNT]; // SRAM footprint: 4 bytes per element
|
||||
@ -830,7 +818,6 @@ class WS2812FX {
|
||||
color_wipe(bool, bool),
|
||||
dynamic(bool),
|
||||
scan(bool),
|
||||
theater_chase(uint32_t, uint32_t, bool),
|
||||
running_base(bool),
|
||||
larson_scanner(bool),
|
||||
sinelon_base(bool,bool),
|
||||
@ -839,7 +826,7 @@ class WS2812FX {
|
||||
gradient_base(bool),
|
||||
ripple_base(bool),
|
||||
police_base(uint32_t, uint32_t, bool),
|
||||
running(uint32_t, uint32_t),
|
||||
running(uint32_t, uint32_t, bool theatre=false),
|
||||
tricolor_chase(uint32_t, uint32_t),
|
||||
twinklefox_base(bool),
|
||||
spots_base(uint16_t),
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
Modified heavily for WLED
|
||||
*/
|
||||
|
||||
#include "wled.h"
|
||||
#include "FX.h"
|
||||
#include "palettes.h"
|
||||
|
||||
@ -44,34 +44,41 @@
|
||||
another example. Switches direction every 5 LEDs.
|
||||
{"map":[
|
||||
0, 1, 2, 3, 4, 9, 8, 7, 6, 5, 10, 11, 12, 13, 14,
|
||||
19, 18, 17, 16, 15, 20, 21, 22, 23, 24, 29, 28, 27, 26, 25]
|
||||
19, 18, 17, 16, 15, 20, 21, 22, 23, 24, 29, 28, 27, 26, 25]}
|
||||
*/
|
||||
|
||||
//do not call this method from system context (network callback)
|
||||
void WS2812FX::finalizeInit(bool supportWhite, uint16_t countPixels, bool skipFirst)
|
||||
void WS2812FX::finalizeInit(void)
|
||||
{
|
||||
if (supportWhite == _useRgbw && countPixels == _length && _skipFirstMode == skipFirst) return;
|
||||
RESET_RUNTIME;
|
||||
_useRgbw = supportWhite;
|
||||
_length = countPixels;
|
||||
_skipFirstMode = skipFirst;
|
||||
|
||||
_lengthRaw = _length;
|
||||
if (_skipFirstMode) {
|
||||
_lengthRaw += LED_SKIP_AMOUNT;
|
||||
}
|
||||
_useRgbw = false;
|
||||
|
||||
//if busses failed to load, add default (FS issue...)
|
||||
if (busses.getNumBusses() == 0) {
|
||||
uint8_t defPin[] = {LEDPIN};
|
||||
BusConfig defCfg = BusConfig(TYPE_WS2812_RGB, defPin, 0, _lengthRaw, COL_ORDER_GRB);
|
||||
BusConfig defCfg = BusConfig(TYPE_WS2812_RGB, defPin, 0, 30, COL_ORDER_GRB, false, false);
|
||||
busses.add(defCfg);
|
||||
}
|
||||
|
||||
deserializeMap();
|
||||
|
||||
_segments[0].start = 0;
|
||||
_segments[0].stop = _length;
|
||||
_length = 0;
|
||||
for (uint8_t i=0; i<busses.getNumBusses(); i++) {
|
||||
Bus *bus = busses.getBus(i);
|
||||
if (bus == nullptr) continue;
|
||||
_useRgbw |= bus->isRgbw();
|
||||
_segments[i].start = bus->getStart();
|
||||
_length += bus->getLength();
|
||||
_segments[i].stop = _segments[i].start + bus->getLength();
|
||||
_segments[i].mode = DEFAULT_MODE;
|
||||
_segments[i].colors[0] = DEFAULT_COLOR;
|
||||
_segments[i].speed = DEFAULT_SPEED;
|
||||
_segments[i].intensity = DEFAULT_INTENSITY;
|
||||
_segments[i].grouping = 1;
|
||||
_segments[i].setOption(SEG_OPTION_SELECTED, 1);
|
||||
_segments[i].setOption(SEG_OPTION_ON, 1);
|
||||
_segments[i].opacity = 255;
|
||||
}
|
||||
|
||||
setBrightness(_brightness);
|
||||
|
||||
@ -154,16 +161,13 @@ uint16_t WS2812FX::realPixelIndex(uint16_t i) {
|
||||
int16_t realIndex = iGroup;
|
||||
if (IS_REVERSE) {
|
||||
if (IS_MIRROR) {
|
||||
realIndex = (SEGMENT.length() -1) / 2 - iGroup; //only need to index half the pixels
|
||||
realIndex = (SEGMENT.length() - 1) / 2 - iGroup; //only need to index half the pixels
|
||||
} else {
|
||||
realIndex = SEGMENT.length() - iGroup - 1;
|
||||
realIndex = (SEGMENT.length() - 1) - iGroup;
|
||||
}
|
||||
}
|
||||
|
||||
realIndex += SEGMENT.start;
|
||||
/* Reverse the whole string */
|
||||
if (reverseMode) realIndex = REV(realIndex);
|
||||
|
||||
return realIndex;
|
||||
}
|
||||
|
||||
@ -183,9 +187,7 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t skip = _skipFirstMode ? LED_SKIP_AMOUNT : 0;
|
||||
if (SEGLEN) {//from segment
|
||||
|
||||
//color_blend(getpixel, col, _bri_t); (pseudocode for future blending of segments)
|
||||
if (_bri_t < 255) {
|
||||
r = scale8(r, _bri_t);
|
||||
@ -195,37 +197,25 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
|
||||
}
|
||||
uint32_t col = ((w << 24) | (r << 16) | (g << 8) | (b));
|
||||
|
||||
/* Set all the pixels in the group, ensuring _skipFirstMode is honored */
|
||||
bool reversed = reverseMode ^ IS_REVERSE;
|
||||
/* Set all the pixels in the group */
|
||||
uint16_t realIndex = realPixelIndex(i);
|
||||
|
||||
for (uint16_t j = 0; j < SEGMENT.grouping; j++) {
|
||||
int16_t indexSet = realIndex + (reversed ? -j : j);
|
||||
int16_t indexSetRev = indexSet;
|
||||
if (reverseMode) indexSetRev = REV(indexSet);
|
||||
if (indexSet < customMappingSize) indexSet = customMappingTable[indexSet];
|
||||
if (indexSetRev >= SEGMENT.start && indexSetRev < SEGMENT.stop) {
|
||||
busses.setPixelColor(indexSet + skip, col);
|
||||
int16_t indexSet = realIndex + (IS_REVERSE ? -j : j);
|
||||
if (indexSet >= SEGMENT.start && indexSet < SEGMENT.stop) { // watch for group out of bounds condition
|
||||
if (IS_MIRROR) { //set the corresponding mirrored pixel
|
||||
if (reverseMode) {
|
||||
busses.setPixelColor(REV(SEGMENT.start) - indexSet + skip + REV(SEGMENT.stop) + 1, col);
|
||||
} else {
|
||||
busses.setPixelColor(SEGMENT.stop - indexSet + skip + SEGMENT.start - 1, col);
|
||||
}
|
||||
int16_t indexSetRev = SEGMENT.stop + SEGMENT.start - indexSet - 1;
|
||||
if (indexSetRev < customMappingSize) indexSetRev = customMappingTable[indexSetRev];
|
||||
busses.setPixelColor(indexSetRev, col);
|
||||
}
|
||||
if (indexSet < customMappingSize) indexSet = customMappingTable[indexSet];
|
||||
busses.setPixelColor(indexSet, col);
|
||||
}
|
||||
}
|
||||
} else { //live data, etc.
|
||||
if (reverseMode) i = REV(i);
|
||||
if (i < customMappingSize) i = customMappingTable[i];
|
||||
|
||||
uint32_t col = ((w << 24) | (r << 16) | (g << 8) | (b));
|
||||
busses.setPixelColor(i + skip, col);
|
||||
}
|
||||
if (skip && i == 0) {
|
||||
for (uint16_t j = 0; j < skip; j++) {
|
||||
busses.setPixelColor(j, BLACK);
|
||||
}
|
||||
busses.setPixelColor(i, col);
|
||||
}
|
||||
}
|
||||
|
||||
@ -498,11 +488,9 @@ uint32_t WS2812FX::getPixelColor(uint16_t i)
|
||||
i = realPixelIndex(i);
|
||||
|
||||
if (i < customMappingSize) i = customMappingTable[i];
|
||||
if (i >= _length) return 0;
|
||||
|
||||
if (_skipFirstMode) i += LED_SKIP_AMOUNT;
|
||||
|
||||
if (i >= _lengthRaw) return 0;
|
||||
|
||||
// TODO: may need to add IS_REVERSE and IS_MIRROR logic
|
||||
return busses.getPixelColor(i);
|
||||
}
|
||||
|
||||
|
16
wled00/NodeStruct.cpp
Normal file
16
wled00/NodeStruct.cpp
Normal file
@ -0,0 +1,16 @@
|
||||
#include "NodeStruct.h"
|
||||
|
||||
String getNodeTypeDisplayString(uint8_t nodeType) {
|
||||
switch (nodeType)
|
||||
{
|
||||
case NODE_TYPE_ID_ESP8266: return F("ESP8266");
|
||||
case NODE_TYPE_ID_ESP32: return F("ESP32");
|
||||
}
|
||||
return "Undefined";
|
||||
}
|
||||
|
||||
NodeStruct::NodeStruct() :
|
||||
age(0), nodeType(0)
|
||||
{
|
||||
for (uint8_t i = 0; i < 4; ++i) { ip[i] = 0; }
|
||||
}
|
33
wled00/NodeStruct.h
Normal file
33
wled00/NodeStruct.h
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef DATASTRUCTS_NODESTRUCT_H
|
||||
#define DATASTRUCTS_NODESTRUCT_H
|
||||
|
||||
/*********************************************************************************************\
|
||||
* NodeStruct from the ESP Easy project (https://github.com/letscontrolit/ESPEasy)
|
||||
\*********************************************************************************************/
|
||||
|
||||
#include <map>
|
||||
#include <IPAddress.h>
|
||||
|
||||
|
||||
#define NODE_TYPE_ID_UNDEFINED 0
|
||||
#define NODE_TYPE_ID_ESP8266 1
|
||||
#define NODE_TYPE_ID_ESP32 2
|
||||
|
||||
String getNodeTypeDisplayString(uint8_t nodeType);
|
||||
|
||||
/*********************************************************************************************\
|
||||
* NodeStruct
|
||||
\*********************************************************************************************/
|
||||
struct NodeStruct
|
||||
{
|
||||
NodeStruct();
|
||||
|
||||
String nodeName;
|
||||
IPAddress ip;
|
||||
uint8_t unit;
|
||||
uint8_t age;
|
||||
uint8_t nodeType;
|
||||
};
|
||||
typedef std::map<uint8_t, NodeStruct> NodesMap;
|
||||
|
||||
#endif // DATASTRUCTS_NODESTRUCT_H
|
@ -17,12 +17,14 @@ struct BusConfig {
|
||||
uint16_t start = 0;
|
||||
uint8_t colorOrder = COL_ORDER_GRB;
|
||||
bool reversed = false;
|
||||
bool skipFirst = false;
|
||||
uint8_t pins[5] = {LEDPIN, 255, 255, 255, 255};
|
||||
BusConfig(uint8_t busType, uint8_t* ppins, uint16_t pstart, uint16_t len = 1, uint8_t pcolorOrder = COL_ORDER_GRB, bool rev = false) {
|
||||
type = busType; count = len; start = pstart; colorOrder = pcolorOrder; reversed = rev;
|
||||
BusConfig(uint8_t busType, uint8_t* ppins, uint16_t pstart, uint16_t len = 1, uint8_t pcolorOrder = COL_ORDER_GRB, bool rev = false, bool skip = false) {
|
||||
type = busType; count = len; start = pstart; colorOrder = pcolorOrder; reversed = rev; skipFirst = skip;
|
||||
uint8_t nPins = 1;
|
||||
if (type > 47) nPins = 2;
|
||||
else if (type > 41 && type < 46) nPins = NUM_PWM_PINS(type);
|
||||
// bit 7 is hacked to include RGBW info (1=RGBW, 0=RGB)
|
||||
if ((type&0x7F) > 47) nPins = 2;
|
||||
else if ((type&0x7F) > 41 && (type&0x7F) < 46) nPins = NUM_PWM_PINS((type&0x7F));
|
||||
for (uint8_t i = 0; i < nPins; i++) pins[i] = ppins[i];
|
||||
}
|
||||
};
|
||||
@ -61,7 +63,7 @@ class Bus {
|
||||
}
|
||||
|
||||
virtual uint16_t getLength() {
|
||||
return 1;
|
||||
return 1; // is this ok? shouldn't it be 0 in virtual function?
|
||||
}
|
||||
|
||||
virtual void setColorOrder() {}
|
||||
@ -70,6 +72,10 @@ class Bus {
|
||||
return COL_ORDER_RGB;
|
||||
}
|
||||
|
||||
virtual bool isRgbw() {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t getType() {
|
||||
return _type;
|
||||
}
|
||||
@ -90,19 +96,22 @@ class Bus {
|
||||
|
||||
class BusDigital : public Bus {
|
||||
public:
|
||||
BusDigital(BusConfig &bc, uint8_t nr) : Bus(bc.type, bc.start) {
|
||||
if (!IS_DIGITAL(bc.type) || !bc.count) return;
|
||||
BusDigital(BusConfig &bc, uint8_t nr) : Bus(bc.type&0x7F, bc.start) {
|
||||
uint8_t type = bc.type & 0x7F; // bit 7 is hacked to include RGBW info
|
||||
if (!IS_DIGITAL(type) || !bc.count) return;
|
||||
_pins[0] = bc.pins[0];
|
||||
if (!pinManager.allocatePin(_pins[0])) return;
|
||||
if (IS_2PIN(bc.type)) {
|
||||
if (IS_2PIN(type)) {
|
||||
_pins[1] = bc.pins[1];
|
||||
if (!pinManager.allocatePin(_pins[1])) {
|
||||
cleanup(); return;
|
||||
}
|
||||
}
|
||||
_len = bc.count;
|
||||
_skip = bc.skipFirst ? LED_SKIP_AMOUNT : 0; //sacrificial pixels
|
||||
_len = bc.count + _skip;
|
||||
reversed = bc.reversed;
|
||||
_iType = PolyBus::getI(bc.type, _pins, nr);
|
||||
_rgbw = (bool)((bc.type>>7) & 0x01); // RGBW override in bit 7
|
||||
_iType = PolyBus::getI(type, _pins, nr, _rgbw);
|
||||
if (_iType == I_NONE) return;
|
||||
_busPtr = PolyBus::create(_iType, _pins, _len);
|
||||
_valid = (_busPtr != nullptr);
|
||||
@ -131,11 +140,13 @@ class BusDigital : public Bus {
|
||||
|
||||
void setPixelColor(uint16_t pix, uint32_t c) {
|
||||
if (reversed) pix = _len - pix -1;
|
||||
pix += _skip;
|
||||
PolyBus::setPixelColor(_busPtr, _iType, pix, c, _colorOrder);
|
||||
}
|
||||
|
||||
uint32_t getPixelColor(uint16_t pix) {
|
||||
if (reversed) pix = _len - pix -1;
|
||||
pix += _skip;
|
||||
return PolyBus::getPixelColor(_busPtr, _iType, pix, _colorOrder);
|
||||
}
|
||||
|
||||
@ -144,7 +155,7 @@ class BusDigital : public Bus {
|
||||
}
|
||||
|
||||
uint16_t getLength() {
|
||||
return _len;
|
||||
return _len - _skip;
|
||||
}
|
||||
|
||||
uint8_t getPins(uint8_t* pinArray) {
|
||||
@ -158,6 +169,10 @@ class BusDigital : public Bus {
|
||||
_colorOrder = colorOrder;
|
||||
}
|
||||
|
||||
bool isRgbw() {
|
||||
return _rgbw;
|
||||
}
|
||||
|
||||
void reinit() {
|
||||
PolyBus::begin(_busPtr, _iType, _pins);
|
||||
}
|
||||
@ -181,6 +196,8 @@ class BusDigital : public Bus {
|
||||
uint8_t _pins[2] = {255, 255};
|
||||
uint8_t _iType = I_NONE;
|
||||
uint16_t _len = 0;
|
||||
uint8_t _skip = 0;
|
||||
bool _rgbw = false;
|
||||
void * _busPtr = nullptr;
|
||||
};
|
||||
|
||||
@ -264,6 +281,10 @@ class BusPwm : public Bus {
|
||||
return numPins;
|
||||
}
|
||||
|
||||
bool isRgbw() {
|
||||
return (_type > TYPE_ONOFF && _type <= TYPE_ANALOG_5CH && _type != TYPE_ANALOG_3CH);
|
||||
}
|
||||
|
||||
void cleanup() {
|
||||
deallocatePins();
|
||||
}
|
||||
@ -305,8 +326,9 @@ class BusManager {
|
||||
} else {
|
||||
busses[numBusses] = new BusPwm(bc);
|
||||
}
|
||||
numBusses++;
|
||||
return numBusses -1;
|
||||
// numBusses++;
|
||||
// return numBusses -1;
|
||||
return numBusses++;
|
||||
}
|
||||
|
||||
//do not call this method from system context (network callback)
|
||||
@ -331,6 +353,7 @@ class BusManager {
|
||||
uint16_t bstart = b->getStart();
|
||||
if (pix < bstart || pix >= bstart + b->getLength()) continue;
|
||||
busses[i]->setPixelColor(pix - bstart, c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,23 +79,25 @@
|
||||
#define I_32_R7_TM1_4 54
|
||||
#define I_32_I0_TM1_4 55
|
||||
#define I_32_I1_TM1_4 56
|
||||
//Bit Bang theoratically possible, but very undesirable and not needed (no pin restrictions on RMT and I2S)
|
||||
//Bit Bang theoretically possible, but very undesirable and not needed (no pin restrictions on RMT and I2S)
|
||||
|
||||
//APA102
|
||||
#define I_HS_DOT_3 57 //hardware SPI
|
||||
#define I_SS_DOT_3 58 //soft SPI
|
||||
#define I_HS_DOT_4 59 //hardware SPI, RGBW?
|
||||
#define I_SS_DOT_4 60 //soft SPI, RGBW?
|
||||
|
||||
//LPD8806
|
||||
#define I_HS_LPD_3 59
|
||||
#define I_SS_LPD_3 60
|
||||
#define I_HS_LPD_3 61
|
||||
#define I_SS_LPD_3 62
|
||||
|
||||
//WS2801
|
||||
#define I_HS_WS1_3 61
|
||||
#define I_SS_WS1_3 62
|
||||
#define I_HS_WS1_3 63
|
||||
#define I_SS_WS1_3 64
|
||||
|
||||
//P9813
|
||||
#define I_HS_P98_3 63
|
||||
#define I_SS_P98_3 64
|
||||
#define I_HS_P98_3 65
|
||||
#define I_SS_P98_3 66
|
||||
|
||||
|
||||
/*** ESP8266 Neopixel methods ***/
|
||||
@ -173,8 +175,10 @@
|
||||
#endif
|
||||
|
||||
//APA102
|
||||
#define B_HS_DOT_3 NeoPixelBrightnessBus<DotStarBgrFeature, DotStarSpiMethod> //hardware SPI
|
||||
#define B_SS_DOT_3 NeoPixelBrightnessBus<DotStarBgrFeature, DotStarMethod> //soft SPI
|
||||
#define B_HS_DOT_3 NeoPixelBrightnessBus<DotStarBgrFeature, DotStarSpiMethod> // hardware SPI
|
||||
#define B_SS_DOT_3 NeoPixelBrightnessBus<DotStarBgrFeature, DotStarMethod> // soft SPI
|
||||
#define B_HS_DOT_4 NeoPixelBrightnessBus<DotStarLbgrFeature,DotStarSpiMethod> // HW SPI, RGBW mode?
|
||||
#define B_SS_DOT_4 NeoPixelBrightnessBus<DotStarLbgrFeature,DotStarMethod> // soft SPI, RGBW mode?
|
||||
|
||||
//LPD8806
|
||||
#define B_HS_LPD_3 NeoPixelBrightnessBus<Lpd8806GrbFeature, Lpd8806SpiMethod>
|
||||
@ -212,6 +216,7 @@ class PolyBus {
|
||||
case I_8266_DM_TM1_4: (static_cast<B_8266_DM_TM1_4*>(busPtr))->Begin(); break;
|
||||
case I_8266_BB_TM1_4: (static_cast<B_8266_BB_TM1_4*>(busPtr))->Begin(); break;
|
||||
case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->Begin(); break;
|
||||
case I_HS_DOT_4: (static_cast<B_HS_DOT_4*>(busPtr))->Begin(); break;
|
||||
case I_HS_LPD_3: (static_cast<B_HS_LPD_3*>(busPtr))->Begin(); break;
|
||||
case I_HS_WS1_3: (static_cast<B_HS_WS1_3*>(busPtr))->Begin(); break;
|
||||
case I_HS_P98_3: (static_cast<B_HS_P98_3*>(busPtr))->Begin(); break;
|
||||
@ -259,11 +264,13 @@ class PolyBus {
|
||||
case I_32_I1_TM1_4: (static_cast<B_32_I1_TM1_4*>(busPtr))->Begin(); break;
|
||||
// ESP32 can (and should, to avoid inadvertantly driving the chip select signal) specify the pins used for SPI, but only in begin()
|
||||
case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->Begin(pins[1], -1, pins[0], -1); break;
|
||||
case I_HS_DOT_4: (static_cast<B_HS_DOT_4*>(busPtr))->Begin(pins[1], -1, pins[0], -1); break;
|
||||
case I_HS_LPD_3: (static_cast<B_HS_LPD_3*>(busPtr))->Begin(pins[1], -1, pins[0], -1); break;
|
||||
case I_HS_WS1_3: (static_cast<B_HS_WS1_3*>(busPtr))->Begin(pins[1], -1, pins[0], -1); break;
|
||||
case I_HS_P98_3: (static_cast<B_HS_P98_3*>(busPtr))->Begin(pins[1], -1, pins[0], -1); break;
|
||||
#endif
|
||||
case I_SS_DOT_3: (static_cast<B_SS_DOT_3*>(busPtr))->Begin(); break;
|
||||
case I_SS_DOT_4: (static_cast<B_SS_DOT_4*>(busPtr))->Begin(); break;
|
||||
case I_SS_LPD_3: (static_cast<B_SS_LPD_3*>(busPtr))->Begin(); break;
|
||||
case I_SS_WS1_3: (static_cast<B_SS_WS1_3*>(busPtr))->Begin(); break;
|
||||
case I_SS_P98_3: (static_cast<B_SS_P98_3*>(busPtr))->Begin(); break;
|
||||
@ -336,6 +343,8 @@ class PolyBus {
|
||||
// for 2-wire: pins[1] is clk, pins[0] is dat. begin expects (len, clk, dat)
|
||||
case I_HS_DOT_3: busPtr = new B_HS_DOT_3(len, pins[1], pins[0]); break;
|
||||
case I_SS_DOT_3: busPtr = new B_SS_DOT_3(len, pins[1], pins[0]); break;
|
||||
case I_HS_DOT_4: busPtr = new B_HS_DOT_4(len, pins[1], pins[0]); break;
|
||||
case I_SS_DOT_4: busPtr = new B_SS_DOT_4(len, pins[1], pins[0]); break;
|
||||
case I_HS_LPD_3: busPtr = new B_HS_LPD_3(len, pins[1], pins[0]); break;
|
||||
case I_SS_LPD_3: busPtr = new B_SS_LPD_3(len, pins[1], pins[0]); break;
|
||||
case I_HS_WS1_3: busPtr = new B_HS_WS1_3(len, pins[1], pins[0]); break;
|
||||
@ -411,6 +420,8 @@ class PolyBus {
|
||||
#endif
|
||||
case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->Show(); break;
|
||||
case I_SS_DOT_3: (static_cast<B_SS_DOT_3*>(busPtr))->Show(); break;
|
||||
case I_HS_DOT_4: (static_cast<B_HS_DOT_4*>(busPtr))->Show(); break;
|
||||
case I_SS_DOT_4: (static_cast<B_SS_DOT_4*>(busPtr))->Show(); break;
|
||||
case I_HS_LPD_3: (static_cast<B_HS_LPD_3*>(busPtr))->Show(); break;
|
||||
case I_SS_LPD_3: (static_cast<B_SS_LPD_3*>(busPtr))->Show(); break;
|
||||
case I_HS_WS1_3: (static_cast<B_HS_WS1_3*>(busPtr))->Show(); break;
|
||||
@ -484,6 +495,8 @@ class PolyBus {
|
||||
#endif
|
||||
case I_HS_DOT_3: return (static_cast<B_HS_DOT_3*>(busPtr))->CanShow(); break;
|
||||
case I_SS_DOT_3: return (static_cast<B_SS_DOT_3*>(busPtr))->CanShow(); break;
|
||||
case I_HS_DOT_4: return (static_cast<B_HS_DOT_4*>(busPtr))->CanShow(); break;
|
||||
case I_SS_DOT_4: return (static_cast<B_SS_DOT_4*>(busPtr))->CanShow(); break;
|
||||
case I_HS_LPD_3: return (static_cast<B_HS_LPD_3*>(busPtr))->CanShow(); break;
|
||||
case I_SS_LPD_3: return (static_cast<B_SS_LPD_3*>(busPtr))->CanShow(); break;
|
||||
case I_HS_WS1_3: return (static_cast<B_HS_WS1_3*>(busPtr))->CanShow(); break;
|
||||
@ -500,11 +513,6 @@ class PolyBus {
|
||||
uint8_t w = c >> 24;
|
||||
RgbwColor col;
|
||||
|
||||
//TODO make color order override possible on a per-strip basis
|
||||
#ifdef COLOR_ORDER_OVERRIDE
|
||||
if (indexPixel >= COO_MIN && indexPixel < COO_MAX) co = COO_ORDER;
|
||||
#endif
|
||||
|
||||
//reorder channels to selected order
|
||||
switch (co)
|
||||
{
|
||||
@ -581,6 +589,8 @@ class PolyBus {
|
||||
#endif
|
||||
case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_SS_DOT_3: (static_cast<B_SS_DOT_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_HS_DOT_4: (static_cast<B_HS_DOT_4*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_SS_DOT_4: (static_cast<B_SS_DOT_4*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_HS_LPD_3: (static_cast<B_HS_LPD_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_SS_LPD_3: (static_cast<B_SS_LPD_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
case I_HS_WS1_3: (static_cast<B_HS_WS1_3*>(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break;
|
||||
@ -654,6 +664,8 @@ class PolyBus {
|
||||
#endif
|
||||
case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_SS_DOT_3: (static_cast<B_SS_DOT_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_HS_DOT_4: (static_cast<B_HS_DOT_4*>(busPtr))->SetBrightness(b); break;
|
||||
case I_SS_DOT_4: (static_cast<B_SS_DOT_4*>(busPtr))->SetBrightness(b); break;
|
||||
case I_HS_LPD_3: (static_cast<B_HS_LPD_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_SS_LPD_3: (static_cast<B_SS_LPD_3*>(busPtr))->SetBrightness(b); break;
|
||||
case I_HS_WS1_3: (static_cast<B_HS_WS1_3*>(busPtr))->SetBrightness(b); break;
|
||||
@ -728,6 +740,8 @@ class PolyBus {
|
||||
#endif
|
||||
case I_HS_DOT_3: col = (static_cast<B_HS_DOT_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_SS_DOT_3: col = (static_cast<B_SS_DOT_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_HS_DOT_4: col = (static_cast<B_HS_DOT_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_SS_DOT_4: col = (static_cast<B_SS_DOT_4*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_HS_LPD_3: col = (static_cast<B_HS_LPD_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_SS_LPD_3: col = (static_cast<B_SS_LPD_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
case I_HS_WS1_3: col = (static_cast<B_HS_WS1_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
@ -736,10 +750,6 @@ class PolyBus {
|
||||
case I_SS_P98_3: col = (static_cast<B_SS_P98_3*>(busPtr))->GetPixelColor(pix); break;
|
||||
}
|
||||
|
||||
#ifdef COLOR_ORDER_OVERRIDE
|
||||
if (indexPixel >= COO_MIN && indexPixel < COO_MAX) co = COO_ORDER;
|
||||
#endif
|
||||
|
||||
switch (co)
|
||||
{
|
||||
// W G R B
|
||||
@ -819,6 +829,8 @@ class PolyBus {
|
||||
#endif
|
||||
case I_HS_DOT_3: delete (static_cast<B_HS_DOT_3*>(busPtr)); break;
|
||||
case I_SS_DOT_3: delete (static_cast<B_SS_DOT_3*>(busPtr)); break;
|
||||
case I_HS_DOT_4: delete (static_cast<B_HS_DOT_4*>(busPtr)); break;
|
||||
case I_SS_DOT_4: delete (static_cast<B_SS_DOT_4*>(busPtr)); break;
|
||||
case I_HS_LPD_3: delete (static_cast<B_HS_LPD_3*>(busPtr)); break;
|
||||
case I_SS_LPD_3: delete (static_cast<B_SS_LPD_3*>(busPtr)); break;
|
||||
case I_HS_WS1_3: delete (static_cast<B_HS_WS1_3*>(busPtr)); break;
|
||||
@ -829,7 +841,7 @@ class PolyBus {
|
||||
}
|
||||
|
||||
//gives back the internal type index (I_XX_XXX_X above) for the input
|
||||
static uint8_t getI(uint8_t busType, uint8_t* pins, uint8_t num = 0) {
|
||||
static uint8_t getI(uint8_t busType, uint8_t* pins, uint8_t num = 0, bool rgbwOverride = false) {
|
||||
if (!IS_DIGITAL(busType)) return I_NONE;
|
||||
if (IS_2PIN(busType)) { //SPI LED chips
|
||||
bool isHSPI = false;
|
||||
@ -840,7 +852,7 @@ class PolyBus {
|
||||
#endif
|
||||
uint8_t t = I_NONE;
|
||||
switch (busType) {
|
||||
case TYPE_APA102: t = I_SS_DOT_3; break;
|
||||
case TYPE_APA102: t = rgbwOverride ? I_SS_DOT_4 : I_SS_DOT_3; break;
|
||||
case TYPE_LPD8806: t = I_SS_LPD_3; break;
|
||||
case TYPE_WS2801: t = I_SS_WS1_3; break;
|
||||
case TYPE_P9813: t = I_SS_P98_3; break;
|
||||
@ -855,9 +867,9 @@ class PolyBus {
|
||||
switch (busType) {
|
||||
case TYPE_WS2812_RGB:
|
||||
case TYPE_WS2812_WWA:
|
||||
return I_8266_U0_NEO_3 + offset;
|
||||
// return I_8266_U0_NEO_3 + offset;
|
||||
case TYPE_SK6812_RGBW:
|
||||
return I_8266_U0_NEO_4 + offset;
|
||||
return (rgbwOverride ? I_8266_U0_NEO_4 : I_8266_U0_NEO_3) + offset;
|
||||
case TYPE_WS2811_400KHZ:
|
||||
return I_8266_U0_400_3 + offset;
|
||||
}
|
||||
@ -867,9 +879,9 @@ class PolyBus {
|
||||
switch (busType) {
|
||||
case TYPE_WS2812_RGB:
|
||||
case TYPE_WS2812_WWA:
|
||||
return I_32_R0_NEO_3 + offset;
|
||||
// return I_32_R0_NEO_3 + offset;
|
||||
case TYPE_SK6812_RGBW:
|
||||
return I_32_R0_NEO_4 + offset;
|
||||
return (rgbwOverride ? I_32_R0_NEO_4 : I_32_R0_NEO_3) + offset;
|
||||
case TYPE_WS2811_400KHZ:
|
||||
return I_32_R0_400_3 + offset;
|
||||
}
|
||||
|
@ -94,7 +94,8 @@ void handleIO()
|
||||
{
|
||||
if (!offMode) {
|
||||
#ifdef ESP8266
|
||||
//turn off built-in LED if strip is turned off
|
||||
// turn off built-in LED if strip is turned off
|
||||
// this will break digital bus so will need to be reinitialised on On
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
#endif
|
||||
|
@ -90,16 +90,18 @@ void deserializeConfig() {
|
||||
// initialize LED pins and lengths prior to other HW
|
||||
JsonObject hw_led = hw[F("led")];
|
||||
|
||||
CJSON(ledCount, hw_led[F("total")]);
|
||||
if (ledCount > MAX_LEDS) ledCount = MAX_LEDS;
|
||||
// CJSON(ledCount, hw_led[F("total")]);
|
||||
// if (ledCount > MAX_LEDS) ledCount = MAX_LEDS;
|
||||
ledCount = 0;
|
||||
|
||||
CJSON(strip.ablMilliampsMax, hw_led[F("maxpwr")]);
|
||||
CJSON(strip.milliampsPerLed, hw_led[F("ledma")]);
|
||||
CJSON(strip.reverseMode, hw_led[F("rev")]);
|
||||
//CJSON(strip.reverseMode, hw_led[F("rev")]);
|
||||
CJSON(strip.rgbwMode, hw_led[F("rgbwm")]);
|
||||
|
||||
JsonArray ins = hw_led["ins"];
|
||||
uint8_t s = 0;
|
||||
bool skipFirst = skipFirstLed = false;
|
||||
useRGBW = false;
|
||||
busses.removeAll();
|
||||
for (JsonObject elm : ins) {
|
||||
@ -107,32 +109,36 @@ void deserializeConfig() {
|
||||
uint8_t pins[5] = {255, 255, 255, 255, 255};
|
||||
JsonArray pinArr = elm[F("pin")];
|
||||
if (pinArr.size() == 0) continue;
|
||||
pins[0] = pinArr[0];
|
||||
// pins[0] = pinArr[0];
|
||||
uint8_t i = 0;
|
||||
for (int p : pinArr) {
|
||||
pins[i] = p;
|
||||
i++;
|
||||
pins[i++] = p;
|
||||
// i++;
|
||||
if (i>4) break;
|
||||
}
|
||||
|
||||
uint16_t length = elm[F("len")];
|
||||
if (length==0) continue;
|
||||
uint8_t colorOrder = (int)elm[F("order")];
|
||||
//only use skip from the first strip (this shouldn't have been in ins obj. but remains here for compatibility)
|
||||
if (s==0) skipFirstLed = elm[F("skip")];
|
||||
if (length==0 || length+ledCount > MAX_LEDS) continue; // zero length or we reached max. number of LEDs, just stop
|
||||
// maybe we should have
|
||||
// start = ledCount; // length of previous strips
|
||||
uint16_t start = elm[F("start")] | 0;
|
||||
if (start >= ledCount) continue;
|
||||
if (start >= ledCount+length) continue; // something is very wrong :)
|
||||
//limit length of strip if it would exceed total configured LEDs
|
||||
if (start + length > ledCount) length = ledCount - start;
|
||||
//if (start + length > ledCount) length = ledCount - start;
|
||||
uint8_t colorOrder = (int)elm[F("order")];
|
||||
//(this shouldn't have been in ins obj. but remains here for compatibility)
|
||||
skipFirstLed |= skipFirst = (bool) elm[F("skip")];
|
||||
uint8_t ledType = elm[F("type")] | TYPE_WS2812_RGB;
|
||||
bool reversed = elm[F("rev")];
|
||||
//RGBW mode is enabled if at least one of the strips is RGBW
|
||||
useRGBW = (useRGBW || BusManager::isRgbw(ledType));
|
||||
if ((bool)elm[F("rgbw")]) SET_BIT(ledType,7); else UNSET_BIT(ledType,7); // hack bit 7 to indicate RGBW (as an override if necessary)
|
||||
useRGBW |= (bool)elm[F("rgbw")];
|
||||
s++;
|
||||
BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed);
|
||||
ledCount += length;
|
||||
BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst);
|
||||
busses.add(bc);
|
||||
}
|
||||
strip.finalizeInit(useRGBW, ledCount, skipFirstLed);
|
||||
strip.finalizeInit();
|
||||
|
||||
JsonObject hw_btn_ins_0 = hw[F("btn")][F("ins")][0];
|
||||
CJSON(buttonEnabled, hw_btn_ins_0[F("type")]);
|
||||
@ -441,7 +447,7 @@ void serializeConfig() {
|
||||
hw_led[F("total")] = ledCount;
|
||||
hw_led[F("maxpwr")] = strip.ablMilliampsMax;
|
||||
hw_led[F("ledma")] = strip.milliampsPerLed;
|
||||
hw_led[F("rev")] = strip.reverseMode;
|
||||
hw_led[F("rev")] = false; //strip.reverseMode; // not used anymore, reversing per-strip
|
||||
hw_led[F("rgbwm")] = strip.rgbwMode;
|
||||
|
||||
JsonArray hw_led_ins = hw_led.createNestedArray("ins");
|
||||
@ -452,16 +458,17 @@ void serializeConfig() {
|
||||
if (!bus || bus->getLength()==0) break;
|
||||
JsonObject ins = hw_led_ins.createNestedObject();
|
||||
ins[F("en")] = true;
|
||||
ins[F("start")] = bus->getStart();
|
||||
ins[F("start")] = bus->getStart(); // really needed?
|
||||
ins[F("len")] = bus->getLength();
|
||||
JsonArray ins_pin = ins.createNestedArray("pin");
|
||||
uint8_t pins[5];
|
||||
uint8_t nPins = bus->getPins(pins);
|
||||
for (uint8_t i = 0; i < nPins; i++) ins_pin.add(pins[i]);
|
||||
ins[F("order")] = bus->getColorOrder();
|
||||
ins[F("rev")] = bus->reversed;
|
||||
ins[F("skip")] = (skipFirstLed && s == 0) ? 1 : 0;
|
||||
ins[F("rev")] = bus->reversed;
|
||||
ins[F("skip")] = skipFirstLed ? 1 : 0;
|
||||
ins[F("type")] = bus->getType();
|
||||
ins[F("rgbw")] = bus->isRgbw();
|
||||
}
|
||||
|
||||
JsonObject hw_btn = hw.createNestedObject("btn");
|
||||
|
@ -207,7 +207,7 @@
|
||||
|
||||
// Size of buffer for API JSON object (increase for more segments)
|
||||
#ifdef ESP8266
|
||||
#define JSON_BUFFER_SIZE 9216
|
||||
#define JSON_BUFFER_SIZE 10240
|
||||
#else
|
||||
#define JSON_BUFFER_SIZE 16384
|
||||
#endif
|
||||
|
@ -251,7 +251,6 @@ button {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
width: calc(100%/var(--n));
|
||||
padding: 11px 0;
|
||||
box-sizing: border-box;
|
||||
border: 0px;
|
||||
overflow: auto;
|
||||
@ -260,10 +259,7 @@ button {
|
||||
}
|
||||
|
||||
#Effects {
|
||||
padding-top: 0;
|
||||
margin-top: 11px;
|
||||
height: calc(100% - 11px);
|
||||
-webkit-overflow-scrolling: touch;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.smooth { transition: transform calc(var(--f, 1)*.5s) ease-out }
|
||||
@ -297,10 +293,7 @@ button {
|
||||
background: var(--c-1);
|
||||
top: -1px;
|
||||
z-index: 1;
|
||||
margin-top: 1px;
|
||||
width: 274px;
|
||||
margin: auto;
|
||||
border-radius: 25px;
|
||||
margin: 1px auto auto;
|
||||
}
|
||||
|
||||
#staytop1 {
|
||||
@ -432,16 +425,23 @@ img {
|
||||
}
|
||||
|
||||
.sliderbubble {
|
||||
width: 36px;
|
||||
line-height: 24px;
|
||||
background: var(--c-3);
|
||||
position: absolute;
|
||||
transform: translateX(-50%);
|
||||
border-radius: 12px;
|
||||
margin-left: 12px;
|
||||
margin-top: 3px;
|
||||
padding: 0px;
|
||||
display: inline;
|
||||
width: 24px;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
border-radius: 5px;
|
||||
background: var(--c-3);
|
||||
color: white;
|
||||
padding: 2px 5px;
|
||||
font-size: 14px;
|
||||
right: 5px;
|
||||
transition: visibility 0.25s ease, opacity 0.25s ease;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
output.sliderbubbleshow {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
@ -487,11 +487,6 @@ input[type=range]::-moz-range-thumb {
|
||||
background: var(--c-f);
|
||||
transform: translateY(7px);
|
||||
}
|
||||
input[type=range]:active + .sliderbubble {
|
||||
display: inline;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
#wwrap {
|
||||
display: none;
|
||||
}
|
||||
@ -633,7 +628,7 @@ textarea {
|
||||
}
|
||||
|
||||
::selection {
|
||||
background: var(--c-b);
|
||||
background: var(--c-b);
|
||||
}
|
||||
|
||||
input[type=text] {
|
||||
@ -683,13 +678,13 @@ input[type=number]::-webkit-outer-spin-button {
|
||||
}
|
||||
|
||||
.pid {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
padding: 11px 0px 0px 11px;
|
||||
font-size: 16px;
|
||||
width: 20px;
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
padding: 11px 0px 0px 11px;
|
||||
font-size: 16px;
|
||||
width: 20px;
|
||||
text-align: center;
|
||||
color: var(--c-b);
|
||||
}
|
||||
|
||||
@ -761,7 +756,7 @@ input[type=number]::-webkit-outer-spin-button {
|
||||
}
|
||||
|
||||
.schkl {
|
||||
padding: 2px 22px 0px 35px;
|
||||
padding: 2px 5px 0px 35px;
|
||||
margin: 0 0 0 2px;
|
||||
}
|
||||
|
||||
@ -860,7 +855,101 @@ input[type=number]::-webkit-outer-spin-button {
|
||||
border-radius: 20px;
|
||||
text-align: left;
|
||||
transition: background-color 0.5s;
|
||||
filter: brightness(1);
|
||||
filter: brightness(1);
|
||||
}
|
||||
|
||||
.list {
|
||||
position: relative;
|
||||
width: 260px;
|
||||
border-radius: 20px;
|
||||
background-color: var(--c-2);
|
||||
transition: background-color 0.5s;
|
||||
overflow: hidden;
|
||||
margin: auto auto 20px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
.lstI {
|
||||
position: relative;
|
||||
border-bottom: 1px solid var(--c-3);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 8px 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.lstI:hover {
|
||||
background: var(--c-4);
|
||||
}
|
||||
|
||||
.lstI:last-child {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.lstI.selected {
|
||||
background: var(--c-5);
|
||||
}
|
||||
|
||||
.lstIcontent {
|
||||
width: 100%;
|
||||
vertical-align: middle;
|
||||
padding: 0 20px 0 5px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.lstIname {
|
||||
margin: 3px 0;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.lstIprev {
|
||||
border: 1px solid var(--c-4);
|
||||
border-radius: 4px;
|
||||
width: 100%;
|
||||
height: 8px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.fndIcn { /* needed for magnifier SVG, can be removed when magnifier is in Wicons font */
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
stroke: var(--c-e);
|
||||
stroke-width: 3px;
|
||||
fill-opacity: 0;
|
||||
}
|
||||
|
||||
div.fnd div {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 13px;
|
||||
}
|
||||
|
||||
div.fnd span {
|
||||
position: absolute;
|
||||
display: none;
|
||||
top: 10px;
|
||||
right: 13px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
input[type="text"].fnd {
|
||||
display: block;
|
||||
width: 260px;
|
||||
box-sizing: border-box;
|
||||
padding: 8px 48px 8px 60px;
|
||||
margin: 0 auto 10px;
|
||||
text-align: left;
|
||||
border-radius: 0;
|
||||
background: var(--c-1);
|
||||
border-bottom: 1px solid var(--c-3);
|
||||
}
|
||||
|
||||
input[type="text"].fnd:focus {
|
||||
background-color: var(--c-5);
|
||||
}
|
||||
|
||||
input[type="text"].fnd:not(:placeholder-shown) {
|
||||
background-color: var(--c-4);
|
||||
}
|
||||
|
||||
.pres {
|
||||
@ -904,6 +993,13 @@ input[type=number]::-webkit-outer-spin-button {
|
||||
background: var(--c-sbh);
|
||||
}
|
||||
|
||||
@media not all and (hover: none) {
|
||||
.sliderwrap:hover + output.sliderbubble {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (max-width: 335px) {
|
||||
.sliderbubble {
|
||||
display: none;
|
||||
|
@ -35,6 +35,7 @@
|
||||
<input id="sliderBri" onchange="setBri()" oninput="updateTrail(this)" max="255" min="1" type="range" value="128" />
|
||||
<div class="sliderdisplay"></div>
|
||||
</div>
|
||||
<output class="sliderbubble"></output>
|
||||
</div>
|
||||
</div>
|
||||
<iframe id="liveview" src="about:blank"></iframe>
|
||||
@ -45,17 +46,26 @@
|
||||
<div id="Colors" class="tabcontent">
|
||||
<div id="picker" class="noslide"></div>
|
||||
<div id="rgbwrap">
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderR" class="noslide" onchange="fromRgb()" oninput="updateTrail(this,1)" max="255" min="0" type="range" value="128" />
|
||||
<div class="sliderdisplay"></div>
|
||||
<div id="rwrap" class="il">
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderR" class="noslide" onchange="fromRgb()" oninput="updateTrail(this,1)" max="255" min="0" type="range" value="128" />
|
||||
<div class="sliderdisplay"></div>
|
||||
</div>
|
||||
<output class="sliderbubble"></output>
|
||||
</div><br>
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderG" class="noslide" onchange="fromRgb()" oninput="updateTrail(this,2)" max="255" min="0" type="range" value="128" />
|
||||
<div class="sliderdisplay"></div>
|
||||
<div id="gwrap" class="il">
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderG" class="noslide" onchange="fromRgb()" oninput="updateTrail(this,2)" max="255" min="0" type="range" value="128" />
|
||||
<div class="sliderdisplay"></div>
|
||||
</div>
|
||||
<output class="sliderbubble"></output>
|
||||
</div><br>
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderB" class="noslide" onchange="fromRgb()" oninput="updateTrail(this,3)" max="255" min="0" type="range" value="128" />
|
||||
<div class="sliderdisplay"></div>
|
||||
<div id="bwrap" class="il">
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderB" class="noslide" onchange="fromRgb()" oninput="updateTrail(this,3)" max="255" min="0" type="range" value="128" />
|
||||
<div class="sliderdisplay"></div>
|
||||
</div>
|
||||
<output class="sliderbubble"></output>
|
||||
</div><br>
|
||||
</div>
|
||||
<div id="wwrap">
|
||||
@ -63,6 +73,7 @@
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderW" class="noslide" onchange="setColor(0)" oninput="updateTrail(this)" max="255" min="0" type="range" value="128" />
|
||||
<div class="sliderdisplay"></div>
|
||||
<output class="sliderbubble"></output>
|
||||
</div>
|
||||
</div>
|
||||
<div id="qcs-w">
|
||||
@ -90,48 +101,74 @@
|
||||
<p class="labels">Color palette</p>
|
||||
<div class="il">
|
||||
<i class="icons sel-icon" onclick="tglHex()"></i>
|
||||
<select class="btn sel" id="selectPalette" onchange="setPalette()">
|
||||
<option>Default</option>
|
||||
<option>Error!</option>
|
||||
</select>
|
||||
<div class="staytop fnd">
|
||||
<input type="text" class="fnd" placeholder="Search" oninput="search(this,'selectPalette')" onfocus="search(this)" />
|
||||
<span onclick="clean(this)" class="icons"></span>
|
||||
<div class="icons"><svg xmlns='http://www.w3.org/2000/svg' class='fndIcn'><circle cx='8' cy='8' r='6' /><line x1='12' y1='12' x2='24' y2='12' transform='rotate(45,12,12)' /></svg></div>
|
||||
</div>
|
||||
<div id="selectPalette" class="list">
|
||||
<div class="lstI" data-id="0">
|
||||
<label class="check schkl">
|
||||
|
||||
<input type="radio" value="${palettes[i].id}" name="palette" onChange="setPalette()">
|
||||
<span class="checkmark schk"></span>
|
||||
</label>
|
||||
<div class="lstIcontent">
|
||||
<span class="lstIname">
|
||||
Default
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lstI">
|
||||
<div class="lstIcontent">
|
||||
<span class="lstIname">
|
||||
Loading
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="Effects" class="tabcontent">
|
||||
<p class="labels">Effect speed</p>
|
||||
<div class="staytop">
|
||||
<div class="staytop" id="staytop">
|
||||
<i class="icons slider-icon"></i>
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderSpeed" class="noslide" onchange="setSpeed()" oninput="updateTrail(this)" max="255" min="0" type="range" value="128" />
|
||||
<output class="sliderbubble hidden"></output>
|
||||
<div class="sliderdisplay"></div>
|
||||
</div>
|
||||
<output class="sliderbubble"></output>
|
||||
</div>
|
||||
<p class="labels">Effect intensity</p>
|
||||
<div class="staytop" id="staytop1">
|
||||
<i class="icons slider-icon" onclick="tglLabels()"></i>
|
||||
<div class="sliderwrap il">
|
||||
<input id="sliderIntensity" class="noslide" onchange="setIntensity()" oninput="updateTrail(this)" max="255" min="0" type="range" value="128" />
|
||||
<output class="sliderbubble hidden"></output>
|
||||
<div class="sliderdisplay"></div>
|
||||
</div>
|
||||
<output class="sliderbubble"></output>
|
||||
</div>
|
||||
<p class="labels">Effect mode</p>
|
||||
<div class="staytop" id="staytop2">
|
||||
<button class="btn" id="fxb0" onclick="setX(0);">Solid</button>
|
||||
<div class="il">
|
||||
<div class="staytop fnd" id="staytop2">
|
||||
<input type="text" class="fnd" placeholder="Search" oninput="search(this,'fxlist')" onfocus="search(this)" />
|
||||
<span onclick="clean(this);" class="icons"></span>
|
||||
<div class="icons"><svg xmlns='http://www.w3.org/2000/svg' class='fndIcn'><circle cx='8' cy='8' r='6' /><line x1='12' y1='12' x2='24' y2='12' transform='rotate(45,12,12)' /></svg></div>
|
||||
</div>
|
||||
<p class="labels">Effect mode</p>
|
||||
<div id="fxlist" class="list">
|
||||
Loading...
|
||||
</div>
|
||||
</div>
|
||||
<div id="fxlist">
|
||||
Loading...
|
||||
</div>
|
||||
<br>
|
||||
</div>
|
||||
|
||||
<div id="Segments" class="tabcontent">
|
||||
<div id="segutil" class="staytop">
|
||||
|
||||
</div>
|
||||
<div id="segcont">
|
||||
Loading...
|
||||
</div>
|
||||
<div id="segutil">
|
||||
|
||||
</div>
|
||||
<div id="segutil2">
|
||||
<button class="btn btn-s" id="rsbtn" onclick="rSegs()">Reset segments</button>
|
||||
@ -139,7 +176,7 @@
|
||||
</div>
|
||||
|
||||
<div id="Favorites" class="tabcontent">
|
||||
<div id="putil">
|
||||
<div id="putil" class="staytop">
|
||||
|
||||
</div>
|
||||
<div id="pql">
|
||||
@ -148,7 +185,7 @@
|
||||
<div id="pcont">
|
||||
Loading...
|
||||
</div><br>
|
||||
<label class="check psvl">
|
||||
<label class="check psvl">
|
||||
Preset cycle
|
||||
<input type="checkbox" id="cyToggle" onchange="toggleCY()">
|
||||
<span class="checkmark psv"></span>
|
||||
@ -156,7 +193,7 @@
|
||||
First preset: <input id="cycs" class="noslide" type="number" min="1" max="249" value="1"><br>
|
||||
Last preset: <input id="cyce" class="noslide" type="number" min="2" max="250" value="3"><br>
|
||||
Time per preset: <input id="cyct" class="noslide" type="number" min="0.2" max="6553.5" step="0.1" value="1.2">s<br>
|
||||
Transition: <input id="cyctt" class="noslide" type="number" min="0" max="65.5" step="0.1" value="0.7">s
|
||||
Transition: <input id="cyctt" class="noslide" type="number" min="0" max="65.5" step="0.1" value="0.7">s<br><br>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -1,13 +1,16 @@
|
||||
//page js
|
||||
const lsPalKey = "wledPalx";
|
||||
var loc = false, locip;
|
||||
var noNewSegs = false;
|
||||
var isOn = false, nlA = false, isLv = false, isInfo = false, syncSend = false, syncTglRecv = true, isRgbw = false;
|
||||
var whites = [0,0,0];
|
||||
var selColors;
|
||||
var expanded = [false];
|
||||
var powered = [true];
|
||||
var nlDur = 60, nlTar = 0;
|
||||
var nlFade = false;
|
||||
var selectedFx = 0;
|
||||
var selectedPal = 0;
|
||||
var csel = 0;
|
||||
var currentPreset = -1;
|
||||
var lastUpdate = 0;
|
||||
@ -15,7 +18,8 @@ var segCount = 0, ledCount = 0, lowestUnused = 0, maxSeg = 0, lSeg = 0;
|
||||
var pcMode = false, pcModeA = false, lastw = 0;
|
||||
var d = document;
|
||||
const ranges = RangeTouch.setup('input[type="range"]', {});
|
||||
var pJson = {};
|
||||
var palettesData;
|
||||
var pJson = {}, eJson = {}, lJson = {};
|
||||
var pN = "", pI = 0;
|
||||
var pmt = 1, pmtLS = 0, pmtLast = 0;
|
||||
var lastinfo = {};
|
||||
@ -157,7 +161,6 @@ function loadBg(iUrl) {
|
||||
}
|
||||
img.addEventListener('load', (event) => {
|
||||
var a = parseFloat(cfg.theme.alpha.bg);
|
||||
d.getElementById('staytop2').style.background = "transparent";
|
||||
if (isNaN(a)) a = 0.6;
|
||||
bg.style.opacity = a;
|
||||
bg.style.backgroundImage = `url(${img.src})`;
|
||||
@ -167,13 +170,13 @@ function loadBg(iUrl) {
|
||||
|
||||
function onLoad() {
|
||||
if (window.location.protocol == "file:") {
|
||||
loc = true;
|
||||
locip = localStorage.getItem('locIp');
|
||||
if (!locip)
|
||||
{
|
||||
locip = prompt("File Mode. Please enter WLED IP!");
|
||||
localStorage.setItem('locIp', locip);
|
||||
}
|
||||
loc = true;
|
||||
locip = localStorage.getItem('locIp');
|
||||
if (!locip)
|
||||
{
|
||||
locip = prompt("File Mode. Please enter WLED IP!");
|
||||
localStorage.setItem('locIp', locip);
|
||||
}
|
||||
}
|
||||
var sett = localStorage.getItem('wledUiCfg');
|
||||
if (sett) cfg = mergeDeep(cfg, JSON.parse(sett));
|
||||
@ -194,14 +197,26 @@ function onLoad() {
|
||||
setColor(1);
|
||||
});
|
||||
pmtLS = localStorage.getItem('wledPmt');
|
||||
setTimeout(function(){requestJson(null, false);}, 25);
|
||||
|
||||
// Load initial data
|
||||
getPalettesDataCached();
|
||||
loadPalettes(function() {
|
||||
loadFX(function() {
|
||||
loadPresets(function() {
|
||||
requestJson(null, false, true, function() {
|
||||
loadPalettesData();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
d.addEventListener("visibilitychange", handleVisibilityChange, false);
|
||||
size();
|
||||
d.getElementById("cv").style.opacity=0;
|
||||
if (localStorage.getItem('pcm') == "true") togglePcMode(true);
|
||||
var sls = d.querySelectorAll('input[type="range"]');
|
||||
for (var sl of sls) {
|
||||
sl.addEventListener('input', updateBubble, true);
|
||||
//sl.addEventListener('input', updateBubble, true);
|
||||
sl.addEventListener('touchstart', toggleBubble);
|
||||
sl.addEventListener('touchend', toggleBubble);
|
||||
}
|
||||
@ -259,19 +274,17 @@ function getRuntimeStr(rt)
|
||||
return str;
|
||||
}
|
||||
|
||||
function inforow(key, val, unit = "")
|
||||
{
|
||||
function inforow(key, val, unit = "") {
|
||||
return `<tr><td class="keytd">${key}</td><td class="valtd">${val}${unit}</td></tr>`;
|
||||
}
|
||||
|
||||
function getLowestUnusedP()
|
||||
{
|
||||
function getLowestUnusedP() {
|
||||
var l = 1;
|
||||
for (var key in pJson)
|
||||
{
|
||||
if (key == l) l++;
|
||||
}
|
||||
if (l > 250) l = 250;
|
||||
}
|
||||
if (l > 250) l = 250;
|
||||
return l;
|
||||
}
|
||||
|
||||
@ -285,13 +298,14 @@ function checkUsed(i) {
|
||||
}
|
||||
|
||||
function pName(i) {
|
||||
if (!pJson || !pJson[i]) return "";
|
||||
var n = "Preset " + i;
|
||||
if (pJson[i].n) n = pJson[i].n;
|
||||
return n;
|
||||
}
|
||||
|
||||
function papiVal(i) {
|
||||
if (!pJson[i]) return "";
|
||||
if (!pJson || !pJson[i]) return "";
|
||||
var o = Object.assign({},pJson[i]);
|
||||
if (o.win) return o.win;
|
||||
delete o.n; delete o.p; delete o.ql;
|
||||
@ -299,9 +313,8 @@ function papiVal(i) {
|
||||
}
|
||||
|
||||
function qlName(i) {
|
||||
if (!pJson[i]) return "";
|
||||
if (!pJson[i].ql) return "";
|
||||
return pJson[i].ql;
|
||||
if (!pJson || !pJson[i] || !pJson[i].ql) return "";
|
||||
return pJson[i].ql;
|
||||
}
|
||||
|
||||
function cpBck() {
|
||||
@ -345,7 +358,7 @@ function presetError(empty)
|
||||
if (hasBackup) d.getElementById('bck').value = bckstr;
|
||||
}
|
||||
|
||||
function loadPresets()
|
||||
function loadPresets(callback = null)
|
||||
{
|
||||
var url = '/presets.json';
|
||||
if (loc) {
|
||||
@ -365,11 +378,87 @@ function loadPresets()
|
||||
.then(json => {
|
||||
pJson = json;
|
||||
populatePresets();
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
})
|
||||
.catch(function (error) {
|
||||
showToast(error, true);
|
||||
console.log(error);
|
||||
presetError(false);
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function loadPalettes(callback = null)
|
||||
{
|
||||
var url = '/json/palettes';
|
||||
if (loc) {
|
||||
url = `http://${locip}/json/palettes`;
|
||||
}
|
||||
|
||||
fetch
|
||||
(url, {
|
||||
method: 'get'
|
||||
})
|
||||
.then(res => {
|
||||
if (!res.ok) {
|
||||
showErrorToast();
|
||||
}
|
||||
return res.json();
|
||||
})
|
||||
.then(json => {
|
||||
lJson = Object.entries(json);
|
||||
populatePalettes();
|
||||
updateUI();
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
})
|
||||
.catch(function (error) {
|
||||
showToast(error, true);
|
||||
console.log(error);
|
||||
presetError(false);
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function loadFX(callback = null)
|
||||
{
|
||||
var url = '/json/effects';
|
||||
if (loc) {
|
||||
url = `http://${locip}/json/effects`;
|
||||
}
|
||||
|
||||
fetch
|
||||
(url, {
|
||||
method: 'get'
|
||||
})
|
||||
.then(res => {
|
||||
if (!res.ok) {
|
||||
showErrorToast();
|
||||
}
|
||||
return res.json();
|
||||
})
|
||||
.then(json => {
|
||||
eJson = Object.entries(json);
|
||||
populateEffects();
|
||||
updateUI();
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
})
|
||||
.catch(function (error) {
|
||||
showToast(error, true);
|
||||
console.log(error);
|
||||
presetError(false);
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -401,13 +490,14 @@ function populateQL()
|
||||
function populatePresets(fromls)
|
||||
{
|
||||
if (fromls) pJson = JSON.parse(localStorage.getItem("wledP"));
|
||||
if (!pJson) {pJson={};return};
|
||||
delete pJson["0"];
|
||||
var cn = "";
|
||||
var arr = Object.entries(pJson);
|
||||
arr.sort(cmpP);
|
||||
var added = false;
|
||||
pQL = [];
|
||||
var is = [];
|
||||
pQL = [];
|
||||
var is = [];
|
||||
|
||||
for (var key of (arr||[]))
|
||||
{
|
||||
@ -452,19 +542,30 @@ function populateInfo(i)
|
||||
var pwru = "Not calculated";
|
||||
if (pwr > 1000) {pwr /= 1000; pwr = pwr.toFixed((pwr > 10) ? 0 : 1); pwru = pwr + " A";}
|
||||
else if (pwr > 0) {pwr = 50 * Math.round(pwr/50); pwru = pwr + " mA";}
|
||||
var urows="";
|
||||
if (i.u) {
|
||||
for (const [k, val] of Object.entries(i.u))
|
||||
{
|
||||
if (val[1]) {
|
||||
urows += inforow(k,val[0],val[1]);
|
||||
} else {
|
||||
urows += inforow(k,val);
|
||||
}
|
||||
}
|
||||
}
|
||||
var urows="";
|
||||
if (i.nodes) {
|
||||
i.nodes.sort((a,b) => (a.name).localeCompare(b.name));
|
||||
for (var x=0;x<i.nodes.length;x++)
|
||||
{
|
||||
var o = i.nodes[x];
|
||||
if (o.name) {
|
||||
var url = `<button class="btn btna-icon tab" onclick="location.assign('http://${o.ip}');">${o.name}</button>`;
|
||||
urows += inforow(url,o.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (i.u) {
|
||||
for (const [k, val] of Object.entries(i.u))
|
||||
{
|
||||
if (val[1]) {
|
||||
urows += inforow(k,val[0],val[1]);
|
||||
} else {
|
||||
urows += inforow(k,val);
|
||||
}
|
||||
}
|
||||
}
|
||||
var vcn = "Kuuhaku";
|
||||
if (i.ver.startsWith("0.12.")) vcn = "Hikari";
|
||||
if (i.ver.startsWith("0.11.")) vcn = "Mirai";
|
||||
if (i.cn) vcn = i.cn;
|
||||
|
||||
cn += `v${i.ver} "${vcn}"<br><br><table class="infot">
|
||||
@ -473,8 +574,7 @@ function populateInfo(i)
|
||||
${inforow("Signal strength",i.wifi.signal +"% ("+ i.wifi.rssi, " dBm)")}
|
||||
${inforow("Uptime",getRuntimeStr(i.uptime))}
|
||||
${inforow("Free heap",heap," kB")}
|
||||
${inforow("Estimated current",pwru)}
|
||||
${inforow("Frames / second",i.leds.fps)}
|
||||
${inforow("Estimated current",pwru)}
|
||||
${inforow("MAC address",i.mac)}
|
||||
${inforow("Filesystem",i.fs.u + "/" + i.fs.t + " kB (" +Math.round(i.fs.u*100/i.fs.t) + "%)")}
|
||||
${inforow("Environment",i.arch + " " + i.core + " (" + i.lwip + ")")}
|
||||
@ -566,6 +666,149 @@ function populateSegments(s)
|
||||
d.getElementById('rsbtn').style.display = (segCount > 1) ? "inline":"none";
|
||||
}
|
||||
|
||||
function populateEffects()
|
||||
{
|
||||
var effects = eJson;
|
||||
var html = "";
|
||||
|
||||
effects.shift(); //remove solid
|
||||
for (let i = 0; i < effects.length; i++) {
|
||||
effects[i] = {id: effects[i][0], name:effects[i][1]};
|
||||
}
|
||||
effects.sort((a,b) => (a.name).localeCompare(b.name));
|
||||
|
||||
effects.unshift({
|
||||
"id": 0,
|
||||
"name": "Solid",
|
||||
});
|
||||
|
||||
for (let i = 0; i < effects.length; i++) {
|
||||
html += generateListItemHtml(
|
||||
'fx',
|
||||
effects[i].id,
|
||||
effects[i].name,
|
||||
'setX'
|
||||
);
|
||||
}
|
||||
|
||||
d.getElementById('fxlist').innerHTML=html;
|
||||
}
|
||||
|
||||
function populatePalettes()
|
||||
{
|
||||
var palettes = lJson;
|
||||
palettes.shift(); //remove default
|
||||
for (let i = 0; i < palettes.length; i++) {
|
||||
palettes[i] = {
|
||||
"id": palettes[i][0],
|
||||
"name": palettes[i][1]
|
||||
};
|
||||
}
|
||||
palettes.sort((a,b) => (a.name).localeCompare(b.name));
|
||||
|
||||
palettes.unshift({
|
||||
"id": 0,
|
||||
"name": "Default",
|
||||
});
|
||||
|
||||
var paletteHtml = "";
|
||||
for (let i = 0; i < palettes.length; i++) {
|
||||
let previewCss = genPalPrevCss(palettes[i].id);
|
||||
paletteHtml += generateListItemHtml(
|
||||
'palette',
|
||||
palettes[i].id,
|
||||
palettes[i].name,
|
||||
'setPalette',
|
||||
`<div class="lstIprev" style="${previewCss}"></div>`
|
||||
);
|
||||
}
|
||||
|
||||
d.getElementById('selectPalette').innerHTML=paletteHtml;
|
||||
}
|
||||
|
||||
function redrawPalPrev()
|
||||
{
|
||||
let palettes = d.querySelectorAll('#selectPalette .lstI');
|
||||
for (let i = 0; i < palettes.length; i++) {
|
||||
let id = palettes[i].dataset.id;
|
||||
let lstPrev = palettes[i].querySelector('.lstIprev');
|
||||
if (lstPrev) {
|
||||
lstPrev.style = genPalPrevCss(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function genPalPrevCss(id)
|
||||
{
|
||||
if (!palettesData) {
|
||||
return;
|
||||
}
|
||||
var paletteData = palettesData[id];
|
||||
var previewCss = "";
|
||||
|
||||
if (!paletteData) {
|
||||
return 'display: none';
|
||||
}
|
||||
|
||||
// We need at least two colors for a gradient
|
||||
if (paletteData.length == 1) {
|
||||
paletteData[1] = paletteData[0];
|
||||
if (Array.isArray(paletteData[1])) {
|
||||
paletteData[1][0] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
var gradient = [];
|
||||
for (let j = 0; j < paletteData.length; j++) {
|
||||
const element = paletteData[j];
|
||||
let r;
|
||||
let g;
|
||||
let b;
|
||||
let index = false;
|
||||
if (Array.isArray(element)) {
|
||||
index = element[0]/255*100;
|
||||
r = element[1];
|
||||
g = element[2];
|
||||
b = element[3];
|
||||
} else if (element == 'r') {
|
||||
r = Math.random() * 255;
|
||||
g = Math.random() * 255;
|
||||
b = Math.random() * 255;
|
||||
} else {
|
||||
if (selColors) {
|
||||
let pos = element[1] - 1;
|
||||
r = selColors[pos][0];
|
||||
g = selColors[pos][1];
|
||||
b = selColors[pos][2];
|
||||
}
|
||||
}
|
||||
if (index === false) {
|
||||
index = j / paletteData.length * 100;
|
||||
}
|
||||
|
||||
gradient.push(`rgb(${r},${g},${b}) ${index}%`);
|
||||
}
|
||||
|
||||
return `background: linear-gradient(to right,${gradient.join()});`;
|
||||
}
|
||||
|
||||
function generateListItemHtml(listName, id, name, clickAction, extraHtml = '')
|
||||
{
|
||||
return `<div class="lstI" data-id="${id}">
|
||||
<label class="check schkl">
|
||||
|
||||
<input type="radio" value="${id}" name="${listName}" onChange="${clickAction}()">
|
||||
<span class="checkmark schk"></span>
|
||||
</label>
|
||||
<div class="lstIcontent" onClick="${clickAction}(${id})">
|
||||
<span class="lstIname">
|
||||
${name}
|
||||
</span>
|
||||
${extraHtml}
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function updateTrail(e, slidercol)
|
||||
{
|
||||
if (e==null) return;
|
||||
@ -581,20 +824,14 @@ function updateTrail(e, slidercol)
|
||||
}
|
||||
var val = `linear-gradient(90deg, ${scol} ${progress}%, var(--c-4) ${progress}%)`;
|
||||
e.parentNode.getElementsByClassName('sliderdisplay')[0].style.background = val;
|
||||
}
|
||||
|
||||
function updateBubble(e)
|
||||
{
|
||||
var bubble = e.target.parentNode.getElementsByTagName('output')[0];
|
||||
|
||||
if (bubble) {
|
||||
bubble.innerHTML = e.target.value;
|
||||
}
|
||||
var bubble = e.parentNode.parentNode.getElementsByTagName('output')[0];
|
||||
if (bubble) bubble.innerHTML = e.value;
|
||||
}
|
||||
|
||||
function toggleBubble(e)
|
||||
{
|
||||
e.target.parentNode.querySelector('output').classList.toggle('hidden');
|
||||
var bubble = e.target.parentNode.parentNode.getElementsByTagName('output')[0];
|
||||
bubble.classList.toggle('sliderbubbleshow');
|
||||
}
|
||||
|
||||
function updateLen(s)
|
||||
@ -641,26 +878,74 @@ function updatePA()
|
||||
}
|
||||
}
|
||||
|
||||
function updateUI()
|
||||
function updateUI(scrollto=false)
|
||||
{
|
||||
d.getElementById('buttonPower').className = (isOn) ? "active":"";
|
||||
d.getElementById('buttonNl').className = (nlA) ? "active":"";
|
||||
d.getElementById('buttonSync').className = (syncSend) ? "active":"";
|
||||
|
||||
d.getElementById('fxb' + selectedFx).style.backgroundColor = "var(--c-6)";
|
||||
updateSelectedPalette();
|
||||
updateSelectedFx(scrollto);
|
||||
|
||||
// d.getElementById('fxb' + selectedFx).style.backgroundColor = "var(--c-6)";
|
||||
//if (d.getElementById('fxb' + selectedFx))
|
||||
//{
|
||||
// d.getElementById('fxb' + selectedFx).style.backgroundColor = "var(--c-6)";
|
||||
// if (scrollto) d.getElementById('Effects').scrollTop = d.getElementById('fxb' + selectedFx).offsetTop - d.getElementById('Effects').clientHeight/1.8;
|
||||
//}
|
||||
updateTrail(d.getElementById('sliderBri'));
|
||||
updateTrail(d.getElementById('sliderSpeed'));
|
||||
updateTrail(d.getElementById('sliderIntensity'));
|
||||
updateTrail(d.getElementById('sliderW'));
|
||||
if (isRgbw) d.getElementById('wwrap').style.display = "block";
|
||||
|
||||
var spal = d.getElementById("selectPalette");
|
||||
spal.style.backgroundColor = (spal.selectedIndex > 0) ? "var(--c-6)":"var(--c-3)";
|
||||
updatePA();
|
||||
updateHex();
|
||||
updateRgb();
|
||||
}
|
||||
|
||||
function updateSelectedPalette()
|
||||
{
|
||||
var parent = d.getElementById('selectPalette');
|
||||
var selectedPalette = parent.querySelector(`input[name="palette"][value="${selectedPal}"]`);
|
||||
if (selectedPalette) {
|
||||
selectedPalette.checked = true;
|
||||
}
|
||||
selElement = parent.querySelector('.selected');
|
||||
if (selElement) {
|
||||
selElement.classList.remove('selected')
|
||||
}
|
||||
var selectedPalette = parent.querySelector(`.lstI[data-id="${selectedPal}"]`);
|
||||
if (selectedPalette) {
|
||||
parent.querySelector(`.lstI[data-id="${selectedPal}"]`).classList.add('selected');
|
||||
}
|
||||
}
|
||||
|
||||
function updateSelectedFx(scrollto=false)
|
||||
{
|
||||
var parent = d.getElementById('fxlist');
|
||||
|
||||
var selectedEffectInput = parent.querySelector(`input[name="fx"][value="${selectedFx}"]`);
|
||||
if (selectedEffectInput) {
|
||||
parent.querySelector(`input[name="fx"][value="${selectedFx}"]`).checked = true;
|
||||
}
|
||||
var selElement = parent.querySelector('.selected');
|
||||
if (selElement) {
|
||||
selElement.classList.remove('selected')
|
||||
}
|
||||
var selectedEffect = parent.querySelector(`.lstI[data-id="${selectedFx}"]`);
|
||||
if (selectedEffect) {
|
||||
selectedEffect.classList.add('selected');
|
||||
}
|
||||
|
||||
if (scrollto && selectedEffect) {
|
||||
selectedEffect.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'center',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function displayRover(i,s)
|
||||
{
|
||||
d.getElementById('rover').style.transform = (i.live && s.lor == 0) ? "translateY(0px)":"translateY(100%)";
|
||||
@ -669,17 +954,13 @@ function displayRover(i,s)
|
||||
d.getElementById('roverstar').style.display = (i.live && s.lor) ? "block":"none";
|
||||
}
|
||||
|
||||
function compare(a, b) {
|
||||
if (a.name < b.name) return -1;
|
||||
return 1;
|
||||
}
|
||||
function cmpP(a, b) {
|
||||
if (!a[1].n) return (a[0] > b[0]);
|
||||
return a[1].n.localeCompare(b[1].n,undefined, {numeric: true});
|
||||
}
|
||||
|
||||
var jsonTimeout;
|
||||
function requestJson(command, rinfo = true, verbose = true) {
|
||||
function requestJson(command, rinfo = true, verbose = true, callback = null) {
|
||||
d.getElementById('connind').style.backgroundColor = "#a90";
|
||||
lastUpdate = new Date();
|
||||
if (!jsonTimeout) jsonTimeout = setTimeout(showErrorToast, 3000);
|
||||
@ -687,7 +968,7 @@ function requestJson(command, rinfo = true, verbose = true) {
|
||||
var e1 = d.getElementById('fxlist');
|
||||
var e2 = d.getElementById('selectPalette');
|
||||
|
||||
var url = rinfo ? '/json/si': (command ? '/json/state':'/json');
|
||||
var url = rinfo ? '/json/si': (command ? '/json/state':'/json/si');
|
||||
if (loc) {
|
||||
url = `http://${locip}${url}`;
|
||||
}
|
||||
@ -695,8 +976,8 @@ function requestJson(command, rinfo = true, verbose = true) {
|
||||
var type = command ? 'post':'get';
|
||||
if (command)
|
||||
{
|
||||
command.v = verbose;
|
||||
command.time = Math.floor(Date.now() / 1000);
|
||||
command.v = verbose;
|
||||
command.time = Math.floor(Date.now() / 1000);
|
||||
req = JSON.stringify(command);
|
||||
//console.log(req);
|
||||
}
|
||||
@ -710,7 +991,7 @@ function requestJson(command, rinfo = true, verbose = true) {
|
||||
})
|
||||
.then(res => {
|
||||
if (!res.ok) {
|
||||
showErrorToast();
|
||||
showErrorToast();
|
||||
}
|
||||
return res.json();
|
||||
})
|
||||
@ -719,53 +1000,54 @@ function requestJson(command, rinfo = true, verbose = true) {
|
||||
jsonTimeout = null;
|
||||
clearErrorToast();
|
||||
d.getElementById('connind').style.backgroundColor = "#070";
|
||||
if (!json) showToast('Empty response', true);
|
||||
if (json.success) return;
|
||||
if (!json) {
|
||||
showToast('Empty response', true);
|
||||
}
|
||||
if (json.success) {
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
return;
|
||||
}
|
||||
var s = json;
|
||||
if (!command || rinfo) {
|
||||
if (!rinfo) {
|
||||
pmt = json.info.fs.pmt;
|
||||
if (pmt != pmtLS || pmt == 0) {
|
||||
setTimeout(loadPresets,99);
|
||||
}
|
||||
else populatePresets(true);
|
||||
pmtLast = pmt;
|
||||
var x='',y='<option value="0">Default</option>';
|
||||
json.effects.shift(); //remove solid
|
||||
for (let i = 0; i < json.effects.length; i++) json.effects[i] = {id: parseInt(i)+1, name:json.effects[i]};
|
||||
json.effects.sort(compare);
|
||||
for (let i = 0; i < json.effects.length; i++) {
|
||||
x += `<button class="btn${(i==0)?" first":""}" id="fxb${json.effects[i].id}" onclick="setX(${json.effects[i].id});">${json.effects[i].name}</button><br>`;
|
||||
}
|
||||
|
||||
json.palettes.shift(); //remove default
|
||||
for (let i = 0; i < json.palettes.length; i++) json.palettes[i] = {"id": parseInt(i)+1, "name":json.palettes[i]};
|
||||
json.palettes.sort(compare);
|
||||
for (let i = 0; i < json.palettes.length; i++) {
|
||||
y += `<option value="${json.palettes[i].id}">${json.palettes[i].name}</option>`;
|
||||
}
|
||||
e1.innerHTML=x; e2.innerHTML=y;
|
||||
}
|
||||
if (!command || rinfo) {
|
||||
if (!rinfo) {
|
||||
pmt = json.info.fs.pmt;
|
||||
populatePresets(true);
|
||||
pmtLast = pmt;
|
||||
}
|
||||
|
||||
var info = json.info;
|
||||
var name = info.name;
|
||||
d.getElementById('namelabel').innerHTML = name;
|
||||
if (name === "Dinnerbone") d.documentElement.style.transform = "rotate(180deg)";
|
||||
if (info.live) name = "(Live) " + name;
|
||||
if (loc) name = "(L) " + name;
|
||||
if (name === "Dinnerbone") {
|
||||
d.documentElement.style.transform = "rotate(180deg)";
|
||||
}
|
||||
if (info.live) {
|
||||
name = "(Live) " + name;
|
||||
}
|
||||
if (loc) {
|
||||
name = "(L) " + name;
|
||||
}
|
||||
d.title = name;
|
||||
isRgbw = info.leds.wv;
|
||||
ledCount = info.leds.count;
|
||||
syncTglRecv = info.str;
|
||||
maxSeg = info.leds.maxseg;
|
||||
pmt = info.fs.pmt;
|
||||
if (!command && pmt != pmtLast) setTimeout(loadPresets,99);
|
||||
pmtLast = pmt;
|
||||
lastinfo = info;
|
||||
if (isInfo) populateInfo(info);
|
||||
s = json.state;
|
||||
displayRover(info, s);
|
||||
maxSeg = info.leds.maxseg;
|
||||
pmt = info.fs.pmt;
|
||||
if (!command && pmt != pmtLast) {
|
||||
setTimeout(loadPresets,99);
|
||||
}
|
||||
pmtLast = pmt;
|
||||
lastinfo = info;
|
||||
if (isInfo) {
|
||||
populateInfo(info);
|
||||
}
|
||||
s = json.state;
|
||||
displayRover(info, s);
|
||||
}
|
||||
|
||||
isOn = s.on;
|
||||
d.getElementById('sliderBri').value= s.bri;
|
||||
nlA = s.nl.on;
|
||||
@ -774,7 +1056,7 @@ function requestJson(command, rinfo = true, verbose = true) {
|
||||
nlFade = s.nl.fade;
|
||||
syncSend = s.udpn.send;
|
||||
currentPreset = s.ps;
|
||||
d.getElementById('cyToggle').checked = (s.pl < 0) ? false : true;
|
||||
d.getElementById('cyToggle').checked = (s.pl >= 0);
|
||||
d.getElementById('cycs').value = s.ccnf.min;
|
||||
d.getElementById('cyce').value = s.ccnf.max;
|
||||
d.getElementById('cyct').value = s.ccnf.time /10;
|
||||
@ -789,9 +1071,14 @@ function requestJson(command, rinfo = true, verbose = true) {
|
||||
var i=s.seg[selc];
|
||||
if (!i) {
|
||||
showToast('No Segments!', true);
|
||||
updateUI();
|
||||
updateUI(false);
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
selColors = i.col;
|
||||
var cd = d.getElementById('csl').children;
|
||||
for (let e = 2; e >= 0; e--)
|
||||
{
|
||||
@ -804,26 +1091,38 @@ function requestJson(command, rinfo = true, verbose = true) {
|
||||
d.getElementById('sliderSpeed').value = i.sx;
|
||||
d.getElementById('sliderIntensity').value = i.ix;
|
||||
|
||||
d.getElementById('fxb' + selectedFx).style.backgroundColor = "var(--c-3)";
|
||||
selectedPal = i.pal;
|
||||
selectedFx = i.fx;
|
||||
e2.value = i.pal;
|
||||
if (!command) d.getElementById('Effects').scrollTop = d.getElementById('fxb' + selectedFx).offsetTop - d.getElementById('Effects').clientHeight/1.8;
|
||||
|
||||
if (s.error && s.error != 0) {
|
||||
var errstr = "";
|
||||
switch (s.error) {
|
||||
case 10: errstr = "Could not mount filesystem!"; break;
|
||||
case 11: errstr = "Not enough space to save preset!"; break;
|
||||
case 12: errstr = "The requested preset does not exist."; break;
|
||||
case 19: errstr = "A filesystem error has occured."; break;
|
||||
}
|
||||
showToast('Error ' + s.error + ": " + errstr, true);
|
||||
}
|
||||
updateUI();
|
||||
var errstr = "";
|
||||
switch (s.error) {
|
||||
case 10:
|
||||
errstr = "Could not mount filesystem!";
|
||||
break;
|
||||
case 11:
|
||||
errstr = "Not enough space to save preset!";
|
||||
break;
|
||||
case 12:
|
||||
errstr = "The requested preset does not exist.";
|
||||
break;
|
||||
case 19:
|
||||
errstr = "A filesystem error has occured.";
|
||||
break;
|
||||
}
|
||||
showToast('Error ' + s.error + ": " + errstr, true);
|
||||
}
|
||||
updateUI(true);
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
})
|
||||
.catch(function (error) {
|
||||
showToast(error, true);
|
||||
console.log(error);
|
||||
console.log(error);
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -1030,14 +1329,35 @@ function setSegBri(s){
|
||||
requestJson(obj);
|
||||
}
|
||||
|
||||
function setX(ind) {
|
||||
function setX(ind = null) {
|
||||
if (ind === null) {
|
||||
ind = parseInt(d.querySelector('#fxlist input[name="fx"]:checked').value);
|
||||
} else {
|
||||
d.querySelector(`#fxlist input[name="fx"][value="${ind}"]`).checked = true;
|
||||
}
|
||||
var selElement = d.querySelector('#fxlist .selected');
|
||||
if (selElement) {
|
||||
selElement.classList.remove('selected')
|
||||
}
|
||||
d.querySelector(`#fxlist .lstI[data-id="${ind}"]`).classList.add('selected');
|
||||
|
||||
var obj = {"seg": {"fx": parseInt(ind)}};
|
||||
requestJson(obj);
|
||||
}
|
||||
|
||||
function setPalette()
|
||||
function setPalette(paletteId = null)
|
||||
{
|
||||
var obj = {"seg": {"pal": parseInt(d.getElementById('selectPalette').value)}};
|
||||
if (paletteId === null) {
|
||||
paletteId = parseInt(d.querySelector('#selectPalette input[name="palette"]:checked').value);
|
||||
} else {
|
||||
d.querySelector(`#selectPalette input[name="palette"][value="${paletteId}`).checked = true;
|
||||
}
|
||||
var selElement = d.querySelector('#selectPalette .selected');
|
||||
if (selElement) {
|
||||
selElement.classList.remove('selected')
|
||||
}
|
||||
d.querySelector(`#selectPalette .lstI[data-id="${paletteId}"]`).classList.add('selected');
|
||||
var obj = {"seg": {"pal": paletteId}};
|
||||
requestJson(obj);
|
||||
}
|
||||
|
||||
@ -1113,14 +1433,14 @@ function saveP(i) {
|
||||
var pQN = d.getElementById(`p${i}ql`).value;
|
||||
if (pQN.length > 0) obj.ql = pQN;
|
||||
|
||||
showToast("Saving " + pN +" (" + pI + ")");
|
||||
showToast("Saving " + pN +" (" + pI + ")");
|
||||
requestJson(obj);
|
||||
if (obj.o) {
|
||||
pJson[pI] = obj;
|
||||
delete pJson[pI].psave;
|
||||
delete pJson[pI].o;
|
||||
delete pJson[pI].v;
|
||||
delete pJson[pI].time;
|
||||
delete pJson[pI].psave;
|
||||
delete pJson[pI].o;
|
||||
delete pJson[pI].v;
|
||||
delete pJson[pI].time;
|
||||
} else {
|
||||
pJson[pI] = {"n":pN, "win":"Please refresh the page to see this newly saved command."};
|
||||
if (obj.win) pJson[pI].win = obj.win;
|
||||
@ -1153,6 +1473,7 @@ function selectSlot(b) {
|
||||
updateTrail(d.getElementById('sliderW'));
|
||||
updateHex();
|
||||
updateRgb();
|
||||
redrawPalPrev();
|
||||
}
|
||||
|
||||
var lasth = 0;
|
||||
@ -1279,6 +1600,98 @@ function rSegs()
|
||||
requestJson(obj);
|
||||
}
|
||||
|
||||
function loadPalettesData()
|
||||
{
|
||||
if (palettesData) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (getPalettesDataCached()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var dateExpiration = new Date();
|
||||
palettesData = {};
|
||||
getPalettesData(1, function() {
|
||||
localStorage.setItem(lsPalKey, JSON.stringify({
|
||||
p: palettesData,
|
||||
expiration: dateExpiration.getTime() + (24 * 60 * 60 * 1000) // 24 hrs expiration
|
||||
}));
|
||||
requestJson(null, false);
|
||||
});
|
||||
}
|
||||
|
||||
function getPalettesDataCached() {
|
||||
var palettesDataJson = localStorage.getItem(lsPalKey);
|
||||
if (palettesDataJson) {
|
||||
try {
|
||||
palettesDataJson = JSON.parse(palettesDataJson);
|
||||
var d = new Date();
|
||||
if (palettesDataJson && palettesDataJson.expiration && palettesDataJson.expiration > d.getTime()) {
|
||||
palettesData = palettesDataJson.p;
|
||||
redrawPalPrev();
|
||||
return true;
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function getPalettesData(page, callback)
|
||||
{
|
||||
var url = `/json/palx?page=${page}`;
|
||||
if (loc) {
|
||||
url = `http://${locip}${url}`;
|
||||
}
|
||||
|
||||
fetch(url, {
|
||||
method: 'get',
|
||||
headers: {
|
||||
"Content-type": "application/json; charset=UTF-8"
|
||||
}
|
||||
})
|
||||
.then(res => {
|
||||
if (!res.ok) {
|
||||
showErrorToast();
|
||||
}
|
||||
return res.json();
|
||||
})
|
||||
.then(json => {
|
||||
palettesData = Object.assign({}, palettesData, json.p);
|
||||
if (page < json.m) {
|
||||
setTimeout(function() { getPalettesData(page + 1, callback); }, 100);
|
||||
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
})
|
||||
.catch(function(error) {
|
||||
showToast(error, true);
|
||||
console.log(error);
|
||||
presetError(false);
|
||||
});
|
||||
}
|
||||
|
||||
function search(f,l=null) {
|
||||
f.nextElementSibling.style.display=(f.value!=='')?'block':'none';
|
||||
if (!l) return;
|
||||
var el = d.getElementById(l).querySelectorAll('.lstI');
|
||||
for (i = 0; i < el.length; i++) {
|
||||
var it = el[i];
|
||||
var itT = it.querySelector('.lstIname').innerText.toUpperCase();
|
||||
it.style.display = itT.indexOf(f.value.toUpperCase())>-1?'':'none';
|
||||
}
|
||||
}
|
||||
|
||||
function clean(c) {
|
||||
c.style.display='none';
|
||||
var i=c.previousElementSibling;
|
||||
i.value='';
|
||||
i.focus();
|
||||
i.dispatchEvent(new Event('input'));
|
||||
}
|
||||
|
||||
function expand(i,a)
|
||||
{
|
||||
if (!a) expanded[i] = !expanded[i];
|
||||
|
@ -22,7 +22,6 @@
|
||||
//check for pin conflicts
|
||||
if (nm=="L0" || nm=="L1" || nm=="RL" || nm=="BT" || nm=="IR" || nm=="AX")
|
||||
if (LCs[i].value!="" && LCs[i].value!="-1") {
|
||||
if (LCs[i].value > 5 && LCs[i].value < 12) {alert("Sorry, pins 6-11 can not be used.");LCs[i].focus();return;}
|
||||
if (d.um_p && d.um_p.some((e)=>e==parseInt(LCs[i].value,10))) {alert("Usermod pin conflict!");LCs[i].focus();return;}
|
||||
for (j=i+1; j<LCs.length; j++)
|
||||
{
|
||||
@ -63,6 +62,7 @@
|
||||
case 255: d.Sf.LAsel.value = 255; break;
|
||||
default: d.getElementById('LAdis').style.display = 'inline';
|
||||
}
|
||||
d.getElementById('wreason2').innerText = d.LDmax?d.LDmax:'500';
|
||||
UI();
|
||||
}
|
||||
//returns mem usage
|
||||
@ -84,9 +84,9 @@
|
||||
if (type == 44 || type == 45) return len*4; //RGBW
|
||||
return len*3;
|
||||
}
|
||||
function UI()
|
||||
function UI(change=false)
|
||||
{
|
||||
var isRGBW = false, memu = 0;
|
||||
var isRGBW = false, memu = 0, p3u = false, lCount = 0;
|
||||
|
||||
d.getElementById('ampwarning').style.display = (d.Sf.MA.value > 7200) ? 'inline':'none';
|
||||
|
||||
@ -97,7 +97,7 @@
|
||||
for (i=0; i<s.length; i++) {
|
||||
if (s[i].name.substring(0,2)=="LT") {
|
||||
n=s[i].name.substring(2);
|
||||
var type = s[i].value;
|
||||
var type = parseInt(s[i].value,10);
|
||||
d.getElementById("p0d"+n).innerHTML = (type > 49) ? "Data pin:" : (type >41) ? "Pins:" : "Pin:";
|
||||
d.getElementById("p1d"+n).innerHTML = (type > 49) ? "Clk:" : "";
|
||||
var LK = d.getElementsByName("L1"+n)[0];
|
||||
@ -117,7 +117,12 @@
|
||||
LK.value="";
|
||||
}
|
||||
}
|
||||
if (type == 30 || type == 31 || type == 44 || type == 45) isRGBW = true;
|
||||
d.getElementById("ls"+n).readOnly = !(type >= 32 && type < 48); // not analog
|
||||
d.getElementById("LC").readOnly = !(type >= 32 && type < 48); // not analog
|
||||
if (change) {
|
||||
d.getElementById("ew"+n).checked = (type == 30 || type == 31 || type == 44 || type == 45); // TYPE_xxxx values from const.h
|
||||
}
|
||||
isRGBW |= d.getElementById("ew"+n).checked;
|
||||
d.getElementById("dig"+n).style.display = (type > 31 && type < 48) ? "none":"inline";
|
||||
d.getElementById("psd"+n).innerHTML = (type > 31 && type < 48) ? "Index:":"Start:";
|
||||
}
|
||||
@ -129,26 +134,43 @@
|
||||
myC[i].style.display = (isRGBW) ? 'inline':'none';
|
||||
}
|
||||
|
||||
var LCs = d.getElementsByTagName("input");
|
||||
var sLC = 0, maxLC = 0;
|
||||
for (i=0; i<LCs.length; i++) {
|
||||
var nm = LCs[i].name.substring(0,2);
|
||||
if (nm=="LC" && LCs[i].name !== "LC") {var c=parseInt(LCs[i].value,10);d.getElementById("ls"+n).value=sLC;if(c){sLC+=c;if(c>maxLC)maxLC=c;}continue;}
|
||||
if (nm=="L0" || nm=="L1") {
|
||||
var lc=d.getElementsByName("LC"+LCs[i].name.substring(2))[0];
|
||||
p3u|=(LCs[i].value==3);
|
||||
if(d.LDmax && p3u) lc.max=d.LDmax;
|
||||
else lc.max=d.LCmax;
|
||||
}
|
||||
if (nm=="L0" || nm=="L1" || nm=="L2" || nm=="L3" || nm=="L4" || nm=="RL" || nm=="BT" || nm=="IR" || nm=="AX")
|
||||
if (LCs[i].value!="" && LCs[i].value!="-1") {
|
||||
if (d.um_p && d.um_p.some((e)=>e==parseInt(LCs[i].value,10))) {alert("Usermod/reserved pin clash!");LCs[i].value="";LCs[i].focus();continue;}
|
||||
for (j=0; j<LCs.length; j++) {
|
||||
if (i==j) continue;
|
||||
var n2 = LCs[j].name.substring(0,2);
|
||||
if (n2=="L0" || n2=="L1" || n2=="L2" || n2=="L3" || n2=="L4" || n2=="RL" || n2=="BT" || n2=="IR" || n2=="AX")
|
||||
if (LCs[j].value!="" && LCs[i].value==LCs[j].value) {alert("Pin clash!");LCs[i].value="";LCs[i].focus();break;}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (d.getElementById("LC").readOnly) d.getElementsByName("LC")[0].value = sLC;
|
||||
if (d.activeElement == d.getElementsByName("LC")[0]) {
|
||||
var o = d.getElementsByClassName("iST");
|
||||
var i = o.length;
|
||||
if (i == 1) d.getElementsByName("LC0")[0].value = d.getElementsByName("LC")[0].value;
|
||||
}
|
||||
|
||||
var LCs = d.getElementsByTagName("input");
|
||||
var sLC = 0, maxLC = 0;
|
||||
for (i=0; i<LCs.length; i++) {
|
||||
var nm = LCs[i].name.substring(0,2);
|
||||
if (nm=="LC" && LCs[i].name != "LC") {var c = parseInt(LCs[i].value,10); if (c) {sLC+=c; if (c>maxLC) maxLC = c;} continue;}
|
||||
}
|
||||
|
||||
d.getElementById('m0').innerHTML = memu;
|
||||
bquot = memu / bmax * 100;
|
||||
d.getElementById('dbar').style.background = `linear-gradient(90deg, ${bquot > 60 ? bquot > 90 ? "red":"orange":"#ccc"} 0 ${bquot}%%, #444 ${bquot}%% 100%%)`;
|
||||
d.getElementById('ledwarning').style.display = (maxLC > 800 || bquot > 80) ? 'inline':'none';
|
||||
d.getElementById('ledwarning').style.display = (sLC > d.LCmax || maxLC > 800 || bquot > 80) ? 'inline':'none';
|
||||
d.getElementById('ledwarning2').style.display = (d.LDmax && p3u && (sLC > d.LDmax || maxLC > d.LDmax)) ? 'inline':'none';
|
||||
//TODO add warning "Recommended pins on ESP8266 are 1 and 2 (3 only with low LED count)"
|
||||
//TODO add overmemory warning
|
||||
//TODO block disallowed pins 6-11
|
||||
d.getElementById('wreason').innerHTML = (bquot > 80) ? "than 60%% of max. LED memory" : "800 LEDs per pin";
|
||||
|
||||
//var val = Math.ceil((100 + d.Sf.LC.value * laprev)/500)/2;
|
||||
@ -188,7 +210,7 @@
|
||||
var cn = `<div class="iST">
|
||||
${i>0?'<hr style="width:260px">':''}
|
||||
${i+1}:
|
||||
<select name="LT${i}" onchange="UI()">
|
||||
<select name="LT${i}" onchange="UI(true)">
|
||||
<option value="22">WS281x</option>
|
||||
<option value="30">SK6812 RGBW</option>
|
||||
<option value="31">TM1814</option>
|
||||
@ -211,14 +233,15 @@
|
||||
<option value="3">RBG</option>
|
||||
<option value="4">BGR</option>
|
||||
<option value="5">GBR</option>
|
||||
</select><br>
|
||||
<span id="p0d${i}">Pin:</span> <input type="number" name="L0${i}" min="0" max="40" required style="width:35px" oninput="UI()"/>
|
||||
<span id="p1d${i}">Clock:</span> <input type="number" name="L1${i}" min="0" max="40" style="width:35px"/>
|
||||
<span id="p2d${i}"></span><input type="number" name="L2${i}" min="0" max="40" style="width:35px"/>
|
||||
<span id="p3d${i}"></span><input type="number" name="L3${i}" min="0" max="40" style="width:35px"/>
|
||||
<span id="p4d${i}"></span><input type="number" name="L4${i}" min="0" max="40" style="width:35px"/>
|
||||
</select><!--br-->
|
||||
RGBW: <input id="ew${i}" type="checkbox" name="EW${i}"><br>
|
||||
<span id="p0d${i}">Pin:</span> <input type="number" name="L0${i}" min="0" max="40" required style="width:35px" onchange="UI()"/>
|
||||
<span id="p1d${i}">Clock:</span> <input type="number" name="L1${i}" min="0" max="40" style="width:35px" onchange="UI()"/>
|
||||
<span id="p2d${i}"></span><input type="number" name="L2${i}" min="0" max="40" style="width:35px" onchange="UI()"/>
|
||||
<span id="p3d${i}"></span><input type="number" name="L3${i}" min="0" max="40" style="width:35px" onchange="UI()"/>
|
||||
<span id="p4d${i}"></span><input type="number" name="L4${i}" min="0" max="40" style="width:35px" onchange="UI()"/>
|
||||
<br>
|
||||
<span id="psd${i}">Start:</span> <input type="number" name="LS${i}" min="0" max="8191" value="0" required />
|
||||
<span id="psd${i}">Start:</span> <input type="number" name="LS${i}" id="ls${i}" min="0" max="8191" value="0" required />
|
||||
<div id="dig${i}" style="display:inline">
|
||||
Count: <input type="number" name="LC${i}" min="0" max="2048" value="1" required oninput="UI()" /><br>
|
||||
Reverse: <input type="checkbox" name="CV${i}"></div><br>
|
||||
@ -237,7 +260,7 @@
|
||||
function GetV()
|
||||
{
|
||||
//values injected by server while sending HTML
|
||||
//d.um_p=[];addLEDs(3);d.Sf.LC.value=250;addLEDs(1);d.Sf.L00.value=2;d.Sf.L10.value=0;d.Sf.LC0.value=250;d.Sf.LT0.value=22;d.Sf.CO0.value=0;d.Sf.LS0.value=0;d.Sf.LS0.checked=0;d.Sf.MA.value=5400;d.Sf.LA.value=55;d.getElementsByClassName("pow")[0].innerHTML="350mA";d.Sf.CA.value=40;d.Sf.AW.value=3;d.Sf.BO.checked=0;d.Sf.BP.value=3;d.Sf.GB.checked=0;d.Sf.GC.checked=1;d.Sf.TF.checked=1;d.Sf.TD.value=700;d.Sf.PF.checked=0;d.Sf.BF.value=64;d.Sf.TB.value=0;d.Sf.TL.value=60;d.Sf.TW.value=1;d.Sf.PB.selectedIndex=0;d.Sf.RV.checked=0;d.Sf.SL.checked=0;d.Sf.RL.value=12;d.Sf.RM.checked=0;d.Sf.BT.value=-1;d.Sf.IR.value=-1;d.Sf.AX.value=-1;
|
||||
//d.LCmax=1536;d.LDmax=500;d.um_p=[1,6,7,8,9,10,...];addLEDs(3);d.Sf.LC.value=250;addLEDs(1);d.Sf.L00.value=2;d.Sf.L10.value=0;d.Sf.LC0.value=250;d.Sf.LT0.value=22;d.Sf.CO0.value=0;d.Sf.LS0.value=0;d.Sf.LS0.checked=0;d.Sf.MA.value=5400;d.Sf.LA.value=55;d.getElementsByClassName("pow")[0].innerHTML="350mA";d.Sf.CA.value=40;d.Sf.AW.value=3;d.Sf.BO.checked=0;d.Sf.BP.value=3;d.Sf.GB.checked=0;d.Sf.GC.checked=1;d.Sf.TF.checked=1;d.Sf.TD.value=700;d.Sf.PF.checked=0;d.Sf.BF.value=64;d.Sf.TB.value=0;d.Sf.TL.value=60;d.Sf.TW.value=1;d.Sf.PB.selectedIndex=0;d.Sf.RV.checked=0;d.Sf.SL.checked=0;d.Sf.RL.value=12;d.Sf.RM.checked=0;d.Sf.BT.value=-1;d.Sf.IR.value=-1;d.Sf.AX.value=-1;
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
@ -249,7 +272,7 @@
|
||||
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
||||
<button type="button" onclick="B()">Back</button><button type="button" onclick="trySubmit()">Save</button><hr>
|
||||
<h2>LED & Hardware setup</h2>
|
||||
Total LED count: <input name="LC" type="number" min="1" max="8192" oninput="UI()" required><br>
|
||||
Total LED count: <input name="LC" id="LC" type="number" min="1" max="8192" oninput="UI()" required readonly><br>
|
||||
<i>Recommended power supply for brightest white:</i><br>
|
||||
<b><span id="psu">?</span></b><br>
|
||||
<span id="psu2"><br></span>
|
||||
@ -280,14 +303,18 @@
|
||||
</div>
|
||||
<h3>Hardware setup</h3>
|
||||
<div id="mLC">LED outputs:</div>
|
||||
<button type="button" id="+" onclick="addLEDs(1)" style="display:none;border-radius:20px;height:36px;">+</button>
|
||||
<button type="button" id="-" onclick="addLEDs(-1)" style="display:none;border-radius:20px;width:36px;height:36px;">-</button><br>
|
||||
<button type="button" id="+" onclick="addLEDs(1)">+</button>
|
||||
<button type="button" id="-" onclick="addLEDs(-1)">-</button><br>
|
||||
LED Memory Usage: <span id="m0">0</span> / <span id="m1">?</span> B<br>
|
||||
<div id="dbar" style="display:inline-block; width: 100px; height: 10px; border-radius: 20px;"></div><br>
|
||||
<div id="ledwarning" style="color: orange; display: none;">
|
||||
⚠ You might run into stability or lag issues.<br>
|
||||
Use less than <span id="wreason">800 LEDs per pin</span> for the best experience!<br>
|
||||
</div><br>
|
||||
</div>
|
||||
<div id="ledwarning2" style="color: orangered; display: none;">
|
||||
⚠ Pin 3 has memory restrictions.<br>
|
||||
Use less than <span id="wreason2">500</span> LEDs in total to avoid memory issues!<br>
|
||||
</div><hr style="width:260px">
|
||||
Relay pin: <input type="number" min="-1" max="40" name="RL" onchange="UI()"> Active high <input type="checkbox" name="RM"><br>
|
||||
Button pin: <input type="number" min="-1" max="40" name="BT" onchange="UI()"><br>
|
||||
IR pin: <input type="number" min="-1" max="40" name="IR" onchange="UI()"><br>
|
||||
|
@ -14,10 +14,12 @@ button {
|
||||
color: #fff;
|
||||
font-family: Verdana, sans-serif;
|
||||
border: 0.3ch solid #333;
|
||||
border-radius: 24px;
|
||||
display: inline-block;
|
||||
font-size: 20px;
|
||||
margin: 8px;
|
||||
margin-top: 12px;
|
||||
margin: 12px 8px 8px;
|
||||
padding: 8px 12px;
|
||||
min-width: 48px;
|
||||
}
|
||||
.helpB {
|
||||
text-align: left;
|
||||
@ -32,6 +34,20 @@ input {
|
||||
}
|
||||
input[type="number"] {
|
||||
width: 4em;
|
||||
font-size: medium;
|
||||
margin: 2px;
|
||||
}
|
||||
select {
|
||||
margin: 2px;
|
||||
font-size: medium;
|
||||
}
|
||||
input[type="checkbox"] {
|
||||
/* Double-sized Checkboxes */
|
||||
-ms-transform: scale(2); /* IE */
|
||||
-moz-transform: scale(2); /* FF */
|
||||
-webkit-transform: scale(2); /* Safari and Chrome */
|
||||
-o-transform: scale(2); /* Opera */
|
||||
transform: scale(2);
|
||||
}
|
||||
select {
|
||||
background: #333;
|
||||
|
@ -149,6 +149,8 @@ void _overlayCronixie();
|
||||
void _drawOverlayCronixie();
|
||||
|
||||
//playlist.cpp
|
||||
void shufflePlaylist();
|
||||
void unloadPlaylist();
|
||||
void loadPlaylist(JsonObject playlistObject);
|
||||
void handlePlaylist();
|
||||
|
||||
@ -170,6 +172,8 @@ void notify(byte callMode, bool followUp=false);
|
||||
void realtimeLock(uint32_t timeoutMs, byte md = REALTIME_MODE_GENERIC);
|
||||
void handleNotifications();
|
||||
void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w);
|
||||
void refreshNodeList();
|
||||
void sendSysInfoUDP(uint8_t repeats=1);
|
||||
|
||||
//um_manager.cpp
|
||||
class Usermod {
|
||||
|
File diff suppressed because one or more lines are too long
4201
wled00/html_ui.h
4201
wled00/html_ui.h
File diff suppressed because it is too large
Load Diff
201
wled00/json.cpp
201
wled00/json.cpp
@ -1,5 +1,7 @@
|
||||
#include "wled.h"
|
||||
|
||||
#include "palettes.h"
|
||||
|
||||
/*
|
||||
* JSON API (De)serialization
|
||||
*/
|
||||
@ -279,7 +281,7 @@ bool deserializeState(JsonObject root)
|
||||
|
||||
JsonObject playlist = root[F("playlist")];
|
||||
if (!playlist.isNull()) {
|
||||
loadPlaylist(playlist); return stateResponse;
|
||||
loadPlaylist(playlist); return stateResponse; //maybe we need not return here
|
||||
}
|
||||
|
||||
colorUpdated(noNotification ? NOTIFIER_CALL_MODE_NO_NOTIFY : NOTIFIER_CALL_MODE_DIRECT_CHANGE);
|
||||
@ -345,6 +347,8 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme
|
||||
root[F("ps")] = currentPreset;
|
||||
root[F("pl")] = (presetCyclingEnabled) ? 0: -1;
|
||||
|
||||
// JsonObject um = root.createNestedObject(F("um"));
|
||||
// usermods.addToJsonState(um);
|
||||
usermods.addToJsonState(root);
|
||||
|
||||
//temporary for preset cycle
|
||||
@ -420,7 +424,13 @@ void serializeInfo(JsonObject root)
|
||||
leds[F("rgbw")] = useRGBW;
|
||||
leds[F("wv")] = useRGBW && (strip.rgbwMode == RGBW_MODE_MANUAL_ONLY || strip.rgbwMode == RGBW_MODE_DUAL); //should a white channel slider be displayed?
|
||||
JsonArray leds_pin = leds.createNestedArray("pin");
|
||||
leds_pin.add(LEDPIN);
|
||||
//leds_pin.add(LEDPIN);
|
||||
for (uint8_t s=0; s<busses.getNumBusses(); s++) {
|
||||
Bus *bus = busses.getBus(s);
|
||||
uint8_t pins[5];
|
||||
bus->getPins(pins);
|
||||
leds_pin.add(pins[0]); // need to elaborate this for multipin strips
|
||||
}
|
||||
|
||||
leds[F("pwr")] = strip.currentMilliamps;
|
||||
leds[F("fps")] = strip.getFps();
|
||||
@ -500,7 +510,6 @@ void serializeInfo(JsonObject root)
|
||||
root[F("freeheap")] = ESP.getFreeHeap();
|
||||
root[F("uptime")] = millis()/1000 + rolloverMillis*4294967;
|
||||
|
||||
|
||||
usermods.addToJsonInfo(root);
|
||||
|
||||
byte os = 0;
|
||||
@ -533,6 +542,187 @@ void serializeInfo(JsonObject root)
|
||||
root[F("brand")] = "WLED";
|
||||
root[F("product")] = F("FOSS");
|
||||
root["mac"] = escapedMac;
|
||||
|
||||
JsonArray nodes = root.createNestedArray("nodes");
|
||||
IPAddress ip = Network.localIP();
|
||||
for (NodesMap::iterator it = Nodes.begin(); it != Nodes.end(); ++it)
|
||||
{
|
||||
if (it->second.ip[0] != 0)
|
||||
{
|
||||
bool isThisUnit = it->first == ip[3];
|
||||
|
||||
if (isThisUnit) continue;
|
||||
|
||||
JsonObject node = nodes.createNestedObject();
|
||||
node[F("name")] = it->second.nodeName;
|
||||
node[F("type")] = getNodeTypeDisplayString(it->second.nodeType);
|
||||
node[F("ip")] = it->second.ip.toString();
|
||||
node[F("age")] = it->second.age;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void setPaletteColors(JsonArray json, CRGBPalette16 palette)
|
||||
{
|
||||
for (int i = 0; i < 16; i++) {
|
||||
JsonArray colors = json.createNestedArray();
|
||||
CRGB color = palette[i];
|
||||
colors.add((((float)i / (float)16) * 255));
|
||||
colors.add(color.red);
|
||||
colors.add(color.green);
|
||||
colors.add(color.blue);
|
||||
}
|
||||
}
|
||||
|
||||
void setPaletteColors(JsonArray json, byte* tcp)
|
||||
{
|
||||
TRGBGradientPaletteEntryUnion* ent = (TRGBGradientPaletteEntryUnion*)(tcp);
|
||||
TRGBGradientPaletteEntryUnion u;
|
||||
|
||||
// Count entries
|
||||
uint16_t count = 0;
|
||||
do {
|
||||
u = *(ent + count);
|
||||
count++;
|
||||
} while ( u.index != 255);
|
||||
|
||||
u = *ent;
|
||||
int indexstart = 0;
|
||||
while( indexstart < 255) {
|
||||
indexstart = u.index;
|
||||
|
||||
JsonArray colors = json.createNestedArray();
|
||||
colors.add(u.index);
|
||||
colors.add(u.r);
|
||||
colors.add(u.g);
|
||||
colors.add(u.b);
|
||||
|
||||
ent++;
|
||||
u = *ent;
|
||||
}
|
||||
}
|
||||
|
||||
void serializePalettes(JsonObject root, AsyncWebServerRequest* request)
|
||||
{
|
||||
#ifdef ESP8266
|
||||
int itemPerPage = 5;
|
||||
#else
|
||||
int itemPerPage = 8;
|
||||
#endif
|
||||
|
||||
int page;
|
||||
if (request->hasParam("page")) {
|
||||
page = request->getParam("page")->value().toInt();
|
||||
} else {
|
||||
page = 1;
|
||||
}
|
||||
|
||||
int palettesCount = strip.getPaletteCount();
|
||||
|
||||
int maxPage = ceil((float)palettesCount / (float)itemPerPage);
|
||||
if (page > maxPage) {
|
||||
page = maxPage;
|
||||
}
|
||||
|
||||
int start = itemPerPage * (page - 1);
|
||||
int end = start + itemPerPage;
|
||||
if (end > palettesCount - 1) {
|
||||
end = palettesCount;
|
||||
}
|
||||
|
||||
root[F("m")] = maxPage;
|
||||
JsonObject palettes = root.createNestedObject("p");
|
||||
|
||||
for (int i = start; i < end; i++) {
|
||||
JsonArray curPalette = palettes.createNestedArray(String(i));
|
||||
CRGB prim;
|
||||
CRGB sec;
|
||||
CRGB ter;
|
||||
switch (i) {
|
||||
case 0: //default palette
|
||||
setPaletteColors(curPalette, PartyColors_p);
|
||||
break;
|
||||
case 1: //random
|
||||
curPalette.add(F("r"));
|
||||
curPalette.add(F("r"));
|
||||
curPalette.add(F("r"));
|
||||
curPalette.add(F("r"));
|
||||
/**setPaletteColors(
|
||||
curPalette,
|
||||
CRGBPalette16(
|
||||
CHSV(random8(), 255, random8(128, 255)),
|
||||
CHSV(random8(), 255, random8(128, 255)),
|
||||
CHSV(random8(), 192, random8(128, 255)),
|
||||
CHSV(random8(), 255, random8(128, 255))
|
||||
)
|
||||
);**/
|
||||
break;
|
||||
case 2: //primary color only
|
||||
curPalette.add(F("c1"));
|
||||
break;
|
||||
case 3: //primary + secondary
|
||||
curPalette.add(F("c1"));
|
||||
curPalette.add(F("c1"));
|
||||
curPalette.add(F("c2"));
|
||||
curPalette.add(F("c2"));
|
||||
break;
|
||||
case 4: //primary + secondary + tertiary
|
||||
curPalette.add(F("c3"));
|
||||
curPalette.add(F("c2"));
|
||||
curPalette.add(F("c1"));
|
||||
break;
|
||||
case 5: {//primary + secondary (+tert if not off), more distinct
|
||||
|
||||
curPalette.add(F("c1"));
|
||||
curPalette.add(F("c1"));
|
||||
curPalette.add(F("c1"));
|
||||
curPalette.add(F("c1"));
|
||||
curPalette.add(F("c1"));
|
||||
curPalette.add(F("c2"));
|
||||
curPalette.add(F("c2"));
|
||||
curPalette.add(F("c2"));
|
||||
curPalette.add(F("c2"));
|
||||
curPalette.add(F("c2"));
|
||||
curPalette.add(F("c3"));
|
||||
curPalette.add(F("c3"));
|
||||
curPalette.add(F("c3"));
|
||||
curPalette.add(F("c3"));
|
||||
curPalette.add(F("c3"));
|
||||
curPalette.add(F("c1"));
|
||||
break;}
|
||||
case 6: //Party colors
|
||||
setPaletteColors(curPalette, PartyColors_p);
|
||||
break;
|
||||
case 7: //Cloud colors
|
||||
setPaletteColors(curPalette, CloudColors_p);
|
||||
break;
|
||||
case 8: //Lava colors
|
||||
setPaletteColors(curPalette, LavaColors_p);
|
||||
break;
|
||||
case 9: //Ocean colors
|
||||
setPaletteColors(curPalette, OceanColors_p);
|
||||
break;
|
||||
case 10: //Forest colors
|
||||
setPaletteColors(curPalette, ForestColors_p);
|
||||
break;
|
||||
case 11: //Rainbow colors
|
||||
setPaletteColors(curPalette, RainbowColors_p);
|
||||
break;
|
||||
case 12: //Rainbow stripe colors
|
||||
setPaletteColors(curPalette, RainbowStripeColors_p);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (i < 13) {
|
||||
break;
|
||||
}
|
||||
byte tcp[72];
|
||||
memcpy_P(tcp, (byte*)pgm_read_dword(&(gGradientPalettes[i - 13])), 72);
|
||||
setPaletteColors(curPalette, tcp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void serveJson(AsyncWebServerRequest* request)
|
||||
@ -541,7 +731,8 @@ void serveJson(AsyncWebServerRequest* request)
|
||||
const String& url = request->url();
|
||||
if (url.indexOf("state") > 0) subJson = 1;
|
||||
else if (url.indexOf("info") > 0) subJson = 2;
|
||||
else if (url.indexOf("si") > 0) subJson = 3;
|
||||
else if (url.indexOf("si") > 0) subJson = 3;
|
||||
else if (url.indexOf("palx") > 0) subJson = 4;
|
||||
else if (url.indexOf("live") > 0) {
|
||||
serveLiveLeds(request);
|
||||
return;
|
||||
@ -568,6 +759,8 @@ void serveJson(AsyncWebServerRequest* request)
|
||||
serializeState(doc); break;
|
||||
case 2: //info
|
||||
serializeInfo(doc); break;
|
||||
case 4: //palettes
|
||||
serializePalettes(doc, request); break;
|
||||
default: //all
|
||||
JsonObject state = doc.createNestedObject("state");
|
||||
serializeState(state);
|
||||
|
@ -30,6 +30,7 @@ void toggleOnOff()
|
||||
{
|
||||
briLast = bri;
|
||||
bri = 0;
|
||||
unloadPlaylist();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,19 +10,83 @@ typedef struct PlaylistEntry {
|
||||
uint16_t tr;
|
||||
} ple;
|
||||
|
||||
byte playlistRepeat = 1;
|
||||
byte playlistEndPreset = 0;
|
||||
|
||||
uint8_t* playlistEntries;
|
||||
|
||||
byte playlistLen;
|
||||
int8_t playlistIndex = -1;
|
||||
|
||||
int8_t playlistRepeat = 1;
|
||||
byte playlistEndPreset = 0;
|
||||
byte *playlistEntries = nullptr;
|
||||
byte playlistLen;
|
||||
int8_t playlistIndex = -1;
|
||||
uint16_t playlistEntryDur = 0;
|
||||
|
||||
|
||||
void shufflePlaylist() {
|
||||
int currentIndex = playlistLen, randomIndex;
|
||||
|
||||
PlaylistEntry temporaryValue, *entries = reinterpret_cast<PlaylistEntry*>(playlistEntries);
|
||||
|
||||
// While there remain elements to shuffle...
|
||||
while (currentIndex--) {
|
||||
// Pick a random element...
|
||||
randomIndex = random(0, currentIndex);
|
||||
// And swap it with the current element.
|
||||
temporaryValue = entries[currentIndex];
|
||||
entries[currentIndex] = entries[randomIndex];
|
||||
entries[randomIndex] = temporaryValue;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The same thing as saving and loading playlist can be achieved using JSON API saved in a preset.
|
||||
*
|
||||
void deserializePlaylist() {
|
||||
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
|
||||
|
||||
DEBUG_PRINTLN(F("Reading playlist from /playlist.json..."));
|
||||
|
||||
if (!readObjectFromFile("/playlist.json", nullptr, &doc)) return; //if file does not exist just exit
|
||||
|
||||
JsonObject playlist = doc[F("playlist")];
|
||||
if (!playlist.isNull()) loadPlaylist(playlist);
|
||||
}
|
||||
|
||||
|
||||
void serializePlaylist() {
|
||||
DynamicJsonDocument doc(JSON_BUFFER_SIZE/8); // we don't need big buffer (>1k is ok)
|
||||
|
||||
DEBUG_PRINTLN(F("Writing playlist to /playlist.json..."));
|
||||
|
||||
PlaylistEntry* entries = reinterpret_cast<PlaylistEntry*>(playlistEntries);
|
||||
|
||||
JsonObject playlist = doc.createNestedObject(F("playlist"));
|
||||
JsonArray ps = playlist.createNestedArray(F("ps"));
|
||||
JsonArray dur = playlist.createNestedArray(F("dur"));
|
||||
JsonArray tr = playlist.createNestedArray(F("transition"));
|
||||
for (uint8_t i=0; i<playlistLen; i++) {
|
||||
ps.add(entries[i].preset);
|
||||
dur.add(entries[i].dur);
|
||||
tr.add(entries[i].tr);
|
||||
}
|
||||
playlist[F("repeat")] = playlistRepeat; // TODO: this one is decreasing with each loop
|
||||
playlist[F("end")] = playlistEndPreset;
|
||||
|
||||
File f = WLED_FS.open("/playlist.json", "w");
|
||||
if (f) serializeJson(doc, f);
|
||||
f.close();
|
||||
}
|
||||
*/
|
||||
|
||||
void unloadPlaylist() {
|
||||
if (playlistEntries != nullptr) {
|
||||
delete[] playlistEntries;
|
||||
playlistEntries = nullptr;
|
||||
}
|
||||
currentPlaylist = playlistIndex = -1;
|
||||
playlistLen = playlistEntryDur = 0;
|
||||
}
|
||||
|
||||
void loadPlaylist(JsonObject playlistObj) {
|
||||
delete playlistEntries;
|
||||
playlistIndex = -1; playlistEntryDur = 0;
|
||||
|
||||
unloadPlaylist();
|
||||
|
||||
JsonArray presets = playlistObj["ps"];
|
||||
playlistLen = presets.size();
|
||||
if (playlistLen == 0) return;
|
||||
@ -72,26 +136,30 @@ void loadPlaylist(JsonObject playlistObj) {
|
||||
currentPlaylist = 0; //TODO here we need the preset ID where the playlist is saved
|
||||
}
|
||||
|
||||
void handlePlaylist()
|
||||
{
|
||||
|
||||
void handlePlaylist() {
|
||||
if (currentPlaylist < 0 || playlistEntries == nullptr || presetCyclingEnabled) return;
|
||||
|
||||
if (millis() - presetCycledTime > (100*playlistEntryDur))
|
||||
{
|
||||
if (millis() - presetCycledTime > (100*playlistEntryDur)) {
|
||||
presetCycledTime = millis();
|
||||
if (bri == 0 || nightlightActive) return;
|
||||
|
||||
playlistIndex++;
|
||||
if (playlistIndex >= playlistLen) {
|
||||
playlistIndex = 0;
|
||||
if (playlistRepeat == 1) { //stop
|
||||
currentPlaylist = -1;
|
||||
delete playlistEntries;
|
||||
playlistEntries = nullptr;
|
||||
if (playlistEndPreset) applyPreset(playlistEndPreset);
|
||||
return;
|
||||
++playlistIndex %= playlistLen; // -1 at 1st run (limit to playlistLen)
|
||||
|
||||
if (!playlistRepeat && !playlistIndex) { //stop if repeat == 0 and restart of playlist
|
||||
currentPlaylist = -1;
|
||||
delete[] playlistEntries;
|
||||
playlistEntries = nullptr;
|
||||
if (playlistEndPreset) applyPreset(playlistEndPreset);
|
||||
return;
|
||||
}
|
||||
// playlist roll-over
|
||||
if (!playlistIndex) {
|
||||
if (playlistRepeat > 0) {// playlistRepeat < 0 => endless loop with shuffling presets
|
||||
playlistRepeat--; // decrease repeat count on each index reset
|
||||
} else {
|
||||
shufflePlaylist(); // shuffle playlist and start over
|
||||
}
|
||||
if (playlistRepeat > 1) playlistRepeat--;
|
||||
}
|
||||
|
||||
PlaylistEntry* entries = reinterpret_cast<PlaylistEntry*>(playlistEntries);
|
||||
|
@ -85,26 +85,39 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
//TODO remove all busses, but not in this system call
|
||||
//busses->removeAll();
|
||||
|
||||
skipFirstLed = request->hasArg(F("SL"));
|
||||
useRGBW = false;
|
||||
ledCount = 0;
|
||||
|
||||
uint8_t colorOrder, type;
|
||||
uint16_t length, start;
|
||||
uint8_t pins[2] = {255, 255};
|
||||
uint8_t pins[5] = {255, 255, 255, 255, 255};
|
||||
|
||||
for (uint8_t s = 0; s < WLED_MAX_BUSSES; s++) {
|
||||
char lp[4] = "L0"; lp[2] = 48+s; lp[3] = 0; //ascii 0-9 //strip data pin
|
||||
char lk[4] = "L1"; lk[2] = 48+s; lk[3] = 0; //strip clock pin. 255 for none
|
||||
char l0[4] = "L0"; l0[2] = 48+s; l0[3] = 0; //ascii 0-9 //strip data pin
|
||||
char l1[4] = "L1"; l1[2] = 48+s; l1[3] = 0; //strip clock pin. 255 for none
|
||||
char l2[4] = "L2"; l2[2] = 48+s; l2[3] = 0; //strip pin. 255 for none
|
||||
char l3[4] = "L3"; l3[2] = 48+s; l3[3] = 0; //strip pin. 255 for none
|
||||
char l4[4] = "L4"; l4[2] = 48+s; l4[3] = 0; //strip pin. 255 for none
|
||||
char lc[4] = "LC"; lc[2] = 48+s; lc[3] = 0; //strip length
|
||||
char co[4] = "CO"; co[2] = 48+s; co[3] = 0; //strip color order
|
||||
char lt[4] = "LT"; lt[2] = 48+s; lt[3] = 0; //strip type
|
||||
char ls[4] = "LS"; ls[2] = 48+s; ls[3] = 0; //strip start LED
|
||||
char cv[4] = "CV"; cv[2] = 48+s; cv[3] = 0; //strip reverse
|
||||
if (!request->hasArg(lp)) {
|
||||
char ew[4] = "EW"; ew[2] = 48+s; ew[3] = 0; //strip RGBW override
|
||||
|
||||
if (!request->hasArg(l0)) {
|
||||
DEBUG_PRINTLN("No data."); break;
|
||||
}
|
||||
pins[0] = request->arg(lp).toInt();
|
||||
if (request->hasArg(lk)) {
|
||||
pins[1] = (request->arg(lk).length() > 0) ? request->arg(lk).toInt() : 255;
|
||||
}
|
||||
pins[0] = request->arg(l0).toInt();
|
||||
if (request->hasArg(l1)) pins[1] = (request->arg(l1).length() > 0) ? request->arg(l1).toInt() : 255;
|
||||
if (request->hasArg(l2)) pins[2] = (request->arg(l2).length() > 0) ? request->arg(l2).toInt() : 255;
|
||||
if (request->hasArg(l3)) pins[3] = (request->arg(l3).length() > 0) ? request->arg(l3).toInt() : 255;
|
||||
if (request->hasArg(l4)) pins[4] = (request->arg(l4).length() > 0) ? request->arg(l4).toInt() : 255;
|
||||
|
||||
type = request->arg(lt).toInt();
|
||||
if (request->hasArg(ew)) SET_BIT(type,7); else UNSET_BIT(type,7); // hack bit 7 to indicate RGBW (as a LED type override if necessary)
|
||||
useRGBW |= request->hasArg(ew);
|
||||
|
||||
if (request->hasArg(lc) && request->arg(lc).toInt() > 0) {
|
||||
length = request->arg(lc).toInt();
|
||||
@ -113,19 +126,21 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
}
|
||||
colorOrder = request->arg(co).toInt();
|
||||
start = (request->hasArg(ls)) ? request->arg(ls).toInt() : 0;
|
||||
ledCount += length;
|
||||
|
||||
// actual finalization is done in loop()
|
||||
if (busConfigs[s] != nullptr) delete busConfigs[s];
|
||||
busConfigs[s] = new BusConfig(type, pins, start, length, colorOrder, request->hasArg(cv));
|
||||
busConfigs[s] = new BusConfig(type, pins, start, length, colorOrder, request->hasArg(cv), skipFirstLed);
|
||||
}
|
||||
|
||||
ledCount = request->arg(F("LC")).toInt();
|
||||
if (t > 0 && t <= MAX_LEDS) ledCount = t;
|
||||
// ledCount = request->arg(F("LC")).toInt();
|
||||
// if (t > 0 && t <= MAX_LEDS) ledCount = t;
|
||||
//DMA method uses too much ram, TODO: limit!
|
||||
|
||||
// upate other pins
|
||||
#ifndef WLED_DISABLE_INFRARED
|
||||
int hw_ir_pin = request->arg(F("IR")).toInt();
|
||||
if (pinManager.isPinOk(hw_ir_pin) && pinManager.allocatePin(hw_ir_pin,false)) {
|
||||
if (pinManager.allocatePin(hw_ir_pin,false)) {
|
||||
irPin = hw_ir_pin;
|
||||
} else {
|
||||
irPin = -1;
|
||||
@ -158,8 +173,8 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
strip.ablMilliampsMax = request->arg(F("MA")).toInt();
|
||||
strip.milliampsPerLed = request->arg(F("LA")).toInt();
|
||||
|
||||
useRGBW = request->hasArg(F("EW"));
|
||||
strip.rgbwMode = request->arg(F("AW")).toInt();
|
||||
// useRGBW = request->hasArg(F("EW"));
|
||||
strip.rgbwMode = request->arg(F("AW")).toInt(); // auto white calculation
|
||||
|
||||
briS = request->arg(F("CA")).toInt();
|
||||
|
||||
@ -184,8 +199,8 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
|
||||
t = request->arg(F("PB")).toInt();
|
||||
if (t >= 0 && t < 4) strip.paletteBlend = t;
|
||||
strip.reverseMode = request->hasArg(F("RV"));
|
||||
skipFirstLed = request->hasArg(F("SL"));
|
||||
// strip.reverseMode = request->hasArg(F("RV"));
|
||||
// skipFirstLed = request->hasArg(F("SL"));
|
||||
t = request->arg(F("BF")).toInt();
|
||||
if (t > 0) briMultiplier = t;
|
||||
}
|
||||
|
122
wled00/udp.cpp
122
wled00/udp.cpp
@ -163,8 +163,30 @@ void handleNotifications()
|
||||
if (!isSupp && notifierUdp.remoteIP() == Network.localIP()) return; //don't process broadcasts we send ourselves
|
||||
|
||||
uint8_t udpIn[packetSize +1];
|
||||
if (isSupp) notifier2Udp.read(udpIn, packetSize);
|
||||
else notifierUdp.read(udpIn, packetSize);
|
||||
uint16_t len;
|
||||
if (isSupp) len = notifier2Udp.read(udpIn, packetSize);
|
||||
else len = notifierUdp.read(udpIn, packetSize);
|
||||
|
||||
// WLED nodes info notifications
|
||||
if (isSupp && udpIn[0] == 255 && udpIn[1] == 1 && len >= 40) {
|
||||
uint8_t unit = udpIn[39];
|
||||
Nodes[unit].age = 0; // Create a new element when not present
|
||||
NodesMap::iterator it = Nodes.find(unit);
|
||||
|
||||
if (it != Nodes.end()) {
|
||||
for (byte x = 0; x < 4; x++) {
|
||||
it->second.ip[x] = udpIn[x + 2];
|
||||
}
|
||||
it->second.age = 0; // reset 'age counter'
|
||||
char tmpNodeName[33] = { 0 };
|
||||
memcpy(&tmpNodeName[0], reinterpret_cast<byte *>(&udpIn[6]), 32);
|
||||
tmpNodeName[32] = 0;
|
||||
it->second.nodeName = tmpNodeName;
|
||||
it->second.nodeName.trim();
|
||||
it->second.nodeType = udpIn[38];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//wled notifier, ignore if realtime packets active
|
||||
if (udpIn[0] == 0 && !realtimeMode && receiveNotifications)
|
||||
@ -358,3 +380,99 @@ void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
Refresh aging for remote units, drop if too old...
|
||||
\*********************************************************************************************/
|
||||
void refreshNodeList()
|
||||
{
|
||||
for (NodesMap::iterator it = Nodes.begin(); it != Nodes.end();) {
|
||||
bool mustRemove = true;
|
||||
|
||||
if (it->second.ip[0] != 0) {
|
||||
if (it->second.age < 10) {
|
||||
it->second.age++;
|
||||
mustRemove = false;
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
if (mustRemove) {
|
||||
it = Nodes.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
Broadcast system info to other nodes. (to update node lists)
|
||||
\*********************************************************************************************/
|
||||
void sendSysInfoUDP(uint8_t repeats)
|
||||
{
|
||||
if (!udpConnected || !repeats) {
|
||||
return;
|
||||
}
|
||||
|
||||
IPAddress ip = Network.localIP();
|
||||
|
||||
// TODO: make a nice struct of it and clean up
|
||||
// 0: 1 byte 'binary token 255'
|
||||
// 1: 1 byte id '1'
|
||||
// 2: 4 byte ip
|
||||
// 6: 32 char name
|
||||
// 38: 1 byte node type id
|
||||
// 39: 1 byte node id
|
||||
// 40 bytes total
|
||||
|
||||
// send my info to the world...
|
||||
for (;repeats--;)
|
||||
{
|
||||
/*
|
||||
escapedMac // mac address
|
||||
*/
|
||||
|
||||
uint8_t data[40] = {0};
|
||||
data[0] = 255;
|
||||
data[1] = 1;
|
||||
|
||||
for (byte x = 0; x < 4; x++) {
|
||||
data[x + 2] = ip[x];
|
||||
}
|
||||
memcpy((byte *)data + 6, serverDescription, 32);
|
||||
#ifdef ESP8266
|
||||
data[38] = NODE_TYPE_ID_ESP8266;
|
||||
#elif defined(ARDUINO_ARCH_ESP32)
|
||||
data[38] = NODE_TYPE_ID_ESP32;
|
||||
#else
|
||||
data[38] = NODE_TYPE_ID_UNDEFINED;
|
||||
#endif
|
||||
data[39] = ip[3]; // unit ID == last IP number
|
||||
|
||||
IPAddress broadcastIP(255, 255, 255, 255);
|
||||
notifier2Udp.beginPacket(broadcastIP, udpPort2);
|
||||
notifier2Udp.write(data, 40);
|
||||
notifier2Udp.endPacket();
|
||||
|
||||
if (repeats) delay(500);
|
||||
}
|
||||
|
||||
Nodes[ip[3]].age = 0; // Create new node when not already present.
|
||||
// store my own info also in the list
|
||||
NodesMap::iterator it = Nodes.find(ip[3]);
|
||||
|
||||
if (it != Nodes.end())
|
||||
{
|
||||
for (byte x = 0; x < 4; x++) {
|
||||
it->second.ip[x] = ip[x];
|
||||
}
|
||||
it->second.age = 0;
|
||||
it->second.nodeName = serverDescription;
|
||||
#ifdef ESP8266
|
||||
it->second.nodeType = NODE_TYPE_ID_ESP8266;
|
||||
#elif defined(ARDUINO_ARCH_ESP32)
|
||||
it->second.nodeType = NODE_TYPE_ID_ESP32;
|
||||
#else
|
||||
it->second.nodeType = NODE_TYPE_ID_UNDEFINED;
|
||||
#endif
|
||||
it->second.unit = ip[3];
|
||||
}
|
||||
}
|
||||
|
@ -203,7 +203,7 @@ void WLED::loop()
|
||||
busses.add(*busConfigs[i]);
|
||||
delete busConfigs[i]; busConfigs[i] = nullptr;
|
||||
}
|
||||
strip.finalizeInit(useRGBW, ledCount, skipFirstLed);
|
||||
strip.finalizeInit();
|
||||
yield();
|
||||
serializeConfig();
|
||||
}
|
||||
@ -221,10 +221,20 @@ void WLED::loop()
|
||||
#ifdef ESP8266
|
||||
MDNS.update();
|
||||
#endif
|
||||
if (millis() - lastMqttReconnectAttempt > 30000) {
|
||||
if (lastMqttReconnectAttempt > millis()) rolloverMillis++; //millis() rolls over every 50 days
|
||||
initMqtt();
|
||||
|
||||
//millis() rolls over every 50 days
|
||||
if (lastMqttReconnectAttempt > millis()) {
|
||||
rolloverMillis++;
|
||||
lastMqttReconnectAttempt = 0;
|
||||
}
|
||||
if (millis() - lastMqttReconnectAttempt > 30000) {
|
||||
// lastMqttReconnectAttempt = millis(); // don't do it in initMqtt()
|
||||
initMqtt();
|
||||
// refresh WLED nodes list
|
||||
refreshNodeList();
|
||||
sendSysInfoUDP();
|
||||
}
|
||||
|
||||
yield();
|
||||
handleWs();
|
||||
handleStatusLED();
|
||||
@ -269,6 +279,9 @@ void WLED::setup()
|
||||
#else
|
||||
DEBUG_PRINT("esp8266 ");
|
||||
DEBUG_PRINTLN(ESP.getCoreVersion());
|
||||
#ifdef WLED_DEBUG
|
||||
pinManager.allocatePin(1,true); // GPIO1 reserved for debug output
|
||||
#endif
|
||||
#endif
|
||||
int heapPreAlloc = ESP.getFreeHeap();
|
||||
DEBUG_PRINT("heap ");
|
||||
@ -360,16 +373,13 @@ void WLED::setup()
|
||||
void WLED::beginStrip()
|
||||
{
|
||||
// Initialize NeoPixel Strip and button
|
||||
|
||||
if (ledCount > MAX_LEDS || ledCount == 0)
|
||||
ledCount = 30;
|
||||
|
||||
strip.finalizeInit(useRGBW, ledCount, skipFirstLed);
|
||||
strip.finalizeInit(); // busses created during deserializeConfig()
|
||||
strip.setBrightness(0);
|
||||
strip.setShowCallback(handleOverlayDraw);
|
||||
|
||||
if (bootPreset > 0) applyPreset(bootPreset);
|
||||
if (turnOnAtBoot) {
|
||||
if (bootPreset > 0) {
|
||||
applyPreset(bootPreset);
|
||||
} else if (turnOnAtBoot) {
|
||||
if (briS > 0) bri = briS;
|
||||
else if (bri == 0) bri = 128;
|
||||
} else {
|
||||
@ -378,12 +388,10 @@ void WLED::beginStrip()
|
||||
colorUpdated(NOTIFIER_CALL_MODE_INIT);
|
||||
|
||||
// init relay pin
|
||||
if (rlyPin>=0)
|
||||
digitalWrite(rlyPin, (rlyMde ? bri : !bri));
|
||||
if (rlyPin>=0) digitalWrite(rlyPin, (bri ? rlyMde : !rlyMde));
|
||||
|
||||
// disable button if it is "pressed" unintentionally
|
||||
if (btnPin>=0 && isButtonPressed())
|
||||
buttonEnabled = false;
|
||||
if (btnPin>=0 && isButtonPressed()) buttonEnabled = false;
|
||||
}
|
||||
|
||||
void WLED::initAP(bool resetAP)
|
||||
|
@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
// version code in format yymmddb (b = daily build)
|
||||
#define VERSION 2102050
|
||||
#define VERSION 2102240
|
||||
|
||||
//uncomment this if you have a "my_config.h" file you'd like to use
|
||||
//#define WLED_USE_MY_CONFIG
|
||||
@ -117,6 +117,7 @@
|
||||
#include "const.h"
|
||||
#include "pin_manager.h"
|
||||
#include "bus_manager.h"
|
||||
#include "NodeStruct.h"
|
||||
|
||||
#ifndef CLIENT_SSID
|
||||
#define CLIENT_SSID DEFAULT_CLIENT_SSID
|
||||
@ -132,12 +133,6 @@
|
||||
Comment out this error message to build regardless.
|
||||
#endif
|
||||
|
||||
#if !defined(IRPIN) || IRPIN < 0
|
||||
#ifndef WLED_DISABLE_INFRARED
|
||||
#define WLED_DISABLE_INFRARED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef WLED_DISABLE_INFRARED
|
||||
#include <IRremoteESP8266.h>
|
||||
#include <IRrecv.h>
|
||||
@ -250,6 +245,8 @@ WLED_GLOBAL char serverDescription[33] _INIT("WLED"); // Name of module
|
||||
WLED_GLOBAL bool syncToggleReceive _INIT(false); // UIs which only have a single button for sync should toggle send+receive if this is true, only send otherwise
|
||||
|
||||
// Sync CONFIG
|
||||
WLED_GLOBAL NodesMap Nodes;
|
||||
|
||||
WLED_GLOBAL bool buttonEnabled _INIT(true);
|
||||
WLED_GLOBAL byte irEnabled _INIT(0); // Infrared receiver
|
||||
|
||||
@ -475,7 +472,7 @@ WLED_GLOBAL uint8_t tpmPacketCount _INIT(0);
|
||||
WLED_GLOBAL uint16_t tpmPayloadFrameSize _INIT(0);
|
||||
|
||||
// mqtt
|
||||
WLED_GLOBAL long lastMqttReconnectAttempt _INIT(0);
|
||||
WLED_GLOBAL unsigned long lastMqttReconnectAttempt _INIT(0);
|
||||
WLED_GLOBAL long lastInterfaceUpdate _INIT(0);
|
||||
WLED_GLOBAL byte interfaceUpdateCallMode _INIT(NOTIFIER_CALL_MODE_INIT);
|
||||
WLED_GLOBAL char mqttStatusTopic[40] _INIT(""); // this must be global because of async handlers
|
||||
@ -604,6 +601,10 @@ WLED_GLOBAL UsermodManager usermods _INIT(UsermodManager());
|
||||
#define WLED_WIFI_CONFIGURED (strlen(clientSSID) >= 1 && strcmp(clientSSID, DEFAULT_CLIENT_SSID) != 0)
|
||||
#define WLED_MQTT_CONNECTED (mqtt != nullptr && mqtt->connected())
|
||||
|
||||
#define GET_BIT(var,bit) ((var>>bit)&0x01)
|
||||
#define SET_BIT(var,bit) (var|=(uint16_t)(0x0001<<bit))
|
||||
#define UNSET_BIT(var,bit) (var&=(~(uint16_t)(0x0001<<bit)))
|
||||
|
||||
// append new c string to temp buffer efficiently
|
||||
bool oappend(const char* txt);
|
||||
// append new number to temp buffer efficiently
|
||||
|
@ -115,7 +115,7 @@ void loadSettingsFromEEPROM()
|
||||
}
|
||||
receiveNotificationBrightness = EEPROM.read(250);
|
||||
fadeTransition = EEPROM.read(251);
|
||||
strip.reverseMode = EEPROM.read(252);
|
||||
// strip.reverseMode = EEPROM.read(252);
|
||||
transitionDelayDefault = EEPROM.read(253) + ((EEPROM.read(254) << 8) & 0xFF00);
|
||||
transitionDelay = transitionDelayDefault;
|
||||
briMultiplier = EEPROM.read(255);
|
||||
|
@ -256,10 +256,10 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
if (subPage == 2) {
|
||||
char nS[3];
|
||||
|
||||
// add usermod pins as d.um_p array (TODO: usermod config shouldn't use state. instead we should load "um" object from cfg.json)
|
||||
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
|
||||
JsonObject mods = doc.createNestedObject(F("mods"));
|
||||
usermods.addToJsonState(mods);
|
||||
// add usermod pins as d.um_p array
|
||||
DynamicJsonDocument doc(JSON_BUFFER_SIZE/2);
|
||||
JsonObject mods = doc.createNestedObject(F("um"));
|
||||
usermods.addToConfig(mods);
|
||||
if (!mods.isNull()) {
|
||||
uint8_t i=0;
|
||||
oappend(SET_F("d.um_p=["));
|
||||
@ -267,26 +267,44 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
if (strncmp_P(kv.key().c_str(),PSTR("pin_"),4) == 0) {
|
||||
if (i++) oappend(SET_F(","));
|
||||
oappend(itoa((int)kv.value(),nS,10));
|
||||
} else if (!kv.value().isNull()) {
|
||||
// element is an JsonObject
|
||||
JsonObject obj = kv.value();
|
||||
if (obj[F("pin")] != nullptr) {
|
||||
if (i++) oappend(SET_F(","));
|
||||
oappend(itoa((int)obj[F("pin")],nS,10));
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef ESP8266
|
||||
#ifdef WLED_DEBUG
|
||||
if (i==0)
|
||||
oappend(SET_F("1"));
|
||||
else
|
||||
oappend(SET_F(",1"));
|
||||
#endif
|
||||
oappend(SET_F(",6,7,8,9,10,11];")); // flash memory pins
|
||||
#else
|
||||
oappend(SET_F("];"));
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(WLED_MAX_BUSSES) && WLED_MAX_BUSSES>1
|
||||
oappend(SET_F("addLEDs("));
|
||||
oappend(itoa(WLED_MAX_BUSSES,nS,10));
|
||||
oappend(SET_F(");"));
|
||||
oappend(SET_F("addLEDs("));
|
||||
oappendi(WLED_MAX_BUSSES);
|
||||
oappend(SET_F(");"));
|
||||
#endif
|
||||
|
||||
oappend(SET_F("d.Sf.LC.max=")); //TODO Formula for max LEDs on ESP8266 depending on types. 500 DMA or 1500 UART (about 4kB mem usage)
|
||||
#if defined(ESP8266) && LEDPIN == 3
|
||||
oappendi(MAX_LEDS_DMA);
|
||||
#else
|
||||
oappend(SET_F("d.LCmax="));
|
||||
oappendi(MAX_LEDS);
|
||||
#endif
|
||||
oappend(";");
|
||||
#ifdef ESP8266
|
||||
oappend(SET_F("d.LDmax="));
|
||||
oappendi(MAX_LEDS_DMA);
|
||||
oappend(";");
|
||||
#endif
|
||||
|
||||
sappend('v',SET_F("LC"),ledCount);
|
||||
// sappend('v',SET_F("LC"),ledCount);
|
||||
|
||||
for (uint8_t s=0; s < busses.getNumBusses(); s++){
|
||||
Bus* bus = busses.getBus(s);
|
||||
@ -297,16 +315,18 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
char lt[4] = "LT"; lt[2] = 48+s; lt[3] = 0; //strip type
|
||||
char ls[4] = "LS"; ls[2] = 48+s; ls[3] = 0; //strip start LED
|
||||
char cv[4] = "CV"; cv[2] = 48+s; cv[3] = 0; //strip reverse
|
||||
char ew[4] = "EW"; ew[2] = 48+s; ew[3] = 0; //strip RGBW override
|
||||
oappend(SET_F("addLEDs(1);"));
|
||||
uint8_t pins[5];
|
||||
uint8_t nPins = bus->getPins(pins);
|
||||
sappend('v', lp, pins[0]);
|
||||
if (pinManager.isPinOk(pins[1])) sappend('v', lk, pins[1]);
|
||||
sappend('v', lc, bus->getLength());
|
||||
sappend('v',lc,bus->getLength());
|
||||
sappend('v',lt,bus->getType());
|
||||
sappend('v',co,bus->getColorOrder());
|
||||
sappend('v',ls,bus->getStart());
|
||||
sappend('c',cv,bus->reversed);
|
||||
sappend('c',ew,bus->isRgbw());
|
||||
}
|
||||
sappend('v',SET_F("MA"),strip.ablMilliampsMax);
|
||||
sappend('v',SET_F("LA"),strip.milliampsPerLed);
|
||||
@ -336,7 +356,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
sappend('v',SET_F("TL"),nightlightDelayMinsDefault);
|
||||
sappend('v',SET_F("TW"),nightlightMode);
|
||||
sappend('i',SET_F("PB"),strip.paletteBlend);
|
||||
sappend('c',SET_F("RV"),strip.reverseMode);
|
||||
// sappend('c',SET_F("RV"),strip.reverseMode);
|
||||
sappend('c',SET_F("SL"),skipFirstLed);
|
||||
sappend('v',SET_F("RL"),rlyPin);
|
||||
sappend('c',SET_F("RM"),rlyMde);
|
||||
|
Loading…
Reference in New Issue
Block a user